// This is a thread started by srt_client_init(). It handles all the incoming // segments from the server. 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) { printf("seghandler receive\n"); seg_t msg ; bzero(&msg,sizeof(msg)); client_tcb_t *client ; while(1){ if(snp_recvseg(mainTcpSockId,&msg) < 0){ printf("client recvseg return negative hence exiting\n"); printf("exiting thread and closing main tcp connection\n"); fflush(stdout); pthread_exit(NULL); } printf("seghandler message received \n"); client = get_client_from_port(msg.header.dest_port); if(client){ switch(msg.header.type){ case SYNACK :{ printf("SYNACK RECIEVED client port = %d and server port = %d\n", client->svr_portNum, msg.header.src_port); handle_syn_ack(client); } break; case FINACK :{ printf("FINACK RECIEVED client port = %d and server port = %d \n", client->svr_portNum, msg.header.src_port); handle_fin_ack(client); } break; case DATAACK: { printf("DATAACK RECIEVED client port = %d and server port = %d \n", client->svr_portNum, msg.header.src_port); handle_data_ack(client,&msg); } break; } }else{ printf("client TCB not found for %d \n",msg.header.src_port); } } fflush(stdout); return 0; }
// 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 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; }
// 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); }
void *seghandler(void* arg) { seg_t seg_recv; while (1 == snp_recvseg(connection, &seg_recv)) { int i; unsigned short int client_portNum = seg_recv.header.dest_port; unsigned short int type = seg_recv.header.type; client_tcb_t *tcb = NULL; for (i = 0; i < MAX_TRANSPORT_CONNECTIONS; i++) { pthread_mutex_lock(lock[i]); if (NULL != tcb_table[i] && client_portNum == tcb_table[i]->client_portNum) { tcb = tcb_table[i]; break; } pthread_mutex_unlock(lock[i]); } if (NULL == tcb) { printf("%s There is no TCB matching port number %d.\n", output, client_portNum); } else { switch (tcb->state) { case CLOSED: break; case SYNSENT: if (SYNACK == type) { printf("%s TCB[%d] Received SYNACK!\n", output, i); printf("%s TCB[%d] State (SYNSENT) ==> (CONNECTED)\n", output, i); tcb->state = CONNECTED; } break; case CONNECTED: if (DATAACK == type) { printf("%s TCB[%d] Received DATAACK! Server Expect %d.\n", output, i, seg_recv.header.ack_num); pthread_mutex_lock(tcb->bufMutex); while (NULL != tcb->sendBufHead && tcb->sendBufHead->seg.header.seq_num < seg_recv.header.ack_num) { printf("%s TCB[%d] Free %d.\n", output, i, tcb->sendBufHead->seg.header.seq_num); segBuf_t *temp = tcb->sendBufHead; tcb->sendBufHead = tcb->sendBufHead->next; free(temp); tcb->unAck_segNum--; } if (NULL != tcb->sendBufHead) { sendN(i); } pthread_mutex_unlock(tcb->bufMutex); } break; case FINWAIT: if (FINACK == type) { printf("%s TCB[%d] Received FINACK!\n", output, i); printf("%s TCB[%d] State (FINWAIT) ==> (CLOSED)\n", output, i); tcb->state = CLOSED; } break; default: break; } pthread_mutex_unlock(lock[i]); } } return NULL; }