Example #1
0
/* Cancel discovery if it is in progress */
static void
miniroute_discovery_cancel()
{
    if (discovery_alarm > -1) {
        deregister_alarm(discovery_alarm);
        discovery_alarm = -1;
        semaphore_V(discovery_sig);
    }
}
Example #2
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;
	}
}
Example #3
0
/*
 * This is the clock interrupt handling routine.
 * You have to call minithread_clock_init with this
 * function as parameter in minithread_system_initialize
 */
void 
clock_handler(void* arg)
{
  
  interrupt_level_t old_level = set_interrupt_level(DISABLED);
  nInterrupts++;
  // get_next_alarm always runs in O(1)
  alarm_t *next_alarm = get_next_alarm();
  while (next_alarm) {
    call_handler(next_alarm);
    // since next_alarm is the first element, deregister also runs in O(1)
    deregister_alarm(next_alarm);
    next_alarm = get_next_alarm();
  }
  implement_scheduler();
  set_interrupt_level(old_level);
}
Example #4
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);
}
Example #5
0
/* 
 * Send a message to the other end of the socket.
 *
 * The send call should block until the remote host has ACKnowledged receipt of
 * the message.  This does not necessarily imply that the application has called
 * 'minisocket_receive', only that the packet is buffered pending a future
 * receive.
 *
 * It is expected that the order of calls to 'minisocket_send' implies the order
 * in which the concatenated messages will be received.
 *
 * 'minisocket_send' should block until the whole message is reliably
 * transmitted or an error/timeout occurs
 *
 * Arguments: the socket on which the communication is made (socket), the
 *            message to be transmitted (msg) and its length (len).
 * Return value: returns the number of successfully transmitted bytes. Sets the
 *               error code and returns -1 if an error is encountered.
 *
 * Comments: invalid params for socket, msg but len = 0 case is ok
 */
int minisocket_send(minisocket_t socket, minimsg_t msg, int len, minisocket_error *error)
{
  unsigned int num_pkt;
  unsigned int i;
  interrupt_level_t l;
  resend_arg* resend_alarm_arg;
  unsigned int max_size;

  //printf("in minisocket_send\n");
  //max size for PAYLOAD, not entire packet
  max_size = MAX_NETWORK_PKT_SIZE - sizeof(struct mini_header_reliable);
  num_pkt = len / max_size + 1; //number of divided packets
  //printf("gonna send %d packet(s)!\n", num_pkt);
  //error checking
  if (!socket || sock_array[socket->src_port] == NULL || msg == NULL 
      || len < 0)
  {
    *error = SOCKET_INVALIDPARAMS;
    return -1;
  }
  //allow this
  if (len == 0){
    return 0;
  }

  //check for invalid cases
  l = set_interrupt_level(DISABLED);
  if (socket->curr_state != CONNECTED){
    if (socket->curr_state == CLOSE_RCV){
      *error = SOCKET_BUSY;
      set_interrupt_level(l);
      return -1;
    }
    *error = SOCKET_SENDERROR;
    set_interrupt_level(l);
    return -1;
  }

  //try sending
  *error = SOCKET_NOERROR;
  (socket->curr_seq)++;
  minisocket_send_data(socket,len>max_size ? max_size:len,msg, error);
  //printf("sent first packet!\n");
  if (*error != SOCKET_NOERROR){
    set_interrupt_level(l);
    return -1;
  }

  resend_alarm_arg = (resend_arg*)calloc(1, sizeof(resend_arg));

  //otherwise register an alarm for resending and proceed
  resend_alarm_arg->sock = socket;
  resend_alarm_arg->msg_type = MSG_ACK;
  resend_alarm_arg->data_len = len>max_size?max_size:len;
  resend_alarm_arg->data = msg; //placeholder
  resend_alarm_arg->error = error; 
  socket->resend_alarm = set_alarm(RESEND_TIME_UNIT, minisocket_resend, resend_alarm_arg, minithread_time());

  if (socket->resend_alarm){
    deregister_alarm(socket->resend_alarm);
    socket->resend_alarm = NULL;
  }
  socket->resend_alarm = set_alarm(RESEND_TIME_UNIT, minisocket_resend, &resend_alarm_arg, minithread_time());
  socket->curr_state = MSG_WAIT;
  set_interrupt_level(l);


  while (i < num_pkt){
    semaphore_P(socket->ack_ready_sem);
    l = set_interrupt_level(DISABLED);
    //packet got acked, deregister alarm from before
    if (socket->resend_alarm){
      deregister_alarm(socket->resend_alarm);
      socket->resend_alarm = NULL;
    }

    switch (socket->curr_state){
    case CLOSE_SEND: //closing connection
      semaphore_V(socket->ack_ready_sem); //notify close thread
      *error = SOCKET_SENDERROR;
      set_interrupt_level(l);
      free(resend_alarm_arg); 
      return i * max_size;
    case CONNECTED: 
      i++;
      if (i >= num_pkt){ //we sent everything
        set_interrupt_level(l);
        break;
      }
      (socket->curr_seq)++;
      minisocket_send_data(socket,
              i<num_pkt-1? max_size : len-(max_size*i),
              ((char*)msg) + i*max_size,
              error);

      if (*error != SOCKET_NOERROR){//TODO:may not need to do this
        set_interrupt_level(l);
        free(resend_alarm_arg); 
        return -1;
      }
      //otherwise register an alarm for resending and proceed
      resend_alarm_arg->sock = socket;
      resend_alarm_arg->msg_type = MSG_ACK;
      resend_alarm_arg->data_len = i<num_pkt-1? max_size : len-(max_size*i);
      resend_alarm_arg->data = ((char*)msg) + i*max_size;
      resend_alarm_arg->error = error;
      if (socket->resend_alarm) {
        deregister_alarm(socket->resend_alarm);
        socket->resend_alarm = NULL;
      }
      socket->resend_alarm = set_alarm(RESEND_TIME_UNIT, minisocket_resend, resend_alarm_arg, minithread_time());
      socket->curr_state = MSG_WAIT;
      set_interrupt_level(l);
      break;
    default: // error case, simply return
      *error = SOCKET_SENDERROR;
      set_interrupt_level(l);
      free(resend_alarm_arg); 
      return i * max_size;
    }
  }
  //we sent all the packets!
  *error = SOCKET_NOERROR;
  //printf("return on send SUCCESS!\n");
  //printf("exiting send with socket at state %d\n", socket->curr_state);
  free(resend_alarm_arg); 
  return len;
}
Example #6
0
/* Initiate the communication with a remote site. When communication is
 * established create a minisocket through which the communication can be made
 * from now on.
 *
 * The first argument is the network address of the remote machine. 
 *
 * The argument "port" is the port number on the remote machine to which the
 * connection is made. The port number of the local machine is one of the free
 * port numbers.
 *
 * Return value: the minisocket_t created, otherwise NULL with the errorcode
 * stored in the "error" variable.
 */
