Exemplo n.º 1
0
/* Relay the message to the next hop using network_send_pkt */
static void
miniroute_relay(network_interrupt_arg_t *intrpt)
{
    int i;
    int len;
    int ttl;
    miniroute_header_t routing_hdr = (miniroute_header_t) intrpt->buffer;
    network_address_t hop;

    len = unpack_unsigned_int(routing_hdr->path_len);
    for (i = 0; i < len; ++i) {
        unpack_address(routing_hdr->path[i], hop);
        if (network_address_same(hostaddr, hop) == 1)
            break;
    }
    if (i + 1 < len) {
        i++;
        ttl = unpack_unsigned_int(routing_hdr->ttl);
        pack_unsigned_int(routing_hdr->ttl, --ttl);
        unpack_address(routing_hdr->path[i], hop);

#if MINIROUTE_CACHE_DEBUG == 1
        printf("Relaying header\n");
        miniroute_print_hdr(routing_hdr);
#endif
        network_send_pkt(hop, 0, NULL, intrpt->size, intrpt->buffer);
    }
    free(intrpt);
}
Exemplo n.º 2
0
/* Receives a message through a locally unbound port. Threads that call this function are
 * blocked until a message arrives. Upon arrival of each message, the function must create
 * a new bound port that targets the sender's address and listening port, so that use of
 * this created bound port results in replying directly back to the sender. It is the
 * responsibility of this function to strip off and parse the header before returning the
 * data payload and data length via the respective msg and len parameter. The return value
 * of this function is the number of data payload bytes received not inclusive of the header.
 */
