Пример #1
0
/*
 * sleep with timeout in milliseconds. Need to disable interrupts during method call as we
  are not using semaphore for sleeping minithreads.
 */
void minithread_sleep_with_timeout(int delay) {
  interrupt_level_t old_level = set_interrupt_level(DISABLED);
  minithread_t* current_thread = schedule_data->running_thread; 
  register_alarm(delay, wakeup_thread, (void *) current_thread); //registers alarm
  minithread_stop(); //moves to next thread
  set_interrupt_level(old_level);
}
Пример #2
0
/*
 * Find path to the destination. Return a pointer to a miniroute_path struct,
 * or NULL if no route can be found.
 */
static miniroute_path_t
miniroute_discover_path(network_address_t dest)
{
    miniroute_path_t path = NULL;
    struct routing_header routing_hdr;
    miniroute_disc_hist_t disc;

    miniroute_pack_discovery_hdr(&routing_hdr, dest);
    disc = miniroute_dischist_from_hdr(&routing_hdr);
    miniroute_cache_put_item(disc_cache, disc);

#if MINIROUTE_CACHE_DEBUG == 1
    printf("Broadcasting discovery packet with header: \n");
    miniroute_print_hdr(&routing_hdr);
#endif
    network_bcast_pkt(MINIROUTE_HDRSIZE, (char*)&routing_hdr, 0, NULL);
    discovery_alarm = register_alarm(12000, semaphore_Signal, discovery_sig);
    semaphore_P(discovery_sig);
    /* Success when alarm is disabled by receiving a reply */
    if (-1 == discovery_alarm) {
        path = discovered_path;
        discovered_path = NULL;
    }
    return path;
}
Пример #3
0
/*
 * sleep with timeout in milliseconds
 */
void minithread_sleep_with_timeout(int delay)
{
	// Create the sleep semaphore
	semaphore_t sleep_sem = semaphore_create();
	interrupt_level_t prev_level; // ISO C90...

	// Initialize it to a value of 0 so it can act as a way to signal threads
	semaphore_initialize(sleep_sem, 0);

	// Disable interrupts
	prev_level = set_interrupt_level(DISABLED);

	// Register the alarm
	register_alarm(delay, &minithread_sleep_alarm_wakeup, sleep_sem); 
	
	// If, at this point, interrupts were enabled, we could context switch away
	// the alarm could be triggered afterwards before the semaphore_P below was
	// called (depending on this threads priority level, etc) and then when this
	// thread finally calls semaphore_P(), it will hang forever.
	// Therefore we have interrupts disabled.

	// Wait on the sleep semaphore
	semaphore_P(sleep_sem);

	// Now that we've awoken, free the sleep semaphore
	semaphore_destroy(sleep_sem);

	// Restore the previous interrupt level
	set_interrupt_level(prev_level); // is this necessary? 

}
Пример #4
0
/*
 * sleep with timeout in milliseconds
 */
