void TcpSrc::rtx_timer_hook(simtime_picosec now) { if (_highest_sent == 0) return; if (now <= _last_sent_time + timeFromMs(1000)) return; // RTX timer expired if (_logger) _logger->logTcp(*this, TcpLogger::TCP_TIMEOUT); if (_in_fast_recovery) { uint32_t flightsize = _highest_sent - _last_acked; _cwnd = min(_ssthresh, flightsize + _mss); } _ssthresh = max(_cwnd/2, (uint32_t)(2 * _mss)); _cwnd = _mss; _unacked = _cwnd; _effcwnd = _cwnd; _in_fast_recovery = false; _recoverq = _highest_sent; _highest_sent = _last_acked + _mss; _dupacks = 0; retransmit_packet(); //reset rtx timer _last_sent_time = now; }
void TcpSrc::receivePacket(Packet& pkt) { TcpAck *p = (TcpAck*)(&pkt); TcpAck::seq_t seqno = p->ackno(); pkt.flow().logTraffic(pkt,*this,TrafficLogger::PKT_RCVDESTROY); p->free(); assert(seqno >= _last_acked); // no dups or reordering allowed in this simple simulator if (seqno > _last_acked) { // a brand new ack if (!_in_fast_recovery) { // best behaviour: proper ack of a new packet, when we were expecting it _last_acked = seqno; _dupacks = 0; inflate_window(); _unacked = _cwnd; _effcwnd = _cwnd; if (_logger) _logger->logTcp(*this, TcpLogger::TCP_RCV); send_packets(); return; } // We're in fast recovery, i.e. one packet has been // dropped but we're pretending it's not serious if (seqno >= _recoverq) { // got ACKs for all the "recovery window": resume // normal service uint32_t flightsize = _highest_sent - seqno; _cwnd = min(_ssthresh, flightsize + _mss); _unacked = _cwnd; _effcwnd = _cwnd; _last_acked = seqno; _dupacks = 0; _in_fast_recovery = false; if (_logger) _logger->logTcp(*this, TcpLogger::TCP_RCV_FR_END); send_packets(); return; } // In fast recovery, and still getting ACKs for the // "recovery window" // This is dangerous. It means that several packets // got lost, not just the one that triggered FR. uint32_t new_data = seqno - _last_acked; _last_acked = seqno; if (new_data < _cwnd) _cwnd -= new_data; else _cwnd=0; _cwnd += _mss; if (_logger) _logger->logTcp(*this, TcpLogger::TCP_RCV_FR); retransmit_packet(); send_packets(); return; } // It's a dup ack if (_in_fast_recovery) { // still in fast recovery; hopefully the prodigal ACK is on it's way _cwnd += _mss; if (_cwnd>_maxcwnd) _cwnd = _maxcwnd; // When we restart, the window will be set to // min(_ssthresh, flightsize+_mss), so keep track of // this _unacked = min(_ssthresh, _highest_sent-_recoverq+_mss); if (_last_acked+_cwnd >= _highest_sent+_mss) _effcwnd=_unacked; // starting to send packets again if (_logger) _logger->logTcp(*this, TcpLogger::TCP_RCV_DUP_FR); send_packets(); return; } // Not yet in fast recovery. What should we do instead? _dupacks++; if (_dupacks!=3) { // not yet serious worry if (_logger) _logger->logTcp(*this, TcpLogger::TCP_RCV_DUP); send_packets(); return; } // _dupacks==3 if (_last_acked < _recoverq) { //See RFC 3782: if we haven't //recovered from timeouts //etc. don't do fast recovery if (_logger) _logger->logTcp(*this, TcpLogger::TCP_RCV_3DUPNOFR); return; } // begin fast recovery _ssthresh = max(_cwnd/2, (uint32_t)(2 * _mss)); retransmit_packet(); _cwnd = _ssthresh + 3 * _mss; _unacked = _ssthresh; _effcwnd = 0; _in_fast_recovery = true; _recoverq = _highest_sent; // _recoverq is the value of the // first ACK that tells us things // are back on track if (_logger) _logger->logTcp(*this, TcpLogger::TCP_RCV_DUP_FASTXMIT); }
/* * Send a message to the other end of the socket. * * The send call should block until the remote host has ACKnowledged receipt of * the message. This does not necessarily imply that the application has called * 'minisocket_receive', only that the packet is buffered pending a future * receive. * * It is expected that the order of calls to 'minisocket_send' implies the order * in which the concatenated messages will be received. * * 'minisocket_send' should block until the whole message is reliably * transmitted or an error/timeout occurs * * Arguments: the socket on which the communication is made (socket), the * message to be transmitted (msg) and its length (len). * Return value: returns the number of successfully transmitted bytes. Sets the * error code and returns -1 if an error is encountered. */ int minisocket_send(minisocket_t socket, minimsg_t msg, int len, minisocket_error *error) { int result, send_len; int bytes_sent; mini_header_reliable_t header; //DEBUG // char* the_msg = (char*) msg; // printf("msg: %s length of msg to send: %i\n", msg, len); // Check for valid arguments if (socket == NULL) { fprintf(stderr, "ERROR: minisocket_send() passed NULL minisocket_t\n"); *error = SOCKET_INVALIDPARAMS; // semaphore_V(skt_mutex); return -1; } if (msg == NULL) { fprintf(stderr, "ERROR: minisocket_send() passed NULL minimsg_t\n"); *error = SOCKET_INVALIDPARAMS; // semaphore_V(skt_mutex); return -1; } // Allocate new header header = malloc(sizeof(struct mini_header_reliable)); if (header == NULL) { // Could not allocate header fprintf(stderr, "ERROR: minisocket_send() failed to malloc new mini_header_reliable\n"); *error = SOCKET_OUTOFMEMORY; // semaphore_V(skt_mutex); return -1; } // Exclude other threads from sending from the same socket while I'm sending semaphore_P(socket->sending); bytes_sent = 0; // Fragment long messages into smaller packets while (bytes_sent < len) { socket->seqnum++; send_len = ((len - bytes_sent) > MAX_NETWORK_PKT_SIZE) ? MAX_NETWORK_PKT_SIZE : (len - bytes_sent); // Length of data to send in this packet set_header(socket, header, MSG_ACK); // printf("Message abt to be sent, length of it: (%s, %i)\n", the_msg[0](char*) msg, send_len); result = retransmit_packet(socket, (char*) header, send_len, (/*(char*)*/ msg) + bytes_sent, error); if (result == 1) { // ACK received (packet send successfully) bytes_sent += send_len; } else if (result == 0) { // All timeout attempts failed - close connection semaphore_V(socket->sending); minisocket_close(socket); return -1; } else { // Generic failure semaphore_V(socket->sending); return -1; } } semaphore_V(socket->sending); return 0; }
/* * Listen for a connection from somebody else. When communication link is * created return a minisocket_t through which the communication can be made * from now on. * * The argument "port" is the port number on the local machine to which the * client will connect. * * Return value: the minisocket_t created, otherwise NULL with the errorcode * stored in the "error" variable. */ minisocket_t minisocket_server_create(int port, minisocket_error *error) { minisocket_t socket; // char* buffer; // int syn_done; int /*send_attempts, timeout,*/ received_ACK; // network_address_t dest, my_address; mini_header_reliable_t hdr; // Header for sending MSG_SYNACK message // network_interrupt_arg_t* packet = NULL; // semaphore_P(skt_mutex); // Check for available ports if (used_server_ports >= NUM_SERVER_PORTS) { fprintf(stderr, "ERROR: minisocket_server_create() unable to execute since no available ports exist\n"); *error = SOCKET_NOMOREPORTS; // semaphore_V(skt_mutex); return NULL; } // Check for valid arguments if (port < SERVER_MIN_PORT || port > SERVER_MAX_PORT) { fprintf(stderr, "ERROR: minisocket_server_create() passed invalid port number\n"); *error = SOCKET_INVALIDPARAMS; // semaphore_V(skt_mutex); return NULL; } if (sockets[port] != NULL) { fprintf(stderr, "ERROR: minisocket_server_create() passed port already in use\n"); *error = SOCKET_PORTINUSE; // semaphore_V(skt_mutex); return NULL; } // Allocate new minisocket socket = malloc(sizeof(struct minisocket)); if (socket == NULL) { // Could not allocate minisocket fprintf(stderr, "ERROR: minisocket_server_create() failed to malloc new minisocket\n"); *error = SOCKET_OUTOFMEMORY; // semaphore_V(skt_mutex); return NULL; } // Set fields in minisocket socket->active = 0; socket->local_port = port; socket->datagrams_ready = semaphore_create(); semaphore_initialize(socket->datagrams_ready, 0); socket->sending = semaphore_create(); semaphore_initialize(socket->sending, 1); socket->receiving = semaphore_create(); semaphore_initialize(socket->receiving, 1); socket->timeout = semaphore_create(); semaphore_initialize(socket->timeout, 0); socket->wait_syn = semaphore_create(); semaphore_initialize(socket->wait_syn, 0); socket->incoming_data = queue_new(); socket->seqnum = 0; socket->acknum = 0; socket->alarm = NULL; sockets[port] = socket; // Add socket to socket ports array used_server_ports++; // Increment server-ports-in-use counter semaphore_P(socket->wait_syn); semaphore_initialize(socket->wait_syn, 0); // Handle case when count may be increased excessively due to extra packets coming in(?) // Send SYNACK w/ 7 retries // Allocate new header for SYNACK packet hdr = malloc(sizeof(struct mini_header_reliable)); if (hdr == NULL) { // Could not allocate header fprintf(stderr, "ERROR: minisocket_server_create() failed to malloc new mini_header_reliable\n"); *error = SOCKET_OUTOFMEMORY; // semaphore_V(skt_mutex); return NULL; } socket->seqnum++; // Assemble packet header set_header(socket, hdr, MSG_SYNACK); // Send SYNACK packet, expect empty ACK packet received_ACK = retransmit_packet(socket, (char*) hdr, 0, NULL, error); // semaphore_V(skt_mutex); if (received_ACK == 1) { socket->alarm = NULL; //No active retransmission alarm *error = SOCKET_NOERROR; return socket; } else { *error = SOCKET_RECEIVEERROR; return NULL; } }
/* * Initiate the communication with a remote site. When communication is * established create a minisocket through which the communication can be made * from now on. * * The first argument is the network address of the remote machine. * * The argument "port" is the port number on the remote machine to which the * connection is made. The port number of the local machine is one of the free * port numbers. * * Return value: the minisocket_t created, otherwise NULL with the errorcode * stored in the "error" variable. */ minisocket_t minisocket_client_create(network_address_t addr, int port, minisocket_error *error) { minisocket_t socket; // char* buffer; int local_port = CLIENT_MIN_PORT; // int synack_done; int /*send_attempts, timeout,*/ received_SYNACK; // network_address_t dest, my_address; mini_header_reliable_t hdr; // Header for sending MSG_SYNACK message // network_interrupt_arg_t* packet = NULL; // semaphore_P(skt_mutex); // Check for available ports if (used_client_ports >= NUM_CLIENT_PORTS) { fprintf(stderr, "ERROR: minisocket_client_create() unable to execute since no available ports exist\n"); *error = SOCKET_NOMOREPORTS; // semaphore_V(skt_mutex); return NULL; } // Check for valid arguments if (addr == NULL) { fprintf(stderr, "ERROR: minisocket_client_create() passed NULL network_address_t\n"); *error = SOCKET_INVALIDPARAMS; // semaphore_V(skt_mutex); return NULL; } if (port < SERVER_MIN_PORT || port > SERVER_MAX_PORT) { fprintf(stderr, "ERROR: minisocket_client_create() passed invalid remote port number\n"); *error = SOCKET_INVALIDPARAMS; // semaphore_V(skt_mutex); return NULL; } if (sockets[local_port] != NULL) { fprintf(stderr, "ERROR: minisocket_client_create() passed port already in use\n"); *error = SOCKET_PORTINUSE; // semaphore_V(skt_mutex); return NULL; } // Allocate new minisocket socket = malloc(sizeof(struct minisocket)); if (socket == NULL) { // Could not allocate minisocket fprintf(stderr, "ERROR: minisocket_client_create() failed to malloc new minisocket\n"); *error = SOCKET_OUTOFMEMORY; // semaphore_V(skt_mutex); return NULL; } // Find next unused local port (guaranteed to exist due to counter and verification) while (local_port <= CLIENT_MAX_PORT && sockets[local_port] != NULL) { local_port++; } if (sockets[local_port] != NULL) { fprintf(stderr, "ERROR: minisocket_client_create() ran out of available ports unexpectedly\n"); *error = SOCKET_NOMOREPORTS; // semaphore_V(skt_mutex); return NULL; } // Set fields in minisocket socket->active = 1; socket->local_port = local_port; socket->remote_port = port; network_address_copy(addr, socket->dest_address); socket->datagrams_ready = semaphore_create(); semaphore_initialize(socket->datagrams_ready, 0); socket->sending = semaphore_create(); semaphore_initialize(socket->sending, 1); socket->receiving = semaphore_create(); semaphore_initialize(socket->receiving, 1); socket->timeout = semaphore_create(); semaphore_initialize(socket->timeout, 0); socket->wait_syn = semaphore_create(); semaphore_initialize(socket->wait_syn, 0); socket->incoming_data = queue_new(); socket->seqnum = 0; socket->acknum = 0; socket->alarm = NULL; sockets[local_port] = socket; // Add socket to socket ports array used_client_ports++; // Increment client-ports-in-use counter // Send MSG_SYN packet to server // Wait timeout, if no response, repeat 7 more times (7 retries) // Allocate new header for SYN packet hdr = malloc(sizeof(struct mini_header_reliable)); if (hdr == NULL) { // Could not allocate header fprintf(stderr, "ERROR: minisocket_client_create() failed to malloc new mini_header_reliable\n"); *error = SOCKET_OUTOFMEMORY; // semaphore_V(skt_mutex); return NULL; } socket->seqnum++; // Assemble packet header set_header(socket, hdr, MSG_SYN); // Send SYN packet, expect SYNACK packet received_SYNACK = retransmit_packet(socket, (char*) hdr, 0, NULL, error); // semaphore_V(skt_mutex); if (received_SYNACK) { *error = SOCKET_NOERROR; return socket; } else { socket->active = 0; *error = SOCKET_RECEIVEERROR; return NULL; } }