/* Performs any initialization of the miniroute layer, if required. */ void miniroute_initialize() { network_get_my_address(hostaddr); discovery_alarm = -1; intrpt_buffer = queue_new(); intrpt_sig = semaphore_create(); discovery_mutex = semaphore_create(); discovery_sig = semaphore_create(); route_cache = miniroute_cache_new(65536, SIZE_OF_ROUTE_CACHE, MINIROUTE_CACHED_ROUTE_EXPIRE); disc_cache = miniroute_cache_new(65536, SIZE_OF_ROUTE_CACHE, MINIROUTE_CACHED_ROUTE_EXPIRE * 10); if (NULL == intrpt_buffer || NULL == intrpt_sig || NULL == route_cache || NULL == discovery_mutex || NULL == discovery_sig) { queue_free(intrpt_buffer); semaphore_destroy(intrpt_sig); semaphore_destroy(discovery_mutex); semaphore_destroy(discovery_sig); miniroute_cache_destroy(route_cache); return; } semaphore_initialize(intrpt_sig, 0); semaphore_initialize(discovery_mutex, 1); semaphore_initialize(discovery_sig, 0); network_get_my_address(hostaddr); minithread_fork(miniroute_control, NULL); }
/* Initializes the minisocket layer. */ void minisocket_initialize() { int i; sock_array = (minisocket_t*)malloc(sizeof(struct minisocket)*NUM_SOCKETS); if (!sock_array) { return; } for (i = 0; i < NUM_SOCKETS; i++) { sock_array[i] = NULL; } client_lock = semaphore_create(); if (!client_lock) { free(sock_array); return; } server_lock = semaphore_create(); if (!server_lock) { free(sock_array); semaphore_destroy(client_lock); return; } semaphore_initialize(client_lock, 1); semaphore_initialize(server_lock, 1); network_get_my_address(my_addr); curr_client_idx = CLIENT_START; //printf("minisocket_initialize complete\n"); }
/* FUNC DEFS */ void miniroute_initialize() { route_cache = miniroute_cache_create(); dcb_table = hash_table_create(); curr_discovery_pkt_id = 1; network_get_my_address(my_addr); //init my_addr return; }
int transmit(int* arg) { char buffer[BUFFER_SIZE]; int length; int i; minithread_t receiver1; minithread_t receiver2; miniport_t write_port1; miniport_t write_port2; network_address_t my_address; network_get_my_address(&my_address); port1 = miniport_create_unbound(0); port2 = miniport_create_unbound(1); write_port1 = miniport_create_bound(my_address, 0); write_port2 = miniport_create_bound(my_address, 1); receiver1 = minithread_fork(receive1, NULL); receiver2 = minithread_fork(receive2, NULL); for (i=0; i<MAX_COUNT; i++) { printf("Sending packet %d to receiver 1.\n", i+1); sprintf(buffer, "Count for receiver 1 is %d.\n", i+1); length = strlen(buffer) + 1; minimsg_send(port1, write_port1, buffer, length); minithread_yield(); printf("Sending packet %d to receiver 2.\n", i+1); sprintf(buffer, "Count for receiver 2 is %d.\n", i+1); length = strlen(buffer) + 1; minimsg_send(port2, write_port2, buffer, length); } return 0; }
int receive(int* arg) { network_address_t my_address; minisocket_t socket; minisocket_error error; printf("starting receive\n"); minithread_yield(); printf("continuing receive\n"); network_get_my_address(my_address); /* create a network connection to the local machine */ socket = minisocket_client_create(my_address, port,&error); if (socket==NULL){ printf("ERROR: %s. Exiting. \n",GetErrorDescription(error)); return -1; } printf("client connected\n"); minisocket_close(socket); return 0; }
int send(int* arg) { char buffer[BUFFER_SIZE]; int length = BUFFER_SIZE; int i; network_address_t addr; miniport_t *dest; miniport_t *equal_test; network_get_my_address(addr); equal_test = miniport_create_unbound(100); if (port != equal_test) { fprintf(stderr, "miniport_create unbound is duplicating ports \n"); exit(0); } dest = miniport_create_bound(addr, 100); for (i=0; i<MSG_PER_PORT; i++) { messageCount++; sprintf(buffer, "Received packet number %d \n", messageCount); length = strlen(buffer) + 1; minimsg_send(port, dest, buffer, length); fprintf(stderr, "sending %d \n", messageCount); } miniport_destroy(dest); return 0; }
int transmit1(int* arg) { char buffer[BUFFER_SIZE]; int length; int i; minithread_t transmitter2; minithread_t receiver; miniport_t write_port; network_get_my_address(&my_address); port = miniport_create_unbound(0); write_port = miniport_create_bound(my_address, 0); transmitter2 = minithread_fork(transmit2, NULL); receiver = minithread_fork(receive, NULL); for (i=0; i<MAX_COUNT; i++) { printf("Sending packet %d from sender 1.\n", i+1); sprintf(buffer, "Count from sender 1 is %d.\n", i+1); length = strlen(buffer) + 1; minimsg_send(port, write_port, buffer, length); minithread_yield(); } return 0; }
int receive(int* arg) { char buffer[BUFFER_SIZE]; int i; int bytes_received; network_address_t my_address; minisocket_t socket; minisocket_error error; /* * It is crucial that this minithread_yield() works properly * (i.e. it really gives the processor to another thread) * othrevise the client starts before the server and it will * fail (there is nobody to connect to). */ minithread_yield(); network_get_my_address(my_address); int x; /* create a network connection to the local machine */ socket = minisocket_client_create(my_address, port,&error); if (socket==NULL){ printf("3ERROR: %s. Exiting. \n",GetErrorDescription(error)); return -1; } //semaphore_P(done_sending); /* receive the message */ bytes_received=0; while (bytes_received!=BUFFER_SIZE/20){ int received_bytes; if ((received_bytes=minisocket_receive(socket,buffer, 2, &error))==-1){ printf("inside, socket status = %d [%p]\n", socket->status, socket); printf("4ERROR: %s. Exiting. \n",GetErrorDescription(error)); /* close the connection */ minisocket_close(socket); return -1; } /* test the information received */ for (i=0; i<received_bytes; i++){ if (buffer[i]!=(char)( (bytes_received+i)%256 )){ printf("The %d'th byte received is wrong ('%d'-'%d'-'%d'-'%d' vs '%d'-'%d'-'%d'-'%d') [%d].\n", bytes_received+i, buffer[i-3], buffer[i-2], buffer[i-1], buffer[i], (bytes_received+i-3)%256, (bytes_received+i-2)%256, (bytes_received+i-1)%256, (bytes_received+i)%256, received_bytes); /* close the connection */ minisocket_close(socket); return -1; } } bytes_received+=received_bytes; } printf("All bytes received correctly (received %d bytes).\n", bytes_received); minisocket_close(socket); return 0; }
int receive(int* arg) { char buffer[BUFFER_SIZE]; int i; int bytes_received; network_address_t my_address; minisocket_t socket; minisocket_error error; /* * It is crucial that this minithread_yield() works properly * (i.e. it really gives the processor to another thread) * othrevise the client starts before the server and it will * fail (there is nobody to connect to). */ minithread_yield(); network_get_my_address(my_address); /* create a network connection to the local machine */ printf("creating client\n"); socket = minisocket_client_create(my_address, port,&error); printf("client unblocked\n"); if (socket==NULL){ printf("ERROR: %s. Exiting. \n",GetErrorDescription(error)); return -1; } /* receive the message */ bytes_received=0; while (bytes_received!=BUFFER_SIZE){ int received_bytes; if ((received_bytes=minisocket_receive(socket,buffer, BUFFER_SIZE-bytes_received, &error))==-1){ printf("ERROR: %s. Exiting. \n",GetErrorDescription(error)); /* close the connection */ minisocket_close(socket); return -1; } printf("checking bytes\n"); /* test the information received */ for (i=0; i<received_bytes; i++){ if (buffer[i]!=(char)( (bytes_received+i)%256 )){ printf("The %d'th byte received is wrong.\n", bytes_received+i); /* close the connection */ minisocket_close(socket); return -1; } } bytes_received+=received_bytes; } printf("All bytes received correctly.\n"); minisocket_close(socket); return 0; }
int clientMethod(int* arg) { char responseBuffer1[10]; char responseBuffer2[10]; minithread_fork(serverMethod, NULL); network_address_t my_address; network_get_my_address(my_address); minisocket_error error; //create client client = minisocket_client_create(my_address, PORT_NUM, &error); assert(client != NULL); assert(error == SOCKET_NOERROR); //receive first 10 bytes int response = minisocket_receive(client, responseBuffer1, 10, &error); assert(response == 10); assert(strcmp(responseBuffer1, "aaaaaaaaaa") == 0); //receive second 10 bytes response = minisocket_receive(client, responseBuffer2, 10, &error); assert(response == 10); assert(strcmp(responseBuffer2, "aaaaaaaaaa") == 0); minithread_sleep_with_timeout(15000); //Make sure that the port does not exist response = minisocket_send(client, aText, strlen(aText), &error); assert(response == -1); assert(error == SOCKET_INVALIDPARAMS); error = SOCKET_NOERROR; fprintf(stderr, "Test Part 1 Passed \n"); //recreate client client = minisocket_client_create(my_address, PORT_NUM, &error); assert(client != NULL); assert(error == SOCKET_NOERROR); //send from client int packets_sent = minisocket_send(client, bText, strlen(bText), &error); assert(packets_sent == strlen(bText)); assert(error == SOCKET_NOERROR); minisocket_close(client); minithread_sleep_with_timeout(15000); //assert that minisocket has closed response = minisocket_send(client, aText, strlen(aText), &error); assert(response == -1); assert(error == SOCKET_INVALIDPARAMS); return 0; }
int transmit_first(int* arg) { char buffer[MINIMSG_MAX_MSG_SIZE + 10]; int length = 0; int i; network_address_t hostaddr, targetaddr; miniport_t port; miniport_t dest; struct mini_header hdr; AbortOnCondition(network_translate_hostname(hostname, targetaddr) < 0, "Could not resolve hostname, exiting."); port = miniport_create_unbound(0); dest = miniport_create_bound(targetaddr, 1); /* Form correct header */ network_get_my_address(hostaddr); hdr.protocol = PROTOCOL_MINIDATAGRAM; pack_address(hdr.source_address, hostaddr); pack_unsigned_short(hdr.source_port, port->num); pack_address(hdr.destination_address, dest->bound.addr); pack_unsigned_short(hdr.destination_port, dest->bound.remote); /* Send packages with short but correct header and zero data */ printf("Sending packages with short headers.\n"); sprintf(buffer, "Receiving packages with short headers.\n"); length = strlen(buffer) + 1; minimsg_send(port, dest, buffer, length); for (i = 0; i < MINIMSG_HDRSIZE; i++) network_send_pkt(targetaddr, i, (char*)&hdr, 0, buffer); /* Send packages to wrong ports */ printf("Sending packages to wrong destination ports.\n"); sprintf(buffer, "Receiving packages with wrong destination ports.\n"); length = strlen(buffer) + 1; minimsg_send(port, dest, buffer, length); sprintf(buffer, "This message is sent to a wrong port.\n"); length = strlen(buffer) + 1; minimsg_send(port, miniport_create_bound(targetaddr, 0), buffer, length); minimsg_send(port, miniport_create_bound(targetaddr, MAX_UNBOUNDED), buffer, length); minimsg_send(port, miniport_create_bound(targetaddr, MAX_UNBOUNDED + 1), buffer, length); minimsg_send(port, miniport_create_bound(targetaddr, MIN_BOUNDED), buffer, length); minimsg_send(port, miniport_create_bound(targetaddr, MAX_BOUNDED), buffer, length); printf("Send-first finished.\n"); return 0; }
void minisocket_initialize() { for (int i = 0; i < N_PORTS; i++) { ports[i] = NULL; } ports_mutex = semaphore_create(); semaphore_initialize(ports_mutex, 1); n_client_ports = MIN_CLIENT_PORT; network_get_my_address(local_host); }
/* Construct a (reliable) header to be sent by the given socket. */ void set_header(minisocket_t socket, mini_header_reliable_t hdr, char message_type) { network_address_t my_address; hdr->protocol = PROTOCOL_MINISTREAM; // Protocol network_get_my_address(my_address); pack_address(hdr->source_address, my_address); // Source address pack_unsigned_short(hdr->source_port, socket->local_port); // Source port pack_address(hdr->destination_address, socket->dest_address); // Destination address pack_unsigned_short(hdr->destination_port, socket->remote_port); // Destination port hdr->message_type = message_type; // Message type pack_unsigned_int(hdr->seq_number, socket->seqnum); // Sequence number pack_unsigned_int(hdr->ack_number, socket->acknum); // Acknowledgment number }
void bcast_initialize(char* configfile, bcast_t* bcast) { FILE* config = fopen(configfile, "r"); char line[BCAST_MAX_LINE_LEN]; int i = 0; char* rv; network_address_t my_addr; unsigned int my_ip_addr; network_get_my_address(my_addr); my_ip_addr = my_addr[0]; while ((rv = fgets(line, BCAST_MAX_LINE_LEN, config)) != NULL) { if (line[0] == '\r' || line[0] == '\n') break; line[strlen(line)-1] = '\0'; strcpy(bcast->entries[i].name, line); bcast->entries[i].n_links = 0; if (network_translate_hostname(line, bcast->entries[i].addr) != 0) { kprintf("Error: could not resolve hostname %s.\n", line); AbortOnCondition(1,"Crashing."); } if (bcast->entries[i].addr[0] == my_ip_addr) bcast->me = i; i++; } bcast->n_entries = i; if (rv != NULL) for (i=0; i<bcast->n_entries; i++) { //int len; int j; AbortOnCondition(fgets(line, BCAST_MAX_LINE_LEN, config) == NULL, "Error: incomplete adjacency matrix."); //len = strlen(line); for (j=0; j<bcast->n_entries; j++) if (i == j) ; /* avoid self-links */ else if (line[j] != '.') { bcast->entries[i].links[bcast->entries[i].n_links] = j; bcast->entries[i].n_links++; } } fclose(config); }
int thread(int* arg) { char buffer[BUFFER_SIZE]; int length = BUFFER_SIZE; miniport_t from; network_address_t my_address; network_get_my_address(&my_address); listen_port = miniport_create_unbound(0); send_port = miniport_create_bound(my_address, 0); minimsg_send(listen_port, send_port, text, textlen); minimsg_receive(listen_port, &from, buffer, &length); printf("%s", buffer); return 0; }
/* Sends a message through a locally bound port (the bound port already has an associated * receiver address so it is sufficient to just supply the bound port number). In order * for the remote system to correctly create a bound port for replies back to the sending * system, it needs to know the sender's listening port (specified by local_unbound_port). * The msg parameter is a pointer to a data payload that the user wishes to send and does not * include a network header; your implementation of minimsg_send must construct the header * before calling miniroute_send_pkt(). The return value of this function is the number of * data payload bytes sent not inclusive of the header. */ int minimsg_send(miniport_t local_unbound_port, miniport_t local_bound_port, minimsg_t msg, int len) { network_address_t dest, my_address; mini_header_t hdr; // semaphore_P(msgmutex); // Check for valid arguments if (local_unbound_port == NULL) { fprintf(stderr, "ERROR: minimsg_send() passed a NULL local_unbound_port miniport argument\n"); semaphore_V(msgmutex); return -1; } if (local_bound_port == NULL) { fprintf(stderr, "ERROR: minimsg_send() passed a NULL local_bound_port miniport argument\n"); semaphore_V(msgmutex); return -1; } // Allocate new header for packet hdr = malloc(sizeof(struct mini_header)); if (hdr == NULL) { // Could not allocate header fprintf(stderr, "ERROR: minimsg_send() failed to malloc new mini_header\n"); semaphore_V(msgmutex); return -1; } // Assemble packet header hdr->protocol = PROTOCOL_MINIDATAGRAM; // Protocol network_get_my_address(my_address); pack_address(hdr->source_address, my_address); // Source address pack_unsigned_short(hdr->source_port, local_bound_port->port_num); // Source port network_address_copy(local_bound_port->u.bound.remote_address, dest); pack_address(hdr->destination_address, dest); // Destination address pack_unsigned_short(hdr->destination_port, local_bound_port->u.bound.remote_unbound_port); // Destination port // Call miniroute_send_pkt() from network.hdr if (network_send_pkt(dest, sizeof(struct mini_header), (char*) hdr, len, msg) < 0) { // REMOVE THIS LINE // if (miniroute_send_pkt(dest, sizeof(struct mini_header), (char*) hdr, len, msg) < 0) { fprintf(stderr, "ERROR: minimsg_send() failed to successfully execute miniroute_send_pkt()\n"); semaphore_V(msgmutex); return -1; } // semaphore_V(msgmutex); return 0; }
int thread(int* arg) { char buffer[BUFFER_SIZE]; int length = BUFFER_SIZE; miniport_t *from; network_address_t my_address; network_get_my_address(my_address); listen_port = miniport_create_unbound(0); send_port = miniport_create_bound(my_address, 0); minimsg_send(listen_port, send_port, text, textlen); minimsg_receive(listen_port, &from, buffer, &length); printf("%s\n", buffer); //newline is to enable printing when truncated before a newline character has been reached return 0; }
//Returns a reliable mini header //TODO: do seq_num and ack_num void minisocket_create_reliable_header(mini_header_reliable_t* header, minisocket_t* socket, unsigned short dest_port, const network_address_t dest_address, char message_type) { header->protocol = PROTOCOL_MINISTREAM; //packs info pack_address(header->destination_address, dest_address); pack_unsigned_short(header->destination_port, dest_port); network_address_t my_address; network_get_my_address(my_address); pack_address(header->source_address, my_address); pack_unsigned_short(header->source_port, socket->local_port_number); //pack seq and ack numbers pack_unsigned_int(header->ack_number, socket->ack); pack_unsigned_int(header->seq_number, socket->seq); //set message type header->message_type = message_type; }
/* performs any required initialization of the minimsg layer. */ void minimsg_initialize() { unsigned int i; network_get_my_address(my_addr); //init my_addr curr_bound_index = BOUND_PORT_START; miniport_array = (miniport_t*)malloc((MAX_PORT_NUM)*sizeof(miniport_t)); if (miniport_array == NULL) { return; } for (i = 0; i < MAX_PORT_NUM; i++) { miniport_array[i] = NULL; } bound_ports_lock = semaphore_create(); if (!bound_ports_lock){ return; } unbound_ports_lock = semaphore_create(); if (!unbound_ports_lock){ semaphore_destroy(bound_ports_lock); return; } pkt_available_sem = semaphore_create(); if (!pkt_available_sem){ semaphore_destroy(bound_ports_lock); semaphore_destroy(unbound_ports_lock); return; } pkt_q = queue_new(); if (!pkt_q){ semaphore_destroy(bound_ports_lock); semaphore_destroy(unbound_ports_lock); semaphore_destroy(pkt_available_sem); return; } semaphore_initialize(bound_ports_lock,1); semaphore_initialize(unbound_ports_lock,1); semaphore_initialize(pkt_available_sem,0); }
int thread(int* arg) { char buffer[BUFFER_SIZE]; int length = BUFFER_SIZE; miniport_t from; network_address_t my_address; network_get_my_address(my_address); receive_port = miniport_create_unbound(0); send_port = miniport_create_bound(my_address, 0); minimsg_send(receive_port, send_port, text, textlen); minithread_sleep_with_timeout(1000); miniport_destroy(receive_port); receive_port = miniport_create_unbound(0); printf("waiting\n"); minimsg_receive(receive_port, &from, buffer, &length); printf("%s", buffer); //should not print return 0; }
int clientMethod(int* arg) { char responseBuffer1[1]; char responseBuffer2[20]; char responseBuffer3[10001]; minithread_fork(serverMethod, NULL); network_address_t my_address; network_get_my_address(my_address); minisocket_error error; //create client client = minisocket_client_create(my_address, PORT_NUM, &error); assert(client != NULL); assert(error == SOCKET_NOERROR); //Test sending output int response = minisocket_receive(client, responseBuffer1, 1, &error); assert(response == 1); assert(responseBuffer1[0] == 'a'); response = minisocket_receive(client, responseBuffer2, 20, &error); assert(response == 20); assert(strcmp(responseBuffer2, "bbbbbbbbbbbbbbbbbbbb") == 0); int bytes_received = 0; while (bytes_received != 10000) { response = minisocket_receive(client, responseBuffer3 + bytes_received, 10000, &error); assert(response > 0); bytes_received += response; } assert(strcmp(responseBuffer3, cText) == 0); fprintf(stderr, "All Tests Passed \n"); return 0; }
int transmit(int* arg) { char buffer[BUFFER_SIZE]; int length; // int i; miniport_t write_port; network_address_t my_address; network_get_my_address(my_address); port = miniport_create_unbound(0); write_port = miniport_create_bound(my_address, 0); // write_port = miniport_create_bound("127.111.111.112", 0); // minithread_fork(receive, NULL); // for (i=0; i<MAX_COUNT; i++) { printf("Sending instant message:\n"); sprintf(buffer, "PUT INSTANT MESSAGE HERE\n"); length = strlen(buffer) + 1; minimsg_send(port, write_port, buffer, length); // } return 0; }
int transmit(int* arg) { char buffer[BUFFER_SIZE]; int length; int i; miniport_t *write_port; network_address_t my_address; network_get_my_address(my_address); port = miniport_create_unbound(0); write_port = miniport_create_bound(my_address, 0); minithread_fork(receive, NULL); for (i=0; i<MAX_COUNT; i++) { printf("Sending packet %d.\n", i+1); sprintf(buffer, "Count is %d.\n", i+1); length = strlen(buffer) + 1; minimsg_send(port, write_port, buffer, length); } return 0; }
int minimsg_send(miniport_t* local_unbound_port, miniport_t* local_bound_port, minimsg_t* msg, int len) { assert(g_boundPortCounter >= 0); //sanity check to ensure minimsg_initialize() has been called first //validate input if (local_unbound_port == NULL || local_bound_port == NULL || msg == NULL || len < 0 || len > MINIMSG_MAX_MSG_SIZE) return -1; //generate the header mini_header_t header; header.protocol = PROTOCOL_MINIDATAGRAM; //set protocol type network_address_t my_address; network_get_my_address(my_address); pack_address(header.source_address, my_address); pack_unsigned_short(header.source_port, local_unbound_port->port_number); pack_address(header.destination_address, local_bound_port->bound_port.remote_addr); pack_unsigned_short(header.destination_port, local_bound_port->bound_port.remote_unbound_port); //send message now int sentBytes = network_send_pkt(local_bound_port->bound_port.remote_addr, sizeof(header), (char*)&header, len, msg); if (sentBytes == -1) return -1; //we failed to send our message else return sentBytes - sizeof(header); //else return size of our message not inclusive of header }
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; }
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; }
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; }
//Transmit a packet and handle retransmission attempts int transmit_packet(minisocket_t socket, network_address_t dst_addr, int dst_port, short incr_seq, char message_type, int data_len, char* data, minisocket_error* error) { mini_header_reliable_t newReliableHeader; void *alarmId; int sendSucessful; network_address_t my_addr; int success = 0; int connected = 0; if (message_type == MSG_ACK) connected = 1; network_get_my_address(my_addr); if (socket == NULL) { *error = SOCKET_INVALIDPARAMS; return -1; } if (socket->status == TCP_PORT_CLOSING) { *error = SOCKET_SENDERROR; return -1; } newReliableHeader = create_reliable_header(my_addr, socket->port_number, dst_addr, dst_port, message_type, socket->seq_number, socket->ack_number); socket->timeout = 100; while(socket->timeout <= 6400) { printf("sending packet to %d, seq=%d, ack=%d, type=%d\n", dst_port, socket->seq_number, socket->ack_number, message_type); sendSucessful = network_send_pkt(dst_addr, sizeof(struct mini_header_reliable), (char*) newReliableHeader, data_len, (char*) data); if (sendSucessful == -1) { socket->timeout *= 2; continue; } alarmId = register_alarm(socket->timeout, &wake_up_semaphore, socket); if (message_type == MSG_SYN) { socket->waiting = TCP_PORT_WAITING_SYNACK; semaphore_P(socket->wait_for_ack_semaphore); } else if (!connected) { socket->waiting = TCP_PORT_WAITING_ACK; semaphore_P(socket->wait_for_ack_semaphore); } else { socket->waiting = TCP_PORT_WAITING_NONE; } semaphore_P(socket->mutex); if (socket->waiting == TCP_PORT_WAITING_NONE) { /* I think incr_seq belongs before the _P on wait_for_ack, but that breaks it for now :/ if (incr_seq) { semaphore_P(socket->mutex); socket->seq_number++; semaphore_V(socket->mutex); } */ if (message_type == MSG_SYN) { //we got a synack back, so we need to make sure to send an ack to the server newReliableHeader = create_reliable_header(my_addr, socket->port_number, dst_addr, dst_port, MSG_ACK, socket->seq_number, socket->ack_number); socket->timeout = 100; message_type = MSG_ACK; connected = 1; semaphore_V(socket->mutex); continue; } deregister_alarm(alarmId); success = 1; semaphore_V(socket->mutex); break; } else { if (socket->status == TCP_PORT_UNABLE_TO_CONNECT) { deregister_alarm(alarmId); success = 0; semaphore_V(socket->mutex); break; } socket->timeout *= 2; semaphore_V(socket->mutex); } } semaphore_P(socket->mutex); socket->timeout = 100; if (success == 0) { socket->waiting = TCP_PORT_WAITING_NONE; *error = SOCKET_NOSERVER; } semaphore_V(socket->mutex); *error = SOCKET_NOERROR; free(newReliableHeader); return 0; }
int network_initialize(interrupt_handler_t network_handler) { int arg = 1; /* initialise the NT socket library, inexplicably required by NT */ assert(WSAStartup(MAKEWORD(2, 0), &winsock_version_data) == 0); if (atomic_test_and_set(&initialized)) { return -1; } memset(&if_info, 0, sizeof(if_info)); if_info.sock = socket(PF_INET, SOCK_DGRAM, 0); if (if_info.sock < 0) { perror("socket"); return -1; } if_info.sin.sin_family = SOCK_DGRAM; if_info.sin.sin_addr.s_addr = htonl(0); if_info.sin.sin_port = htons(my_udp_port); if (bind(if_info.sock, (struct sockaddr *) &if_info.sin, sizeof(if_info.sin)) < 0) { /* kprintf("Error: code %ld.\n", GetLastError());*/ AbortOnError(0); perror("bind"); return -1; } /* set for fast reuse */ assert(setsockopt(if_info.sock, SOL_SOCKET, SO_REUSEADDR, (char *) &arg, sizeof(int)) == 0); if (BCAST_ENABLED){ if (BCAST_USE_TOPOLOGY_FILE){ bcast_initialize(BCAST_TOPOLOGY_FILE, &topology); } else { assert(setsockopt(if_info.sock, SOL_SOCKET, SO_BROADCAST, (char *) &arg, sizeof(int)) == 0); network_translate_hostname(BCAST_ADDRESS,broadcast_addr); } } /* * Print network information on the screen (mostly for Joranda). */ { network_address_t my_address; char my_hostname[256]; network_get_my_address(my_address); network_format_address(my_address, my_hostname, 256); kprintf("Hostname of local machine: %s.\n",my_hostname); } /* * Interrupts are handled through the caller's handler. */ start_network_poll(network_handler, &if_info.sock); return 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; }