/* Listen for a connection from somebody else. When communication link is * created return a minisocket_t through which the communication can be made * from now on. * * The argument "port" is the port number on the local machine to which the * client will connect. * * Return value: the minisocket_t created, otherwise NULL with the errorcode * stored in the "error" variable. */ minisocket_t minisocket_server_create(int port, minisocket_error *error) { minisocket_t new_sock; interrupt_level_t l; network_interrupt_arg_t * pkt; resend_arg* resend_alarm_arg; char tmp; //check valid portnum if (port < 0 || port >= CLIENT_START){ *error = SOCKET_INVALIDPARAMS; return NULL; } //check port in use semaphore_P(server_lock); //printf("calling server_create at port %d.\n", port); //printf("value at port %d is %li.\n", port, (long)sock_array[port]); if (sock_array[port] != NULL){ *error = SOCKET_PORTINUSE; return NULL; } new_sock = (minisocket_t)malloc(sizeof(struct minisocket)); if (!new_sock){ semaphore_V(server_lock); *error = SOCKET_OUTOFMEMORY; return NULL; } new_sock->pkt_ready_sem = semaphore_create(); if (!(new_sock->pkt_ready_sem)){ semaphore_V(server_lock); free(new_sock); *error = SOCKET_OUTOFMEMORY; return NULL; } new_sock->pkt_q = queue_new(); if (!(new_sock->pkt_q)){ semaphore_V(server_lock); semaphore_destroy(new_sock->pkt_ready_sem); free(new_sock); *error = SOCKET_OUTOFMEMORY; return NULL; } new_sock->sock_lock = semaphore_create(); if (!(new_sock->sock_lock)){ semaphore_V(server_lock); free(new_sock->pkt_ready_sem); queue_free(new_sock->pkt_q); free(new_sock); *error = SOCKET_OUTOFMEMORY; return NULL; } new_sock->ack_ready_sem = semaphore_create(); if (!(new_sock->ack_ready_sem)){ semaphore_V(server_lock); semaphore_destroy(new_sock->pkt_ready_sem); queue_free(new_sock->pkt_q); semaphore_destroy(new_sock->sock_lock); free(new_sock); *error = SOCKET_OUTOFMEMORY; return NULL; } semaphore_initialize(new_sock->pkt_ready_sem, 0); semaphore_initialize(new_sock->ack_ready_sem, 0); semaphore_initialize(new_sock->sock_lock, 1); new_sock->curr_state = LISTEN; new_sock->try_count = 0; new_sock->curr_ack = 0; new_sock->curr_seq = 1; new_sock->resend_alarm = NULL; // no alarm set new_sock->src_port = port; new_sock->dst_port = -1; // not paired with client network_address_blankify(new_sock->dst_addr); // not paired with client sock_array[port] = new_sock; semaphore_V(server_lock); resend_alarm_arg = (resend_arg*)calloc(1, sizeof(resend_arg)); while (1) { // wait for MSG_SYN semaphore_P(new_sock->ack_ready_sem); l = set_interrupt_level(DISABLED); switch (new_sock->curr_state) { case CONNECTING: minisocket_send_ctrl(MSG_SYNACK, new_sock, error); resend_alarm_arg->sock = new_sock; resend_alarm_arg->msg_type = MSG_SYNACK; resend_alarm_arg->data_len = 0; resend_alarm_arg->data = &tmp; //placeholder resend_alarm_arg->error = error; new_sock->resend_alarm = set_alarm(RESEND_TIME_UNIT, minisocket_resend, resend_alarm_arg, minithread_time()); new_sock->curr_state = MSG_WAIT; set_interrupt_level(l); break; case CONNECTED: // must have gotten a MSG_ACK //printf("in server_create, SUCCESS!\n"); new_sock->try_count = 0; deregister_alarm(new_sock->resend_alarm); new_sock->resend_alarm = NULL; *error = SOCKET_NOERROR; set_interrupt_level(l); //printf("exiting server_create\n"); free(resend_alarm_arg); return new_sock; break; case EXIT: default: *error = SOCKET_SENDERROR; // clean out the queue while (queue_dequeue(new_sock->pkt_q,(void**)&pkt) != -1){ free(pkt); } new_sock->curr_state = LISTEN; new_sock->curr_ack = 0; new_sock->curr_seq = 1; set_interrupt_level(l); break; } } free(resend_alarm_arg); return new_sock; }
/* * 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; }
/* * 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 minisocket; interrupt_level_t prev_level; int transmit_ret; int success = 0; if (error == NULL) { return NULL; } // Ensure the port is in the valid range if (port < TCP_MIN_SERVER || port > TCP_MAX_SERVER) { *error = SOCKET_INVALIDPARAMS; return NULL; } // We need to synchronize access to the server port range of the minisockets // pool, as we don't want another thread to try to create a socket on this port // concurrently semaphore_P(server_sem); // Ensure the port doesn't exist if (minisockets[port] != NULL) { *error = SOCKET_PORTINUSE; semaphore_V(server_sem); return NULL; } // Try to setup the socket struct minisocket = minisocket_setup_socket(port); if (minisocket == NULL) { *error = SOCKET_OUTOFMEMORY; semaphore_V(server_sem); return NULL; } // Set the port type minisocket->port_type = TCP_PORT_TYPE_SERVER; // Insert the minisocket into the array minisockets[port] = minisocket; // Ensure we don't have with the server semaphore, so other servers // can be made while we wait for a client semaphore_V(server_sem); // Continuously wait for a successful connection while (success == 0) { // Wait for a connection prev_level = set_interrupt_level(DISABLED); semaphore_P(minisocket->wait_for_ack_sem); set_interrupt_level(prev_level); // When we're awoken and have a client, set the status minisocket->status = TCP_PORT_CONNECTING; // And send the SYNACK sequence minisocket->ack_num++; // we're acknowledging the SYN, and also sending a packet that increments seq# transmit_ret = transmit_packet(minisocket, minisocket->dst_addr, minisocket->dst_port, 1, MSG_SYNACK, 0, NULL, error); if (transmit_ret == -1) { // This means we didn't get ACKs back, so this is a bad connection // Reset some port details and continue waiting minisocket->status = TCP_PORT_LISTENING; network_address_blankify(minisocket->dst_addr); minisocket->dst_port = 0; minisocket->ack_num--; minisocket->seq_num--; } else { // Established connection successfully minisocket->status = TCP_PORT_CONNECTED; success = 1; } } *error = SOCKET_NOERROR; return minisocket; }