Sponge
CS144's user-space TCP library
tcp_ip_ethernet.cc
Go to the documentation of this file.
2 #include "tcp_config.hh"
3 #include "tcp_sponge_socket.hh"
4 #include "tun.hh"
5 
6 #include <cstdint>
7 #include <cstdlib>
8 #include <cstring>
9 #include <iostream>
10 #include <random>
11 #include <string>
12 #include <tuple>
13 
14 using namespace std;
15 
16 constexpr const char *TAP_DFLT = "tap10";
17 const string LOCAL_ADDRESS_DFLT = "169.254.10.9";
18 const string GATEWAY_DFLT = "169.254.10.1";
19 
20 static void show_usage(const char *argv0, const char *msg) {
21  cout << "Usage: " << argv0 << " [options] <host> <port>\n\n"
22  << " Option Default\n"
23  << " -- --\n\n"
24 
25  << " -a <addr> Set IP source address (client mode only) " << LOCAL_ADDRESS_DFLT << "\n"
26  << " -s <port> Set TCP source port (client mode only) (random)\n\n"
27  << " -n <addr> Set IP next-hop address " << GATEWAY_DFLT << "\n"
28 
29  << " -w <winsz> Use a window of <winsz> bytes " << TCPConfig::MAX_PAYLOAD_SIZE
30  << "\n\n"
31 
32  << " -t <tmout> Set rt_timeout to tmout " << TCPConfig::TIMEOUT_DFLT << "\n\n"
33 
34  << " -d <tapdev> Connect to tap <tapdev> " << TAP_DFLT << "\n\n"
35 
36  << " -h Show this message.\n\n";
37 
38  if (msg != nullptr) {
39  cout << msg;
40  }
41  cout << endl;
42 }
43 
44 static void check_argc(int argc, char **argv, int curr, const char *err) {
45  if (curr + 3 >= argc) {
46  show_usage(argv[0], err);
47  exit(1);
48  }
49 }
50 
52  TCPConfig c_fsm{};
53  FdAdapterConfig c_filt{};
54  string tapdev = TAP_DFLT;
55 
56  int curr = 1;
57 
58  string source_address = LOCAL_ADDRESS_DFLT;
59  string source_port = to_string(uint16_t(random_device()()));
60  string next_hop_address = GATEWAY_DFLT;
61 
62  while (argc - curr > 2) {
63  if (strncmp("-a", argv[curr], 3) == 0) {
64  check_argc(argc, argv, curr, "ERROR: -a requires one argument.");
65  source_address = argv[curr + 1];
66  curr += 2;
67 
68  } else if (strncmp("-s", argv[curr], 3) == 0) {
69  check_argc(argc, argv, curr, "ERROR: -s requires one argument.");
70  source_port = argv[curr + 1];
71  curr += 2;
72 
73  } else if (strncmp("-n", argv[curr], 3) == 0) {
74  check_argc(argc, argv, curr, "ERROR: -n requires one argument.");
75  next_hop_address = argv[curr + 1];
76  curr += 2;
77 
78  } else if (strncmp("-w", argv[curr], 3) == 0) {
79  check_argc(argc, argv, curr, "ERROR: -w requires one argument.");
80  c_fsm.recv_capacity = strtol(argv[curr + 1], nullptr, 0);
81  curr += 2;
82 
83  } else if (strncmp("-t", argv[curr], 3) == 0) {
84  check_argc(argc, argv, curr, "ERROR: -t requires one argument.");
85  c_fsm.rt_timeout = strtol(argv[curr + 1], nullptr, 0);
86  curr += 2;
87 
88  } else if (strncmp("-d", argv[curr], 3) == 0) {
89  check_argc(argc, argv, curr, "ERROR: -t requires one argument.");
90  tapdev = argv[curr + 1];
91  curr += 2;
92 
93  } else if (strncmp("-h", argv[curr], 3) == 0) {
94  show_usage(argv[0], nullptr);
95  exit(0);
96 
97  } else {
98  show_usage(argv[0], string("ERROR: unrecognized option " + string(argv[curr])).c_str());
99  exit(1);
100  }
101  }
102 
103  // parse positional command-line arguments
104  c_filt.destination = {argv[curr], argv[curr + 1]};
105  c_filt.source = {source_address, source_port};
106 
107  Address next_hop{next_hop_address, "0"};
108 
109  return make_tuple(c_fsm, c_filt, next_hop, tapdev);
110 }
111 
112 int main(int argc, char **argv) {
113  try {
114  if (argc < 3) {
115  show_usage(argv[0], "ERROR: required arguments are missing.");
116  return EXIT_FAILURE;
117  }
118 
119  // choose a random local Ethernet address (and make sure it's private, i.e. not owned by a manufacturer)
120  EthernetAddress local_ethernet_address;
121  for (auto &byte : local_ethernet_address) {
122  byte = random_device()(); // use a random local Ethernet address
123  }
124  local_ethernet_address.at(0) |= 0x02; // "10" in last two binary digits marks a private Ethernet address
125  local_ethernet_address.at(0) &= 0xfe;
126 
127  auto [c_fsm, c_filt, next_hop, tap_dev_name] = get_config(argc, argv);
128 
130  TCPOverIPv4OverEthernetAdapter(TapFD(tap_dev_name), local_ethernet_address, c_filt.source, next_hop)));
131 
132  tcp_socket.connect(c_fsm, c_filt);
133 
134  bidirectional_stream_copy(tcp_socket);
135  tcp_socket.wait_until_closed();
136  } catch (const exception &e) {
137  cerr << "Exception: " << e.what() << endl;
138  return EXIT_FAILURE;
139  }
140 
141  return EXIT_SUCCESS;
142 }
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
GATEWAY_DFLT
const string GATEWAY_DFLT
Definition: tcp_ip_ethernet.cc:18
std::exception
std::tuple
check_argc
static void check_argc(int argc, char **argv, int curr, const char *err)
Definition: tcp_ip_ethernet.cc:44
Address
Wrapper around IPv4 addresses and DNS operations.
Definition: address.hh:13
LOCAL_ADDRESS_DFLT
const string LOCAL_ADDRESS_DFLT
Definition: tcp_ip_ethernet.cc:17
FdAdapterConfig
Config for classes derived from FdAdapter.
Definition: tcp_config.hh:26
tcp_config.hh
std::random_device
std::cout
tun.hh
std::to_string
T to_string(T... args)
std::array
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
TCPOverIPv4OverEthernetAdapter
A FD adapter for IPv4 datagrams read from and written to a TAP device.
Definition: tuntap_adapter.hh:44
get_config
static tuple< TCPConfig, FdAdapterConfig, Address, string > get_config(int argc, char **argv)
Definition: tcp_ip_ethernet.cc:51
std::uint16_t
TCPConfig
Config for TCP sender and receiver.
Definition: tcp_config.hh:12
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)
std
main
int main(int argc, char **argv)
Definition: tcp_ip_ethernet.cc:112
TCPConfig::TIMEOUT_DFLT
static constexpr uint16_t TIMEOUT_DFLT
Default re-transmit timeout is 1 second.
Definition: tcp_config.hh:16
TAP_DFLT
constexpr const char * TAP_DFLT
Definition: tcp_ip_ethernet.cc:16
TapFD
A FileDescriptor to a Linux TAP device.
Definition: tun.hh:23
show_usage
static void show_usage(const char *argv0, const char *msg)
Definition: tcp_ip_ethernet.cc:20
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