Пример #1
0
//Transmit a packet and handle retransmission attempts
int transmit_packet(minisocket_t socket, network_address_t dst_addr, int dst_port, 
		short incr_seq, char message_type, int data_len, char* data,
		minisocket_error* error)
{
	mini_header_reliable_t newReliableHeader;

	void *alarmId;
	int sendSucessful;
	network_address_t my_addr;
	int success = 0;
	int connected = 0;
	if (message_type == MSG_ACK)
		connected = 1;

	network_get_my_address(my_addr);

	if (socket == NULL)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	if (socket->status == TCP_PORT_CLOSING)
	{
		*error = SOCKET_SENDERROR;
		return -1;
	}

	newReliableHeader = create_reliable_header(my_addr, socket->port_number, dst_addr,
			dst_port, message_type, socket->seq_number, socket->ack_number);

	socket->timeout = 100;
	while(socket->timeout <= 6400)
	{
		printf("sending packet to %d, seq=%d, ack=%d, type=%d\n", dst_port, socket->seq_number, socket->ack_number, message_type);
		sendSucessful = network_send_pkt(dst_addr, sizeof(struct mini_header_reliable),
				(char*) newReliableHeader, data_len, (char*) data);

		if (sendSucessful == -1)
		{
			socket->timeout *= 2;
			continue;
		}



		alarmId = register_alarm(socket->timeout, &wake_up_semaphore, socket);
		if (message_type == MSG_SYN)
		{
			socket->waiting = TCP_PORT_WAITING_SYNACK;
			semaphore_P(socket->wait_for_ack_semaphore);
		}
		else if (!connected)
		{
			socket->waiting = TCP_PORT_WAITING_ACK;
			semaphore_P(socket->wait_for_ack_semaphore);
		}
		else {
			socket->waiting = TCP_PORT_WAITING_NONE;
		}

		semaphore_P(socket->mutex);
		if (socket->waiting == TCP_PORT_WAITING_NONE)
		{
/* I think incr_seq belongs before the _P on wait_for_ack, but that breaks it for now :/
			if (incr_seq)
			{
				semaphore_P(socket->mutex);
				socket->seq_number++;
				semaphore_V(socket->mutex);
			}
*/			if (message_type == MSG_SYN)
			{
				//we got a synack back, so we need to make sure to send an ack to the server
				newReliableHeader = create_reliable_header(my_addr, socket->port_number, dst_addr,
				dst_port, MSG_ACK, socket->seq_number, socket->ack_number);
				socket->timeout = 100;
				message_type = MSG_ACK;
				connected = 1;
				semaphore_V(socket->mutex);
				continue;
			}

			deregister_alarm(alarmId);
			success = 1;
			semaphore_V(socket->mutex);
			break;
		}
		else
		{
			if (socket->status == TCP_PORT_UNABLE_TO_CONNECT)
			{
				deregister_alarm(alarmId);
				success = 0;
				semaphore_V(socket->mutex);
				break;
			}
			socket->timeout *= 2;
			semaphore_V(socket->mutex);
		}
	}

	semaphore_P(socket->mutex);
	socket->timeout = 100;
	if (success == 0)
	{
		socket->waiting = TCP_PORT_WAITING_NONE;
		*error = SOCKET_NOSERVER;
	}
	semaphore_V(socket->mutex);
	*error = SOCKET_NOERROR;
	free(newReliableHeader);
	return 0;
}
Пример #2
0
/* Transmit a packet and handle retransmissions */
int transmit_packet(minisocket_t socket, network_address_t dst_addr, int dst_port, 
					short incr_seq, char message_type, int data_len, char* data,
					minisocket_error* error)
{
	mini_header_reliable_t header;
	int alarm_id;
	short success = 0;
	network_address_t my_addr;
	int send_ret;
	interrupt_level_t prev_level;
	network_get_my_address(my_addr);
	
	// Return if the socket is invalid
	if (socket == NULL)
	{
		*error = SOCKET_INVALIDPARAMS;
		return -1;
	}

	// Don't allow new packets to be transmitted if the port's closing
	if (socket->status == TCP_PORT_CLOSING)
	{
		*error = SOCKET_SENDERROR;
		return -1;
	}

	// Increment the seq# if needed
	if (incr_seq == 1)
	{
		socket->seq_num++;
	}

	// Create the header
	header = create_reliable_header(my_addr, socket->port_number, dst_addr,
									dst_port, message_type, socket->seq_num, 
									socket->ack_num);


	// Can retransmit for each timeout up to 6400 (100 + 200 + 400 + ... + 6400 = 12.7s)
	socket->timeout = 100;
	while (socket->timeout <= 6400) 
	{
		// send the packet
		send_ret = network_send_pkt(dst_addr, sizeof(struct mini_header_reliable), 
									(char*) header, data_len, (char*) data);

		// Check if there was an error sending
		if (send_ret == -1)
		{
			// Could've been a fluke, let it keep going
			continue;
		}

		// Seq # is count of retransmissable packets... if dont increment it,
		// then this isn't retransmissable, so end
		if (incr_seq == 0)
		{
			free(header);
			return 0;
		}

		// Set an alarm to wake us up after timeout
		alarm_id = register_alarm(socket->timeout, &wake_up_sem, socket);

		// Specify the type of packet we're waiting for
		if (message_type == MSG_SYN)
		{
			socket->waiting = TCP_PORT_WAITING_SYNACK;
		}
		 else
		{
			socket->waiting = TCP_PORT_WAITING_ACK;
		}

		// Sleep on semaphore
		prev_level = set_interrupt_level(DISABLED);
		semaphore_P(socket->wait_for_ack_sem);
		set_interrupt_level(prev_level);

		// Check if we got the packet when we've awoken
		if (socket->waiting == TCP_PORT_WAITING_NONE)
		{
			// Yes, we did - delete the alarm and break out of the loop
			deregister_alarm(alarm_id);
			success = 1;
			break;
		}	
		 else
		{
			if (socket->status == TCP_PORT_COULDNT_CONNECT)
			{
				// This means the client sent a FIN while we were trying to connect
				success = 0;
				deregister_alarm(alarm_id);
				break;
			} 

			// No, we didn't - double the timeout and repeat if we can
			socket->timeout *= 2;
		}
	}

	// So the IH knows the sequence is done (see comment block in network_common:170)
	// There is a small chance that the code around network_common:170 won't catch
	// this in time and won't send one last packet - that is okay, as Prof. Sirer
	// mentioned sending that packet isn't even necessary in the first place.
	socket->timeout = 100;

	// Free the header as it's no longer needed
	free(header);

	// If we weren't successful...
	if (success == 0)
	{
		// Decrement the seq# if we incremented it earlier
		if (incr_seq == 1)
		{
			socket->seq_num--;
		}

		// Reset the socket's waiting status
		socket->waiting = TCP_PORT_WAITING_NONE;

		// Set the error & return
		*error = SOCKET_NOSERVER;
		return -1;
	}

	return 0;
}