Exemple #1
0
// Create a packed reliable header given the parameters
mini_header_reliable_t create_reliable_header(network_address_t src_addr_raw, 
		int src_port_raw, network_address_t dst_addr_raw, int dst_port_raw, 
		char message_type, unsigned int seq_num_raw, unsigned int ack_num_raw) 
{
	mini_header_reliable_t header = (mini_header_reliable_t) malloc(sizeof(struct mini_header_reliable));
	//Fields
	char src_port[2];
	char dst_port[2];
	char src_addr[8];
	char dst_addr[8];
	char seq_num[4];
	char ack_num[4];

	//Pack everything
	pack_unsigned_short(src_port, (unsigned short) src_port_raw);
	pack_unsigned_short(dst_port, (unsigned short) dst_port_raw);
	pack_address(src_addr, src_addr_raw);
	pack_address(dst_addr, dst_addr_raw);
	pack_unsigned_int(seq_num, seq_num_raw);
	pack_unsigned_int(ack_num, ack_num_raw);

	//Set header fields
	header->protocol = (char) PROTOCOL_MINISTREAM;
	header->message_type = message_type;
	memcpy(header->source_address, src_addr, 8);
	memcpy(header->destination_address, dst_addr, 8);
	memcpy(header->source_port, src_port, 2);
	memcpy(header->destination_port, dst_port, 2);
	memcpy(header->seq_number, seq_num, 4);
	memcpy(header->ack_number, ack_num, 4);

	return header;
}
Exemple #2
0
static mini_header_reliable_t *create_control_header(int msg_type, unsigned int dest_port,
						    network_address_t dest_addr, unsigned int src_port,
						     unsigned int seq, unsigned int ack)
{
  mini_header_reliable_t *header = (mini_header_reliable_t *) malloc(sizeof(mini_header_reliable_t));
  if (!header) {
    return NULL;
  }
    
  header->protocol = PROTOCOL_MINISTREAM + '0';

  network_address_t local_addr;
  network_address_copy(local_host, local_addr);
  //network_get_my_address(local_addr);

  pack_address(header->source_address, local_addr);
  pack_unsigned_short(header->source_port, src_port);

  header->message_type = msg_type + '0';
  pack_address(header->destination_address, dest_addr);
  pack_unsigned_short(header->destination_port, dest_port);
  pack_unsigned_int(header->seq_number, seq); 
  pack_unsigned_int(header->ack_number, ack); 
  return header;
}
Exemple #3
0
/*
 * Pack header using the local receiving and sending ports.
 * Called by minimsg_sent.
 */
static void
minimsg_packhdr(mini_header_t hdr, miniport_t unbound, miniport_t bound)
{
    hdr->protocol = PROTOCOL_MINIDATAGRAM;
    pack_address(hdr->source_address, hostaddr);
    pack_unsigned_short(hdr->source_port, unbound->num);
    pack_address(hdr->destination_address, bound->bound.addr);
    pack_unsigned_short(hdr->destination_port, bound->bound.remote);
}
Exemple #4
0
/* Pack header for discovery packets */
static void
miniroute_pack_discovery_hdr(miniroute_header_t hdr, network_address_t dest)
{
    hdr->routing_packet_type = ROUTING_ROUTE_DISCOVERY;
    pack_address(hdr->destination, dest);
    pack_unsigned_int(hdr->id, discovery_id++);
    pack_unsigned_int(hdr->ttl, MAX_ROUTE_LENGTH);
    pack_unsigned_int(hdr->path_len, 1);
    pack_address(hdr->path[0], hostaddr);
}
int transmit_first(int* arg)
{
    char buffer[MINIMSG_MAX_MSG_SIZE + 10];
    int length = 0;
    int i;
    network_address_t hostaddr, targetaddr;
    miniport_t port;
    miniport_t dest;
    struct mini_header hdr;

    AbortOnCondition(network_translate_hostname(hostname, targetaddr) < 0,
                     "Could not resolve hostname, exiting.");

    port = miniport_create_unbound(0);
    dest = miniport_create_bound(targetaddr, 1);

    /* Form correct header */
    network_get_my_address(hostaddr);
    hdr.protocol = PROTOCOL_MINIDATAGRAM;
    pack_address(hdr.source_address, hostaddr);
    pack_unsigned_short(hdr.source_port, port->num);
    pack_address(hdr.destination_address, dest->bound.addr);
    pack_unsigned_short(hdr.destination_port, dest->bound.remote);

    /* Send packages with short but correct header and zero data */
    printf("Sending packages with short headers.\n");
    sprintf(buffer, "Receiving packages with short headers.\n");
    length = strlen(buffer) + 1;
    minimsg_send(port, dest, buffer, length);

    for (i = 0; i < MINIMSG_HDRSIZE; i++)
        network_send_pkt(targetaddr, i, (char*)&hdr, 0, buffer);

    /* Send packages to wrong ports */
    printf("Sending packages to wrong destination ports.\n");
    sprintf(buffer, "Receiving packages with wrong destination ports.\n");
    length = strlen(buffer) + 1;
    minimsg_send(port, dest, buffer, length);
    sprintf(buffer, "This message is sent to a wrong port.\n");
    length = strlen(buffer) + 1;
    minimsg_send(port, miniport_create_bound(targetaddr, 0),
                 buffer, length);
    minimsg_send(port, miniport_create_bound(targetaddr, MAX_UNBOUNDED),
                 buffer, length);
    minimsg_send(port, miniport_create_bound(targetaddr, MAX_UNBOUNDED + 1),
                 buffer, length);
    minimsg_send(port, miniport_create_bound(targetaddr, MIN_BOUNDED),
                 buffer, length);
    minimsg_send(port, miniport_create_bound(targetaddr, MAX_BOUNDED),
                 buffer, length);

    printf("Send-first finished.\n");

    return 0;
}
Exemple #6
0
/* Construct a (reliable) header to be sent by the given socket. */
void set_header(minisocket_t socket, mini_header_reliable_t hdr, char message_type) {
	network_address_t my_address;

	hdr->protocol = PROTOCOL_MINISTREAM; // Protocol
	network_get_my_address(my_address);
	pack_address(hdr->source_address, my_address); // Source address
	pack_unsigned_short(hdr->source_port, socket->local_port); // Source port
	pack_address(hdr->destination_address, socket->dest_address); // Destination address
	pack_unsigned_short(hdr->destination_port, socket->remote_port); // Destination port
	hdr->message_type = message_type; // Message type
	pack_unsigned_int(hdr->seq_number, socket->seqnum); // Sequence number
	pack_unsigned_int(hdr->ack_number, socket->acknum); // Acknowledgment number
}
Exemple #7
0
/* minisocket_send_ctrl creates an ctrl packet of type type and with
 * fields taken from the sock parameter.
 * This ack packet is sent over the network.
 * If there is an underlying network failure, error is updated
 * but the pkt is not resent.
 * The address of pkt is given as the data buffer, 
 * but no data from pkt is written since the data_len is 0.
 */ 
void minisocket_send_ctrl(char type, minisocket_t sock, minisocket_error* error) {
  struct mini_header_reliable pkt;
  pkt.protocol = PROTOCOL_MINISTREAM;
  pack_address(pkt.source_address, my_addr);
  pack_unsigned_short(pkt.source_port, sock->src_port);
  pack_address(pkt.destination_address, sock->dst_addr);
  pack_unsigned_short(pkt.destination_port, sock->dst_port);
  pkt.message_type = type;
  pack_unsigned_int(pkt.seq_number, sock->curr_seq);
  pack_unsigned_int(pkt.ack_number, sock->curr_ack);
  
  if (network_send_pkt(sock->dst_addr, sizeof(pkt), 
      (char*)&pkt, 0, (char*)&pkt) == -1) {
    *error = SOCKET_SENDERROR;
  }  
}
Exemple #8
0
/* Sends a message through a locally bound port (the bound port already has an associated
 * receiver address so it is sufficient to just supply the bound port number). In order
 * for the remote system to correctly create a bound port for replies back to the sending
 * system, it needs to know the sender's listening port (specified by local_unbound_port).
 * The msg parameter is a pointer to a data payload that the user wishes to send and does not
 * include a network header; your implementation of minimsg_send must construct the header
 * before calling miniroute_send_pkt(). The return value of this function is the number of
 * data payload bytes sent not inclusive of the header.
 */
