Sponge
CS144's user-space TCP library
tcp_udp.cc
Go to the documentation of this file.
2 #include "tcp_config.hh"
3 #include "tcp_sponge_socket.hh"
4 
5 #include <cstdlib>
6 #include <cstring>
7 #include <iostream>
8 #include <limits>
9 #include <random>
10 #include <string>
11 #include <tuple>
12 
13 using namespace std;
14 
15 constexpr uint16_t DPORT_DFLT = 1440;
16 
17 static void show_usage(const char *argv0, const char *msg) {
18  cout << "Usage: " << argv0 << " [options] <host> <port>\n\n"
19 
20  << " Option Default\n"
21  << " -- --\n\n"
22 
23  << " -l Server (listen) mode. (client mode)\n"
24  << " In server mode, <host>:<port> is the address to bind.\n\n"
25 
26  << " -w <winsz> Use a window of <winsz> bytes " << TCPConfig::MAX_PAYLOAD_SIZE
27  << "\n\n"
28 
29  << " -t <tmout> Set rt_timeout to tmout " << TCPConfig::TIMEOUT_DFLT << "\n\n"
30 
31  << " -Lu <loss> Set uplink loss to <rate> (float in 0..1) (no loss)\n"
32  << " -Ld <loss> Set downlink loss to <rate> (float in 0..1) (no loss)\n\n"
33 
34  << " -h Show this message and quit.\n\n";
35 
36  if (msg != nullptr) {
37  cout << msg;
38  }
39  cout << endl;
40 }
41 
42 static void check_argc(int argc, char **argv, int curr, const char *err) {
43  if (curr + 3 >= argc) {
44  show_usage(argv[0], err);
45  exit(1);
46  }
47 }
48 
49 static tuple<TCPConfig, FdAdapterConfig, bool> get_config(int argc, char **argv) {
50  TCPConfig c_fsm{};
51  FdAdapterConfig c_filt{};
52 
53  int curr = 1;
54  bool listen = false;
55 
56  while (argc - curr > 2) {
57  if (strncmp("-l", argv[curr], 3) == 0) {
58  listen = true;
59  curr += 1;
60 
61  } else if (strncmp("-w", argv[curr], 3) == 0) {
62  check_argc(argc, argv, curr, "ERROR: -w requires one argument.");
63  c_fsm.recv_capacity = strtol(argv[curr + 1], nullptr, 0);
64  curr += 2;
65 
66  } else if (strncmp("-t", argv[curr], 3) == 0) {
67  check_argc(argc, argv, curr, "ERROR: -t requires one argument.");
68  c_fsm.rt_timeout = strtol(argv[curr + 1], nullptr, 0);
69  curr += 2;
70 
71  } else if (strncmp("-Lu", argv[curr], 3) == 0) {
72  check_argc(argc, argv, curr, "ERROR: -Lu requires one argument.");
73  float lossrate = strtof(argv[curr + 1], nullptr);
74  using LossRateUpT = decltype(c_filt.loss_rate_up);
75  c_filt.loss_rate_up =
76  static_cast<LossRateUpT>(static_cast<float>(numeric_limits<LossRateUpT>::max()) * lossrate);
77  curr += 2;
78 
79  } else if (strncmp("-Ld", argv[curr], 3) == 0) {
80  check_argc(argc, argv, curr, "ERROR: -Lu requires one argument.");
81  float lossrate = strtof(argv[curr + 1], nullptr);
82  using LossRateDnT = decltype(c_filt.loss_rate_dn);
83  c_filt.loss_rate_dn =
84  static_cast<LossRateDnT>(static_cast<float>(numeric_limits<LossRateDnT>::max()) * lossrate);
85  curr += 2;
86 
87  } else if (strncmp("-h", argv[curr], 3) == 0) {
88  show_usage(argv[0], nullptr);
89  exit(0);
90 
91  } else {
92  show_usage(argv[0], std::string("ERROR: unrecognized option " + std::string(argv[curr])).c_str());
93  exit(1);
94  }
95  }
96 
97  if (listen) {
98  c_filt.source = {"0", argv[argc - 1]};
99  } else {
100  c_filt.destination = {argv[argc - 2], argv[argc - 1]};
101  }
102 
103  return make_tuple(c_fsm, c_filt, listen);
104 }
105 
106 int main(int argc, char **argv) {
107  try {
108  if (argc < 3) {
109  show_usage(argv[0], "ERROR: required arguments are missing.");
110  exit(1);
111  }
112 
113  // handle configuration and UDP setup from cmdline arguments
114  auto [c_fsm, c_filt, listen] = get_config(argc, argv);
115 
116  // build a TCP FSM on top of the UDP socket
117  UDPSocket udp_sock;
118  if (listen) {
119  udp_sock.bind(c_filt.source);
120  }
122  if (listen) {
123  tcp_socket.listen_and_accept(c_fsm, c_filt);
124  } else {
125  tcp_socket.connect(c_fsm, c_filt);
126  }
127 
128  bidirectional_stream_copy(tcp_socket);
129  tcp_socket.wait_until_closed();
130  } catch (const exception &e) {
131  cerr << "Exception: " << e.what() << endl;
132  return EXIT_FAILURE;
133  }
134 
135  return EXIT_SUCCESS;
136 }
bidirectional_stream_copy.hh
std::strtol
T strtol(T... args)
TCPConfig::MAX_PAYLOAD_SIZE
static constexpr size_t MAX_PAYLOAD_SIZE
Max TCP payload that fits in either IPv4 or UDP datagram.
Definition: tcp_config.hh:15
std::make_tuple
T make_tuple(T... args)
TCPSpongeSocket::wait_until_closed
void wait_until_closed()
Definition: tcp_sponge_socket.cc:194
std::string
std::exception
std::move
T move(T... args)
get_config
static tuple< TCPConfig, FdAdapterConfig, bool > get_config(int argc, char **argv)
Definition: tcp_udp.cc:49
std::tuple
FdAdapterConfig
Config for classes derived from FdAdapter.
Definition: tcp_config.hh:26
tcp_config.hh
std::cout
show_usage
static void show_usage(const char *argv0, const char *msg)
Definition: tcp_udp.cc:17
listen
sock1 listen(1)
Socket::bind
void bind(const Address &address)
Bind a socket to a specified address with bind(2), usually for listen/accept.
Definition: socket.cc:61
TCPSpongeSocket::connect
void connect(const TCPConfig &c_tcp, const FdAdapterConfig &c_ad)
Connect using the specified configurations; blocks until connect succeeds or fails.
Definition: tcp_sponge_socket.cc:206
std::uint16_t
TCPConfig
Config for TCP sender and receiver.
Definition: tcp_config.hh:12
DPORT_DFLT
constexpr uint16_t DPORT_DFLT
Definition: tcp_udp.cc:15
TCPSpongeSocket::listen_and_accept
void listen_and_accept(const TCPConfig &c_tcp, const FdAdapterConfig &c_ad)
Listen and accept using the specified configurations; blocks until accept succeeds or fails.
Definition: tcp_sponge_socket.cc:234
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::strncmp
T strncmp(T... args)
std::endl
T endl(T... args)
UDPSocket
A wrapper around UDP sockets.
Definition: socket.hh:51
main
int main(int argc, char **argv)
Definition: tcp_udp.cc:106
std
std::strtof
T strtof(T... args)
check_argc
static void check_argc(int argc, char **argv, int curr, const char *err)
Definition: tcp_udp.cc:42
TCPConfig::TIMEOUT_DFLT
static constexpr uint16_t TIMEOUT_DFLT
Default re-transmit timeout is 1 second.
Definition: tcp_config.hh:16
TCPOverUDPSocketAdapter
A FD adaptor that reads and writes TCP segments in UDP payloads.
Definition: fd_adapter.hh:46
LossyTCPOverUDPSocketAdapter
LossyFdAdapter< TCPOverUDPSocketAdapter > LossyTCPOverUDPSocketAdapter
Typedef for TCPOverUDPSocketAdapter.
Definition: fd_adapter.hh:68
std::numeric_limits::max
T max(T... args)
tcp_sponge_socket.hh
std::exit
T exit(T... args)
std::exception::what
T what(T... args)
TCPSpongeSocket
Multithreaded wrapper around TCPConnection that approximates the Unix sockets API.
Definition: tcp_sponge_socket.hh:21