int minimsg_receive(miniport_t local_unbound_port, miniport_t* new_local_bound_port, minimsg_t msg, int *len)
{
  network_interrupt_arg_t* pkt;
  mini_header_t pkt_header;
  char protocol;
  network_address_t src_addr;
  unsigned short src_port;
  network_address_t dst_addr;
  int i;
  char* buff;
  if (local_unbound_port == NULL
        || local_unbound_port->p_type != UNBOUND_PORT
        || local_unbound_port->p_num >= BOUND_PORT_START
        || miniport_array[local_unbound_port->p_num] != local_unbound_port){
    return -1;
  }
  //block until packet arrives
  semaphore_P(local_unbound_port->u.unbound.port_pkt_available_sem);

  semaphore_P(local_unbound_port->u.unbound.q_lock);
  if( queue_dequeue(local_unbound_port->u.unbound.port_pkt_q,
                  (void**)&pkt)){
    return -1;
  }
  semaphore_V(local_unbound_port->u.unbound.q_lock);

  pkt_header = (mini_header_t)(&pkt->buffer);
  protocol = pkt_header->protocol;
  unpack_address(pkt_header->source_address, src_addr);
  src_port = unpack_unsigned_short(pkt_header->source_port);
  unpack_address(pkt_header->destination_address, dst_addr);
  if (protocol != PROTOCOL_MINIDATAGRAM
        && protocol != PROTOCOL_MINISTREAM){
    return -1;
  }
  if (protocol == PROTOCOL_MINISTREAM){
    return 0; //currently unsupported
  } 
  else { //UDP
    if ( pkt->size < sizeof(struct mini_header)){
      return -1;
    }
    *len = pkt->size-sizeof(struct mini_header) > *len?
                  *len : pkt->size-sizeof(struct mini_header);
    *new_local_bound_port = miniport_create_bound(pkt->sender, src_port);
    //copy payload
    buff = (char*)&(pkt->buffer);
    buff += sizeof(struct mini_header);
    for (i = 0; i < *len; i++){
      msg[i] = *buff;
      buff++;
    }
    free(pkt); 
    return *len;
  }
}
Exemplo n.º 3
0
static void
miniroute_process_data(network_interrupt_arg_t *intrpt)
{
    int i;
    miniroute_header_t routing_hdr = (miniroute_header_t) intrpt->buffer;
    network_address_t dest;
    unpack_address(routing_hdr->destination, dest);

#if MINIROUTE_DEBUG == 1
    printf("Processing data in Network packet.\n");
#endif
    /* Relay packets if it is intended for others */
    if (network_address_same(dest, hostaddr) != 1)
        miniroute_relay(intrpt);
    else {
        /* Drop packets with incomplete header */
        if (intrpt->size < MINIROUTE_HDRSIZE + MINIMSG_HDRSIZE) {
            free(intrpt);
            return;
        } else {
            /* Strip header */
            intrpt->size -= MINIROUTE_HDRSIZE;
            for (i = 0; i < intrpt->size; ++i)
                intrpt->buffer[i] = intrpt->buffer[MINIROUTE_HDRSIZE + i];
        }

        /* Free the interrupt if no protocol can handle it. */
        if (miniroute_sort_data(intrpt) == 1)
            free(intrpt);
    }

    return;
}
Exemplo n.º 4
0
/* Process a route discovery packet */
static void
miniroute_process_discovery(network_interrupt_arg_t *intrpt)
{
    miniroute_header_t hdr = (miniroute_header_t) intrpt->buffer;
    network_address_t orig;
    network_address_t dest;
    int id;
    int len;
    int ttl;
    miniroute_path_t path;
    miniroute_disc_hist_t disc;

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

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

    free(intrpt);
}
Exemplo n.º 5
0
int minisocket_receive(minisocket_t *socket, char *msg, int max_len, minisocket_error *error) {
  if (socket == NULL || msg == NULL || max_len < 0) {
    *error = SOCKET_INVALIDPARAMS;
    return -1;
  }
  if (socket->state == CLOSED) {
    *error = SOCKET_RECEIVEERROR;
    return -1;
  }
  if (max_len == 0) {
    return 0;
  }
  
  int received = 0;
  while (!received) {
    semaphore_P(socket->datagrams_ready);

    network_interrupt_arg_t *interrupt_message = NULL;
    interrupt_level_t old_level = set_interrupt_level(DISABLED);
    queue_dequeue(socket->incoming_data, (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);
      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 && interrupt_message->size > sizeof(mini_header_reliable_t)) {
        //same address, same ports, right message
        received = 1; 
        int data_left = interrupt_message->size - sizeof(mini_header_reliable_t) - socket->next_read;
        interrupt_level_t old_level = set_interrupt_level(DISABLED);
        
        if (data_left <= max_len) {
          memcpy(msg, interrupt_message->buffer + sizeof(mini_header_reliable_t) + socket->next_read, data_left);
          socket->next_read = 0;
          free(interrupt_message);
          set_interrupt_level(old_level); // must protect global data field next_read 
          return data_left;
        }
        else {
          memcpy(msg, interrupt_message->buffer + sizeof(mini_header_reliable_t) + socket->next_read, max_len);
          socket->next_read += max_len;
          queue_prepend(socket->incoming_data, interrupt_message); //ack works as well when there is data 
          semaphore_V(socket->datagrams_ready); //another message in queue, V semaphore
          set_interrupt_level(old_level); 
          return max_len;
        }
      }
      else {
        free(interrupt_message);
      }
    }
  }
  return -1;
}
 int run_tests() {
  int i;
  int success = 0, total = 0;
  for (i = 0; i < (sizeof(test_cases) / sizeof(test_cases[0])); i++) {
    struct in6_addr addr, correct;
    uint8_t buf[512];
    char *rv;
    uint8_t *btr = test_cases[i].buf;
    size_t len = 32;
    int ret;
    uint8_t stateful;
    ieee154_addr_t l2addr;
    total++;

    inet_pton6(test_cases[i].address, &correct);

    ieee154_parse(test_cases[i].l2addr, &l2addr);
    ieee154_print(&l2addr, buf, 512);
    printf("%s\n", buf);
    printf("in6_addr: %s\n", test_cases[i].address);
    ret = unpack_address(&addr,
                         test_cases[i].dispatch,
                         test_cases[i].context,
                         &btr,
                         &len,
                         &l2addr,
                         test_cases[i].panid,
                         &stateful);

    inet_ntop6(&addr, buf, 512);
    printf("result: %s length: %li\n", buf, 32 - len);

    if (test_cases[i].len != 32 - len) {
      printf("case %u: result len: %li expected: %i\n",
             i, 32 - len, test_cases[i].len);
      continue;
    }

    if (memcmp(&addr, &correct, 16) != 0) {
      printf("case %u: unexpected result\n", i);
      print_buffer(correct.s6_addr, 16);
      print_buffer(addr.s6_addr, 16);
      continue;
    }

    if (test_cases[i].stateful != stateful) {
      printf("case %u: stateful compression was used!\n", test_cases[i].stateful);
      continue;
    }

    success++;
  }
  printf("%s: %i/%i tests succeeded\n", __FILE__, success, total);
  if (success == total) return 0;
  return 1;
}
Exemplo n.º 7
0
/* Print the miniroute header in a readable way for debugging */
int
miniroute_print_hdr(miniroute_header_t hdr)
{
    int i;
    int len;
    network_address_t dest;
    network_address_t hop;

    switch (hdr->routing_packet_type) {
    case ROUTING_ROUTE_DISCOVERY:
        printf("Discovery: ");
        break;
    case ROUTING_ROUTE_REPLY:
        printf("Reply    : ");
        break;
    case ROUTING_DATA:
        printf("Data     : ");
        break;
    default:
        printf("Unknown %d: ", hdr->routing_packet_type);
    }

    printf("id = %d, ", unpack_unsigned_int(hdr->id));
    printf("ttl = %d, ", unpack_unsigned_int(hdr->ttl));
    printf("len = %d\n", len = unpack_unsigned_int(hdr->path_len));

    unpack_address(hdr->destination, dest);
    printf("Destination: ");
    network_printaddr(dest);
    printf("\n");

    for (i = 0; i < len; ++i) {
        unpack_address(hdr->path[i], hop);
        printf("Hop %d: ", i);
        network_printaddr(hop);
        printf("\n");
    }

    return 0;
}
Exemplo n.º 8
0
/* Receives a message through a locally unbound port. Threads that call this function are
 * blocked until a message arrives. Upon arrival of each message, the function must create
 * a new bound port that targets the sender's address and listening port, so that use of
 * this created bound port results in replying directly back to the sender. It is the
 * responsibility of this function to strip off and parse the header before returning the
 * data payload and data length via the respective msg and len parameter. The return value
 * of this function is the number of data payload bytes received not inclusive of the header.
 */