int minimsg_send(miniport_t local_unbound_port, miniport_t local_bound_port, minimsg_t msg, int len) {
	network_address_t dest, my_address;
	mini_header_t hdr;

	// semaphore_P(msgmutex);

	// Check for valid arguments
	if (local_unbound_port == NULL) {
		fprintf(stderr, "ERROR: minimsg_send() passed a NULL local_unbound_port miniport argument\n");
		semaphore_V(msgmutex);
		return -1;
	}
	if (local_bound_port == NULL) {
		fprintf(stderr, "ERROR: minimsg_send() passed a NULL local_bound_port miniport argument\n");
		semaphore_V(msgmutex);
		return -1;
	}

	// Allocate new header for packet
	hdr = malloc(sizeof(struct mini_header));
	if (hdr == NULL) {	// Could not allocate header
		fprintf(stderr, "ERROR: minimsg_send() failed to malloc new mini_header\n");
		semaphore_V(msgmutex);
		return -1;
	}

	// Assemble packet header
	hdr->protocol = PROTOCOL_MINIDATAGRAM; // Protocol
	network_get_my_address(my_address);
	pack_address(hdr->source_address, my_address); // Source address
	pack_unsigned_short(hdr->source_port, local_bound_port->port_num); // Source port
	network_address_copy(local_bound_port->u.bound.remote_address, dest);
	pack_address(hdr->destination_address, dest); // Destination address
	pack_unsigned_short(hdr->destination_port, local_bound_port->u.bound.remote_unbound_port); // Destination port

	// Call miniroute_send_pkt() from network.hdr
	if (network_send_pkt(dest, sizeof(struct mini_header), (char*) hdr, len, msg) < 0) {			// REMOVE THIS LINE
	// if (miniroute_send_pkt(dest, sizeof(struct mini_header), (char*) hdr, len, msg) < 0) {
		fprintf(stderr, "ERROR: minimsg_send() failed to successfully execute miniroute_send_pkt()\n");
		semaphore_V(msgmutex);
		return -1;
	}

	// semaphore_V(msgmutex);

    return 0;
}
Exemple #9
0
/* Pack header for reply packets */
static void
miniroute_pack_reply_hdr(miniroute_header_t hdr, int id, miniroute_path_t path)
{
    hdr->routing_packet_type = ROUTING_ROUTE_REPLY;
    pack_address(hdr->destination, path->addr);
    pack_unsigned_int(hdr->id, id);
    pack_unsigned_int(hdr->ttl, MAX_ROUTE_LENGTH);
    miniroute_pack_hdr_from_path(hdr, path);
}
Exemple #10
0
/* Pack the routing portion of the header */
static void
miniroute_pack_hdr_from_path(miniroute_header_t hdr, miniroute_path_t path)
{
    unsigned int i;
    pack_unsigned_int(hdr->ttl, MAX_ROUTE_LENGTH);
    pack_unsigned_int(hdr->path_len, path->path_len);
    for (i = 0; i < path->path_len; ++i)
        pack_address(hdr->path[i], path->hop[i]);
}
Exemple #11
0
//Returns a reliable mini header
//TODO: do seq_num and ack_num
void minisocket_create_reliable_header(mini_header_reliable_t* header, minisocket_t* socket, unsigned short dest_port, const network_address_t dest_address, char message_type) {
  header->protocol = PROTOCOL_MINISTREAM;

  //packs info
  pack_address(header->destination_address, dest_address);
  pack_unsigned_short(header->destination_port, dest_port);
  network_address_t my_address;
  network_get_my_address(my_address);
  pack_address(header->source_address, my_address);
  pack_unsigned_short(header->source_port, socket->local_port_number);

  //pack seq and ack numbers
  pack_unsigned_int(header->ack_number, socket->ack);
  pack_unsigned_int(header->seq_number, socket->seq);

  //set message type
  header->message_type = message_type;
}
Exemple #12
0
/* Pack the header of an outgoing data packet */
static void
miniroute_pack_data_hdr(miniroute_header_t hdr, miniroute_path_t path)
{

    hdr->routing_packet_type = ROUTING_DATA;
    pack_address(hdr->destination, path->addr);
    pack_unsigned_int(hdr->id, 0);
    pack_unsigned_int(hdr->ttl, MAX_ROUTE_LENGTH);
    miniroute_pack_hdr_from_path(hdr, path);
}
Exemple #13
0
/* Create a miniroute header */
routing_header_t create_miniroute_header(char packet_type, network_address_t dst_addr,
										unsigned int id, unsigned int ttl, 
										unsigned int path_len, network_address_t* path)
{

	routing_header_t header = (routing_header_t) malloc(sizeof(struct routing_header));
	int i;

	if (header == NULL)
		return NULL;

	header->routing_packet_type = packet_type;
	pack_address(header->destination, dst_addr);
	pack_unsigned_int(header->id, id);
	pack_unsigned_int(header->ttl, ttl);
	pack_unsigned_int(header->path_len, path_len);

	for (i = 0; i < path_len; i++)
	{
		pack_address(header->path[i], path[i]);
	}

	return header;
}
int
minimsg_send(miniport_t* local_unbound_port, miniport_t* local_bound_port, minimsg_t* msg, int len)
{
	assert(g_boundPortCounter >= 0); //sanity check to ensure minimsg_initialize() has been called first

	//validate input
	if (local_unbound_port == NULL || local_bound_port == NULL || msg == NULL || len < 0 || len > MINIMSG_MAX_MSG_SIZE) return -1;

	//generate the header
	mini_header_t header;
	header.protocol = PROTOCOL_MINIDATAGRAM; //set protocol type
	network_address_t my_address;
	network_get_my_address(my_address);
	pack_address(header.source_address, my_address);
	pack_unsigned_short(header.source_port, local_unbound_port->port_number);
	pack_address(header.destination_address, local_bound_port->bound_port.remote_addr);
	pack_unsigned_short(header.destination_port, local_bound_port->bound_port.remote_unbound_port);
	
	//send message now
	int sentBytes = network_send_pkt(local_bound_port->bound_port.remote_addr, sizeof(header), (char*)&header, len, msg);

	if (sentBytes == -1) return -1; //we failed to send our message
	else return sentBytes - sizeof(header); //else return size of our message not inclusive of header
}
Exemple #15
0
/* Sends a message through a locally bound port (the bound port already has an associated
 * receiver address so it is sufficient to just supply the bound port number). In order
 * for the remote system to correctly create a bound port for replies back to the sending
 * system, it needs to know the sender's listening port (specified by local_unbound_port).
 * The msg parameter is a pointer to a data payload that the user wishes to send and does not
 * include a network header; your implementation of minimsg_send must construct the header
 * before calling network_send_pkt(). The return value of this function is the number of
 * data payload bytes sent not inclusive of the header. Returns -1 on error.
 * Fails if msg is too long. 
 */
