Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
/* 
 * 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;
}
Ejemplo n.º 4
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;
	}
}
Ejemplo n.º 5
0
/*
 * 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;
	}
}