int
minimsg_receive(miniport_t local_unbound_port, miniport_t* new_local_bound_port,
                minimsg_t msg, int *len)
{
    int received;
    miniport_t port;
    network_interrupt_arg_t *intrpt;
    network_address_t dest_addr;
    mini_header_t header;
    unsigned short dest_port;
    interrupt_level_t oldlevel;

    if (NULL == local_unbound_port || NULL == new_local_bound_port
            || UNBOUNDED != local_unbound_port->type
            || NULL == len || BOUNDED == local_unbound_port->type)
        return -1;

    /*
     * These shared data structures can be changed in the newtwork interrupt
     * handler, so interrupts should be disabled here as well.
     */
    oldlevel = set_interrupt_level(DISABLED);
    semaphore_P(local_unbound_port->unbound.ready);
    queue_wrap_dequeue(local_unbound_port->unbound.data, (void**) &intrpt);
    set_interrupt_level(oldlevel);

    /*
     * The copied size should be the minimum among the user provided buffer
     * size (original *len), the received data size (received), and
     * MINIMSG_MAX_MSG_SIZE.
     */
    received = intrpt->size - MINIMSG_HDRSIZE;
    if (*len >= received)
        *len = received;
    if (*len >= MINIMSG_MAX_MSG_SIZE)
        *len = MINIMSG_MAX_MSG_SIZE;

    header = (mini_header_t) intrpt->buffer;
    unpack_address(header->source_address, dest_addr);
    dest_port = unpack_unsigned_short(header->source_port);

    port = miniport_create_bound(dest_addr, dest_port);
    if (NULL == port)
        return -1;
    *new_local_bound_port = port;

    memcpy(msg, header + 1, *len);
    free(intrpt);

    return received;
}
Exemplo n.º 9
0
/* Process a reply packet */
static void
miniroute_process_reply(network_interrupt_arg_t *intrpt)
{
    miniroute_header_t hdr = (miniroute_header_t) intrpt->buffer;
    network_address_t dest;
    unpack_address(hdr->destination, dest);

    /* Relay packets if it is intended for others */
    if (network_address_same(dest, hostaddr) != 1) {
        miniroute_relay(intrpt);
    } else {
        discovered_path = miniroute_path_from_hdr(hdr);
        miniroute_cache_put_item(route_cache, (miniroute_item_t*)discovered_path);
        free(intrpt);
        miniroute_discovery_cancel();
    }
}
Exemplo n.º 10
0
/* Reverse a route */
network_address_t* miniroute_reverse_raw_path(routing_header_t header, int path_len)
{
	network_address_t unpacked_addr;
	int i = 0;

	network_address_t* reversed_path = (network_address_t*) malloc(path_len * sizeof(network_address_t));
	if (reversed_path == NULL)
		return NULL;

	for (i = 0; i < path_len; i++)
	{
		unpack_address(header->path[i], unpacked_addr);
		network_address_copy(unpacked_addr, reversed_path[path_len-1-i]);
	}

	return reversed_path;
}
Exemplo n.º 11
0
int
minimsg_receive(miniport_t* local_unbound_port, miniport_t** new_local_bound_port, minimsg_t* msg, int *len)
{
	assert(g_boundPortCounter >= 0); //sanity check to ensure minimsg_initialize() has been called first

	//validate input
	if (new_local_bound_port == NULL || local_unbound_port == NULL|| msg == NULL || len == NULL || *len < 0) return -1;
	assert(local_unbound_port->port_type == 'u' && local_unbound_port->unbound_port.datagrams_ready != NULL && local_unbound_port->unbound_port.datagrams_ready != NULL);

	semaphore_P(local_unbound_port->unbound_port.datagrams_ready); //P the semaphore, if the count is 0 we're blocked until packet arrives

	//once a packet arrives and we've woken
	network_interrupt_arg_t* dequeuedPacket = NULL;
	interrupt_level_t old_level = set_interrupt_level(DISABLED); // critical session (to dequeue the packet queue)
	assert(queue_length(local_unbound_port->unbound_port.incoming_data) > 0); //sanity check - our queue should have a packet waiting
	int dequeueSuccess = queue_dequeue(local_unbound_port->unbound_port.incoming_data, (void**)&dequeuedPacket); 
	AbortOnCondition(dequeueSuccess != 0, "Queue_dequeue failed in minimsg_receive()");
	set_interrupt_level(old_level); //end of critical session to restore interrupt level

	//Our packet size should be valid
	assert(dequeuedPacket->size >= 0);

	//get our header and message from the dequeued packet
	assert(dequeuedPacket->size >= sizeof(mini_header_t));
	mini_header_t receivedHeader;
	memcpy(&receivedHeader, dequeuedPacket->buffer, sizeof(mini_header_t));
	//set *len to the msg length to be copied: if the length of the message received is >= *len, no change to *len. Otherwise, set *len to the length of our received message
	if (dequeuedPacket->size - sizeof(mini_header_t) < *len) *len = dequeuedPacket->size - sizeof(mini_header_t);
	memcpy(msg, dequeuedPacket->buffer + sizeof(mini_header_t), *len); // msg is after header

	//create our new local bound port pointed back to the sender
	int sourcePort = (int)unpack_unsigned_short(receivedHeader.source_port);	// get source's listening port
	assert(sourcePort >= UNBOUNDED_PORT_START && sourcePort <= UNBOUNDED_PORT_END); //make sure source port num is valid
	network_address_t remoteAddr;
	unpack_address(receivedHeader.source_address, remoteAddr);	// get source's network address
	free(dequeuedPacket);	// release the memory allocated to the packet

	*new_local_bound_port = miniport_create_bound(remoteAddr, sourcePort);	// create a bound port
	if (*new_local_bound_port == NULL) return -1;

    return *len; //return data payload bytes received not inclusive of header
}
Exemplo n.º 12
0
/**
 * method for packet processor to repeatedly
 * check for new packets that arrived and upon
 * sanity checks forward them to the appropriate
 * port to be queued up. If the destination port
 * is not initialized, the packet is thrown away.
 *
 * We protect important global data structures (ie.
 * our array of miniports) with semaphores. Each 
 * miniport has an associated semaphore as well.
 */