int
minimsg_send(miniport_t local_unbound_port, miniport_t local_bound_port, minimsg_t msg, int len) {
  struct mini_header hdr;
  network_address_t dst_addr;
  
  if (len > MINIMSG_MAX_MSG_SIZE) {
    return -1;
  }

  if (local_unbound_port == NULL || 
      local_unbound_port->p_type != UNBOUND_PORT || 
      local_unbound_port->p_num >= BOUND_PORT_START ||
      miniport_array[local_unbound_port->p_num] != local_unbound_port) {
    return -1;
  }

  if (local_bound_port == NULL ||
      local_bound_port->p_type != BOUND_PORT ||
      local_bound_port->p_num < BOUND_PORT_START ||
      miniport_array[local_bound_port->p_num] != local_bound_port) {
    return -1;
  }


  network_address_copy(local_bound_port->u.bound.dest_addr, dst_addr); 
  hdr.protocol = PROTOCOL_MINIDATAGRAM;
  pack_address(hdr.source_address, my_addr);
  pack_unsigned_short(hdr.source_port, local_unbound_port->p_num);
  pack_address(hdr.destination_address, local_bound_port->u.bound.dest_addr);
  pack_unsigned_short(hdr.destination_port, local_bound_port->u.bound.dest_num);
  
  if (network_send_pkt(dst_addr, sizeof(hdr), (char*)&hdr, len, msg)) {
    return -1;
  }
  return len;
}
Exemple #16
0
/* Process a route discovery packet */
static void
miniroute_process_discovery(network_interrupt_arg_t *intrpt)
{
    miniroute_header_t hdr = (miniroute_header_t) intrpt->buffer;
    network_address_t orig;
    network_address_t dest;
    int id;
    int len;
    int ttl;
    miniroute_path_t path;
    miniroute_disc_hist_t disc;

#if MINIROUTE_CACHE_DEBUG == 1
    printf("Received discovery packet with header: \n");
    miniroute_print_hdr(hdr);
#endif
    id = unpack_unsigned_int(hdr->id);
    len = unpack_unsigned_int(hdr->path_len);
    pack_unsigned_int(hdr->path_len, ++len);
    pack_address(hdr->path[len - 1], hostaddr);
    unpack_address(hdr->path[0], orig);
    unpack_address(hdr->destination, dest);

    if (network_address_same(dest, hostaddr) != 1) {
        miniroute_cache_get_by_addr(disc_cache, orig, (void**)&disc);
        if (!(NULL != disc && disc->id ==  id)) {
            disc = miniroute_dischist_from_hdr(hdr);
            miniroute_cache_put_item(disc_cache, disc);
            ttl = unpack_unsigned_int(hdr->ttl);
            pack_unsigned_int(hdr->ttl, --ttl);
            network_bcast_pkt(0, NULL, intrpt->size, intrpt->buffer);
        }
    } else {
        path = miniroute_path_from_hdr(hdr);
        miniroute_cache_put_item(route_cache, path);
        miniroute_pack_reply_hdr(hdr, id, path);
#if MINIROUTE_CACHE_DEBUG == 1
        printf("Processed discovery packet, replying with header: \n");
        miniroute_print_hdr(hdr);
#endif
        network_send_pkt(path->hop[1], MINIROUTE_HDRSIZE, (char*)hdr, 0, NULL);
    }

    free(intrpt);
}
 int run_tests() {
  int i;
  int success = 0, total = 0;
  for (i = 0; i < (sizeof(test_cases) / sizeof(test_cases[0])); i++) {
    uint8_t flags;
    struct in6_addr addr;
    uint8_t buf[512], *rv;
    ieee154_addr_t l2addr;
    total++;

    inet_pton6(test_cases[i].in6_addr, &addr);
    ieee154_parse(test_cases[i].l2addr, &l2addr);
    ieee154_print(&l2addr, buf, 512);
    printf("%s\n", buf);
    printf("in6_addr: %s\n", test_cases[i].in6_addr);
    rv = pack_address(buf, &addr, test_cases[i].context_match_len, &l2addr,
                      test_cases[i].panid, &flags);

    printf("flags: 0x%x(0x%x) len: %li\n", flags, test_cases[i].result_rv, rv - buf );
    print_buffer(buf, rv - buf);
    if (test_cases[i].result_len != (rv - buf)) {
      printf("case %u: result len failed expected: %i got: %li\n",
             i, test_cases[i].result_len, (rv - buf));
      continue;
    }
    if (test_cases[i].result_rv != flags) {
      printf("case %u: desired rv: 0x%x flags: %x\n",
             i, test_cases[i].result_rv, flags);
      continue;
    }
    if (memcmp(test_cases[i].result, buf, test_cases[i].result_len) != 0) {
      printf("case %u: buffers did not match\n", i);
      print_buffer(test_cases[i].result, test_cases[i].result_len);
      print_buffer(buf, test_cases[i].result_len);
      continue;
    }

    success++;
  }
  printf("%s: %i/%i tests succeeded\n", __FILE__, success, total);
  if (success == total) return 0;
  return 1;
}
Exemple #18
0
/* sends a miniroute packet, automatically discovering the path if necessary. See description in the
 * .h file.
 */
