Sponge
CS144's user-space TCP library
bidirectional_stream_copy.cc
Go to the documentation of this file.
2 
3 #include "byte_stream.hh"
4 #include "eventloop.hh"
5 
6 #include <algorithm>
7 #include <iostream>
8 #include <unistd.h>
9 
10 using namespace std;
11 
13  constexpr size_t max_copy_length = 65536;
14  constexpr size_t buffer_size = 1048576;
15 
16  EventLoop _eventloop{};
17  FileDescriptor _input{STDIN_FILENO};
18  FileDescriptor _output{STDOUT_FILENO};
19  ByteStream _outbound{buffer_size};
20  ByteStream _inbound{buffer_size};
21  bool _outbound_shutdown{false};
22  bool _inbound_shutdown{false};
23 
24  socket.set_blocking(false);
25  _input.set_blocking(false);
26  _output.set_blocking(false);
27 
28  // rule 1: read from stdin into outbound byte stream
29  _eventloop.add_rule(
30  _input,
32  [&] {
33  _outbound.write(_input.read(_outbound.remaining_capacity()));
34  if (_input.eof()) {
35  _outbound.end_input();
36  }
37  },
38  [&] { return (not _outbound.error()) and (_outbound.remaining_capacity() > 0) and (not _inbound.error()); },
39  [&] { _outbound.end_input(); });
40 
41  // rule 2: read from outbound byte stream into socket
42  _eventloop.add_rule(socket,
44  [&] {
45  const size_t bytes_to_write = min(max_copy_length, _outbound.buffer_size());
46  const size_t bytes_written = socket.write(_outbound.peek_output(bytes_to_write), false);
47  _outbound.pop_output(bytes_written);
48  if (_outbound.eof()) {
49  socket.shutdown(SHUT_WR);
50  _outbound_shutdown = true;
51  }
52  },
53  [&] { return (not _outbound.buffer_empty()) or (_outbound.eof() and not _outbound_shutdown); },
54  [&] { _outbound.set_error(); });
55 
56  // rule 3: read from socket into inbound byte stream
57  _eventloop.add_rule(
58  socket,
60  [&] {
61  _inbound.write(socket.read(_inbound.remaining_capacity()));
62  if (socket.eof()) {
63  _inbound.end_input();
64  }
65  },
66  [&] { return (not _inbound.error()) and (_inbound.remaining_capacity() > 0) and (not _outbound.error()); },
67  [&] { _inbound.end_input(); });
68 
69  // rule 4: read from inbound byte stream into stdout
70  _eventloop.add_rule(_output,
72  [&] {
73  const size_t bytes_to_write = min(max_copy_length, _inbound.buffer_size());
74  const size_t bytes_written = _output.write(_inbound.peek_output(bytes_to_write), false);
75  _inbound.pop_output(bytes_written);
76 
77  if (_inbound.eof()) {
78  _output.close();
79  _inbound_shutdown = true;
80  }
81  },
82  [&] { return (not _inbound.buffer_empty()) or (_inbound.eof() and not _inbound_shutdown); },
83  [&] { _inbound.set_error(); });
84 
85  // loop until completion
86  while (true) {
87  if (EventLoop::Result::Exit == _eventloop.wait_next_event(-1)) {
88  return;
89  }
90  }
91 }
bidirectional_stream_copy.hh
EventLoop
Waits for events on file descriptors and executes corresponding callbacks.
Definition: eventloop.hh:12
EventLoop::Direction::Out
@ Out
Callback will be triggered when Rule::fd is writable.
if
if(out0 !=0x32||out1 !=val1||out2 !=val2||out3 !=val3||out4 !=val4)
Definition: parser_example.cc:30
FileDescriptor
A reference-counted handle to a file descriptor.
Definition: file_descriptor.hh:12
byte_stream.hh
eventloop.hh
ByteStream
An in-order byte stream.
Definition: byte_stream.hh:11
bidirectional_stream_copy
void bidirectional_stream_copy(Socket &socket)
Copy socket input/output to stdin/stdout until finished.
Definition: bidirectional_stream_copy.cc:12
std::min
T min(T... args)
std
Socket
Base class for network sockets (TCP, UDP, etc.)
Definition: socket.hh:14
EventLoop::Result::Exit
@ Exit
All rules have been canceled or were uninterested; make no further calls to EventLoop::wait_next_even...
EventLoop::Direction::In
@ In
Callback will be triggered when Rule::fd is readable.