void 
minithread_sleep_with_timeout(int delay)
{
  interrupt_level_t l = set_interrupt_level(DISABLED);
  register_alarm(delay, get_new_alarm_handler(), minithread_self());
  set_interrupt_level(l);
  minithread_stop();
}
Пример #5
0
//Supposed to be run in the background
void delete_sockets(void *arg) {
	minisocket_t socket;
	semaphore_P(delete_semaphore);
	queue_dequeue(sockets_to_delete, (void**) &socket);

	register_alarm(15000, &delete_socket, (void*) socket);
	semaphore_V(delete_semaphore);
}
Пример #6
0
int wait_for_arrival_or_timeout(semaphore_t sema, alarm_t* alarm, int timeout) {
	if (sema == NULL) {
		fprintf(stderr, "ERROR: wait_for_arrival_or_timeout() passed uninitialized semaphore\n");
		return -1;
	}
	*alarm = (alarm_t) register_alarm(timeout, (alarm_handler_t) semaphore_V, (void*) sema);
	semaphore_P(sema);
	// fprintf(stderr, "Woke up!\n");
	if (*alarm != NULL) {
		return deregister_alarm((alarm_id) (*alarm));
	} else {
		return 0;
	}
}
Пример #7
0
/* Prune entries older than 3 seconds from the route cache */
void prune_route_cache(void* arg)
{
	// This will store the next item in the linked list of hashmap entries
	hashmap_item_t next_item;

	// This will store a pointer to the route data struct
	route_data_t route_data;

	hashmap_item_t item;

	// Get the first item in the hashmap (first in the chronological sense)
	semaphore_P(route_cache_sem);
	item = hashmap_get_first(route_cache);

	// Go through all the items until we arrive at one that isn't ready for deletion
	while (item != NULL)
	{
		// Get the next item ahead of time, in case we delete this item
		next_item = hashmap_get_next(item);

		// Get the value of the hashmap, which is a route_data struct
		route_data = (route_data_t) hashmap_item_get_value(item);

		// Check if the entry is more than 3 seconds old
		if ((ticks - route_data->time_found) * PERIOD/MILLISECOND > 3000)
		{
//printf("Deleting key %d\n", hashmap_item_get_key(item));

			// Delete the route data struct
			delete_route_data(route_data);

			// Run hashmap delete, which will delete the hashmap_item struct (i.e. "item")
			hashmap_delete(route_cache, hashmap_item_get_key(item));
		}
		 else
		{
			// If the entry wasn't ready for deletion, then we can end (since the
			// linked list is maintained in chronological order of insertion)
			break;
		}

		// If we deleted the item, move to the next one
		item = next_item;
	}
	semaphore_V(route_cache_sem);

	// Once we're done, register the alarm to run again in 3 seconds
	register_alarm(3000, &prune_route_cache, NULL);
}
Пример #8
0
/* Performs any initialization of the miniroute layer, if required. */
void miniroute_initialize()
{
	int i;

	// Cache routes to hosts we've already found - it's of a static size
	route_cache = hashmap_create(SIZE_OF_ROUTE_CACHE, 0);

	// Cache the ID of the last discovery request we've seen from each host
	discovery_packets_seen = hashmap_create(10, 1);

	// The current discovery requests that are running
	current_discovery_requests = hashmap_create(10, 1);

	// The starting ID for discovery requests emanating from this host
	route_request_id = 0;

	// Setup a semaphore to control access to the route cache
	// also used to ensure the cache cleanup thread doesn't delete a route while
	// we're using it
	route_cache_sem = semaphore_create();
	semaphore_initialize(route_cache_sem, 1);

	// Create a semaphore to control access to the request ID variable
	request_id_sem = semaphore_create();
	semaphore_initialize(request_id_sem, 1);

	// Create a malloc'd chunk of route_req_seen structs to store info on 
	// route requests we've recently seen
	route_reqs_seen = (route_req_seen_t*) malloc(sizeof(route_req_seen_t) * ROUTE_REQS_TO_STORE);

	for (i = 0; i < ROUTE_REQS_TO_STORE; i++)
	{
		route_reqs_seen[i] = (route_req_seen_t) malloc(sizeof(struct route_req_seen));
		route_reqs_seen[i]->in_use = 0; // used to indicate this isn't in use
	}

	route_reqs_idx = 0;

	// Register an alarm to prune the route cache every 3 seconds
	register_alarm(3000, &prune_route_cache, NULL);
}
Пример #9
0
void minisocket_close(minisocket_t *socket)
{
  if (socket) {
    if (socket->socket_state == CLOSING) {
      socket->socket_state = WAITING_SYN;
      return;
    }
    if (socket->socket_state == CLOSED) {
      minisocket_free(socket);
      return;
    }

    minisocket_error s_error;
    int wait_val = 100;
    while (wait_val <= 12800) {
      send_control_message(MSG_FIN, socket->remote_port, socket->remote_addr,
			   socket->local_port, socket->seq_number, socket->ack_number, &s_error);
      socket->seq_number += 1;
      if (s_error == SOCKET_OUTOFMEMORY) {
	return;
      }
      
      alarm_id a = register_alarm(wait_val, (alarm_handler_t) semaphore_V, socket->wait_for_ack);
      semaphore_P(socket->wait_for_ack);
      interrupt_level_t old_level = set_interrupt_level(DISABLED);
      if (socket->ack_flag == 0) {
	wait_val *= 2;
	socket->seq_number--;
	set_interrupt_level(old_level);
	continue;
      }
      else if (socket->ack_flag == 1) {
	deregister_alarm(a);
	minisocket_free(socket);
	set_interrupt_level(old_level);
	return;
      }
    }
  }
  semaphore_V(socket->send_receive_mutex);
}
Пример #10
0
void delete_sockets(void* arg)
{
	// This is a background thread, because we can't register alarms in the IH as
	// it uses malloc, which is very inefficient...

	minisocket_t socket;
	interrupt_level_t prev_level;

	while (1)
	{
		// Both of the below data structures are accessed by the IH, so we must
		// disable interrupts
		prev_level = set_interrupt_level(DISABLED);
		semaphore_P(socket_needs_delete);

		queue_dequeue(sockets_to_delete, (void**) &socket);
		set_interrupt_level(prev_level);

		register_alarm(15000,  &delete_socket, (void*) socket);
		//minisocket_destroy(socket, 0);
	}
}
Пример #11
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;
}
Пример #12
0
void minisocket_close(minisocket_t *socket) {
  if (socket == NULL || mini_socket_data[socket->local_port_number] == NULL || socket->state == CLOSED) {
    return; // no cleanup necessary 
  }

  fprintf(stderr, "Closing time \n");
  mini_header_reliable_t header;
  minisocket_create_reliable_header((mini_header_reliable_t *) &header, socket, socket->remote_port_number, socket->remote_address, MSG_FIN); 
  int send_success = 0;
  int timeout = START_TIMEOUT / 2; 
  
  for (int i = 0; i < MAX_FAILURES; i++) {
    if (socket->state == CLOSED) {
      return; //received a MSG_FIN message in network_handler, so stop re-tries
    } 
    timeout = timeout * 2;
    network_send_pkt(socket->remote_address, 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 (!send_success && !alarm_fired) {
      semaphore_P(socket->ack_ready);

      //alarm has fired, since there are no packets to be received
      if (queue_length(socket->acknowledgements) == 0) {
        printf("CLOSE queue length: %d\n", queue_length(socket->acknowledgements)); 
        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; 
         
          //already checked port and address in network_handler 
          if (received_header->message_type == MSG_ACK) { 
            deregister_alarm(timeout_alarm_id); //only deregister alarm when the right packet is found
            send_success = 1; 
            free(interrupt_message); 
            break;
          }
          else {
            free(interrupt_message);
          }
        }
      }
    }
    if (send_success) {
      break;
    }
  }
  printf("out of CLOSE\n");
  //sender considers the connection closed, even if MSG_ACK not received
  if (socket->state != CLOSED) {
    printf("calling DESTROY from CLOSE\n"); 
    minisocket_destroy(socket);
  }
}
Пример #13
0
int minisocket_send(minisocket_t *socket, const char *msg, int len, minisocket_error *error) {
  //Check params
  if (socket == NULL || mini_socket_data[socket->local_port_number] != socket || len < 0 || msg == NULL) {
    *error = SOCKET_INVALIDPARAMS;
    return -1;
  }
  if (socket->state == CLOSED) {
    *error = SOCKET_SENDERROR;
    return -1;
  }
  if (len == 0) {
    return 0;
  }
  //can't send more bytes than we have
  if (len > strlen(msg)) {
    len = strlen(msg);
  }

  int bytes_sent = 0;
  int max_data_size = MAX_NETWORK_PKT_SIZE - sizeof(mini_header_reliable_t);
  int data_left = len;
  int packet_size;
 
  mini_header_reliable_t header; 
  minisocket_create_reliable_header((mini_header_reliable_t *) &header, socket, socket->remote_port_number, socket->remote_address, MSG_ACK);

  //Keep sending until all is sent
  while (data_left != 0) {
    if (data_left >= max_data_size) {
      packet_size = max_data_size;
    }
    else {
      packet_size = data_left;
    }
    data_left -= packet_size;
    pack_unsigned_int(header.seq_number, socket->seq);
    int send_success = 0;

    //Attempt to send message
    int timeout = START_TIMEOUT/2; 
    for (int i = 0; i < MAX_FAILURES; i++) {
      //printf("i: %d\n", i); 
      timeout = timeout * 2;
      //update the seq and ack numbers for the header from the socket  
      //printf("seq: %u, ack: %u\n", socket->seq, socket->ack);
      
      pack_unsigned_int(header.ack_number, socket->ack);
      pack_unsigned_int(header.seq_number, socket->seq);

      network_send_pkt(socket->remote_address, sizeof(mini_header_reliable_t), (char *) &header, packet_size, (char *) msg); 
      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 (!send_success && !alarm_fired) {
        semaphore_P(socket->ack_ready);

        if (queue_length(socket->acknowledgements) == 0) {
       //   printf("no message in queue\n");
          alarm_fired = 1; //goes to next iteration of for loop
        }
        else {
        //  printf("length of queue currently %d\n", queue_length(socket->acknowledgements));
          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); 

          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);
            unsigned int new_ack = unpack_unsigned_int(received_header->ack_number);
            //printf("Received an acknowledgment with ack number %u \n", new_ack);
          
            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 && new_ack == (socket->seq + packet_size)) {
                  //same address, same ports, right message, right ack
                  deregister_alarm(timeout_alarm_id); //only deregister alarm when the right packet is found
                  send_success = 1; 
                  bytes_sent += packet_size;
                  msg += packet_size;
                  socket->seq += packet_size;
                  free(interrupt_message); 
                  break;
            }
            else {
              free(interrupt_message);
            }
          }
        }
      }
      if (send_success) {
        break;
      }
      
    }
    if (!send_success) { //Got a timeout, should close down socket
      *error = SOCKET_SENDERROR;
      minisocket_destroy(socket);
      return bytes_sent;
    }
  }
  //printf("\n\n");
  return bytes_sent;
}
Пример #14
0
minisocket_t* minisocket_client_create(const network_address_t addr, int port, minisocket_error *error) {
    //Check socket number first 
  if (valid_server_port(port) == 0) {
    *error = SOCKET_INVALIDPARAMS;
    return NULL;
  }       
  //Then check if we can make another client
  if (client_count >= MAX_CLIENTS) {
    *error = SOCKET_NOMOREPORTS;
    return NULL;
  }
  //create new minisocket
  minisocket_t* socket = (minisocket_t *) malloc(sizeof(minisocket_t));
  if (socket == NULL) {
    *error = SOCKET_OUTOFMEMORY;
    return NULL; //OOM
  }
  
  while (mini_socket_data[next_port]) {
    next_port = ((next_port + 1) % PORT_RANGE);
  }
 
  socket->socket_type = CLIENT_TYPE;
  socket->local_port_number = next_port;
  next_port = ((next_port + 1) % PORT_RANGE);
  socket->state = CONNECTING;
  socket->seq = 0;
  socket->ack = 0;
  network_address_copy(addr, socket->remote_address);
  socket->remote_port_number = (unsigned short) port;
  network_address_copy(addr, socket->remote_address);
  socket->next_read = 0;

  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();

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

  mini_header_reliable_t header; 
  minisocket_create_reliable_header((mini_header_reliable_t *) &header, socket, socket->remote_port_number, addr, MSG_SYN);

  //minisocket and header now created, try to establish connection
  pack_unsigned_int(header.seq_number, socket->seq);
  pack_unsigned_int(header.ack_number, socket->ack); 

  //send first message and wait for response
  int response = 0; //no response yet
  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_SYN in client, i: %d\n", i);
    timeout = timeout * 2;
    network_send_pkt(addr, 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;

    while (!response && !alarm_fired) {
      semaphore_P(socket->ack_ready);
      
      //If queue length == 0, then the alarm must have fired
      if (queue_length(socket->acknowledgements) == 0) {
        alarm_fired = 1; //goes to next iteration of for loop
      }
      //otherwise, we received a packet
      else {
        network_interrupt_arg_t *interrupt_message;
        interrupt_level_t old_level = set_interrupt_level(DISABLED);
        queue_dequeue(socket->acknowledgements, (void **) &interrupt_message);
        set_interrupt_level(old_level); 

        // if message not null
        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) {
            //if SYNACK
             printf("CLIENT\n");

            if (received_header->message_type == MSG_SYNACK) {
              printf("GOT message SYN_ACK\n"); 
              deregister_alarm(timeout_alarm_id);
              response = 1;
              break;
            }
            //if MSG_FIN
            else if (received_header->message_type == MSG_FIN) {
              printf("got message MSG_FIN in client\n");
              //server already in use
              deregister_alarm(timeout_alarm_id);
              *error = SOCKET_BUSY;
              response = 1;
              minisocket_destroy(socket);
              return NULL; 
            }
            //WRONG MESSAGE TYPE
            else {
              printf("wrong message type received in client\n");
              //TODO : try another message type, maybe do nothing?
            }
          }
        }
      }
    }
    if (response) {
      break;
    }
  }
  // timeout after 12.8s occured, close down socket
  if (response != 1) {
    printf("full timeout in client sending SYN\n"); 
    *error = SOCKET_NOSERVER;
    minisocket_destroy(socket);
    return NULL;
  }

  // send final MSG_ACK once to server (future data packets will also have MSG_ACK as header type)
  header.message_type = MSG_ACK; 
  printf("sending final MSG_ACK and leaving client create\n"); 
  network_send_pkt(addr, sizeof(mini_header_reliable_t), (char *) &header, 0, empty_message);   
  socket->state = CONNECTED;
  client_count++;
  return socket;
}
Пример #15
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; 
}
Пример #16
0
minisocket_t* minisocket_client_create(const network_address_t addr, int port, minisocket_error *error)
{

  if (!addr || port < MIN_SERVER_PORT || port > MAX_SERVER_PORT) {
    *error = SOCKET_INVALIDPARAMS;
    return NULL;
  }

  int port_val = -1;
  // CHECK what n_client_ports does
  if (!ports[n_client_ports]) {
    port_val = n_client_ports;
  }
  else {
    for (int i = MIN_CLIENT_PORT; i <= MAX_CLIENT_PORT; i++) {
      if (!ports[i]) {
	port_val = i;
	break;
      }
    }
  }
  n_client_ports = port_val + 1;
  if (n_client_ports > MAX_CLIENT_PORT) {
    n_client_ports = 0;
  }
    
  if (port_val == -1) {
    *error = SOCKET_NOMOREPORTS;
    return NULL;
  }

  minisocket_t *new_socket =  (minisocket_t *) malloc(sizeof(minisocket_t));
  if (!new_socket) {
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_socket->socket_state = INITIAL;
  semaphore_P(ports_mutex);
  ports[port_val] = new_socket;
  semaphore_V(ports_mutex);
  new_socket->socket_type = 'c';

  network_address_copy(local_host, new_socket->local_addr);
  //network_get_my_address(new_socket->local_addr);

  new_socket->local_port = port_val;
  network_address_copy(addr, new_socket->remote_addr);
  new_socket->remote_port = port;
  new_socket->data = queue_new();
  new_socket->data_ready = semaphore_create();
  new_socket->wait_for_ack = semaphore_create();
  new_socket->send_receive_mutex = semaphore_create();
  semaphore_initialize(new_socket->data_ready, 0);
  semaphore_initialize(new_socket->wait_for_ack, 0);
  semaphore_initialize(new_socket->send_receive_mutex, 1);
  new_socket->socket_state = WAITING_SYNACK;
  
  minisocket_error s_error;
  int wait_val = 100;
  interrupt_level_t old_level;
  while (wait_val <= 12800) {

    send_control_message(MSG_SYN, new_socket->remote_port, new_socket->remote_addr, new_socket->local_port, 0, 0, &s_error);
    new_socket->seq_number = 1;
    new_socket->ack_number = 0;   
    if (s_error == SOCKET_OUTOFMEMORY) {
      minisocket_free(new_socket);
      semaphore_P(ports_mutex);
      ports[new_socket->local_port] = NULL;
      semaphore_V(ports_mutex);
      *error = s_error;
      return NULL;
    }
    
    alarm_id a = register_alarm(wait_val, (alarm_handler_t) semaphore_V, new_socket->data_ready);
    semaphore_P(new_socket->data_ready);
    old_level = set_interrupt_level(DISABLED);
    if (queue_length(new_socket->data)) {
      deregister_alarm(a);
    }
    set_interrupt_level(old_level);
    if (!queue_length(new_socket->data)) {
      wait_val *= 2;
      continue;
    }
    network_interrupt_arg_t *arg = NULL;
    queue_dequeue(new_socket->data, (void **) &arg);
    mini_header_reliable_t *header = (mini_header_reliable_t *) arg->buffer;
    network_address_t saddr;
    unpack_address(header->source_address, saddr);
    int sport = unpack_unsigned_short(header->source_port);
    if (sport == new_socket->remote_port && network_compare_network_addresses(saddr, new_socket->remote_addr)) {
      if (header->message_type - '0' == MSG_SYNACK) {
	new_socket->seq_number = 1;
	new_socket->ack_number = 1;
	send_control_message(MSG_ACK, new_socket->remote_port, new_socket->remote_addr, new_socket->local_port, 1, 1, &s_error);
	if (s_error == SOCKET_OUTOFMEMORY) {
	  minisocket_free(new_socket);
	  semaphore_P(ports_mutex);
	  ports[new_socket->local_port] = NULL;
	  semaphore_V(ports_mutex);
	  *error = s_error;
	  return NULL;
	}
	network_interrupt_arg_t *packet = NULL;
	while (queue_dequeue(new_socket->data, (void **)&packet) != -1) {
	  free(packet);
	}
	semaphore_initialize(new_socket->data_ready, 0);
	new_socket->socket_state = OPEN;
	new_socket->seq_number = 2;
	new_socket->ack_number = 1;
	return new_socket;
      }
      if (header->message_type -'0' == MSG_FIN) {
	minisocket_free(new_socket);
	return NULL;
      }
    }
    free(arg);
  }
  minisocket_free(new_socket);
  return NULL;
}
Пример #17
0
int minisocket_send(minisocket_t *socket, const char *msg, int len, minisocket_error *error)
{
  if (socket->socket_state == CLOSED || socket->socket_state == CLOSING) {
    *error=SOCKET_SENDERROR;
    return 0;
  }
  if (!socket || socket->socket_state != OPEN || !msg || len == 0)
  {
    *error = SOCKET_INVALIDPARAMS;
    return -1;
  }
  semaphore_P(socket->send_receive_mutex);
  int fragment_length = MAX_NETWORK_PKT_SIZE - sizeof(mini_header_reliable_t);
  int transfer_length = len > fragment_length ? fragment_length : len;
  //int start_byte = 0;
  int sent_byte = 0;

  do {
    int wait = 100;
    mini_header_reliable_t *header = create_control_header(MSG_ACK, socket->remote_port,
							   socket->remote_addr, socket->local_port,
							   socket->seq_number, socket->ack_number);
    
    transfer_length = len - sent_byte > fragment_length ? fragment_length : len - sent_byte;
    while (wait <= 12800) {
      socket->ack_flag = 0;
      int res = network_send_pkt(socket->remote_addr, sizeof(mini_header_reliable_t),
				 (char *)header, transfer_length, msg + sent_byte);
      socket->seq_number += transfer_length;
      if (res == -1) {
        *error = SOCKET_SENDERROR;
	semaphore_V(socket->send_receive_mutex);
	return (sent_byte == 0) ? -1 : sent_byte; 
      }
      alarm_id a = register_alarm(wait, (alarm_handler_t) semaphore_V, socket->data_ready);
      semaphore_P(socket->wait_for_ack);
      if (socket->socket_state == CLOSED || socket->socket_state == CLOSING) {
	*error=SOCKET_SENDERROR;
	return 0;
      }
      interrupt_level_t old_level = set_interrupt_level(DISABLED);
      // Function was woken up by the firing of the alarm
      if (socket->ack_flag == 0) {
        wait *= 2;
	socket->seq_number -= transfer_length;
	semaphore_V(socket->send_receive_mutex);
        set_interrupt_level(old_level);
        continue;
      }
      // Function was woken up by the network handler
      else if (socket->ack_flag == 1) {
	// ACK has been received
        deregister_alarm(a);
	sent_byte += transfer_length;
	semaphore_V(socket->send_receive_mutex);
        set_interrupt_level(old_level);
        break;
      }
    }
    if (wait > 12800) {
      *error = SOCKET_SENDERROR;
      semaphore_V(socket->send_receive_mutex);
      return (sent_byte == 0) ? -1 : sent_byte; 
    }
  } while (sent_byte != len);
  semaphore_V(socket->send_receive_mutex);
  return len;
}
Пример #18
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;
}
Пример #19
0
minisocket_t* minisocket_server_create(int port, minisocket_error *error)
{
  if (port < MIN_SERVER_PORT || port > MAX_SERVER_PORT) {
    *error = SOCKET_INVALIDPARAMS;
    return NULL;
  }
  if (ports[port]) {
    *error = SOCKET_PORTINUSE;
    return NULL;
  }

  minisocket_t *new_socket =  (minisocket_t *) malloc(sizeof(minisocket_t));
  if (!new_socket) {
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  // Initialize new socket
  new_socket->socket_state = INITIAL;
  semaphore_P(ports_mutex);
  ports[port] = new_socket;
  semaphore_V(ports_mutex);
  new_socket->socket_type = 's';
  new_socket->local_port = port;
  network_address_copy(local_host, new_socket->local_addr);

  new_socket->data = queue_new();
  new_socket->data_ready = semaphore_create();
  new_socket->ack_flag = 0;
  new_socket->wait_for_ack = semaphore_create();
  new_socket->send_receive_mutex = semaphore_create();
  semaphore_initialize(new_socket->data_ready, 0);
  semaphore_initialize(new_socket->wait_for_ack, 0);
  semaphore_initialize(new_socket->send_receive_mutex, 1);

  interrupt_level_t old_level;
  while (1) {
    new_socket->seq_number = 0;
    new_socket->ack_number = 0;
    new_socket->remote_port = -1;
    new_socket->remote_addr[0] = 0;
    new_socket->remote_addr[1] = 0;
    new_socket->socket_state = WAITING_SYN;
    
    // receiving SYN
    while (1) {
      semaphore_P(new_socket->data_ready);
      network_interrupt_arg_t *arg = NULL;
      queue_dequeue(new_socket->data, (void **) &arg);
      mini_header_reliable_t *header = (mini_header_reliable_t *) arg->buffer;

      if (header->message_type -'0'== MSG_SYN) {
	unpack_address(header->source_address, new_socket->remote_addr);
	new_socket->remote_port = unpack_unsigned_short(header->source_port);
	new_socket->socket_state = WAITING_ACK;
	new_socket->seq_number = 0;
	new_socket->ack_number = 1;
	break;
      }
      else {
	free(arg);
      }
    }
    minisocket_error s_error;
    int wait_val = 100;
    while (wait_val <= 12800) {
      send_control_message(MSG_SYNACK, new_socket->remote_port, new_socket->remote_addr, new_socket->local_port, 0 , 1, &s_error);
      new_socket->seq_number = 1;
      new_socket->ack_number = 1;
      if (s_error == SOCKET_OUTOFMEMORY) {
	minisocket_free(new_socket);
	semaphore_P(ports_mutex);
	ports[new_socket->local_port] = NULL;
	semaphore_V(ports_mutex);
	*error = s_error;
	return NULL;
      }
      alarm_id a = register_alarm(wait_val, (alarm_handler_t) semaphore_V, new_socket->data_ready);
      semaphore_P(new_socket->data_ready);
      old_level = set_interrupt_level(DISABLED);
      if (queue_length(new_socket->data)) {
	deregister_alarm(a);
      }
      set_interrupt_level(old_level);
      if (!queue_length(new_socket->data)) {
	wait_val *= 2;
	continue;
      }
      network_interrupt_arg_t *arg = NULL;
      queue_dequeue(new_socket->data, (void **) &arg); 
      mini_header_reliable_t *header = (mini_header_reliable_t *) arg->buffer;
      network_address_t saddr;
      unpack_address(header->source_address, saddr);
      int sport = unpack_unsigned_short(header->source_port);
      if (header->message_type - '0' == MSG_SYN) {

	if (new_socket->remote_port == sport && network_compare_network_addresses(new_socket->remote_addr, saddr)) {
	  continue;
	}
	send_control_message(MSG_FIN, sport, saddr, new_socket->local_port, 0, 0, &s_error);
      }
      if (header->message_type - '0' == MSG_ACK) {

      	if (new_socket->remote_port == sport && network_compare_network_addresses(new_socket->remote_addr, saddr)) {
	  
	  network_interrupt_arg_t *packet = NULL;
	  while (queue_dequeue(new_socket->data, (void **)&packet) != -1) {
	    free(packet);
	  }
	  semaphore_initialize(new_socket->data_ready, 0);
	  new_socket->socket_state = OPEN;
	  new_socket->seq_number = 1;
	  new_socket->ack_number = 2;
	  return new_socket;
	}
      }
      free (arg);
    }
  }
  return NULL;
}
Пример #20
0
void minisocket_handle_tcp_packet(network_interrupt_arg_t *arg)
{
  mini_header_reliable_t *header = (mini_header_reliable_t *) (arg->buffer);
  int port = unpack_unsigned_short(header->destination_port);
  if (port < MIN_SERVER_PORT || port > MAX_CLIENT_PORT || !ports[port]) {
    free(arg);
    return;
  }
  if (ports[port]->socket_state == INITIAL || ports[port]->socket_state == CLOSED) {
    free(arg);
    return;
  }

  if (ports[port]->socket_state != OPEN) {
    // handled in handshake
    queue_append(ports[port]->data, arg);
    semaphore_V(ports[port]->data_ready);
    return;
  }

  minisocket_error s_error;
  network_address_t saddr;
  unpack_address(header->source_address, saddr);
  int sport = unpack_unsigned_short(header->source_port);
  if (!network_compare_network_addresses(ports[port]->remote_addr, saddr) || ports[port]->remote_port != sport) {
    if(header->message_type -'0' == MSG_SYN)
    {
      send_control_message(MSG_FIN, sport, saddr, port, 0, 0, &s_error);
    }

    free(arg);
    return;    
  }

  //If the message is of type SYNACK and from the same client
  if (header->message_type - '0' == MSG_SYNACK) {
    send_control_message(MSG_ACK, sport, saddr, port, 0, 0, &s_error);
    free(arg);
    return;
  }

  //If the message is of type FIN
  if (header->message_type - '0' == MSG_FIN) {
    ports[port]->ack_number += 1;
    send_control_message(MSG_ACK, sport, saddr, port, ports[port]->seq_number, ports[port]->ack_number, &s_error);
    ports[port]->socket_state = CLOSING;
    int count = semaphore_get_count(ports[port]->data_ready);
    while (count < 0) {
      semaphore_V(ports[port]->data_ready);
      count++;
    }
    register_alarm(15000, (alarm_handler_t) minisocket_close, ports[port]); 
    //minisocket_free(ports[port]);
    free(arg);
    return;
  }

  //If the message is of type ACK from the same client
  if (header->message_type - '0' == MSG_ACK)
  {
    unsigned int ack_no = unpack_unsigned_int(header->ack_number);
    int packet_size = arg->size - sizeof(mini_header_reliable_t);
    minisocket_error s_error;
    //If it's a correct acknowledgement of the sent data, enqueue it and V the wait for ack semaphore
    if (ack_no == ports[port]->seq_number/* + MAX_NETWORK_PKT_SIZE - sizeof(mini_header_reliable_t) + 1*/) {
      if (packet_size != 0) {
	queue_append(ports[port]->data, arg);
	semaphore_V(ports[port]->data_ready);
        ports[port]->ack_number += packet_size;
        send_control_message(MSG_ACK, sport, saddr, port, ports[port]->seq_number, ports[port]->ack_number, &s_error);
      }
      if (ports[port]->ack_flag == 0) {
        ports[port]->ack_flag = 1;
        semaphore_V(ports[port]->wait_for_ack);
      }
      return;
    }
    else {
      free(arg);
      return;
    }
  }
}
Пример #21
0
void network_handler(network_interrupt_arg_t* packet) {
  interrupt_level_t old_level = set_interrupt_level(DISABLED);

  //strip relevant packet header information
  mini_header_t* header = (mini_header_t *) packet->buffer;
  unsigned short dest_port = unpack_unsigned_short(header->destination_port);
  char packet_protocol = header->protocol;
  
  if (packet_protocol == PROTOCOL_MINIDATAGRAM) {
    //appends entire packet (including header) to the relevant miniport queue
    miniport_t* mini = minimsg_get_port(dest_port);
    if (mini == NULL) {
      set_interrupt_level(old_level);
      free(packet); 
      return; //unallocated mini_port within minimsg, so drop packet!
    }

    //wake up possible waiting threads (or keep track of enqueued packets)
    queue_append(mini->port_data.incoming_data, packet);
    semaphore_V(mini->port_data.datagrams_ready);

    set_interrupt_level(old_level);
  }
  else {
    //printf("handling TCP packet\n\n");  
    mini_header_reliable_t* received_header = (mini_header_reliable_t *) packet->buffer;  

    minisocket_t* socket = minisocket_get_socket(dest_port);
    if (socket == NULL) {
      printf("no socket found type: %u\n", received_header->message_type);
      
      free(packet);
      set_interrupt_level(old_level);
      return; 
    }

    //check packet size
    if (packet->size < sizeof(mini_header_reliable_t)) {
      free(packet);
      return;
    }
    
    //sending header data
    network_address_t send_address;
    unpack_address(received_header->source_address, send_address);
    mini_header_reliable_t send_header; 
    unsigned short source_port = unpack_unsigned_short(received_header->source_port); 
    minisocket_create_reliable_header((mini_header_reliable_t *) &send_header, socket, source_port, send_address, MSG_ACK);
    
    if (socket->state == CLOSED && received_header->message_type == MSG_FIN) {
      printf("ACKing FIN packet\n");
      //closed socket that hasn't been re-allocated, send back MSG_ACK
      send_header.message_type = MSG_ACK; 
      network_send_pkt(send_address, sizeof(mini_header_reliable_t), (char *) &send_header, 0, NULL); 
     
      free(packet); 
      set_interrupt_level(old_level);
      return;   
    }
   
    if (socket->state == CONNECTING || socket->state == LISTENING) {
      //currently trying to establish a connection to socket   
      queue_append(socket->acknowledgements, packet);
      semaphore_V(socket->ack_ready);

      set_interrupt_level(old_level);
      return; 
    }

    //check that this packet source information matches expected socket connection
    if (socket->state == CONNECTED && socket->remote_port_number == source_port && network_compare_network_addresses(socket->remote_address, send_address) != 0) {
      if (packet->size == sizeof(mini_header_reliable_t) && received_header->message_type == MSG_ACK) {
        //printf("got empty ACK packet with ack: %u\n", unpack_unsigned_int(received_header->ack_number));
        // received ack return message for pending sent message
        queue_append(socket->acknowledgements, packet); 
        semaphore_V(socket->ack_ready);
        
        set_interrupt_level(old_level);
        return;
      }

      if (packet->size == sizeof(mini_header_reliable_t) && received_header->message_type == MSG_SYNACK) {
        send_header.message_type = MSG_ACK; 
        network_send_pkt(send_address, sizeof(mini_header_reliable_t), (char *) &send_header, 0, NULL); 
        free(packet);
        return;
      }

      if (received_header->message_type == MSG_FIN) {
        printf("received messsage FIN\n");
        // received termination message for currently connected socket 
        // send back MSG_ACK to closer
        send_header.message_type = MSG_ACK; 
        network_send_pkt(send_address, sizeof(mini_header_reliable_t), (char *) &send_header, 0, NULL); 
      
        //mark socket as closed, so no further calls can be made to send() or receive()
        socket->state = CLOSED;
        
        printf("REGISTERING ALARM\n");
        //sleep for 15s before destroying the socket 
        register_alarm(15000, minisocket_destroy, (void *) socket);  
         
        set_interrupt_level(old_level);
        return;
      }

      //check sequence number
      unsigned int seq_number = unpack_unsigned_int(received_header->seq_number);
      if (seq_number < socket->ack) {
        //printf("already seen this!\n");
        //have seen this packet before, send an ACK to client
        send_header.message_type = MSG_ACK;

        network_send_pkt(send_address, sizeof(mini_header_reliable_t), (char *) &send_header, 0, NULL); 
        
        //free(packet); 
        set_interrupt_level(old_level);
        return; 
      }
      else if (seq_number > socket->ack) {
        //printf("don't want packet yet!\n");
        //want to wait for earlier sequential packet
        free(packet);
        set_interrupt_level(old_level);
        return;
      }
      else if (seq_number == socket->ack && received_header->message_type == MSG_ACK && packet->size > sizeof(mini_header_reliable_t))  { //else seq_number == socket->ack
        // append data packet and increment ack number
        queue_append(socket->incoming_data, packet);
        semaphore_V(socket->datagrams_ready);

        send_header.message_type = MSG_ACK;
        unsigned int new_ack = seq_number + packet->size - sizeof(mini_header_reliable_t);
        pack_unsigned_int(send_header.ack_number, new_ack); 
        socket->ack = new_ack; 
        //printf("sending ack %u\n", socket->ack);
        network_send_pkt(send_address, sizeof(mini_header_reliable_t), (char *) &send_header, 0, NULL); 

        set_interrupt_level(old_level);
      } 
    } 
    else {
      //send back a MSG_FIN to request that this client stop sending messages
      network_send_pkt(send_address, sizeof(mini_header_reliable_t), (char *) &send_header, 0, NULL); 
      
      set_interrupt_level(old_level); 
    }
  }
}
Пример #22
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;
}