int miniroute_send_pkt(network_address_t dest_address, int hdr_len, char* hdr, int data_len, char* data)
{
	// This will store the route request struct, which is a structure related to the
	// search for a path to the host
	route_request_t route_request;

	// Store the routing header
	routing_header_t routing_header;

	// Store the route to the host, which is an array of addresses
	network_address_t* route;

	// Store the route data struct, which holds the route and some metadata
	route_data_t route_data;

	// Store my address
	network_address_t my_addr;

	// Used to synchronize access with structures the network handler touches
	interrupt_level_t prev_level;

	// This will store the combined routing + normal headers
	char* full_header;

	network_address_t dest_address2;

	// These will store data related to the routes
	int time_route_found;
	int route_len;
	int route_valid = 1;

	// Used to get data from the header containing the paht
	routing_header_t tmp_routing_header;

	// Used to just check the IP of senders; combats UDP port issues w/ simulated broadcasts
	unsigned int dest_address_ip = dest_address[0];

	// Loop + tmp variables
	int current_req_id;
	int success = 0;
	int alarm_id;
	int x;
	int i;

	if (hdr_len == 0 || hdr == NULL
		|| data_len == 0 || data == NULL)
		return -1;

	// Get the route item, which is a hashmap_item_t, from the hashmap for this addr
	semaphore_P(route_cache_sem);
	route_data = (route_data_t) hashmap_get(route_cache, hash_address(dest_address));

	// If it's not NULL, extract the data from the item
	if (route_data != NULL)
	{
		time_route_found = route_data->time_found;

		route_len = route_data->route_len;

		// caveat: the cleanup thread may delete the route data, so we need to 
		// save it in a separate variable, just incase.
		route = (network_address_t*) malloc(sizeof(network_address_t) * route_len);
		if (route == NULL)
		{
			semaphore_V(route_cache_sem);
			return -1;
		}
		memcpy(route, route_data->route, sizeof(network_address_t) * route_len);
	}
	 else
	{
		route_valid = 0;
	}
	semaphore_V(route_cache_sem);

	// Check, if the route isn't NULL, if it's expired
	if (route_valid == 1 && (ticks - time_route_found) * PERIOD/MILLISECOND > 3000)
	{
		route_valid = 0;
	}

	// If the route is invalid (either not in the cache or expired)...
	if (route_valid == 0)
	{
		// We won't be needing that previous route variable
		if (route_data != NULL)
		{
			// But, just in case someone is still using it, use the route cache semaphore
			semaphore_P(route_cache_sem);
			free(route);
			semaphore_V(route_cache_sem);
		}

		// Check if someone else already initiated this route discovery request
		prev_level = set_interrupt_level(DISABLED);
		route_request = (route_request_t) hashmap_get(current_discovery_requests, dest_address_ip);
		set_interrupt_level(prev_level);

		// If so, we can just wait for their result
		if (route_request != NULL)
		{		
			// Wait for the other thread to get the path	
			// The threads waiting variable needs to be synchronized. We decided
			// to reuse the route cache sem, as there will not be much lock
			// contention
			semaphore_P(route_cache_sem);
			route_request->threads_waiting++;	
			semaphore_V(route_cache_sem);
			semaphore_P(route_request->waiting_sem);

			// Get the route from the hashmap
			semaphore_P(route_cache_sem);
			route_data = (route_data_t) hashmap_get(route_cache, hash_address(dest_address));

			// If the other thread didn't get the route, return an error
			if (route_data == NULL)
			{
				// Return failure...
				semaphore_V(route_cache_sem);
				return -1;
			}
			 else
			{
				time_route_found = route_data->time_found;
				route_len = route_data->route_len;

				if ((ticks - time_route_found) * PERIOD/MILLISECOND > 3000)
				{
					// This could have been a left-over expired cache entry that we haven't
					// deleted yet.
					semaphore_V(route_cache_sem);
					return -1;
				}

				// Save the route in a separate variable in case the route gets cleaned up
				// while we're using it
				route = (network_address_t*) malloc(sizeof(network_address_t) * route_len);
				if (route == NULL)
				{
					semaphore_V(route_cache_sem);
					return -1;
				}

				memcpy(route, route_data->route, sizeof(network_address_t) * route_len);
				semaphore_V(route_cache_sem);
			}
		}
		 else
		{
			// Otherwise, we have to do the route discovery process

			// Create a new route request struct
			route_request = create_route_request();
			if (route_request == NULL)
			{
				return -1;		
			}

			// Add the route request to the current discovery requests
			prev_level = set_interrupt_level(DISABLED);
			hashmap_insert(current_discovery_requests, dest_address_ip, route_request);
			set_interrupt_level(prev_level);

			// We'll try the route discovery process three times
			for (i = 0; i < 3; i++)
			{
				// Register an alarm to wake this thread up as it waits for a response
				alarm_id = register_alarm(12000, &alarm_wakeup_sem, (void*) route_request->initiator_sem);

				// Increment the request ID - must be synchronized, obviously
				semaphore_P(request_id_sem);
				current_req_id = route_request_id++;
				semaphore_V(request_id_sem);

				// We need to make a header for the discovery request, but the path
				// needs to have our address in it, so the reply can be forwarded back
				// to us
				network_get_my_address(my_addr);

				// Passing in the address of this local variable will suffice, as the
				// value is immediately copied into the header and then not used again

			 	// Create a routing header for the route discovery request
				routing_header = create_miniroute_header(ROUTING_ROUTE_DISCOVERY,
														dest_address, current_req_id, 
														MAX_ROUTE_LENGTH, 1,
														&my_addr);

				if (routing_header == NULL)
				{
					return -1;
				}

				// Combine it with the given header
				full_header = merge_headers(routing_header, hdr, hdr_len);
				if (full_header == NULL)
				{
					free(routing_header);
					return -1;
				}

				// Send out the route discovery request
				network_bcast_pkt(sizeof(struct routing_header)+hdr_len,
									(char*) full_header, data_len, data);

				// Wait for a reply (which will be signalled by the network handler)
				prev_level = set_interrupt_level(DISABLED);
				semaphore_P(route_request->initiator_sem);
				set_interrupt_level(prev_level);


				// Check if we got a successful response
				if (route_request->interrupt_arg != NULL)
				{
					// Deregister the alarm before it tries to wake us up
					// Needs to be synchronized, as the IH touches it and we destroy it here
					prev_level = set_interrupt_level(alarm_id);
					deregister_alarm(alarm_id);
					set_interrupt_level(alarm_id);

					// Get the header
					tmp_routing_header = (routing_header_t) route_request->interrupt_arg->buffer;
					route_len = unpack_unsigned_int(tmp_routing_header->path_len);

					// Then the path, for our own use later in this function
					// We'll also create one copy and put it in the route data struct
					route = miniroute_reverse_raw_path(tmp_routing_header, route_len);
					if (route == NULL)
					{
						free(routing_header);
						free(full_header);
						return -1;
					}

					// Create a route data struct - with a different route (as it will be deleted by a diff thread)
					route_data = create_route_data(miniroute_reverse_raw_path(tmp_routing_header, route_len),
													 route_len, ticks);
					if (route_data == NULL)
					{
						free(routing_header);
						free(full_header);
						return -1;
					}

					// add it to the cache hashmap
					semaphore_P(route_cache_sem);
					hashmap_insert(route_cache, hash_address(dest_address), route_data);
					semaphore_V(route_cache_sem);

					// Wake up the other threads waiting
					for (x = 0; x < route_request->threads_waiting; x++)
					{
						semaphore_V(route_request->waiting_sem);
					}

					// Clean up the route request struct, then delete it from the hashmap
					// DELETE ROUTE REQUEST WILL FREE THE NETWORK INTERRUPT ARG!
					prev_level = set_interrupt_level(DISABLED);
					delete_route_request(route_request);
					hashmap_delete(current_discovery_requests, dest_address_ip);	
					set_interrupt_level(prev_level);

					// We don't need to actually get any of the routing stuff from the
					// route_ite, as this process also sent the data packet

					// Free the headers
					free(routing_header);
					free(full_header);		

					// Return the total bytes sent, not including the routing header
					success = 1;
					break;
				}
			}

			// If we didn't get a successful response after 3 tries...
			if (success == 0)
			{
				// Wake up the other threads waiting so they can see we failed
				for (x = 0; x < route_request->threads_waiting; x++)
				{
					semaphore_V(route_request->waiting_sem);
				}

				// clean up the route request struct, then delete it from the hashmap
				prev_level = set_interrupt_level(DISABLED);
				delete_route_request(route_request);
				hashmap_delete(current_discovery_requests, dest_address_ip);
				set_interrupt_level(prev_level);	

				// Free the headers
				free(routing_header);
				free(full_header);

				// Return failure...
				return -1;
			}
		}
	}

	// If we're here, we either found the route in the cache or waited for another
	// thread to finish getting the route (and it did so successfully)
	network_address_copy(route[route_len-1], dest_address2);

	// Need to update the dst address to deal with UDP port issues
	// This again is due to UDP port issues...
	pack_address(((mini_header_t) hdr)->destination_address, dest_address2);

 	// Create a routing header for the data packet
	routing_header = create_miniroute_header(ROUTING_DATA,
											dest_address2, 0, 
											MAX_ROUTE_LENGTH, route_len,
											route);

	if (routing_header == NULL)
	{
		return -1;
	}

	// Combine it with the given header
	full_header = merge_headers(routing_header, hdr, hdr_len);
	if (full_header == NULL)
	{
		free(routing_header);
	}

	// Set the right destination address
	network_address_copy(route[1], dest_address2);

	// Send the packet
	network_send_pkt(dest_address2, sizeof(struct routing_header) + hdr_len, 
					full_header, data_len, data);

	// Free the route + headers
	free(route);
	free(routing_header);
	free(full_header);

	// Return the total data sent
	return hdr_len + data_len;
}
Exemple #19
0
minisocket_t* minisocket_server_create(int port, minisocket_error *error) {	
  //Check socket number first 
  if (valid_server_port(port) == 0) {
    *error = SOCKET_INVALIDPARAMS;
    return NULL;
  }				
  //check if socket is already in use
  if (mini_socket_data[port] != NULL) {
    *error = SOCKET_PORTINUSE; 
    return NULL;
  }
  minisocket_t* socket = (minisocket_t *) malloc(sizeof(minisocket_t));
  if (socket == NULL) {
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }

  socket->state = LISTENING;
  socket->socket_type = SERVER_TYPE;
  socket->local_port_number = port;
  network_address_t my_address;
  network_get_my_address(my_address);
  network_address_copy(my_address, socket->local_address);
  socket->datagrams_ready = semaphore_create();
  semaphore_initialize(socket->datagrams_ready, 0);
  socket->ack_ready = semaphore_create();
  semaphore_initialize(socket->ack_ready, 0);
  socket->incoming_data = queue_new();
  socket->acknowledgements = queue_new();
  socket->seq = 0;
  socket->ack = 0;
  socket->next_read = 0;

  //add socket to global array
  mini_socket_data[socket->local_port_number] = socket;

  char connection_established = 0;
  mini_header_reliable_t header; 
  minisocket_create_reliable_header((mini_header_reliable_t *) &header, socket, socket->remote_port_number, socket->remote_address, MSG_SYNACK); 
  network_address_t dest;
  
  pack_unsigned_int(header.seq_number, socket->seq);
  pack_unsigned_int(header.ack_number, socket->ack); 

  //loop until a full connection is established
  while (connection_established == 0) {
    //sleep until initial MSG_SYN arrives from client
    char message_received = 0;
    while (message_received == 0) {
      //Waits until it receives a packet
      semaphore_P(socket->ack_ready);

      interrupt_level_t old_level = set_interrupt_level(DISABLED);
      network_interrupt_arg_t* interrupt_message = NULL;
      queue_dequeue(socket->acknowledgements, (void **) &interrupt_message);
      set_interrupt_level(old_level);

      //TODO: check more contents of message? change seq and ack values in response??}
      if (interrupt_message != NULL ) {
        mini_header_reliable_t* received_header = (mini_header_reliable_t *) interrupt_message->buffer; 
        unpack_address(received_header->source_address, dest);
        pack_address(header.destination_address, dest);
        pack_unsigned_short(header.destination_port, unpack_unsigned_short(received_header->source_port));

        if (valid_client_port(unpack_unsigned_short(received_header->source_port)) == 1) { //check valid port number
          if (received_header->message_type != MSG_SYN) { //check valid message type
            header.message_type = MSG_FIN; 
            network_send_pkt(dest, sizeof(mini_header_reliable_t), (char *) &header, 0, empty_message); 
            free(interrupt_message); 
          }
          else {
            //set remote port values
            printf("server got the SYN message\n");
            socket->remote_port_number = unpack_unsigned_short(received_header->source_port);
            network_address_copy(dest, socket->remote_address);
            socket->seq = unpack_unsigned_int(received_header->seq_number);
            message_received = 1; //will break loop
            free(interrupt_message); 
            socket->state = CONNECTING;
            break;
          }
        }  
      }
    }
    //reset loop value for return
    message_received = 0;
    //otherwise the message was the correct type and format

    int timeout = START_TIMEOUT / 2; //this way first timeout will be at START_TIMEOUT
    for (int i = 0; i < MAX_FAILURES; i++) {
      printf("sending MSG_SYNACK in server, i: %d\n", i); 
      timeout = timeout * 2;
      header.message_type = MSG_SYNACK; 
      network_send_pkt(dest, sizeof(mini_header_reliable_t), (char *) &header, 0, empty_message); 
      alarm_id timeout_alarm_id = register_alarm(timeout, handshake_timeout_handler, (void *) socket->ack_ready);
      int alarm_fired = 0;

      //keep looking through received packets until either the alarm fires or it finds the correct packet
      while (!connection_established && !alarm_fired) {
        semaphore_P(socket->ack_ready);

        //alarm has fired, since there are no packets to be received
        if (queue_length(socket->acknowledgements) == 0) {
          alarm_fired = 1; //goes to next iteration of for loop
        }
        //There is a packet (alarm hasnt fired yet)
        else {
          network_interrupt_arg_t* interrupt_message = NULL;
          interrupt_level_t old_level = set_interrupt_level(DISABLED);
          queue_dequeue(socket->acknowledgements, (void **) &interrupt_message);
          set_interrupt_level(old_level); 

          // verify non null message
          if (interrupt_message != NULL) {
            mini_header_reliable_t* received_header = (mini_header_reliable_t *) interrupt_message->buffer; 
            network_address_t temp_address;
            unpack_address(received_header->source_address, temp_address);
            if (socket->remote_port_number == unpack_unsigned_short(received_header->source_port) &&
              network_compare_network_addresses(socket->remote_address, temp_address) != 0 &&
              received_header->message_type == MSG_ACK) {
              //same address, same ports, right message
              deregister_alarm(timeout_alarm_id); //only deregister alarm when the right packet is found
              connection_established = 1; 
              //queue_prepend(socket->acknowledgements, interrupt_message); //ack works as well when there is data 
              break;
            }
            else {
              free(interrupt_message);
            }
          }
        }
      }
      if (connection_established) { 
        //correct response has been found, get out of this timeout loop!
        break;
      }
    }
    //if timeout occurs, will loop back to initial waiting phase for MSG_SYN from client
  } 
  
  printf("leaving server create\n");
  //update server socket values with client connection
  socket->state = CONNECTED;
  assert(socket != NULL);
  return socket; 
}
Exemple #20
0
/* Returns the route to dest or NULL on failure.
 */