int process_packets() {
  interrupt_level_t l;
  network_interrupt_arg_t* pkt;
  char protocol;
  network_address_t src_addr;
  mini_header_t header; 
  unsigned short src_port_num;
  network_address_t dst_addr;
  unsigned short dst_port_num;
  //char message_type;
  //unsigned int seq_number;
  //unsigned int ack_number; // TCP
  miniport_t dst_port;

  while (1) {
    semaphore_P(pkt_available_sem);
    l = set_interrupt_level(DISABLED);
    if (queue_dequeue(pkt_q, (void**)&pkt)){
      //dequeue fails
      set_interrupt_level(l);
      continue; //move on with life
    }
    set_interrupt_level(l);

    //perform checks on packet, free & return if invalid
    protocol = pkt->buffer[0];
    if (protocol != PROTOCOL_MINIDATAGRAM &&
          protocol != PROTOCOL_MINISTREAM){
      free(pkt);
      continue;
    } 
    else {
      // JUMP ON IT
      header = (mini_header_t)(&pkt->buffer);
      unpack_address(header->source_address, src_addr);
      src_port_num = unpack_unsigned_short(header->source_port);
      unpack_address(header->destination_address, dst_addr);
      dst_port_num = unpack_unsigned_short(header->destination_port);

      if (protocol == PROTOCOL_MINIDATAGRAM){
        //check address
        if (!network_compare_network_addresses(my_addr, dst_addr) ||
              src_port_num >= BOUND_PORT_START ||
              dst_port_num >= BOUND_PORT_START ) {
          free(pkt);
          continue;
        }
        //if port DNE or not an unbound port, fail
        if (miniport_array[dst_port_num] == NULL ||
            miniport_array[dst_port_num]->p_type != UNBOUND_PORT) {
          free(pkt);
          continue;
        }
        dst_port = miniport_array[dst_port_num]; 
        semaphore_P(dst_port->u.unbound.q_lock);
        queue_append(dst_port->u.unbound.port_pkt_q,pkt);
        semaphore_V(dst_port->u.unbound.q_lock);
        semaphore_V(dst_port->u.unbound.port_pkt_available_sem);
        continue;
      }
      else if (protocol == PROTOCOL_MINISTREAM) {
        free(pkt);
        continue; //for now, ignore tcp packets
      }
    }
    //DROP DA BASE
    //JUUUUUMPP ONNNN ITTT
  }
  return -1;
}
Exemplo n.º 13
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 newMinisocket;
	int ack_check;
	int connected = 1;
	network_interrupt_arg_t *arg;
	mini_header_reliable_t header;

	if (error == NULL)
		return NULL;

	if (port < TCP_MINIMUM_SERVER || port > TCP_MAXIMUM_SERVER)
	{
		*error = SOCKET_INVALIDPARAMS;
		return NULL;
	}

	semaphore_P(server_mutex);

	//Checks if port already exists
	if (minisockets[port] != NULL)
	{
		*error = SOCKET_PORTINUSE;
		semaphore_V(server_mutex);
		return NULL;
	}

	newMinisocket = minisocket_create_socket(port);
	if (newMinisocket == NULL)
	{
		*error = SOCKET_OUTOFMEMORY;
		semaphore_V(server_mutex);
		return NULL;
	}

	newMinisocket->port_type = TCP_PORT_TYPE_SERVER;
	minisockets[port] = newMinisocket;

	semaphore_V(server_mutex);

	while (connected == 1)
	{
		semaphore_P(newMinisocket->packet_ready);
		
		queue_dequeue(newMinisocket->waiting_packets, (void **) &arg);
		header = (mini_header_reliable_t) arg->buffer;
		if (header->message_type != MSG_SYN)
			continue;

		newMinisocket->status = TCP_PORT_CONNECTING;

		unpack_address(header->source_address, newMinisocket->destination_addr);
		newMinisocket->destination_port = unpack_unsigned_short(header->source_port);
		ack_check = transmit_packet(newMinisocket, newMinisocket->destination_addr, 
				newMinisocket->destination_port, 1, MSG_SYNACK, 0, NULL, error);

		if (ack_check == -1)
		{
			newMinisocket->status = TCP_PORT_LISTENING;
			network_address_blankify(newMinisocket->destination_addr);
			newMinisocket->destination_port = 0;
		}	
		else
		{
			newMinisocket->status = TCP_PORT_CONNECTED;
			connected = 0;
		}
	}

	*error = SOCKET_NOERROR;
	return newMinisocket;
}
Exemplo n.º 14
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;
    }
  }
}
Exemplo n.º 15
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); 
    }
  }
}
Exemplo n.º 16
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;
}
Exemplo n.º 17
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; 
}
Exemplo n.º 18
0
/* Receives a message through a locally unbound port. Threads that call this function are
 * blocked until a message arrives. Upon arrival of each message, the function must create
 * a new bound port that targets the sender's address and listening port, so that use of
 * this created bound port results in replying directly back to the sender. It is the
 * responsibility of this function to strip off and parse the header before returning the
 * data payload and data length via the respective msg and len parameter. The return value
 * of this function is the number of data payload bytes received not inclusive of the header.
 */