minisocket_t minisocket_client_create(network_address_t addr, int port, minisocket_error *error)
{
  minisocket_t new_sock;
  interrupt_level_t l;
  resend_arg* resend_alarm_arg;
  unsigned short start; 
  char tmp;

  //check valid portnum
  if (port < 0 || port >= CLIENT_START) {
    *error = SOCKET_INVALIDPARAMS;
    return NULL;
  }

  semaphore_P(client_lock);
  start = curr_client_idx;
  while (sock_array[curr_client_idx] != NULL){
    curr_client_idx++;
    if (curr_client_idx >= NUM_SOCKETS){
      curr_client_idx = CLIENT_START;
    }
    if (curr_client_idx == start){ // client sockets full
      semaphore_V(client_lock);
      *error = SOCKET_NOMOREPORTS; 
      return NULL;
    }
  }
 
  new_sock = (minisocket_t)malloc(sizeof(struct minisocket));
  if (!new_sock){
    semaphore_V(client_lock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->pkt_ready_sem = semaphore_create();
  if (!(new_sock->pkt_ready_sem)){
    semaphore_V(client_lock);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->pkt_q = queue_new();
  if (!(new_sock->pkt_q)){
    semaphore_V(client_lock);
    semaphore_destroy(new_sock->pkt_ready_sem);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->sock_lock = semaphore_create();
  if (!(new_sock->sock_lock)){
    semaphore_V(client_lock);
    semaphore_destroy(new_sock->pkt_ready_sem);
    queue_free(new_sock->pkt_q);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->ack_ready_sem = semaphore_create();
  if (!(new_sock->ack_ready_sem)){
    semaphore_V(client_lock);
    semaphore_destroy(new_sock->pkt_ready_sem);
    queue_free(new_sock->pkt_q);
    semaphore_destroy(new_sock->sock_lock);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  
  semaphore_initialize(new_sock->pkt_ready_sem, 0);
  semaphore_initialize(new_sock->ack_ready_sem, 0);
  semaphore_initialize(new_sock->sock_lock, 1);

  new_sock->curr_state = CONNECT_WAIT;
  new_sock->try_count = 0;
  new_sock->curr_ack = 0;
  new_sock->curr_seq = 1;
  new_sock->resend_alarm = NULL; //no alarm set
  new_sock->src_port = curr_client_idx;
  new_sock->dst_port = port; 
  network_address_copy(addr, new_sock->dst_addr);

  sock_array[curr_client_idx] = new_sock;
  semaphore_V(client_lock);
 
  l = set_interrupt_level(DISABLED);
  minisocket_send_ctrl(MSG_SYN, new_sock, error);
  resend_alarm_arg = (resend_arg*)calloc(1, sizeof(resend_arg));
  resend_alarm_arg->sock = new_sock;
  resend_alarm_arg->msg_type = MSG_SYN;
  resend_alarm_arg->data_len = 0;
  resend_alarm_arg->data = &tmp; //placeholder
  resend_alarm_arg->error = error; 
  new_sock->resend_alarm = set_alarm(RESEND_TIME_UNIT, minisocket_resend, resend_alarm_arg, minithread_time());
  set_interrupt_level(l);

  semaphore_P(new_sock->ack_ready_sem);
  l = set_interrupt_level(DISABLED);

  switch(new_sock->curr_state) {
  case CONNECTED: //we are connected
    // must have gotten a MSG_SYNACK
    new_sock->curr_state = CONNECTED;
    new_sock->try_count = 0;
    if (new_sock->resend_alarm){
      deregister_alarm(new_sock->resend_alarm);
    }
    new_sock->resend_alarm = NULL;
    *error = SOCKET_NOERROR;
    set_interrupt_level(l); 
    break;
  
  case CLOSE_RCV:
    *error = SOCKET_BUSY;
    minisocket_destroy(new_sock, error);
    if (new_sock->resend_alarm){
      deregister_alarm(new_sock->resend_alarm);
    }
    new_sock->resend_alarm = NULL;
    *error = SOCKET_BUSY;
    set_interrupt_level(l);
    new_sock = NULL;
    break; 
  
  default:
    // error
    *error = SOCKET_NOSERVER;
    minisocket_destroy(new_sock, error);
    set_interrupt_level(l); 
    new_sock = NULL;
    break;
  }
  free(resend_alarm_arg);
  return new_sock;
}
Example #7
0
/* Listen for a connection from somebody else. When communication link is
 * created return a minisocket_t through which the communication can be made
 * from now on.
 *
 * The argument "port" is the port number on the local machine to which the
 * client will connect.
 *
 * Return value: the minisocket_t created, otherwise NULL with the errorcode
 * stored in the "error" variable.
 */
minisocket_t minisocket_server_create(int port, minisocket_error *error)
{
  minisocket_t new_sock;
  interrupt_level_t l;
  network_interrupt_arg_t * pkt;
  resend_arg* resend_alarm_arg;
  char tmp; 

  //check valid portnum
  if (port < 0 || port >= CLIENT_START){
    *error = SOCKET_INVALIDPARAMS;
    return NULL;
  }

  //check port in use
  semaphore_P(server_lock);

  //printf("calling server_create at port %d.\n", port);
  //printf("value at port %d is %li.\n", port, (long)sock_array[port]);
  if (sock_array[port] != NULL){
    *error = SOCKET_PORTINUSE;
    return NULL;
  }
  new_sock = (minisocket_t)malloc(sizeof(struct minisocket));
  if (!new_sock){
    semaphore_V(server_lock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->pkt_ready_sem = semaphore_create();
  if (!(new_sock->pkt_ready_sem)){
    semaphore_V(server_lock);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->pkt_q = queue_new();
  if (!(new_sock->pkt_q)){
    semaphore_V(server_lock);
    semaphore_destroy(new_sock->pkt_ready_sem);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->sock_lock = semaphore_create();
  if (!(new_sock->sock_lock)){
    semaphore_V(server_lock);
    free(new_sock->pkt_ready_sem);
    queue_free(new_sock->pkt_q);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  new_sock->ack_ready_sem = semaphore_create();
  if (!(new_sock->ack_ready_sem)){
    semaphore_V(server_lock);
    semaphore_destroy(new_sock->pkt_ready_sem);
    queue_free(new_sock->pkt_q);
    semaphore_destroy(new_sock->sock_lock);
    free(new_sock);
    *error = SOCKET_OUTOFMEMORY;
    return NULL;
  }
  semaphore_initialize(new_sock->pkt_ready_sem, 0);
  semaphore_initialize(new_sock->ack_ready_sem, 0);
  semaphore_initialize(new_sock->sock_lock, 1);

  new_sock->curr_state = LISTEN;
  new_sock->try_count = 0;
  new_sock->curr_ack = 0;
  new_sock->curr_seq = 1;
  new_sock->resend_alarm = NULL; // no alarm set
  new_sock->src_port = port;
  new_sock->dst_port = -1; // not paired with client
  network_address_blankify(new_sock->dst_addr); // not paired with client

  sock_array[port] = new_sock;
  semaphore_V(server_lock);
 
  resend_alarm_arg = (resend_arg*)calloc(1, sizeof(resend_arg));
  while (1) {
    // wait for MSG_SYN
    semaphore_P(new_sock->ack_ready_sem);
    l = set_interrupt_level(DISABLED);
 
    switch (new_sock->curr_state) {
    case CONNECTING:  
      minisocket_send_ctrl(MSG_SYNACK, new_sock, error);

      resend_alarm_arg->sock = new_sock;
      resend_alarm_arg->msg_type = MSG_SYNACK;
      resend_alarm_arg->data_len = 0;
      resend_alarm_arg->data = &tmp; //placeholder
      resend_alarm_arg->error = error; 
      new_sock->resend_alarm = set_alarm(RESEND_TIME_UNIT, minisocket_resend, resend_alarm_arg, minithread_time());
      
      new_sock->curr_state = MSG_WAIT;
      set_interrupt_level(l);
      break;

    case CONNECTED:
      // must have gotten a MSG_ACK 
      //printf("in server_create, SUCCESS!\n");
      new_sock->try_count = 0;
      deregister_alarm(new_sock->resend_alarm);
      new_sock->resend_alarm = NULL;
      *error = SOCKET_NOERROR;
      set_interrupt_level(l);
      //printf("exiting server_create\n");
      free(resend_alarm_arg);
      return new_sock;
      break;

    case EXIT: default:
      *error = SOCKET_SENDERROR;
      // clean out the queue
      while (queue_dequeue(new_sock->pkt_q,(void**)&pkt) != -1){
        free(pkt);
      }
      new_sock->curr_state = LISTEN;
      new_sock->curr_ack = 0;
      new_sock->curr_seq = 1;
      set_interrupt_level(l);
      break;
    }
  }
  free(resend_alarm_arg);
  return new_sock;
}
Example #8
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;
}
Example #9
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);
  }
}
Example #10
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;
}
Example #11
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; 
}
Example #12
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;
}
Example #13
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;
}
Example #14
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;
}
Example #15
0
/* Close a connection. If minisocket_close is issued, any send or receive should
 * fail.  As soon as the other side knows about the close, it should fail any
 * send or receive in progress. The minisocket is destroyed by minisocket_close
 * function.  The function should never fail.
 */
void minisocket_close(minisocket_t socket)
{
  interrupt_level_t l;
  minisocket_error error;
  resend_arg_t resend_alarm_arg;

  resend_alarm_arg = (resend_arg_t)calloc(1,sizeof(struct resend_arg));
  if (!resend_alarm_arg){
    return;
  }
  error = SOCKET_NOERROR;

  //printf("in minisocket_close\n");
  
  //set state to close_wait
  //send close, wait using alarms
  //(after 7 retries, close connection)
  //P on ack_ready
  //if ack_ready, close connection
 
  //ill formed argument 
  if (!sock_array){
    free(resend_alarm_arg);
    return;
  }

  l = set_interrupt_level(DISABLED);
  //ill formed argument
  if (sock_array[socket->src_port] == NULL){
    set_interrupt_level(l);
    free(resend_alarm_arg);
    return;
  }
  if (socket->curr_state == CLOSE_SEND || socket->curr_state == CLOSE_RCV){
    set_interrupt_level(l);
    free(resend_alarm_arg);
    return;
  }
  socket->curr_state = CLOSE_SEND;
  socket->try_count = 0;
  socket->curr_seq++;

  minisocket_send_ctrl( MSG_FIN, socket, &error);
  //printf("in minisocket_close, sent my MSG_FIN\n");
  resend_alarm_arg->sock = socket;
  resend_alarm_arg->msg_type = MSG_FIN;
  resend_alarm_arg->data_len = 0;
  resend_alarm_arg->data = (char*) &socket; //placeholder
  resend_alarm_arg->error = &error;
  if (socket->resend_alarm){
    deregister_alarm(socket->resend_alarm);
  }
  socket->resend_alarm = NULL;
  socket->resend_alarm = set_alarm(RESEND_TIME_UNIT, minisocket_resend, resend_alarm_arg, minithread_time());
  //printf("in minisocket_close, set my alarm.\n");
  set_interrupt_level(l);

  semaphore_P(socket->ack_ready_sem); //wait for ack packet...
  //received ack, close connection
  //printf("in minisocket_close, got my ACK baby\n");
  l = set_interrupt_level(DISABLED);
  if (socket->resend_alarm){
    deregister_alarm(socket->resend_alarm);
  }
  socket->resend_alarm = NULL;

  minisocket_destroy(socket, &error);
  //printf("Closed. Error is %d", error);
  if (error != SOCKET_NOERROR){
    //printf("Something went wrong. Close connection failure.\n");
  }
  set_interrupt_level(l);

  //printf("in minisocket_close, SUCCESS\n");
  free(resend_alarm_arg);
  return;

}
Example #16
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;
}
Example #17
0
/* minisocket_process_packet is called within the network interrupt handler.
 * Therefore we can safely assume that interrupts are disabled.
 *
 */
void minisocket_process_packet(void* packet) {
  network_interrupt_arg_t* pkt;
  mini_header_reliable_t pkt_hdr;
  unsigned int seq_num;
  unsigned int ack_num;
  minisocket_error error;
  network_address_t src_addr;
  network_address_t dst_addr;
  unsigned int src_port;
  unsigned int dst_port;
  minisocket_t sock;
  int type;
  int data_len;

  pkt = (network_interrupt_arg_t*)packet;
  pkt_hdr = (mini_header_reliable_t)(&pkt->buffer);
 
  //printf("in minisocket_process_packet\n");
  // error checking
  if (pkt->size < sizeof(struct mini_header_reliable)) {
    free(pkt);
    return;
  }

  unpack_address(pkt_hdr->source_address, src_addr);
  src_port = unpack_unsigned_short(pkt_hdr->source_port);
  dst_port = unpack_unsigned_short(pkt_hdr->destination_port);
  unpack_address(pkt_hdr->destination_address, dst_addr);
  seq_num = unpack_unsigned_int(pkt_hdr->seq_number);
  ack_num = unpack_unsigned_int(pkt_hdr->ack_number);
  data_len = pkt->size - sizeof(struct mini_header_reliable);
  if (src_port < 0 || dst_port < 0 
        || src_port >= NUM_SOCKETS || dst_port >= NUM_SOCKETS
        || !network_compare_network_addresses(dst_addr, my_addr)){
    free(pkt);
    return;
  }

  error = SOCKET_NOERROR;
  sock = sock_array[dst_port];
  if (sock == NULL) {
    free(pkt);
    return;
  }

  type = pkt_hdr->message_type;
  //printf("socket %d with state %d\n", sock->src_port, sock->curr_state);
  //printf("pkt ack number is %d\n", ack_num);
  //printf("pkt seq number is %d\n", seq_num);
  //printf("my ack number is %d\n", sock->curr_ack);
  //printf("my seq number is %d\n", sock->curr_seq);
  //printf("type of msg received is %d\n", type);

  if (sock->curr_state != LISTEN &&
        ( !network_compare_network_addresses(src_addr, sock->dst_addr)
            || src_port != sock->dst_port ) ){
    if (type == MSG_SYN){
      minisocket_send_ctrl_to(MSG_FIN, sock, &error, src_addr, src_port);
    }
    free(pkt);
    return;
  }

  switch (sock->curr_state) {
    case LISTEN:
      if (type == MSG_SYN) {
        sock->curr_ack = 1;
        semaphore_V(sock->ack_ready_sem);
        sock->curr_state = CONNECTING;
        sock->dst_port = src_port;
        network_address_copy(src_addr, sock->dst_addr);
      }
      free(pkt);
      break;
    
    case CONNECTING:
      if (type == MSG_ACK) {
        if (ack_num == sock->curr_seq) {
        semaphore_V(sock->ack_ready_sem);
        sock->curr_state = CONNECTED;
        }
        if (seq_num == sock->curr_ack+1 && data_len > 0) {
          queue_append(sock->pkt_q, pkt);
          semaphore_V(sock->pkt_ready_sem);
          minisocket_send_ctrl(MSG_ACK, sock, &error);
          sock->curr_ack++;
        }
        else {
          free(pkt);
        }
      }
      else {
        free(pkt);
      }
      break;
    
    case CONNECT_WAIT://TODO
      if (type == MSG_FIN) {
        sock->curr_state = CLOSE_RCV;
        semaphore_V(sock->ack_ready_sem);//notify blocked guy
      }
      else if (type == MSG_SYNACK) {
        if (ack_num == sock->curr_seq) {
          sock->curr_state = CONNECTED;
          sock->curr_ack++;
          minisocket_send_ctrl(MSG_ACK, sock, &error);
          semaphore_V(sock->ack_ready_sem);
        }
      }       
      free(pkt); 
      break;
    
    case MSG_WAIT:
      if (type == MSG_FIN){
        sock->curr_ack++;
        minisocket_send_ctrl(MSG_ACK, sock, &error);//notify to closer
        sock->curr_state = CLOSE_RCV;

        if (sock->resend_alarm){
          deregister_alarm(sock->resend_alarm);
          sock->resend_alarm = NULL;
        }
        sock->resend_alarm = set_alarm(RESEND_TIME_UNIT * 150, 
                                          self_destruct, 
                                          (void*)sock, 
                                          minithread_time());
        semaphore_V(sock->ack_ready_sem);//notify blocked guy
      }
      else if (type == MSG_ACK) {
        if (ack_num == sock->curr_seq) {
          //printf("got an ACK!\n");
          semaphore_V(sock->ack_ready_sem);
          sock->curr_state = CONNECTED;
        }
        if (seq_num == sock->curr_ack+1 && data_len > 0) {
          //printf("got a MESSAGE!\n");
          queue_append(sock->pkt_q, pkt);
          sock->curr_ack++;
          minisocket_send_ctrl(MSG_ACK, sock, &error);
          semaphore_V(sock->pkt_ready_sem);
        }
        else {
          free(pkt);
        }
      }
      else {
        free(pkt);
      }        
      break;

    case CLOSE_SEND:
      if (type == MSG_ACK && ack_num == sock->curr_seq) {
          semaphore_V(sock->ack_ready_sem);
      }
      if (type == MSG_FIN){
        sock->curr_ack++;
        minisocket_send_ctrl(MSG_ACK, sock, &error);//notify to closer
        sock->curr_state = CLOSE_RCV;

        if (sock->resend_alarm){
          deregister_alarm(sock->resend_alarm);
          sock->resend_alarm = NULL;
        }
        sock->resend_alarm = set_alarm(RESEND_TIME_UNIT * 150, 
                                          self_destruct, 
                                          (void*)sock, 
                                          minithread_time());
        //minisocket_send_ctrl(MSG_ACK, sock, &error);
      }
      //free(pkt);
      break;

    case CLOSE_RCV:
      if (type == MSG_FIN && ack_num == sock->curr_seq) {
        minisocket_send_ctrl(MSG_ACK, sock, &error);
        //semaphore_V(sock->ack_ready_sem);
      }
      free(pkt);
      break;

    case CONNECTED:
      if (type == MSG_FIN){
        sock->curr_ack++;
        minisocket_send_ctrl(MSG_ACK, sock, &error);//notify to closer
        sock->curr_state = CLOSE_RCV;

        if (sock->resend_alarm){
          deregister_alarm(sock->resend_alarm);
          sock->resend_alarm = NULL;
        }
        sock->resend_alarm = set_alarm(RESEND_TIME_UNIT * 150, 
                                          self_destruct, 
                                          (void*)sock, 
                                          minithread_time());
      }
      if (type == MSG_ACK) {
        if (ack_num == sock->curr_seq) {
          //semaphore_V(sock->ack_ready_sem);
          sock->curr_state = CONNECTED;
        }
        if (seq_num == sock->curr_ack+1 && data_len > 0) {
          //printf("got some DATA\n"); 
          queue_append(sock->pkt_q, pkt);
          sock->curr_ack++;
          minisocket_send_ctrl(MSG_ACK, sock, &error);
          semaphore_V(sock->pkt_ready_sem);
          //printf("got data, no seg fault\n");
        }
        else if (seq_num == sock->curr_ack && data_len > 0){
          minisocket_send_ctrl(MSG_ACK, sock, &error);
        }
        else {
          free(pkt);
        }
      }
      else {
        free(pkt);
      }
      break;

    case EXIT: default:
      free(pkt);
      break;
    }
}
Example #18
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;
}
Example #19
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;
}
Example #20
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;
}