miniroute_t miniroute_discover_route(network_address_t dest) {
  char tmp;
  struct resend_arg arg;
  interrupt_level_t l;
  miniroute_t path;
  dcb_t control_block;
  struct routing_header hdr;

  //printf("entering miniroute_discover_route\n"); 
  l = set_interrupt_level(DISABLED);
  path = miniroute_cache_get(route_cache, dest);
  if (path != NULL) {
    //printf("got route from cache\n");
    set_interrupt_level(l);
    return path;
  }
  if (!hash_table_contains(dcb_table, dest)) {
    control_block = (dcb_t)malloc(sizeof(struct discover_control_block));
    if (!control_block) {
      set_interrupt_level(l);
      return NULL;
    }
    control_block->count = 0;
    control_block->mutex = semaphore_create();
    if (!control_block->mutex) {
      free(control_block);
      set_interrupt_level(l);
      return NULL;
    }
    control_block->route_ready = semaphore_create();
    if (!control_block->route_ready) {
      free(control_block);
      semaphore_destroy(control_block->mutex);
      set_interrupt_level(l);
      return NULL;
    }
    semaphore_initialize(control_block->mutex, 1);
    semaphore_initialize(control_block->route_ready, 0);
    control_block->resend_alarm = NULL;
    control_block->alarm_arg = NULL;
    hash_table_add(dcb_table, dest, control_block);
    //printf("made a NEW discover control block\n"); 
    }
  control_block = hash_table_get(dcb_table, dest);
  if (!control_block) {
    //printf("ERROR: could not find discover control block\n");
    set_interrupt_level(l);
    return NULL;
  }

  control_block->count++;
  set_interrupt_level(l);
  
  semaphore_P(control_block->mutex);
  path = miniroute_cache_get(route_cache, dest);
  if (path) {
    l = set_interrupt_level(DISABLED);
    control_block->count--;
    semaphore_V(control_block->mutex);
    set_interrupt_level(l);
    //printf("exiting miniroute_discover_route on SUCCESS\n"); 
    return path;
  }
  else {
    hdr.routing_packet_type = ROUTING_ROUTE_DISCOVERY;
    pack_address(hdr.destination, dest);
    l = set_interrupt_level(DISABLED);
    pack_unsigned_int(hdr.id, curr_discovery_pkt_id++);
    pack_unsigned_int(hdr.ttl, MAX_ROUTE_LENGTH);
    pack_unsigned_int(hdr.path_len, 1);
    pack_address(hdr.path[0], my_addr);
    //make arg
    arg.try_count = 0;
    arg.hdr = &hdr;
    arg.control_block = control_block;    
    control_block->alarm_arg = &arg; 

    //printf("sending first DISCOVERY pkt\n");
    if (network_bcast_pkt(sizeof(struct routing_header), (char*)(&hdr), 0, &tmp) == -1) {
      //error
      control_block->count--;
      semaphore_V(control_block->mutex);
      set_interrupt_level(l);
      return NULL;
    } 
    control_block->resend_alarm = set_alarm(120, miniroute_resend, 
        control_block->alarm_arg, minithread_time());  
    set_interrupt_level(l);
    semaphore_P(control_block->route_ready); 
    //got a reply pkt or timed out
    path = miniroute_cache_get(route_cache, dest);
    l = set_interrupt_level(DISABLED);
    control_block->count--;
    semaphore_V(control_block->mutex);
    set_interrupt_level(l);
    //printf("exiting miniroute_discover_route on SUCCESS\n"); 
    return path;
  }
}
Exemple #21
0
/* sends a miniroute packet, automatically discovering the path if necessary. 
 * See description in the .h file.
 */
int miniroute_send_pkt(network_address_t dest_address, int hdr_len, 
                        char* hdr, int data_len, char* data) {
  interrupt_level_t l;
  miniroute_t path;
  dcb_t control_block;
  struct routing_header new_hdr;
  int i;
  int path_len;
  int new_data_len;
  char* new_data;
  int bytes_sent;
  
  //printf("entering miniroute_send_pkt\n");
  if (hdr_len < 0 || data_len < 0 || hdr == NULL || data == NULL) {
    //printf("invalid params\n");
    return -1;
  }
  path = miniroute_discover_route(dest_address);

  if (path == NULL) {
    return -1;
  }

  l = set_interrupt_level(DISABLED);
  control_block = hash_table_get(dcb_table, dest_address);
  if (control_block != NULL && control_block->count == 0) {
    //no threads are blocked on route. cleanup
    semaphore_destroy(control_block->mutex); 
    semaphore_destroy(control_block->route_ready);
    hash_table_remove(dcb_table, dest_address);
    free(control_block);
    //printf("destroyed a discovery control block\n");
  }
  set_interrupt_level(l);

  //JUST DO IT
  new_hdr.routing_packet_type = ROUTING_DATA;
  pack_address(new_hdr.destination, dest_address);
  pack_unsigned_int(new_hdr.ttl, MAX_ROUTE_LENGTH);
  pack_unsigned_int(new_hdr.id, 0);
  pack_unsigned_int(new_hdr.path_len, path->len);
  if (path->len > MAX_ROUTE_LENGTH) {
    path_len = MAX_ROUTE_LENGTH; 
  }
  else {
    path_len = path->len;
  }
  for (i = 0; i < path_len; i++) {
    pack_address(new_hdr.path[i], path->route[i]);
  }
  new_data_len = hdr_len + data_len;
  new_data = (char*)malloc(new_data_len);
  memcpy(new_data, hdr, hdr_len);
  memcpy(new_data+hdr_len, data, data_len);
  bytes_sent = network_send_pkt(path->route[1], sizeof(struct routing_header), 
      (char*)&new_hdr, new_data_len, new_data);
  free(new_data);
  if ((bytes_sent - hdr_len) < 0) {
    //printf("exiting miniroute_send_pkt on FAILURE\n");
    return -1;
  }
  else {
    //printf("exiting miniroute_send_pkt on SUCCESS\n");
    return (bytes_sent - hdr_len);
  }
}
Exemple #22
0
/* Takes in a routing packet and does error checking.
 * Adds it to the cache if this packet was destined for us. 
 * Returns 1 if this packet has data to be passed along,
 * O otherwise.
 */