int minimsg_receive(miniport_t local_unbound_port, miniport_t* new_local_bound_port, minimsg_t msg, int *len) {
	unsigned short remote_port;
	char* buffer;
	// int size = 0;
	int i = 0;
	network_address_t remote_receive_addr;
	network_interrupt_arg_t* packet = NULL;
	// mini_header_t header;

	// semaphore_P(msgmutex);

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

	// semaphore_V(msgmutex);

	// fprintf(stderr, "minimsg_receive() paused\n");

	semaphore_P(local_unbound_port->u.unbound.datagrams_ready); // Block until message arrives

	// fprintf(stderr, "minimsg_receive() resuming\n");

	// semaphore_P(msgmutex);

	// Obtain received message from miniport queue and extract header data
	if (queue_dequeue(local_unbound_port->u.unbound.incoming_data, (void**) &packet) < 0) {
		fprintf(stderr, "ERROR: minimsg_receive() failed to dequeue message from miniport queue\n");
		semaphore_V(msgmutex);
		return -1;
	}

	// Extract header stuff
	buffer = packet->buffer;
	// size = packet->size;
	// *len = ((packet->size) - 20) / sizeof(char);
	*len = sizeof(buffer[21]) / sizeof(char);
	unpack_address(&buffer[1], remote_receive_addr);
	remote_port = unpack_unsigned_short(&buffer[9]);
	// msg = (minimsg_t) &buffer[21];
	// *msg = *((minimsg_t) &buffer[21]);

	while (buffer[21 + i]) {
		msg[i] = buffer[21 + i];
		i++;
	}

	// fprintf(stderr, "minimsg_receive() past extracting header stuff\n");
	/*fprintf(stderr, "minimsg_receive() msg: %s\n", msg);
	fprintf(stderr, "minimsg_receive() msg size: %d\n", (int) sizeof(msg));
	fprintf(stderr, "minimsg_receive() len: %d\n", *len);
	fprintf(stderr, "minimsg_receive() force msg len: %d\n", (int) (sizeof((minimsg_t) &buffer[21]) / sizeof(char)));
	fprintf(stderr, "minimsg_receive() get body length: %lu\n", sizeof(buffer) / sizeof(buffer[21]) - 20);*/

	// Create new bound port
	*new_local_bound_port = miniport_create_bound(remote_receive_addr, remote_port);

 	//return number of bytes of payload actually received (drop stuff beyond max)

 	free(packet);

 	// semaphore_V(msgmutex);

    return sizeof(msg);
}
Exemplo n.º 19
0
 void network_handler(network_interrupt_arg_t* arg)
{
	// Used to extract the network address out of the interrupt argument
	//network_address_t addr;

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

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

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

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

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

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

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

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

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

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

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

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

	// This will store the socket
	minisocket_t socket;

	// This will store the TCP error
	minisocket_error error;

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

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

	// Used for general for loops
	int i;

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

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

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

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

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

	// Handle the mini route stuff

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

			break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	// Restore the interrupt level
	set_interrupt_level(prev_level);

	return;
}
Exemplo n.º 20
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;
}
Exemplo n.º 21
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;
    }
}
Exemplo n.º 22
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;
}
Exemplo n.º 23
0
 void network_handler(network_interrupt_arg_t* arg)
{
	// Used to extract the network address out of the interrupt argument
	//network_address_t addr;

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

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

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

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

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

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

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

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

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

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

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

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

	// This will store the socket
	minisocket_t socket;

	// This will store the TCP error
	minisocket_error error;

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

	// Check the protocol
	switch (arg->buffer[0])
	{
		case (char) PROTOCOL_MINIDATAGRAM:
			// Extract data from the network interrupt arg
			//network_address_copy(arg->addr, addr);

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

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

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

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

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

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

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

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

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

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

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

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

					set_interrupt_level(prev_level);
					return;
				}


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

					set_interrupt_level(prev_level);
					return;
				}

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

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

					set_interrupt_level(prev_level);
					return;
				}

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

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

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

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

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

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

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

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

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

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

					// Set the status to connecting
					socket->status = TCP_PORT_CONNECTING;

					// Awake the create_server thread, it'll handle the rest
					semaphore_V(socket->wait_for_ack_sem);
				}
			}

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

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

	// Restore the interrupt level
	set_interrupt_level(prev_level);

	return;
}
Exemplo n.º 24
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;
}
Exemplo n.º 25
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;
}