int srt_client_disconnect(int sockfd) { seg_t s; memset(&s, 0, sizeof(seg_t)); s.header.src_port = tcb_table[sockfd]->client_portNum; s.header.dest_port = tcb_table[sockfd]->svr_portNum; s.header.length = 0; s.header.type = FIN; if (-1 == snp_sendseg(connection, &s)) { printf("%s TCB[%d] First Try: Sending FIN Failure!\n", output, sockfd); } else { printf("%s TCB[%d] First Try: Sending FIN Success!\n", output, sockfd); } printf("%s TCB[%d] State (CONNECTED) ==> (FINWAIT)\n", output, sockfd); tcb_table[sockfd]->state = FINWAIT; int retry = 0; int p = 0; do { struct timespec tm; tm.tv_sec = 0; tm.tv_nsec = FIN_TIMEOUT; nanosleep(&tm, NULL); if (CLOSED == tcb_table[sockfd]->state) { p = 1; } else if (++retry > FIN_MAX_RETRY) { printf("%s TCB[%d] Exceeded Retry Limit!\n", output, sockfd); tcb_table[sockfd]->state = CLOSED; p = -1; } else { if (-1 == snp_sendseg(connection, &s)) { printf("%s TCB[%d] Retry [%d]: Sending FIN Failure!\n", output, sockfd, retry); } else { printf("%s TCB[%d] Retry [%d]: Sending FIN Success!\n", output, sockfd, retry); } } } while (p == 0); //clear send buffer pthread_mutex_lock(tcb_table[sockfd]->bufMutex); segBuf_t *cur = tcb_table[sockfd]->sendBufHead; while (NULL != cur) { segBuf_t *temp = cur; cur = cur->next; free(temp); } pthread_mutex_unlock(tcb_table[sockfd]->bufMutex); return p; }
// This function is used to connect to the server. It takes the socket ID and the // server's port number as input parameters. The socket ID is used to find the TCB entry. // This function sets up the TCB's server port number and a SYN segment to send to // the server using snp_sendseg(). After the SYN segment is sent, a timer is started. // If no SYNACK is received after SYNSEG_TIMEOUT timeout, then the SYN is // retransmitted. If SYNACK is received, return 1. Otherwise, if the number of SYNs // sent > SYN_MAX_RETRY, transition to CLOSED state and return -1. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // int srt_client_connect(int sockfd, unsigned int server_port) { printf("srt_client_connect\n"); if(sockfd < 0 || sockfd > MAX_TRANSPORT_CONNECTIONS || clients[sockfd] == NULL) { printf("Error in srt_client_connect sockfd = %d max clients supported = %d\n", sockfd, MAX_TRANSPORT_CONNECTIONS); return -1; } client_tcb_t *client = clients[sockfd]; seg_t segment; bzero(&segment,sizeof(segment)); segment.header.src_port = client->client_portNum; segment.header.dest_port = client->svr_portNum = server_port; segment.header.type = SYN; segment.header.seq_num = 0; segment.header.length = 0; int trialNum = 0 ; // first trial if(snp_sendseg(mainTcpSockId,&segment) < 0){ // error check for sendseg when there is TCP socket error printf("Error in sending message in TCP layer = %d \n", mainTcpSockId); return -1; } long start_time = current_time_millis(); // timer started trialNum++; // increment trial num client->state = SYNSENT ; while(client->state == SYNSENT){ wait_for_some_time(LOOP_WAITING_TIME); long now = current_time_millis(); long diff = now - start_time ; if((diff ) > SYN_TIMEOUT_MS){ printf("TIMEOUT in connect %d for trial num = %d \n", sockfd, trialNum); if(trialNum < SYN_MAX_RETRY){ printf("resending segment \n"); if(snp_sendseg(mainTcpSockId,&segment) < 0){ // error check for sendseg when there is TCP socket error printf("ERROR in sending message sockfd = %d \n", sockfd); return -1; } start_time = (long)time(NULL); // reset timer trialNum++; }else{ printf("MAX TRIAL reached in connect segment of sock fd %d\n" ,sockfd); client->state = CLOSED; return -1; } } } printf("srt_client_connect ends \n"); fflush(stdout); return 1; // returning success it can be rechecked with state = CONNECTED }
void send_unsent_segments(client_tcb_t *client){ pthread_mutex_lock(client->bufMutex); printf("send_unsent_segments starts \n"); while(client->sendBufunSent!=NULL && client->unAck_segNum < GBN_WINDOW){ // 1. send the segment // 2. check if it was succesfull // 3. update the sent time // 4. start the timeout thread if required which means client->unAck_segNum should be zero // 5. switch to next segment if(snp_sendseg(mainTcpSockId,(seg_t*)client->sendBufunSent)){ printf("DATA PACKET SENT sequence number %d sent to server \n",client->sendBufunSent->seg.header.seq_num); client->sendBufunSent->sentTime = current_time_millis(); client->sendBufunSent = client->sendBufunSent->next; if(client->unAck_segNum == 0) { // check printf("TIMEOUT thread create called\n"); pthread_t timeout_thread; pthread_create(&timeout_thread,NULL,sendBuf_timer, (void*)client); } client->unAck_segNum++; printf("UNACKED count = %d \n", client->unAck_segNum); }else{ printf("ERROR (send_unsent_segments) in snp_sendseg exiting TCP error \n"); exit(-1); } } pthread_mutex_unlock(client->bufMutex); printf("send_unsent_segments ends \n"); fflush(stdout); }
// This thread continuously polls send buffer to trigger timeout events // It should always be running when the send buffer is not empty // If the current time - first sent-but-unAcked segment's sent time > DATA_TIMEOUT, a timeout event occurs // When timeout, resend all sent-but-unAcked segments // When the send buffer is empty, this thread terminates //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void* sendBuf_timer(void* arg) { int i = *(int *) arg; while (1) { struct timespec tm; tm.tv_sec = 0; tm.tv_nsec = SENDBUF_POLLING_INTERVAL; nanosleep(&tm, NULL); pthread_mutex_lock(tcb_table[i]->bufMutex); if (NULL == tcb_table[i]->sendBufHead) { pthread_mutex_unlock(tcb_table[i]->bufMutex); printf("%s TCB[%d] sendBuf_timer thread killed...\n", output, i); return NULL; } if (clock() - tcb_table[i]->sendBufHead->sentTime > DATA_TIMEOUT) { segBuf_t *cur = tcb_table[i]->sendBufHead; int T = tcb_table[i]->unAck_segNum; printf("%s TCB[%d] Resend Buffer %d...\n", output, i, cur->seg.header.seq_num); while (T-- > 0) { snp_sendseg(connection, &(cur->seg)); cur->sentTime = clock(); cur = cur->next; } } pthread_mutex_unlock(tcb_table[i]->bufMutex); } return NULL; }
//sendN send from first unsent to GBN_WINDOW or TAIL void sendN(int i) { while (NULL != tcb_table[i]->sendBufunSent && tcb_table[i]->unAck_segNum < GBN_WINDOW) { snp_sendseg(connection, &(tcb_table[i]->sendBufunSent->seg)); printf("%s TCB[%d] Send Buffer %d!\n", output, i, tcb_table[i]->sendBufunSent->seg.header.seq_num); tcb_table[i]->sendBufunSent->sentTime = clock(); tcb_table[i]->sendBufunSent = tcb_table[i]->sendBufunSent->next; tcb_table[i]->unAck_segNum++; } }
int srt_client_connect(int sockfd, unsigned int server_port) { tcb_table[sockfd]->svr_portNum = server_port; seg_t s; memset(&s, 0, sizeof(seg_t)); s.header.src_port = tcb_table[sockfd]->client_portNum; s.header.dest_port = tcb_table[sockfd]->svr_portNum; s.header.length = 0; s.header.type = SYN; if (-1 == snp_sendseg(connection, &s)) { printf("%s TCB[%d] First Try: Sending SYN Failure!\n", output, sockfd); } else { printf("%s TCB[%d] First Try: Sending SYN Success!\n", output, sockfd); } printf("%s TCB[%d] State (CLOSED) ==> (SYNSENT)\n", output, sockfd); tcb_table[sockfd]->state = SYNSENT; int retry = 0; int p = 0; do { struct timespec tm; tm.tv_sec = 0; tm.tv_nsec = SYN_TIMEOUT; nanosleep(&tm, NULL); if (CONNECTED == tcb_table[sockfd]->state) { p = 1; } else if (++retry > SYN_MAX_RETRY) { printf("%s TCB[%d] Exceeded Retry Limit!\n", output, sockfd); tcb_table[sockfd]->state = CLOSED; p = -1; } else { if (-1 == snp_sendseg(connection, &s)) { printf("%s TCB[%d] Retry [%d]: Sending SYN Failure!\n", output, sockfd, retry); } else { printf("%s TCB[%d] Retry [%d]: Sending SYN Success!\n", output, sockfd, retry); } } } while (p == 0); return p; }
void handle_timeout_resend(client_tcb_t *client){ printf("handle_timeout_resend starts\n"); int unack_count = 0 ; segBuf_t *head = client->sendBufHead; pthread_mutex_lock(client->bufMutex); while(head && unack_count < client->unAck_segNum){ if(snp_sendseg(mainTcpSockId,(seg_t*)head)){ printf("DATA PACKET RESENT sequence number %d sent to server total UNACKED = %d \n",head->seg.header.seq_num, client->unAck_segNum ); head->sentTime = current_time_millis(); head = head->next; unack_count++; }else{ printf("ERROR (handle_timeout_resend) in snp_sendseg exiting TCP error \n"); exit(-1); } } pthread_mutex_unlock(client->bufMutex); printf("handle_timeout_resend ends\n"); }
// This is a thread started by srt_server_init(). It handles all the incoming // segments from the client. The design of seghanlder is an infinite loop that calls snp_recvseg(). If // snp_recvseg() fails then the overlay connection is closed and the thread is terminated. Depending // on the state of the connection when a segment is received (based on the incoming segment) various // actions are taken. See the client FSM for more details. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // void* seghandler(void* arg) { seg_t* seg = (seg_t*) malloc(sizeof(seg_t)); seg_t* ack = (seg_t*) malloc(sizeof(seg_t)); // memset(&seg, 0, sizeof(seg)); svr_tcb_t* tp = (svr_tcb_t*) malloc(sizeof(svr_tcb_t)); while (1) { // Find the right server tp = NULL; if (snp_recvseg(tcp_socknum,seg) != 1) { printf("Can't receive data in server, ready to close\n"); close(tcp_socknum); pthread_exit(NULL); } // Get socketfd by port int sockfd = -1; for (int i = 0; i < MAX_TRANSPORT_CONNECTIONS; ++i) { if (svr_tcb_table[i] != NULL && svr_tcb_table[i] -> svr_portNum == seg->header.dest_port) { // Get the right tcb based on dest port sockfd = i; /*get socket number in srt for client port*/ // tp -> client_port = seg.header.src_port; tp = svr_tcb_table[i]; } } printf("Server sockfd =%d,Received seg header type =%d\n",sockfd,seg->header.type); if (!tp){ printf("Server: Can't get server_tcp for the seg\n"); continue; } printf("seghandler sockfd=%d , state=%d \n", sockfd, tp->state); switch(tp->state) { case CLOSED: printf("Server: sockfd=%d received seg in CLOSED\n", sockfd); break; case LISTENING: { if(seg->header.type == SYN) { pthread_mutex_lock(tp -> bufMutex); tp->client_portNum = seg->header.src_port; tp->state=CONNECTED; printf("Server:sockfd = %d Got SYN from client\n", sockfd); // Set tcb expect_seqNum tp -> expect_seqNum = seg->header.seq_num; pthread_mutex_unlock(tp -> bufMutex); // memset(&ack,0, sizeof(ack)); // Received SYN and send SYNACK back ack->header.type = SYNACK; ack->header.src_port = tp -> svr_portNum; ack->header.dest_port = tp -> client_portNum; ack->header.length = 0; snp_sendseg(tcp_socknum, ack); printf("Server:sockfd = %d Sent SYNACK to client\n", sockfd); } else printf("Server: Listening received SYN\n"); break; } case CONNECTED: { switch (seg->header.type) { printf("Server: tp %d: receive %d\n", sockfd, seg->header.type); case SYN: { // Received SYN and send SYNACK back // seg_t ack; // memset(&ack,0, sizeof(ack)); pthread_mutex_lock(tp -> bufMutex); tp -> expect_seqNum = seg->header.seq_num; pthread_mutex_unlock(tp -> bufMutex); ack->header.type = SYNACK; ack->header.src_port = tp -> svr_portNum; ack->header.dest_port = tp -> client_portNum; ack->header.length = 0; snp_sendseg(tcp_socknum, ack); break; } case DATA: { // tp -> expect_seqNum will be updated if right; Otherwise, same old expect_seqNum if (seg -> header.seq_num == tp -> expect_seqNum){ // Update tp -> expect_seqNum and store data in tp -> recvBuf restore_data(tp, seg); } // Send ack back anayway ack->header.type = DATAACK; ack->header.src_port = tp -> svr_portNum; ack->header.dest_port = tp -> client_portNum; ack->header.length = 0; ack->header.ack_num = tp -> expect_seqNum; // Send the new expect_seqNum(added by data length) if the expect_seqNum is right snp_sendseg(tcp_socknum, ack); break; } case FIN: { time_t timer = time(NULL); printf("Server: tp %d: receive FIN %s", sockfd, ctime(&timer)); // send FINACK // seg_t ack; // memset(&ack,0, sizeof(ack)); ack->header.type = FINACK; ack->header.src_port = tp -> svr_portNum; ack->header.dest_port = tp -> client_portNum; ack->header.length = 0; snp_sendseg(tcp_socknum, ack); tp->state = CLOSEWAIT; // start a thread for CLOSE_WAIT_TIMEOUT; If time expires, Set tp state as CLOSED pthread_t closetimer; pthread_create(&closetimer,NULL,closewait, (void*)tp); break; } default: break; } break; } case CLOSEWAIT: // receive FIN if (seg->header.type == FIN) { // send FINACK // seg_t ack; // memset(&ack,0, sizeof(ack)); ack->header.type = FINACK; ack->header.src_port = tp -> svr_portNum; ack->header.dest_port = tp -> client_portNum; ack->header.length = 0; snp_sendseg(tcp_socknum, ack); printf("Server: sent FINACK in closewait\n"); } else { printf("Server: Received not fin in CLOSEWAIT\n"); } break; default: printf("Server: sockfd= %d: wrong state\n", sockfd); break; } } }
// This is a thread started by srt_server_init(). It handles all the incoming // segments from the client. The design of seghanlder is an infinite loop that calls snp_recvseg(). If // snp_recvseg() fails then the overlay connection is closed and the thread is terminated. Depending // on the state of the connection when a segment is received (based on the incoming segment) various // actions are taken. See the client FSM for more details. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // void* seghandler(void* arg) { seg_t *segPtr = malloc(sizeof(seg_t)); MALLOC_CHECK(segPtr); memset(segPtr, 0, sizeof(seg_t)); char *segTypeStrings[] = {"SYN", "SYNACK", "FIN", "FINACK", "DATA", "DATAACK"}; char *states[] = {"Unknown", "CLOSED", "LISTENING", "CONNECTED", "CLOSEWAIT"}; int src_nodeID; while (snp_recvseg(overlay_conn_fd, &src_nodeID, segPtr) > 0) { if(!segPtr) break; //get the right server_tcb_t index unsigned int destPort = segPtr->header.dest_port; int idx = 0; while (idx < MAX_TRANSPORT_CONNECTIONS) { if (server_TCB_Table[idx] != NULL) { if (server_TCB_Table[idx]->svr_portNum == destPort){ break; } } idx++; } if (idx < MAX_TRANSPORT_CONNECTIONS){ svr_tcb_t *currentTCB = server_TCB_Table[idx]; printf("\nReceived %s in state %s. client: %u, server: %u.\n", segTypeStrings[segPtr->header.type], states[currentTCB->state], segPtr->header.src_port, segPtr->header.dest_port); switch(currentTCB->state) { case CLOSED: //printf("State is CLOSED.\n"); printf("Doing nothing.\n"); break; case LISTENING: //printf("State is LISTENING.\n"); if (segPtr->header.type == SYN){ printf("Changing state to CONNECTED. client_portNum: %u, expect_seqNum: %u. Sending SYNACK.\n", segPtr->header.src_port, segPtr->header.seq_num); currentTCB->state = CONNECTED; currentTCB->client_portNum = segPtr->header.src_port; currentTCB->expect_seqNum = segPtr->header.seq_num; currentTCB->client_nodeID = src_nodeID; //new //create SYNACK seg_t seg_t* synSegPtr = malloc(sizeof(seg_t)); MALLOC_CHECK(synSegPtr); memset(synSegPtr, 0, sizeof(seg_t)); synSegPtr->header.src_port = currentTCB->svr_portNum; synSegPtr->header.dest_port = currentTCB->client_portNum; synSegPtr->header.type = SYNACK; //send SYNACK seg_t if (snp_sendseg(overlay_conn_fd, currentTCB->client_nodeID, synSegPtr) < 0) { printf("Error sending SYNACK seg_t.\n"); } free(synSegPtr); } else { printf("Doing nothing.\n"); } break; case CONNECTED: //printf("State is CONNECTED.\n"); if (segPtr->header.type == SYN && currentTCB->client_portNum == segPtr->header.src_port && currentTCB->client_nodeID == src_nodeID){ printf("Sending SYNACK.\n"); //create SYNACK seg_t seg_t* synSegPtr = malloc(sizeof(seg_t)); MALLOC_CHECK(synSegPtr); memset(synSegPtr, 0, sizeof(seg_t)); synSegPtr->header.src_port = currentTCB->svr_portNum; synSegPtr->header.dest_port = currentTCB->client_portNum; synSegPtr->header.type = SYNACK; //send SYNACK seg_t if (snp_sendseg(overlay_conn_fd, currentTCB->client_nodeID, synSegPtr) < 0) { printf("Error sending SYNACK seg_t.\n"); } free(synSegPtr); } else if (segPtr->header.type == FIN && currentTCB->client_portNum == segPtr->header.src_port && currentTCB->client_nodeID == src_nodeID) { printf("Changing state to CLOSEWAIT and sending FINACK.\n"); currentTCB->state = CLOSEWAIT; pthread_t closeWaitThread; if (pthread_create(&closeWaitThread, NULL, closeWaitTimer, currentTCB)){ printf("Error creating closeWaitTimer thread.\n"); } //create FINACK seg_t seg_t *finSegPtr = malloc(sizeof(seg_t)); MALLOC_CHECK(finSegPtr); memset(finSegPtr, 0, sizeof(seg_t)); finSegPtr->header.src_port = currentTCB->svr_portNum; finSegPtr->header.dest_port = currentTCB->client_portNum; finSegPtr->header.type = FINACK; //send FINACK seg_t if (snp_sendseg(overlay_conn_fd, currentTCB->client_nodeID, finSegPtr) < 0) { printf("Error sending FINACK seg_t.\n"); } free(finSegPtr); } else if (segPtr->header.type == DATA && currentTCB->client_portNum == segPtr->header.src_port && currentTCB->client_nodeID == src_nodeID) { //create DATAACK seg_t seg_t *dataSegPtr = malloc(sizeof(seg_t)); MALLOC_CHECK(dataSegPtr); memset(dataSegPtr, 0, sizeof(seg_t)); dataSegPtr->header.src_port = currentTCB->svr_portNum; dataSegPtr->header.dest_port = currentTCB->client_portNum; dataSegPtr->header.type = DATAACK; //if the seq_nums match, add to buffer and increment relevant variables pthread_mutex_lock(currentTCB->bufMutex); if (segPtr->header.seq_num == currentTCB->expect_seqNum) { //put received data in recv buffer if it can fit if (segPtr->header.length + currentTCB->usedBufLen < RECEIVE_BUF_SIZE) { printf("Seq_nums match (%u)! Adding to buffer.\n", segPtr->header.seq_num); memcpy(currentTCB->recvBuf, segPtr->data, segPtr->header.length); currentTCB->recvBuf += segPtr->header.length; currentTCB->usedBufLen += segPtr->header.length; currentTCB->expect_seqNum += segPtr->header.length; } else { printf("Seq_nums match but recv Buf is too full. Dropping data and sending DATAACK.\n"); } } else { printf("Out of order packet (%u).\n", segPtr->header.seq_num); } dataSegPtr->header.seq_num = currentTCB->expect_seqNum; pthread_mutex_unlock(currentTCB->bufMutex); //send DATAACK seg_t printf("Sending DATAACK with expect_seqNum %u.\n", dataSegPtr->header.seq_num); if (snp_sendseg(overlay_conn_fd, currentTCB->client_nodeID, dataSegPtr) < 0) { printf("Error sending DATAACK seg_t.\n"); } free(dataSegPtr); } else { printf("Doing nothing.\n"); } break; case CLOSEWAIT: //printf("State is CLOSEWAIT.\n"); if (segPtr->header.type == FIN && currentTCB->client_portNum == segPtr->header.src_port && currentTCB->client_nodeID == src_nodeID){ printf("Sending FINACK.\n"); //create FINACK seg_t seg_t* synSegPtr = malloc(sizeof(seg_t)); MALLOC_CHECK(synSegPtr); memset(synSegPtr, 0, sizeof(seg_t)); synSegPtr->header.src_port = currentTCB->svr_portNum; synSegPtr->header.dest_port = currentTCB->client_portNum; synSegPtr->header.type = FINACK; //send FINACK seg_t if (snp_sendseg(overlay_conn_fd, currentTCB->client_nodeID, synSegPtr) < 0) { printf("Error sending FINACK seg_t.\n"); } free(synSegPtr); } else { printf("Doing nothing.\n"); } break; default: printf("Unknown state.\n"); break; } } else { printf("Couldn't find the server_tcb the client was trying to reach.\n"); } memset(segPtr, 0, sizeof(seg_t)); } printf("seghandler is closing the overlay connection.\n"); close(overlay_conn_fd); free(segPtr); pthread_exit(NULL); }
// This is a thread started by srt_server_init(). It handles all the incoming // segments from the client. The design of seghandler is an infinite loop that calls snp_recvseg(). If // snp_recvseg() fails then the overlay connection is closed and the thread is terminated. Depending // on the state of the connection when a segment is received (based on the incoming segment) various // actions are taken. See the client FSM for more details. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // void* seghandler(void* arg) { /* seg_t struct to receive messages from client */ seg_t* segPtr = calloc (1, sizeof(seg_t)); if (NULL == segPtr) { free(segPtr); fprintf(stderr, "Failed to allocate memory for segment\n"); exit(1); } /* Infinite loop that receives segments */ int src_nodeID; while (1) { /* For timing from CLOSEWAIT to CLOSED for server-client connection, loop through all connections */ /* If Timer has already been started, then check for timeout */ // int j; // for (j = 0; j < MAX_TRANSPORT_CONNECTIONS; j++) { // svr_tcb_t* sTp = svrConnList[j]; // if ((NULL != sTp) && (sTp->timeSetBool) && (CLOSED != sTp->state)) { /* Don't want to track time if client connection already closed */ // gettimeofday(&(sTp->t2), NULL); // keep checking the time // /* compute the elapsed time in milliseconds */ // sTp->elapsedTime = (sTp->t2.tv_sec - sTp->t1.tv_sec) * 1000.0; // sec to ms // sTp->elapsedTime += (sTp->t2.tv_usec - sTp->t1.tv_usec) / 1000.0; // us to ms // //fprintf(stdout, "\nElapsed time: %lf\n", sTp->elapsedTime); // /* CLOSE after CLOSEWAIT period */ // if (sTp->elapsedTime > (CLOSEWAIT_TIMEOUT * 1000.0)) { // fprintf(stdout, "\nNow closing server port %d after CLOSEWAIT_TIME: %f MS\n", sTp->svr_portNum, sTp->elapsedTime); // /* set state of that server port to CLOSED */ // sTp->state = CLOSED; // } // } // } if (0 > snp_recvseg(svrSockGlobal, &src_nodeID, segPtr)) { /* Receive failed */ ; } /* Packet received */ else { /* check the packet for bit errors */ if (0 < checkchecksum(segPtr)) { // If the packet is valid /* Determine the serverPort it's meant for */ int svrPort = segPtr->header.dest_port; int clientPort = segPtr->header.src_port; /* Determine what entry in the TCB table that serverPort corresponds to */ int i; svr_tcb_t *tp; for (i = 0; i < MAX_TRANSPORT_CONNECTIONS; i++) { if ((NULL != svrConnList[i]) && (svrPort == svrConnList[i]->svr_portNum)) { tp = svrConnList[i]; tp->client_portNum = clientPort; break; } } if (NULL == tp) { fprintf(stderr, "Bad packet, found no matching port number on server side\n"); exit(1); } /* Switch on the type of packet */ switch(segPtr->header.type) { case SYN: /* Update server state and send a SYNACK */ fprintf(stdout, "Server at server port: %d received SYN from client NodeID: %d at port: %d\n", svrPort, src_nodeID, clientPort); if ((LISTENING == tp->state) || (CONNECTED == tp->state)) { tp->state = CONNECTED; tp->client_nodeID = src_nodeID; /* Set tp->expect_seqNum using the sequence number in the received SYN segment */ tp->expect_seqNum = segPtr->header.seq_num; /* Setup a SYNACK segment and send the segment to the server */ seg_t* segSYNACK = calloc (1, sizeof(seg_t)); if (NULL == segSYNACK) { free(segSYNACK); fprintf(stderr, "Failed to allocate memory for SYNACK segment\n"); exit(1); } segSYNACK->header.type = SYNACK; segSYNACK->header.src_port = svrPort; segSYNACK->header.dest_port = clientPort; /* Generate a checksum and add to PacketHeader */ unsigned short int crcSumSYNACK = checksum(segSYNACK); segSYNACK->header.checksum = crcSumSYNACK; if (0 > snp_sendseg(svrSockGlobal, tp->client_nodeID, segSYNACK)) { fprintf(stderr, "Overlay send failed\n"); exit(1); } free(segSYNACK); } break; case FIN: /* Stay at CLOSEWAIT and keep sending FINACKs */ /* If currently CONNECTED or in CLOSEWAIT, stay/transition to CLOSEWAIT, and send FINACK */ fprintf(stdout, "\nServer at server port: %d received FIN from client NodeID: %d at port: %d\n", svrPort, src_nodeID, clientPort); if ((CONNECTED == tp->state) || (CLOSEWAIT == tp->state)) { /* If originally CONNECTED, then start timer for this server-client port connection */ if (CONNECTED == tp->state) { /* gettimeofday(&(tp->t1), NULL); tp->timeSetBool = 1; // indicate that timer has been started*/ pthread_t segMain; int segRC = pthread_create(&segMain, NULL, serverTimer, tp); /* Params: fourth param is arg to function */ if (segRC) { fprintf(stderr, "pthread_create failed for server, rc=%d\n", segRC); exit(segRC); } else { fprintf(stdout, "Starting timer for CLOSE_WAIT for server port: %d\n", svrPort); } } tp->state = CLOSEWAIT; /* Setup a FINACK segment and send the segment to the server */ seg_t* segFINACK = calloc (1, sizeof(seg_t)); if (NULL == segFINACK) { free(segFINACK); fprintf(stderr, "Failed to allocate memory for FINACK segment\n"); exit(1); } segFINACK->header.type = FINACK; segFINACK->header.src_port = svrPort; segFINACK->header.dest_port = clientPort; /* Generate a checksum and add to PacketHeader */ unsigned short int crcSumFINACK = checksum(segFINACK); segFINACK->header.checksum = crcSumFINACK; if (0 > snp_sendseg(svrSockGlobal, tp->client_nodeID, segFINACK)) { fprintf(stderr, "Overlay send failed\n"); exit(1); } free(segFINACK); } break; case DATA: fprintf(stdout, "Server at server port: %d received DATA from client NodeID: %d at port: %d\n", svrPort, src_nodeID, clientPort); if (CONNECTED == tp->state) { /* If the sequence number of the segment matches server tcb's expected sequence number */ if (tp->expect_seqNum == segPtr->header.seq_num) { pthread_mutex_lock(tp->bufMutex); /* If receive buffer can still accommodate for received DATA segment */ if ((tp->usedBufLen + segPtr->header.length) < RECEIVE_BUF_SIZE) { /* Store the received data into the receive buffer */ char * receiveBuffer = tp->recvBuf; unsigned int usedBufferLen = tp->usedBufLen; memcpy(receiveBuffer + usedBufferLen, segPtr->data, segPtr->header.length); /* Increment usedBufLen and expect_seqNum by data size of received DATA segment */ tp->expect_seqNum += segPtr->header.length; tp->usedBufLen += segPtr->header.length; } else { /* Simply discard received DATA segment */ fprintf(stdout, "Receive buffer storage exceeded!!!\n"); } pthread_mutex_unlock(tp->bufMutex); } /* Send DATAACK back to client w/ updated expect_seqNum or old expect_seqNum */ seg_t* segDATAACK = calloc (1, sizeof(seg_t)); if (NULL == segDATAACK) { free(segDATAACK); fprintf(stderr, "Failed to allocate memory for DATAACK segment\n"); exit(1); } segDATAACK->header.type = DATAACK; segDATAACK->header.src_port = svrPort; segDATAACK->header.dest_port = clientPort; segDATAACK->header.ack_num = tp->expect_seqNum; /* Generate a checksum and add to Packet Header */ unsigned short int crcSumDATAACK = checksum(segDATAACK); segDATAACK->header.checksum = crcSumDATAACK; if (0 > snp_sendseg(svrSockGlobal, tp->client_nodeID, segDATAACK)) { fprintf(stderr, "Overlay send failed\n"); exit(1); } free(segDATAACK); } else { fprintf(stdout, "BAD RECEIVING STATE, NOT CONNECTED\n"); } break; } free(segPtr); /* Allocate memory for new segPtr to receive a segment from a client */ segPtr = calloc (1, sizeof(seg_t)); if (NULL == segPtr) { free(segPtr); fprintf(stderr, "Failed to allocate memory for segment\n"); exit(1); } } else { /* Packet contains a bit error, so free it and drop the packet */ fprintf(stdout, "Packet bit corruption detected!\n"); free (segPtr); segPtr = calloc (1, sizeof(seg_t)); if (NULL == segPtr) { free(segPtr); fprintf(stderr, "Failed to allocate memory for segment\n"); exit(1); } } } } return 0; }