// Create a packed reliable header given the parameters mini_header_reliable_t create_reliable_header(network_address_t src_addr_raw, int src_port_raw, network_address_t dst_addr_raw, int dst_port_raw, char message_type, unsigned int seq_num_raw, unsigned int ack_num_raw) { mini_header_reliable_t header = (mini_header_reliable_t) malloc(sizeof(struct mini_header_reliable)); //Fields char src_port[2]; char dst_port[2]; char src_addr[8]; char dst_addr[8]; char seq_num[4]; char ack_num[4]; //Pack everything pack_unsigned_short(src_port, (unsigned short) src_port_raw); pack_unsigned_short(dst_port, (unsigned short) dst_port_raw); pack_address(src_addr, src_addr_raw); pack_address(dst_addr, dst_addr_raw); pack_unsigned_int(seq_num, seq_num_raw); pack_unsigned_int(ack_num, ack_num_raw); //Set header fields header->protocol = (char) PROTOCOL_MINISTREAM; header->message_type = message_type; memcpy(header->source_address, src_addr, 8); memcpy(header->destination_address, dst_addr, 8); memcpy(header->source_port, src_port, 2); memcpy(header->destination_port, dst_port, 2); memcpy(header->seq_number, seq_num, 4); memcpy(header->ack_number, ack_num, 4); return header; }
static mini_header_reliable_t *create_control_header(int msg_type, unsigned int dest_port, network_address_t dest_addr, unsigned int src_port, unsigned int seq, unsigned int ack) { mini_header_reliable_t *header = (mini_header_reliable_t *) malloc(sizeof(mini_header_reliable_t)); if (!header) { return NULL; } header->protocol = PROTOCOL_MINISTREAM + '0'; network_address_t local_addr; network_address_copy(local_host, local_addr); //network_get_my_address(local_addr); pack_address(header->source_address, local_addr); pack_unsigned_short(header->source_port, src_port); header->message_type = msg_type + '0'; pack_address(header->destination_address, dest_addr); pack_unsigned_short(header->destination_port, dest_port); pack_unsigned_int(header->seq_number, seq); pack_unsigned_int(header->ack_number, ack); return header; }
/* * Pack header using the local receiving and sending ports. * Called by minimsg_sent. */ static void minimsg_packhdr(mini_header_t hdr, miniport_t unbound, miniport_t bound) { hdr->protocol = PROTOCOL_MINIDATAGRAM; pack_address(hdr->source_address, hostaddr); pack_unsigned_short(hdr->source_port, unbound->num); pack_address(hdr->destination_address, bound->bound.addr); pack_unsigned_short(hdr->destination_port, bound->bound.remote); }
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; }
/* 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 }
/* minisocket_send_ctrl creates an ctrl packet of type type and with * fields taken from the sock parameter. * This ack packet is sent over the network. * If there is an underlying network failure, error is updated * but the pkt is not resent. * The address of pkt is given as the data buffer, * but no data from pkt is written since the data_len is 0. */ void minisocket_send_ctrl(char type, minisocket_t sock, minisocket_error* error) { struct mini_header_reliable pkt; pkt.protocol = PROTOCOL_MINISTREAM; pack_address(pkt.source_address, my_addr); pack_unsigned_short(pkt.source_port, sock->src_port); pack_address(pkt.destination_address, sock->dst_addr); pack_unsigned_short(pkt.destination_port, sock->dst_port); pkt.message_type = type; pack_unsigned_int(pkt.seq_number, sock->curr_seq); pack_unsigned_int(pkt.ack_number, sock->curr_ack); if (network_send_pkt(sock->dst_addr, sizeof(pkt), (char*)&pkt, 0, (char*)&pkt) == -1) { *error = SOCKET_SENDERROR; } }
/* 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; }
//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; }
/* Sends a message through a locally bound port (the bound port already has an associated * receiver address so it is sufficient to just supply the bound port number). In order * for the remote system to correctly create a bound port for replies back to the sending * system, it needs to know the sender's listening port (specified by local_unbound_port). * The msg parameter is a pointer to a data payload that the user wishes to send and does not * include a network header; your implementation of minimsg_send must construct the header * before calling network_send_pkt(). The return value of this function is the number of * data payload bytes sent not inclusive of the header. Returns -1 on error. * Fails if msg is too long. */ int minimsg_send(miniport_t local_unbound_port, miniport_t local_bound_port, minimsg_t msg, int len) { struct mini_header hdr; network_address_t dst_addr; if (len > MINIMSG_MAX_MSG_SIZE) { return -1; } if (local_unbound_port == NULL || local_unbound_port->p_type != UNBOUND_PORT || local_unbound_port->p_num >= BOUND_PORT_START || miniport_array[local_unbound_port->p_num] != local_unbound_port) { return -1; } if (local_bound_port == NULL || local_bound_port->p_type != BOUND_PORT || local_bound_port->p_num < BOUND_PORT_START || miniport_array[local_bound_port->p_num] != local_bound_port) { return -1; } network_address_copy(local_bound_port->u.bound.dest_addr, dst_addr); hdr.protocol = PROTOCOL_MINIDATAGRAM; pack_address(hdr.source_address, my_addr); pack_unsigned_short(hdr.source_port, local_unbound_port->p_num); pack_address(hdr.destination_address, local_bound_port->u.bound.dest_addr); pack_unsigned_short(hdr.destination_port, local_bound_port->u.bound.dest_num); if (network_send_pkt(dst_addr, sizeof(hdr), (char*)&hdr, len, msg)) { return -1; } return len; }
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 }
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; }