CS144Lab/libsponge/tcp_helpers/fd_adapter.cc
2021-10-19 18:08:12 -07:00

58 lines
2.0 KiB
C++

#include "fd_adapter.hh"
#include <iostream>
#include <stdexcept>
#include <utility>
using namespace std;
//! \details This function first attempts to parse a TCP segment from the next UDP
//! payload recv()d from the socket.
//!
//! If this succeeds, it then checks that the received segment is related to the
//! current connection. When a TCP connection has been established, this means
//! checking that the source and destination ports in the TCP header are correct.
//!
//! If the TCP FSM is listening (i.e., TCPOverUDPSocketAdapter::_listen is `true`)
//! and the TCP segment read from the wire includes a SYN, this function clears the
//! `_listen` flag and calls calls connect() on the underlying UDP socket, with
//! the result that future outgoing segments go to the sender of the SYN segment.
//! \returns a std::optional<TCPSegment> that is empty if the segment was invalid or unrelated
optional<TCPSegment> TCPOverUDPSocketAdapter::read() {
auto datagram = _sock.recv();
// is it for us?
if (not listening() and (datagram.source_address != config().destination)) {
return {};
}
// is the payload a valid TCP segment?
TCPSegment seg;
if (ParseResult::NoError != seg.parse(move(datagram.payload), 0)) {
return {};
}
// should we target this source in all future replies?
if (listening()) {
if (seg.header().syn and not seg.header().rst) {
config_mutable().destination = datagram.source_address;
set_listening(false);
} else {
return {};
}
}
return seg;
}
//! Serialize a TCP segment and send it as the payload of a UDP datagram.
//! \param[in] seg is the TCP segment to write
void TCPOverUDPSocketAdapter::write(TCPSegment &seg) {
seg.header().sport = config().source.port();
seg.header().dport = config().destination.port();
_sock.sendto(config().destination, seg.serialize(0));
}
//! Specialize LossyFdAdapter to TCPOverUDPSocketAdapter
template class LossyFdAdapter<TCPOverUDPSocketAdapter>;