int miniroute_process_packet(network_interrupt_arg_t* pkt) {
  struct routing_header* pkt_hdr = NULL;
  network_address_t tmp_addr;
  network_address_t src_addr;
  network_address_t dst_addr;
  network_address_t nxt_addr;
  unsigned int discovery_pkt_id;
  unsigned int pkt_ttl;
  unsigned int path_len;
  miniroute_t path = NULL; 
  miniroute_t new_path = NULL;
  network_address_t* new_route = NULL;
  unsigned int i;
  unsigned int found;
  struct routing_header hdr;
  char tmp;
  dcb_t control_block;
  
  
  //printf("entering miniroute_process_packet\n");
  if (pkt == NULL || pkt->size < sizeof(struct routing_header)) {
    //printf("exiting miniroute_process_packet on INVALID PARAMS\n");
    return 0;
  }
  
  pkt_hdr = (struct routing_header*)pkt->buffer;
  unpack_address(pkt_hdr->destination, dst_addr);
  discovery_pkt_id = unpack_unsigned_int(pkt_hdr->id);
  pkt_ttl = unpack_unsigned_int(pkt_hdr->ttl);
  path_len = unpack_unsigned_int(pkt_hdr->path_len);
  unpack_address(pkt_hdr->path[0], src_addr);

  if (network_compare_network_addresses(my_addr, dst_addr)) {
    //same
    if (!miniroute_cache_get(route_cache, src_addr)) {
      //not in cache 
      if (pkt_hdr->routing_packet_type == ROUTING_ROUTE_DISCOVERY) {
        //add myself to the path vector
        pack_address(pkt_hdr->path[path_len], my_addr); 
        path_len++;
        pack_unsigned_int(pkt_hdr->path_len, path_len);
      }
      new_route = (network_address_t*)calloc(path_len, sizeof(network_address_t));
      if (new_route == NULL) {
        free(pkt);
        //printf("exiting miniroute_process_packet on CALLOC ERROR\n");
        return 0;
      }
      for (i = 0; i < path_len; i++) {
        unpack_address(pkt_hdr->path[path_len - i - 1], tmp_addr);
        network_address_copy(tmp_addr, new_route[i]);
      }
      new_path = (miniroute_t)calloc(1, sizeof(struct miniroute));
      if (new_path == NULL) {
        free(pkt);
        free(new_route);
        //printf("exiting miniroute_process_packet on CALLOC ERROR\n");
        return 0;
      }
      new_path->route = new_route;
      new_path->len = path_len; 
      miniroute_cache_put(route_cache, src_addr, new_path);
    } //added new route to cache
  }
  else if (pkt_ttl <= 0) {
    free(pkt);
    //printf("exiting miniroute_process_packet on TTL ERROR\n");
    return 0;
  }
  else if (pkt_hdr->routing_packet_type != ROUTING_ROUTE_DISCOVERY) {
    //different

    //check from 2nd to second to last address
    found = 0;
    for (i = 1; i < path_len - 1; i++) {
      unpack_address(pkt_hdr->path[i], tmp_addr);
      if (network_compare_network_addresses(my_addr, tmp_addr)) {
        unpack_address(pkt_hdr->path[i+1], nxt_addr);
        found = 1;
        break; 
      }
    }
    if (!found) {
      free(pkt);
      return 0;
    }
  }

  switch (pkt_hdr->routing_packet_type) {
  case ROUTING_DATA:
    //printf("got a DATA pkt\n");
    if (network_compare_network_addresses(my_addr, dst_addr)) {
      //same
      //printf("exiting miniroute_process_packet on DATA PKT\n"); 
      return 1;
    }
    else {
      //skip packet type, shouldn't change
      //skip destination, shouldn't change
      //skip id, shouldn't change
      pack_unsigned_int(pkt_hdr->ttl, pkt_ttl - 1); //subtract ttl
      network_send_pkt(nxt_addr, sizeof(struct routing_header), (char*)pkt_hdr, 0, &tmp);
    }
    break;

  case ROUTING_ROUTE_DISCOVERY:
    if (network_compare_network_addresses(my_addr, dst_addr)) {
      //printf("got a DISCOVERY pkt, for me\n");
      //same  
      path = miniroute_cache_get(route_cache, src_addr);

      hdr.routing_packet_type = ROUTING_ROUTE_REPLY;
      pack_address(hdr.destination, src_addr);
      pack_unsigned_int(hdr.id, discovery_pkt_id);
      pack_unsigned_int(hdr.ttl, MAX_ROUTE_LENGTH);
      pack_unsigned_int(hdr.path_len, path->len);
      for (i = 0; i < path->len; i++) {
        pack_address(hdr.path[i], path->route[i]);
      }
      network_send_pkt(path->route[1], sizeof(struct routing_header), (char*)(&hdr), 0, &tmp);
    }
    else {
      //printf("got a DISCOVERY pkt, for someone else\n");
      //different
      //scan to check if i am in list
      //if yes then discard
      //else append to path vector and broadcast
      //
      //scan to check if i am in list
      //if yes then pass along, else discard
      for (i = 0; i < path_len - 1; i++) {
        unpack_address(pkt_hdr->path[i], tmp_addr);
        if (network_compare_network_addresses(my_addr, tmp_addr)) {
          free(pkt);
         // printf("exiting miniroute_process_packet on BROADCAST LOOP\n");
          return 0;
        }
      }
      //printf("checks passed\n");
      pack_address(pkt_hdr->path[path_len], my_addr);
      pack_unsigned_int(pkt_hdr->path_len, path_len + 1); //add path_len
      pack_unsigned_int(pkt_hdr->ttl, pkt_ttl - 1); //subtract ttl
      //printf("packet header configured\n");
      //printf("my addr is (%i,%i)\n", my_addr[0], my_addr[1]);
      //printf("source addr is (%i,%i)\n", src_addr[0], src_addr[1]);
      //printf("dst addr is (%i,%i)\n", dst_addr[0], dst_addr[1]);
      //for (i = 0 ; i < path_len + 1; i++){
        //unpack_address(pkt_hdr->path[i], tmp_addr);
        //printf("->(%i,%i)", tmp_addr[0], tmp_addr[1]);
      //}
      //printf("\n");
      network_bcast_pkt(sizeof(struct routing_header), (char*)pkt_hdr, 0, &tmp); //send to neighbors
      //printf("broadcast successful\n");
    }
    break;

  case ROUTING_ROUTE_REPLY:
    //printf("got a REPLY pkt\n");
    if (network_compare_network_addresses(my_addr, dst_addr)) {
      //same
      control_block = hash_table_get(dcb_table, src_addr);
      if (control_block) {
        deregister_alarm(control_block->resend_alarm);
        control_block->resend_alarm = NULL;
        control_block->alarm_arg = NULL;
        semaphore_V(control_block->route_ready);
      }
    }
    else {
      //different
      //check ttl
      //scan to check if i am in list
      //if yes then pass along, else discard
      //
      //skip packet type, shouldn't change
      //skip destination, shouldn't change
      //skip id, shouldn't change
      pack_unsigned_int(pkt_hdr->ttl, pkt_ttl - 1); //subtract ttl
      network_send_pkt(nxt_addr, sizeof(struct routing_header), (char*)pkt_hdr, 0, &tmp);
    }
    break;

  default:
    //WTFFF???
    break;
  }    
  //printf("exiting miniroute_process_packet on SUCCESS\n"); 
  free(pkt);
  return 0;
}
Exemple #23
0
 void network_handler(network_interrupt_arg_t* arg)
{
	// Used to extract the network address out of the interrupt argument
	//network_address_t addr;

	// The source port number - this is really the remote unbound port number
	int src_port_number;

	// The port number the packet was sent to
	int dst_port_number;

	// Used to store the header data for UDP/minimsgs
	mini_header_t header;

	// This is used to extract the sender's address from the header
	network_address_t src_addr;

	// This is used to extract the destination (our) address from the header
	network_address_t dst_addr;

	// Disable interrupts...
	interrupt_level_t prev_level = set_interrupt_level(DISABLED);

	// This is used to check our own address for sanity checks
	network_address_t my_addr;

	// This will store the total packet size
	int packet_size;

	// This will store the size of the data in the packet
	int data_len;

	// This will store the header of a TCP packet
	mini_header_reliable_t header_reliable;

	// This will store the ACK number of a TCP packet
	int ack_num;

	// This will store the Sequence number of a TCP packet
	int seq_num;

	// This will store the socket
	minisocket_t socket;

	// This will store the TCP error
	minisocket_error error;

	// This will be used to indicate whether the TCP packet is a duplicate or not
	int duplicate = 0;

	// This will tell us if we need to free the arg or not
	int enqueued;

	// Used for general for loops
	int i;

	// Used to check if we've already broadcasted a route discovery req
	int* last_seen_req_id;

	// Used for various tasks
	network_address_t tmp_addr;
	network_address_t tmp_addr2;

	// Used to handle routing and discovery requests
	route_request_t route_request;
	int current_req_id;
	int path_len;
	int ttl; 

	// Get the buffer without the routing header
	char* buffer_without_routing = (char*) (arg->buffer + sizeof(struct routing_header));

	// Used to get the data buffer
	char* data_buffer;

	// Handle the mini route stuff

	// Extract the information from the routing header
	routing_header_t routing_header = (routing_header_t) arg->buffer;
	char routing_packet_type = routing_header->routing_packet_type;
	unpack_address(routing_header->destination, dst_addr);
	current_req_id = unpack_unsigned_int(routing_header->id);
	ttl = unpack_unsigned_int(routing_header->ttl);
	path_len = unpack_unsigned_int(routing_header->path_len);

	// Get the data buffer & data length
	switch(buffer_without_routing[0])
	{
		case (char) PROTOCOL_MINISTREAM:
			data_buffer = (char*) (buffer_without_routing + sizeof(struct mini_header_reliable));
			data_len = arg->size - sizeof(struct routing_header) - sizeof(struct mini_header_reliable);
			break;

		//default: todo: put this back in, but leave w/o it for testing
		case (char) PROTOCOL_MINIDATAGRAM:
			data_buffer = (char*) (buffer_without_routing + sizeof(struct mini_header));
			data_len = arg->size - sizeof(struct routing_header) - sizeof(struct mini_header);
			break;	
	}

	network_get_my_address(my_addr);
	//if (network_compare_network_addresses(my_addr, dst_addr) == 0 && ttl == 0)
	if (my_addr[0] != dst_addr[0] && ttl == 0)
	{
		free(arg);
		set_interrupt_level(prev_level);
		return;
	}

	switch (routing_packet_type)
	{
		// If this is a data packet
		case ROUTING_DATA:
			// If the data packet is meant for us, then break and let the higher
			// protocols get the data
			unpack_address(routing_header->path[path_len-1], tmp_addr);
			if (network_compare_network_addresses(my_addr, tmp_addr) != 0)
			{
				break;
			}
			 else
			{
				// If it's not meant for us, we must pass it along

				// Go through the path and find the next node
				for (i = 0; i < path_len; i++)
				{
					unpack_address(routing_header->path[i], tmp_addr);

					// If this node is us, break - the node we need to send to is next
					if (network_compare_network_addresses(tmp_addr, my_addr) != 0)
					{
						break;
					}
				}

				// If we're the last node (i == path_len-1) or we weren't found in it, quit
				if (i >= path_len - 1)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// Now we'll forward the packet by reusing the headers we have

				// Get the next host in the path and set it as the packet's dst
				unpack_address(routing_header->path[i+1], tmp_addr);
				pack_unsigned_int(routing_header->ttl, ttl - 1);

				// Send the packet onward in the route
				network_send_pkt(tmp_addr, arg->size - data_len, 
								(char*) arg->buffer, data_len, data_buffer);

				// Revert the header back (not entirely necessary)
				//pack_unsigned_int(routing_header->ttl, ttl);
			}

			free(arg);
			set_interrupt_level(prev_level);
			return;
			break;

		case ROUTING_ROUTE_DISCOVERY:
			// We're not the dst, so just forward this packet along
			//if (network_compare_network_addresses(my_addr, dst_addr) == 0)
			if (my_addr[0] != dst_addr[0])
			{
				// Check if we're in the path, if so, no need to send again (no loops)
				for (i = 0; i < path_len; i++)
				{
					unpack_address(routing_header->path[i], tmp_addr);
					if (network_compare_network_addresses(tmp_addr, my_addr) != 0)
					{
						break;
					}
				}

				// If we were in the path, return - no need to do anything else
				if (i < path_len) 
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// todo: this next part w/ the discovery packets seen is probably wrong...
				// also, lookup the "explain" part in my txt

				// todo: need something to clean up old discovery packets

				// Check if we've already seen this discovery request - if so, don't resend
				last_seen_req_id = (int*) hashmap_get(discovery_packets_seen, current_req_id);
				if (last_seen_req_id != NULL)
				{
					// If this exists, then we've already seen this packet - no need to resend
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// Now we'll rebroadcast the discovery packet by reusing the header we have

				// Modify the header as needed
				pack_unsigned_int(routing_header->path_len, path_len+1);
				pack_address(routing_header->path[path_len], my_addr);
				pack_unsigned_int(routing_header->ttl, ttl - 1);

				// Broadcast this packet
				network_bcast_pkt(arg->size - data_len, (char*) arg->buffer, data_len, data_buffer);

				// Revert the header - dont need to actually remove from route
				/*pack_unsigned_int(routing_header->path_len, path_len);
				pack_unsigned_int(routing_header->ttl, ttl);

				// update already broadcasted hashmap - just put a garbage ptr in 
				hashmap_insert(discovery_packets_seen, current_req_id, (void*) 0x555555);
				*/
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}
			 else
			{
				// If we were the host being sought, send a reply packet back
				// and ensure the higher protocols get the data sent

				// reverse the path so we can send a packet back to the host
				// Don't forget to add ourselves to the route
				path_len++;
				pack_unsigned_int(routing_header->path_len, path_len);
				pack_address(routing_header->path[path_len-1], my_addr);

				for (i = 0; i < path_len/2; i++)
				{
					unpack_address(routing_header->path[path_len-1-i], tmp_addr);
					unpack_address(routing_header->path[i], tmp_addr2);
					pack_address(routing_header->path[i], tmp_addr);
					pack_address(routing_header->path[path_len-1-i], tmp_addr2);
				}

				// We'll start sending the packet back now by reusing the header we have

				// Prepare the headers
				pack_unsigned_int(routing_header->ttl, MAX_ROUTE_LENGTH);
				routing_header->routing_packet_type = ROUTING_ROUTE_REPLY;

				// send a route reply packet, starting from the next host in the reversed route
				unpack_address(routing_header->path[1], tmp_addr);
				pack_address(routing_header->destination, tmp_addr);

				network_send_pkt(tmp_addr, arg->size - data_len, 
								(char*) arg->buffer, 0, NULL);				

				// Revert the header
				/*pack_unsigned_int(routing_header->ttl, ttl);
				routing_header->routing_packet_type = ROUTING_ROUTE_DISCOVERY;

				// Reverse the path back
				for (i = 0; i < path_len/2; i++)
				{
					unpack_address(routing_header->path[path_len-1-i], tmp_addr);
					unpack_address(routing_header->path[i], tmp_addr2);
					pack_address(routing_header->path[i], tmp_addr);
					pack_address(routing_header->path[path_len-1-i], tmp_addr);
				}
				*/
				// DONT return, ensure that the higher protocols will get the data
				// ^ never mind. return, it will send a data packet later.
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			break;

		case ROUTING_ROUTE_REPLY:
			unpack_address(routing_header->path[path_len-1], tmp_addr);

			// If we were the initiator of the request and just got our response
			//if (network_compare_network_addresses(my_addr, tmp_addr) != 0)
			if (my_addr[0] == tmp_addr[0])
			{
				// Get the addr of the host we were trying to discover
				unpack_address(routing_header->path[0], tmp_addr);

				// find the discovery request struct for this dst addr
				//route_request = (route_request_t) hashmap_get(current_discovery_requests, hash_address(tmp_addr));
			route_request = (route_request_t) hashmap_get(current_discovery_requests, tmp_addr[0]);
				if (route_request == NULL)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
					// it could be we already got this path
					break;
				}
				// Check if we already got this path, but miniroute_send_pkt() hasn't deleted the req struct yet
				if (route_request->interrupt_arg != NULL)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
					break;
				}

				route_request->interrupt_arg = arg;
				semaphore_V(route_request->initiator_sem);
				set_interrupt_level(prev_level);
				return;
			}
			 else
			{
				// Find the next node in the route

				for (i = 0; i < path_len; i++)
				{
					unpack_address(routing_header->path[i], tmp_addr);

					// Stop if we found ourselves - we need to send to the next node
					if (network_compare_network_addresses(tmp_addr, my_addr) != 0)
					{
						break;
					}
				}

				// If we were the last node OR not in the route at all
				if (i >= path_len - 1)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// We'll forward the reply along by reusing the header

				// Get the next host in the path and set it as the packet's dst
				unpack_address(routing_header->path[i+1], tmp_addr);
				pack_unsigned_int(routing_header->ttl, ttl - 1);
				pack_address(routing_header->destination, tmp_addr);

				// Send the packet onward in the route
				network_send_pkt(tmp_addr, arg->size - data_len, 
								(char*) arg->buffer, 0, NULL);

				// Make sure we set the header back
				//pack_unsigned_int(routing_header->ttl, ttl);
			}

			free(arg);
			set_interrupt_level(prev_level);
			return;
			break;
	}

	// If we're here, the packet was meant for us
	// The "normal" packet without the routing header is in buffer_without_routing

	// Adjust arg->size in case something uses it
	arg->size -= sizeof(struct routing_header);

	// Check the protocol
	switch (buffer_without_routing[0])
	{
		case (char) PROTOCOL_MINIDATAGRAM:

			// Extract data from the network interrupt arg
			//network_address_copy(arg->addr, addr);

			// Get the header struct, unpack the parameters
			header = (mini_header_t) buffer_without_routing; 
			dst_port_number = (int) unpack_unsigned_short(header->destination_port);

			// Ensure the port number is valid
			if (dst_port_number < MIN_UNBOUND || dst_port_number > MAX_UNBOUND)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Then ensure the miniport exists
			if (miniports[dst_port_number] == NULL)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Add the arg to the queue
			queue_append(miniports[dst_port_number]->port_data.unbound.data_queue, arg);

			// Wake up thread that's waiting to receive - sem_V()
			semaphore_V(miniports[dst_port_number]->port_data.unbound.data_ready);

			// Ensure the argument isn't free'd
			enqueued = 1;
			set_interrupt_level(prev_level);
			return;
			break;

		case PROTOCOL_MINISTREAM:
			// Get the total size of the packet and data length
			packet_size = arg->size;
			data_len = packet_size - sizeof(struct mini_header_reliable);

			// Get the header and extract information
			header_reliable = (mini_header_reliable_t) buffer_without_routing;
			src_port_number = (int) unpack_unsigned_short(header_reliable->source_port);
			dst_port_number = (int) unpack_unsigned_short(header_reliable->destination_port);
			unpack_address(header_reliable->source_address, src_addr);
			unpack_address(header_reliable->destination_address, dst_addr);
			seq_num = (int) unpack_unsigned_int(header_reliable->seq_number);
			ack_num = (int) unpack_unsigned_int(header_reliable->ack_number);

			// Don't respond if socket doesn't exist - will trigger SOCKET_NOSERVER for client
			if (minisockets[dst_port_number] == NULL)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Get the socket in question
			socket = minisockets[dst_port_number];

			// Check if packet was meant for us - ignore if not
			network_get_my_address(my_addr);
			if (network_compare_network_addresses(my_addr, dst_addr) == 0)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			if (socket->status == TCP_PORT_CLOSING || socket->waiting == TCP_PORT_WAITING_CLOSE)
			{
				free(arg);
				set_interrupt_level(prev_level);
				return;
			}

			// Packet handling for established connections
			if (socket->status != TCP_PORT_LISTENING)
			{
				// Ensure source address is correct - ignore if not
				if (network_compare_network_addresses(src_addr, socket->dst_addr) == 0 
					|| src_port_number != socket->dst_port)
				{
					if (header_reliable->message_type == MSG_SYN)
					{
						// A client is trying to connect to an already-connected port
						// Send them a FIN, which will result in their client
						// returning a SOCKET_BUSY error
						transmit_packet(socket, src_addr, src_port_number, 0, 
											MSG_FIN, 0, NULL, &error);
					}

					free(arg);
					set_interrupt_level(prev_level);
					return;
				}


				/* We got a duplicate SYN and need to ensure that the host gets
				 * another SYNACK. The thread that sent the SYNACK will currently
				 * be retransmitting the SYNACKs, as it didn't get an ACK. If it 
				 * was done with the retransmission sequence, the socket would be
				 * closed, and this would therefore not have gotten this far.
				 * HOWEVER:
				 * If the retransmission sequence already sent its LAST 
				 * retransmission and was waiting on it, then this duplicate SYN 
				 * will NOT get a SYNACK, as the retransmission is just waiting
				 * out the last alarm before it ends. Therefore, if this is the case,
				 * reset the timeout to the last timeout value so it sends just
				 * one more SYNACK.
				 *
				 * Professor Sirer mentioned that this isn't even necessary,
				 * but this does seem to make the code follow the specs more.
				 */
				if (header_reliable->message_type == MSG_SYN)
				{
					// If the timeout is at 6400, then it's the last transmission
					// but it hasn't been doubled yet. If it's 12800, it's just
					// been doubled. In each case we want to keep it at 6400 
					// at the end of the while loop, so we set the timeout to half
					// it's current value.
					if (socket->timeout >= 6400)
					{
						socket->timeout /= 2;
					}

					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// If we were trying to connect and got a FIN, that means the socket's busy
				if (socket->status == TCP_PORT_CONNECTING && header_reliable->message_type == MSG_FIN)
				{
					// Not connected, got a FIN - that means we couldnt start connection b/c it was busy
					// This will let the client function infer that
					socket->status = TCP_PORT_COULDNT_CONNECT;

					// Wake it up so it can end the retransmission sequence
					semaphore_V(socket->wait_for_ack_sem);

					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				/* Note: the code below handles ACKs. It also inherently deals with
				 * duplicate ACKs. We have a status code that indicates whether the socket
				 * is waiting for an ACK or not. If it's set and we get an ACK (or any 
				 * packet) with the right ACK number, we can process it. However, if our 
				 * status indicates we're NOT waiting for an ACK, we can infer from the
				 * fact that window_size = 1 that we already got the only ACK we could've
				 * been expecting, and this new one is therefore a duplicate. 
				 */

				// If we're waiting on an ACK
				if (socket->waiting == TCP_PORT_WAITING_ACK /*|| socket->waiting == TCP_PORT_WAITING_ACK_WAKING*/)
				{
					// This can be an ACK or really any other data packet, we just
					// need the ACK number
					if (ack_num == socket->seq_num)
					{
						// Update our status to show we're no longer waiting for an ACK
						socket->waiting = TCP_PORT_WAITING_NONE;

						// Wake up the thread waiting for the ACK
						semaphore_V(socket->wait_for_ack_sem);
					}
					 else if (ack_num == socket->seq_num - 1)
					{
						// This follows the same logic from the comment block around
						// line 170. 
						if (socket->timeout >= 6400)
						{
							socket->timeout /= 2;
						}	
					}
				}

				// If it's an ACK, it requires no further processing
				if (header_reliable->message_type == MSG_ACK && data_len == 0)
				{
					free(arg);
					set_interrupt_level(prev_level);
					return;
				}

				// Check if it's a SYNACK we're waiting for
				if (socket->waiting == TCP_PORT_WAITING_SYNACK && header_reliable->message_type == MSG_SYNACK)
				{
					// We're now fully connected in our eyes, handshake complete
					socket->waiting = TCP_PORT_WAITING_NONE;
					semaphore_V(socket->wait_for_ack_sem);
				}

				// If we're here, the packet isnt an ACK or SYN, so we should ACK it

				// First check if we should increment our ack number
				if (seq_num == socket->ack_num + 1)
				{
					socket->ack_num++;
				}
				 else
				{
					// It's a duplicate, don't add to queue
					duplicate = 1;
				}

				// Next, perform the ACK, don't incr the seq#
				transmit_packet(socket, socket->dst_addr, socket->dst_port, 
								0, MSG_ACK, 0, NULL, &error);	

				/* Note: the code below handles FINs, and is also protected against
				 * duplicate FINs inherently. The seq_num == ack_num check doesn't
				 * guarantee it's not a duplicate; however, if we process one FIN,
				 * then the socket's status is set to TCP_PORT_CLOSING. Therefore, 
				 * if we get another FIN, we can tell that the port is already closing
				 * and we don't need to process it, which also ensures we don't 
				 * process duplicate FINs multiple times. We'll include the
				 * duplicate == 0 check just for good measure, however.
				 */

				// We're required to close the conn 15s after we ACK a FIN, so do that here
				if (seq_num == socket->ack_num
					&& header_reliable->message_type == MSG_FIN
					&& socket->status != TCP_PORT_CLOSING
					&& duplicate == 0)
				{
					socket->status = TCP_PORT_CLOSING;
					queue_append(sockets_to_delete, socket);
					semaphore_V(socket_needs_delete);			
				}
			}
			 else if (socket->status == TCP_PORT_LISTENING)
			{
				// Start a connection with the client
				if (header_reliable->message_type == MSG_SYN)
				{
					// Update socket's dst addr & dst port to the client's
					network_address_copy(src_addr, socket->dst_addr);
					socket->dst_port = src_port_number;

					// Set the status to connecting
					socket->status = TCP_PORT_CONNECTING;
					
					// Awake the create_server thread, it'll handle the rest
					semaphore_V(socket->wait_for_ack_sem);
				}
			}

			// Add the packet to the socket's packet queue if not duplicate & it's a data pkt
			if (duplicate == 0 && header_reliable->message_type == MSG_ACK && data_len != 0)
			{
				enqueued = 1;
				queue_append(socket->waiting_packets, arg);
				if (socket->data_len == 0)
					semaphore_V(socket->packet_ready);
			}

			// remember to free arg if we dont push this to the tcp recv queue
			break;
	}

	if (enqueued == 0)
	{
		free(arg);
	}

	// Restore the interrupt level
	set_interrupt_level(prev_level);

	return;
}