ssize_t dg_send_recv(int fd, const void *outbuff, size_t outbytes, void *inbuff, size_t inbytes, const SA *destaddr, socklen_t destlen) { ssize_t n; struct iovec iovsend[2], iovrecv[2]; if (rttinit == 0) { rtt_init(&rttinfo); /* first time we're called */ rttinit = 1; rtt_d_flags = 1; } sendhdr.seq++; msgsend.msg_name = destaddr; msgsend.msg_namelen = destlen; msgsend.msg_iov = iovsend; msgsend.msg_iovlen = 2; iovsend[0].iov_base = &sendhdr; iovsend[0].iov_len = sizeof(struct hdr); iovsend[1].iov_base = outbuff; iovsend[1].iov_len = outbytes; msgrecv.msg_name = NULL; msgrecv.msg_namelen = 0; msgrecv.msg_iov = iovrecv; msgrecv.msg_iovlen = 2; iovrecv[0].iov_base = &recvhdr; iovrecv[0].iov_len = sizeof(struct hdr); iovrecv[1].iov_base = inbuff; iovrecv[1].iov_len = inbytes; Signal(SIGALRM, sig_alrm); rtt_newpack(&rttinfo); /* initialize for this packet */ sendagain: sendhdr.ts = rtt_ts(&rttinfo); Sendmsg(fd, &msgsend, 0); alarm(rtt_start(&rttinfo)); /* calc timeout value & start timer */ if (sigsetjmp(jmpbuf, 1) != 0) { if (rtt_timeout(&rttinfo) < 0) { err_msg("dg_send_recv: no response from server, giving up"); rtt_init = 0; /* reinit in case we're called again */ errno = ETIMEDOUT; return -1; } goto sendagain; } do { n = Recvmsg(fd, &msgrecv, 0); } while (n < sizeof(struct hdr) || recvhdr.seq != sendhdr.seq); alarm(0); /* stop SIGALRM timer. */ /* calculate & store new RTT estimator value. */ rtt_stop(&rttinfo, rtt_ts(&rttinfo) - recvhdr.ts); return (n - sizeof(struct hdr)); /* return size of received datagram. */ }
struct hdr cli_recv(int fd, void *inbuff, size_t inbytes) { ssize_t n; struct iovec iovrecv[2]; struct rtt_info rttinfo; msgrecv.msg_name = NULL; msgrecv.msg_namelen = 0; msgrecv.msg_iov = iovrecv; msgrecv.msg_iovlen = 2; iovrecv[0].iov_base = &recvhdr; iovrecv[0].iov_len = sizeof(struct hdr); iovrecv[1].iov_base = inbuff; iovrecv[1].iov_len = inbytes; rttinfo.rtt_rto = CLI_TIMEOUT; //8 sec time out if (rttinit == 0) { rtt_init(&rttinfo); /* first time we're called */ rttinit = 1; rtt_d_flag = 1; } Signal(SIGALRM, sig_alrm); rtt_newpack(&rttinfo); /* initialize for this packet */ alarm(rtt_start(&rttinfo)/1000); /* calc timeout value & start timer */ //#ifdef RTT_DEBUG rtt_debug(&rttinfo); //#endif if (sigsetjmp(jmpbuf, 1) != 0) { err_msg("cli_recv: no response from server, giving up"); rttinit = 0; /* reinit in case we're called again */ errno = ETIMEDOUT; err_sys("[ERROR]: Timeout"); return recvhdr; } n = Recvmsg(fd, &msgrecv, 0); if (n < sizeof(struct hdr)){ err_sys("[ERROR]: Received packet incomplete"); } printf("Length: %d\n", (int)n); //printf("BUFFER: %s\n", (char *)iovrecv[1].iov_base); printf("SEQ NUM: %u\n", recvhdr.seq); printf("IS FIN: %u\n", recvhdr.fin); alarm(0); /* stop SIGALRM timer */ return(recvhdr); /* return size of received datagram */ }
ssize_t dg_send_recv(int fd, const void *outbuff, size_t outbytes, void *inbuff, size_t inbytes, const SA *destaddr, socklen_t destlen) { ssize_t n; struct iovec iovsend[2], iovrecv[2]; if (rttinit == 0) { rtt_init(&rttinfo); /* first time we're called */ rttinit = 1; rtt_d_flag = 1; } sendhdr.seq++; msgsend.msg_name = destaddr; msgsend.msg_namelen = destlen; msgsend.msg_iov = iovsend; msgsend.msg_iovlen = 2; iovsend[0].iov_base = &sendhdr; iovsend[0].iov_len = sizeof(struct hdr); iovsend[1].iov_base = outbuff; iovsend[1].iov_len = outbytes; msgrecv.msg_name = NULL; msgrecv.msg_namelen = 0; msgrecv.msg_iov = iovrecv; msgrecv.msg_iovlen = 2; iovrecv[0].iov_base = &recvhdr; iovrecv[0].iov_len = sizeof(struct hdr); iovrecv[1].iov_base = inbuff; iovrecv[1].iov_len = inbytes; /* end dgsendrecv1 */ /* include dgsendrecv2 */ if (signal(SIGALRM, sig_alrm) == SIG_ERR) { perror("signal error"); exit(1); } rtt_newpack(&rttinfo); /* initialize for this packet */ sendagain: #ifdef RTT_DEBUG fprintf(stderr, "send %4d: ", sendhdr.seq); #endif sendhdr.ts = rtt_ts(&rttinfo); int nbytes = 0; /* must first figure out what return value should be */ int i; for (i = 0; i < msgsend.msg_iovlen; i++) nbytes += msgsend.msg_iov[i].iov_len; if (sendmsg(fd, &msgsend, 0) != nbytes) { perror("sendmsg error"); exit(1); } alarm(rtt_start(&rttinfo)); /* calc timeout value & start timer */ #ifdef RTT_DEBUG rtt_debug(&rttinfo); #endif if (sigsetjmp(jmpbuf, 1) != 0) { if (rtt_timeout(&rttinfo) < 0) { fprintf(stderr, "dg_send_recv: no response from server, giving up\n"); rttinit = 0; /* reinit in case we're called again */ errno = ETIMEDOUT; return(-1); } #ifdef RTT_DEBUG fprintf(stderr, "dg_send_recv: timeout, retransmitting\n"); #endif goto sendagain; } do { if ((n = recvmsg(fd, &msgrecv, 0)) < 0) { perror("recvmsg error"); exit(1); } #ifdef RTT_DEBUG fprintf(stderr, "recv %4d\n", recvhdr.seq); #endif } while (n < sizeof(struct hdr) || recvhdr.seq != sendhdr.seq); alarm(0); /* stop SIGALRM timer */ /* 4calculate & store new RTT estimator values */ rtt_stop(&rttinfo, rtt_ts(&rttinfo) - recvhdr.ts); return(n - sizeof(struct hdr)); /* return size of received datagram */ }
/* This routine does the first phase of the client-server Setup. * On successfule return, the out parameter sockfd will have the * connection socket fd. * */ int connection_setup(int *sockfd, ifi_t *ifi_array[], int num_ifi, circ_buffer_t *rcv_buf, client_config_t *config) { packet_t *send_pkt; int n, optval=1; char in_packet[PACKET_LEN],client_ip[IP_MAX]; struct sockaddr_in serv_addr, cliaddr, tempaddr; unsigned int ack_seq; unsigned short curr_win; bool is_error = FALSE; packet_info_t *rcv_pkt_info, *send_pkt_info = calloc(1, sizeof(packet_info_t)); *sockfd = Socket(AF_INET, SOCK_DGRAM, 0); if(server_on_same_subnet(config->server_ip,ifi_array, num_ifi, client_ip)) { printf("server on same subnet, SO_DONTROUTE set\n"); //printf("client ip set to: %s\n",client_ip); setsockopt(*sockfd,SOL_SOCKET, SO_DONTROUTE, &optval, sizeof(optval)); } //update cli_ip after if it's on the same host or n/w bzero(&cliaddr, sizeof(cliaddr)); cliaddr.sin_family = AF_INET; cliaddr.sin_port = 0; inet_pton(AF_INET,client_ip,&cliaddr.sin_addr); Bind(*sockfd, (SA*) &cliaddr, sizeof(cliaddr)); //cli addr and port using getsockname int cli_port; char cli_ip[IP_MAX]; socklen_t len = sizeof(tempaddr); bzero(&tempaddr, sizeof(tempaddr)); getsockname(*sockfd, (SA*) &tempaddr, &len); Inet_ntop(AF_INET, &tempaddr.sin_addr, cli_ip, IP_MAX); printf("[Info]client bound to ip:%s\n",cli_ip); cli_port = ntohs(tempaddr.sin_port); //connect bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(config->server_port); Inet_pton(AF_INET, config->server_ip, &serv_addr.sin_addr); Connect(*sockfd, (SA *)&serv_addr, sizeof(serv_addr)); assert(send_pkt_info); Signal(SIGALRM, sig_alarm); rtt_newpack(&rttinfo); /* initialize for this packet */ /* Prepare to send file name */ send_pkt_info->seq = 0; send_pkt_info->ack = 0; send_pkt_info->window_size = config->window_size; SET_FILE_FLAG(send_pkt_info); send_pkt_info->data = strdup(config->file_name); send_pkt_info->data_len = strlen(config->file_name) + 1; printf("[Info] Sending file name %s to server ..\n", send_pkt_info->data); sendagain: send_pkt_info->timestamp = rtt_ts(&rttinfo); send_pkt = build_packet(send_pkt_info); Write(*sockfd, (char *)send_pkt, send_pkt_info->data_len+HEADER_SIZE); /* set alarm for RTO seconds using setitimer */ set_alarm(rtt_start(&rttinfo)); if (sigsetjmp(jmpbuf, 1) != 0) { if (rtt_timeout(&rttinfo)) { printf("[Error] Timed out Sending File Name, giving Up\n"); free_pkt_info(send_pkt_info); free(send_pkt); errno = ETIMEDOUT; return -1; } printf("[Timeout] Retransmitting file name, next RTO:%d ms\n", rttinfo.rtt_rto); free(send_pkt); goto sendagain; } /* Now Attempt to read the Port message from the Server */ while (1) { if ((n = read(*sockfd, in_packet, PACKET_LEN)) < 0) { if (errno == EINTR) continue; else err_sys("[Error] Read Error while waiting for Port number"); } rcv_pkt_info = get_packet_info(in_packet, n); if (consume_random_packet(rcv_pkt_info, config->prob_loss, TRUE)) { free_pkt_info(rcv_pkt_info); continue; } if (IS_ACK(rcv_pkt_info) && (rcv_pkt_info->ack == (send_pkt_info->seq+1))) { break; } else { free_pkt_info(rcv_pkt_info); continue; } } set_alarm(0); /* Turn off the Alarm */ free_pkt_info(send_pkt_info); free(send_pkt); assert(rcv_pkt_info->data_len == sizeof(short)); /* Fetch the new port from the server message */ memcpy(&serv_addr.sin_port, rcv_pkt_info->data, sizeof(short)); printf("[Info] Received new Port number %hu from Server.\n", ntohs(serv_addr.sin_port)); /* Connect to the new port of the server child process */ if (connect(*sockfd, (SA *)&serv_addr, sizeof(serv_addr)) < 0) { printf("[Error] Connect failure to server child: [%s : %hu]\n", config->server_ip, ntohs(serv_addr.sin_port)); return -1; } printf("[Info] Connected to server's child process.\n"); /* Advance the Circular buffer's read/write pointers to rcv_pkt_info->seq+1. * Basically, we are simulating the producer/consumer behavior here, in that we * have written and read from the buffer. * Note: The server has to continue the file transfer starting from rcv_pkt_info->seq+1 * as we will not accept anything lower than this sequence for this session * This is similar to the SYN+ACK in TCP */ rcv_buf->next_read_seq = rcv_buf->next_contig_write_seq = rcv_pkt_info->seq+1; printf("rcv_buf->next_read_seq = rcv_buf->next_contig_write_seq = %u", rcv_pkt_info->seq+1); curr_win = window_size(rcv_buf); ack_seq = NEXT_ACK(rcv_buf); /* Exit if the file does not exist on the server after sending ACK. * In the event this ACK is lost, the server ichild timeout mechanism will kick in * and eventually it will timeout and give up */ if(is_error = IS_ERR(rcv_pkt_info)) { printf("[Info] Received Error message from server [Seq: %u] Responding with [Ack:%u] [Window Size:%hu]\n", rcv_pkt_info->seq, ack_seq, curr_win); } else { printf("[Info] Received Port message [Seq: %u] Responding with [Ack:%u] [Window Size:%hu]\n", rcv_pkt_info->seq, ack_seq, curr_win); } /* Simulate Loss On Tx */ if (!consume_random_packet(rcv_pkt_info, config->prob_loss, FALSE)) { send_ack(*sockfd, curr_win, rcv_pkt_info->seq, ack_seq, rcv_pkt_info->timestamp, config->prob_loss); } free_pkt_info(rcv_pkt_info); if(is_error) { printf("[Error] File %s does not exist, terminating..\n", config->file_name); errno = EBADF; return -1; } printf("[Info] Successful Connection Setup with [%s:%u], ready for file reception\n", config->server_ip, ntohs(serv_addr.sin_port)); return 0; }
void mydg_echo( int sockfd, SA *servaddr, socklen_t servlen, SA *cliaddr , socklen_t clilen, char *filename ) { int n, persist_timer_flag=0; char mesg[MAXLINE]; socklen_t len, slen, slen1; int connfd; struct sockaddr_in ss, ss1; char IPServer[20], IPClient[20]; FILE *ifp; ssize_t bytes; char sendline[MAXLINE], recvline[MAXLINE + 1]; const int on=1; int onlength; onlength = sizeof( on ); printf( "\n******************* CHILD SERVER INITIATED *********************\n" ); //printf( "Creating Datagram...\n" ); if( ( connfd = socket( AF_INET, SOCK_DGRAM, 0 ) ) == NULL ) { printf( "socket error\n" ); exit(1); } getsockopt( sockfd, SOL_SOCKET, SO_DONTROUTE, &on, &onlength ) ; setsockopt( connfd, SOL_SOCKET, SO_DONTROUTE, &on, sizeof( on ) ); printf("Setting connection socket to SO_DONTROUTE..\n", on ); /* Bind to IPServer and EPHEMERAL PORT and return EPHEMERAL PORT */ bind( connfd, (SA *) servaddr, sizeof( struct sockaddr_in ) ); slen = sizeof( ss ); if( getsockname( connfd, (SA *)&ss, &slen ) < 0 ) { printf( "sockname error\n" ); exit(1); } printf("BOUND SOCKET ADDRESSES : %s\n", inet_ntop( AF_INET, &(ss.sin_addr), IPServer, MAXLINE )); printf( "SERVER PORT: %d\n", ntohl(ss.sin_port) ); /* Connect to IPClient */ if( connect( connfd, cliaddr, clilen ) < 0 ) { printf( "Error in connecting to server..\n" ); exit(1); } slen1 = sizeof( ss1 ); if( getpeername( connfd, (SA *)&ss1, &slen1 ) < 0 ) { printf( "peername error\n" ); exit(1); } inet_ntop( AF_INET, &(ss1.sin_addr), IPClient, MAXLINE ); printf( "DESTINATION ADDRESS : %s\n",IPClient ); printf( "DESTINATION PORT : %d\n", ss1.sin_port); sprintf( mesg, "%d\n", ss.sin_port ); printf("Sending the Ephemeral port number to client : %s..\n", mesg ); if( sendto( sockfd, mesg, sizeof( mesg ), 0, cliaddr, clilen) < 0 ) { printf("ERROR IN SENDTO : %d ",errno); exit(0); } printf( "Reading from the newly connected socket..\n" ); n = read( connfd, mesg, MAXLINE ); printf("Received data : %s\n",mesg ); if( n > 0 && strcmp( mesg, "ACK\n" ) == 0 ) { printf("ACK recieved..\n"); printf("Closing the listening socket on parent..\n"); close( sockfd ); } printf( "Reading file..\n" ); ifp = fopen( filename, "r" ); swnd1 = malloc( sender_window_size*sizeof(send_buffer) ); int i; for( i = 0 ; i<sender_window_size; i++) { swnd1[i].data[0] = '\0'; } int buffer_position, send_counter = 0, t, previous_na; memset( sendline, '\0', sizeof( sendline ) ); printf("Sending file to the client..\n"); int j, sender_usable_window, ack_recieved, closing_child=0 ; recv_advertisement = INT_MAX; ssthresh=recv_window_size; printf("\nSSTHRESH initiated to: %d\n",ssthresh); while(1) { if( cwnd > ( nt - na ) ) sender_usable_window = cwnd - ( nt - na ) ; else sender_usable_window = 0 ; printf("\nCongestion window : \nSender usable window : %d\nReciever window advertisement : %d\n", cwnd, sender_usable_window, recv_advertisement ); if(sender_usable_window==0) { printf( "\n*********************BUFFER FULL*************************\n"); } /* Check for if recv_adv == 0 i.e. no more packets to be sent. */ j = MIN( sender_usable_window , recv_advertisement ); if( (j == 0) || (send_counter == recv_advertisement) ) { while(1) { if( recv_advertisement == 0 && persist_timer_flag == 0 ) { persist_timer_flag = 1; //signal(SIGALRM, sig_alrm); //rtt_newpack( &rttinfo ); printf("************** PERSIST TIMER **************\n"); printf("Sending Probe packet..\n"); dg_retransmit( connfd, -1 ); } // previous_na = na; ack_recieved = dg_recieve_ack( connfd ); if( persist_timer_flag == 1 ) { if( recv_advertisement > 0) { persist_timer_flag = 0; struct itimerval value, ovalue, pvalue; value.it_interval.tv_sec = 0; /* Zero seconds */ value.it_interval.tv_usec = 0; /* Two hundred milliseconds */ value.it_value.tv_sec = 0; /* Zero seconds */ value.it_value.tv_usec = 0; /* Five hundred milliseconds */ setitimer( ITIMER_REAL, &value, &ovalue ); //alarm(0); break; } } if( dup_ack == 3 && persist_timer_flag == 0 ) { /* DUP ACK's case */ //dup_ack = 0; ssthresh = MIN( cwnd, recv_advertisement ); ssthresh = ( MAX( ssthresh, 2 ) )/2; printf("\n****************** 3 DUPLICATE ACK'S REC'VED ******************\n"); printf("Retransmitting the packet %d.. \n", ack_recieved); printf("Setting ssthresh to half of current window size : '%d'.. \n", ssthresh ); dg_retransmit( connfd, ack_recieved ); } if( ack_recieved == nt && persist_timer_flag == 0 ) { /* All Acks have been recieved.. */ printf("All ACK's have been recieved for buffer..\n"); struct itimerval value, ovalue, pvalue; value.it_interval.tv_sec = 0; /* Zero seconds */ value.it_interval.tv_usec = 0; /* Two hundred milliseconds */ value.it_value.tv_sec = 0; /* Zero seconds */ value.it_value.tv_usec = 0; /* Five hundred milliseconds */ setitimer( ITIMER_REAL, &value, &ovalue ); send_counter = 0; break; } } if( slowstart == 0 ) { cwnd += 1; } } else if( fread( sendline, 1, PACKET_SIZE, ifp ) != NULL ) { printf("********************************* SENDING DATA ************************************\n"); printf("DATA being sent : '%s'\n", sendline ); printf("Size : %d\n", strlen(sendline) ); printf("***********************************************************************************\n"); printf("Starting RTT timer..\n"); if( rttinit == 0 ) { rtt_init( &rttinfo ); /* first time we're called */ rttinit = 1; rtt_d_flag = 1; } if( send_counter == 0 ) { struct itimerval value, ovalue, pvalue; signal(SIGALRM, sig_alrm); rtt_newpack( &rttinfo ); /* initialize for this packet and sets retransmission counter to 0*/ value=rtt_start(&rttinfo); setitimer( ITIMER_REAL, &value, &ovalue ); } buffer_position = dg_send( connfd, sendline, strlen( sendline ) ); if ( sigsetjmp( jmpbuf, 1 ) != 0 ) { if ( rtt_timeout( &rttinfo ) < 0 && persist_timer_flag == 1 ) { err_msg( "Error : no response from client, giving up" ); rttinit = 0; /* reinit in case we're called again */ errno = ETIMEDOUT; return(-1); } goto sendagain; } send_counter++; status_report(); printf("Buffer position : %d\n", buffer_position ); memset( sendline, '\0', sizeof( sendline ) ); } else { /* the last packets */ while( na != nt || (closing_child == 1) ) { ack_recieved = dg_recieve_ack( connfd ); if( dup_ack == 3 ) { /* DUP ACK's case */ ssthresh = MIN( cwnd, recv_advertisement ); ssthresh = ( MAX( ssthresh, 2 ) )/2; printf("****************** 3 DUPLICATE ACK'S REC'VED ******************\n"); printf("Retransmitting the packet %d.. \n", ack_recieved); printf("Setting ssthresh to half of current window size : '%d'.. \n", ssthresh ); dg_retransmit( connfd, ack_recieved ); } status_report(); } printf("**************** SERVER CHILD SHUTDOWN PROCEDURE INTITIATED *****************\n"); printf("\nCOMPLETED SENDING ALL PACKETS TO CLIENT..\n"); printf("SENDING A FIN..\n"); dg_retransmit(connfd,-3); //FIN PACKET dg_recieve_ack( connfd ); dg_retransmit(connfd,-4); //final ACK closing_child = 1; printf("\nSHUTTING DOWN CHILD SERVER IN 2MSL seconds (ASSUMED AS 10 SECONDS)..\n"); struct itimerval value, ovalue, pvalue; value.it_interval.tv_sec = 0; /* Zero seconds */ value.it_interval.tv_usec = 0; /* Two hundred milliseconds */ value.it_value.tv_sec = 10; /* Zero seconds */ value.it_value.tv_usec = 0; /* Five hundred milliseconds */ setitimer( ITIMER_REAL, &value, &ovalue ); } continue; sendagain : if( closing_child == 1 ) { printf("CLOSING THE CHILD PROCESS ON THE SERVER..\n"); exit(0); break; // TERMINATE SAFELY } if( recv_advertisement == 0 ) { dg_retransmit( connfd, -1 ); } else { printf("******************RTT TIMEOUT EXPERIENCED******************..\n"); printf("Retransmitting the packet %d.. )\n", na); dg_retransmit( connfd, na ); } ssthresh = MIN( cwnd, recv_advertisement ); ssthresh = ( MAX( ssthresh, 2 ) )/2; cwnd = 1; slowstart = 1; printf("\n\nSetting ssthresh to half of current window size : '%d'.. \n", ssthresh ); } }
/* RETURNS ACK_NO */ int dg_recieve_ack( int fd ) { ssize_t n; struct iovec iovrecv[2]; char IPClient[20]; memset( &msgrecv, '\0', sizeof(msgrecv) ); memset( &recvhdr, '\0', sizeof(recvhdr) ); msgrecv.msg_name = NULL; msgrecv.msg_namelen = 0; msgrecv.msg_iov = iovrecv; msgrecv.msg_iovlen = 2; iovrecv[0].iov_base = &recvhdr; iovrecv[0].iov_len = sizeof(struct hdr); if( n = Recvmsg( fd, &msgrecv, 0) < 0 ) { printf("Error in RecvMsg!!\n"); printf("Error no : %d\n", errno ); exit(0); } if( recvhdr.ack_no == -3 ) { printf("Recieved a FIN-ACK from client..\n"); // struct itimerval value, ovalue, pvalue; // value.it_interval.tv_sec = 0; /* Zero seconds */ // value.it_interval.tv_usec = 0; /* Two hundred milliseconds */ // value.it_value.tv_sec = 0; /* Zero seconds */ // value.it_value.tv_usec = 0; /* Five hundred milliseconds */ // setitimer( ITIMER_REAL, &value, &ovalue ); return -3; } /* If we recieved the right packet ACKNOWLEDGEMENT, that is one which na was pointing to, we calculate RTT */ if( na == (recvhdr.ack_no - 1) ) { rtt_stop(&rttinfo, rtt_ts(&rttinfo) - recvhdr.ts); rtt_newpack( &rttinfo ); printf("Recieved an ACK-%d from client..\n", recvhdr.ack_no ); } printf( "Updating the reciever advertisement global variable with %d..\n", recvhdr.recv_window_advertisement ); recv_advertisement = recvhdr.recv_window_advertisement; update_na( recvhdr.ack_no ); current_ack = recvhdr.ack_no; if( prev_ack == current_ack ) { /* We got 3 DUP's */ dup_ack++; } else { dup_ack = 0; } /* swap fpr next ACK */ prev_ack = current_ack; return recvhdr.ack_no; }
static int su_serv_send_recv_act(su_serv_t *psvr, SA *destaddr, socklen_t destlen, const void *outbuff, int outbytes, void *inbuff, int inbytes, int retransmit) { int n; struct iovec iovsend[2]= {{0}}; struct msghdr msgsend = {0}; /* assumed init to 0 */ suhdr_t *r, sendhdr = {0}; /* protocol header */ int ret, waitsec; struct list *node = 0; frames_t *packet = 0; pthread_mutex_lock(&psvr->mutex); pthread_mutex_lock(&psvr->lock); if (retransmit == 0) { psvr->seq++; psvr->retransmission = 1; } else { if (psvr->retransmission == 0) { pthread_mutex_unlock(&psvr->mutex); pthread_mutex_unlock(&psvr->lock); errno = ETIMEDOUT; return -1; } psvr->retransmission --; } if (psvr->rttinit == 0) { rtt_init(&psvr->rttinfo, psvr->retry); /* first time we're called */ psvr->rttinit = 1; } sendhdr.act = SU_SYN; sendhdr.type = SU_RELIABLE; sendhdr.sid = psvr->sid; sendhdr.seq = psvr->seq; msgsend.msg_name = (void*)destaddr; msgsend.msg_namelen = destlen; msgsend.msg_iov = iovsend; msgsend.msg_iovlen = 2; iovsend[0].iov_base = (void*)&sendhdr; iovsend[0].iov_len = sizeof(suhdr_t); iovsend[1].iov_base = (void*)outbuff; iovsend[1].iov_len = outbytes; struct timespec abstime = {0}; suhdr_t *precvhdr; rtt_newpack(&psvr->rttinfo); /* initialize for this packet */ psvr->ackwaitnum ++; sendagain: sendhdr.ts = rtt_ts(&psvr->rttinfo); if (sendmsg(psvr->fd, &msgsend, 0) < 0) { ERR_RET("sendmsg error"); goto error_ret; } waitsec = rtt_start(&psvr->rttinfo); /* calc timeout value & start timer */ #ifdef SU_DEBUG_RTT fprintf(stderr, ColorRed "send seq %4d: " ColorEnd, sendhdr.seq); rtt_debug(&psvr->rttinfo); #endif /* set timed wait time-point */ maketimeout_seconds(&abstime, waitsec); #ifdef SU_DEBUG_TIMEVERBOSE struct timeval now; gettimeofday(&now, 0); log_msg( ColorBlue "pthread_cond_timedwait : %u.%u time expire" ColorEnd, abstime.tv_sec, abstime.tv_nsec); log_msg( ColorBlue "pthread_cond_timedwait : %d.%d now time" ColorEnd, now.tv_sec, now.tv_usec*1000); #endif timedwaitagain: ret = pthread_cond_timedwait(&psvr->ackcond, &psvr->lock, &abstime); if (ret == 0) { #ifdef SU_DEBUG_TIMEVERBOSE struct timeval now; gettimeofday(&now, 0); log_msg(ColorBlue "pthread_cond_timedwait : %d.%d ack cond interrupt" ColorEnd, now.tv_sec, now.tv_usec*1000); #endif node = psvr->ackrecvls.next; for (; node != &psvr->ackrecvls; node = node->next) { packet = container_of(node, frames_t, node); r = &packet->recvhdr; if (su_cmp_ack_SU_RELIABLE(&sendhdr, r)) { break; } } if ( node == &psvr->ackrecvls ) { /* Be careful of the lock, locked -> timedwait -> unlock */ #ifdef SU_DEBUG_LIST log_msg("serv %x no found seq %d ack, timed wait again", psvr, sendhdr.seq); #endif goto timedwaitagain; } /* Find response packet node */ list_remove(&packet->node); n = packet->len; precvhdr = &packet->recvhdr; #if defined SU_DEBUG_PEER_RECV || defined SU_DEBUG_LIST log_msg("serv %x finded ack " ColorRed "%p" ColorEnd " seq %d datagram len %d", psvr, packet, r->seq, packet->len); #endif #ifdef SU_DEBUG_RTT fprintf(stderr, ColorRed "recv seq %4d \n" ColorEnd, precvhdr->seq); #endif // SU_RELIABLE received response, copy to user buffer memcpy(inbuff, packet->data, n > inbytes ? inbytes : n); } else if (ret == EINTR) { log_msg("pthread_cond_timedwait system EINTR"); goto timedwaitagain; } else if (ret == ETIMEDOUT) { #ifdef SU_DEBUG_TIMEVERBOSE struct timeval now; gettimeofday(&now, 0); log_msg(ColorBlue "pthread_cond_timedwait : %u.%u ETIMEOUT have expired" ColorEnd, now.tv_sec, now.tv_usec*1000); #endif if (rtt_timeout(&psvr->rttinfo) < 0) { #ifdef SU_DEBUG_RTT err_msg(ColorYel "no response from server, giving up" ColorEnd); #endif psvr->rttinit = 0; /* reinit in case we're called again */ errno = ETIMEDOUT; goto error_ret; } #ifdef SU_DEBUG_RTT err_msg(ColorRed " seq %4d timeout, retransmitting %d" ColorEnd, sendhdr.seq, ++retransmit); #endif goto sendagain; } else { errno = ret; ERR_RET(" su_serv_send_recv_act unknown error[%d]", ret); goto error_ret; } /* calculate & store new RTT estimator values */ rtt_stop(&psvr->rttinfo, rtt_ts(&psvr->rttinfo) - precvhdr->ts); if (--psvr->ackwaitnum == 0) { su_serv_list_empty(psvr, &psvr->ackrecvls); } pthread_mutex_unlock(&psvr->mutex); pthread_mutex_unlock(&psvr->lock); #ifdef SU_DEBUG_LIST log_msg("serv %x free node " ColorRed "%p"ColorEnd" seq %d", psvr, packet, sendhdr.seq); #endif free(packet); return(n); /* return size of received datagram */ error_ret: if (--psvr->ackwaitnum == 0) { su_serv_list_empty(psvr, &psvr->ackrecvls); } pthread_mutex_unlock(&psvr->mutex); pthread_mutex_unlock(&psvr->lock); return(-1); }
int sendFileContents(int sockfd,int totalblocks, int windowsize){ //printf("%d\n", totalblocks); int first_unacknowledged_pos = 0; int pos_sent = -1; int prev_ack = 0; struct dgram recv_packet; int dups = 0; int recv_ack = -1; int retransmit = 0; int rtt_measured_packet = 0; uint32_t ts; int starttimer = 1; int hasBeenRtransmitted = 0; int slow_start = 1; Signal(SIGALRM, sig_alrm); if (rttinit == 0) { rtt_init(&rttinfo); /* first time we're called */ rttinit = 1; rtt_d_flag = 1; } while(1){ retransmitpack: if(retransmit){ printf("RETRANSMIT PACKET: %d\n", first_unacknowledged_pos); hasBeenRtransmitted = 1; slow_start = 1; Sendto(sockfd, (void *)&fileContent[first_unacknowledged_pos], sizeof(struct dgram), 0, NULL, NULL); retransmit = 0; } if (sigsetjmp(jmpbuf, 1) != 0) { //rtt_debug(&rttinfo); if (rtt_timeout(&rttinfo) < 0) { err_msg("no response from client, giving up"); rttinit = 0; errno = ETIMEDOUT; return(-1); } retransmit = 1; goto retransmitpack; } int sent_packets = 0; while( (0 < slow_start) && (pos_sent < totalblocks-1) && (pos_sent + 1 < first_unacknowledged_pos + windowsize)){ if(starttimer){ rtt_newpack(&rttinfo); alarm(rtt_start(&rttinfo)); ts = rtt_ts(&rttinfo); starttimer = 0; rtt_measured_packet = fileContent[pos_sent+1].seqNum; hasBeenRtransmitted = 0; } Sendto(sockfd, (void *)&fileContent[pos_sent+1], sizeof(struct dgram), 0, NULL, NULL); printf("SEND PACKET: %d\n", pos_sent+1); pos_sent++; slow_start--; } if(Recvfrom(sockfd, &recv_packet, sizeof(struct dgram), 0, NULL, NULL) < 0){ err_msg("Receive error from client"); return -1; } else{ //rtt_debug(&rttinfo); windowsize = recv_packet.windowsize; if(recv_packet.ack == recv_ack){ dups++; } else { dups = 0; } recv_ack = recv_packet.ack; printf("RECEIVED ACK: %d\n", recv_ack); if(dups == 0){ alarm(0); if(!hasBeenRtransmitted && recv_ack > rtt_measured_packet) rtt_stop(&rttinfo, rtt_ts(&rttinfo) - ts); starttimer = 1; slow_start += 2*(recv_ack - prev_ack); } prev_ack = recv_ack; first_unacknowledged_pos = recv_packet.ack; retransmit = 0; if(dups >= MAXDUPS){ // retransmit first unack pos retransmit = 1; goto retransmitpack; } } if( first_unacknowledged_pos > 0 && fileContent[first_unacknowledged_pos-1].eof){ printf("SUCCESS: SENT ENTIRE FILE\n"); break; } } return totalblocks; }
ssize_t dg_send_recv(int fd, const void *outbuff, size_t outbytes, void *inbuff, size_t inbytes, const SA *destaddr, socklen_t destlen) { ssize_t n; struct iovec iovsend[2], iovrecv[2]; fd_set rset; int nsel, maxfdp1; struct timeval tv; if (rttinit == 0) { rtt_init(&rttinfo); /* first time we're called */ rttinit = 1; rtt_d_flag = 1; } sendhdr.seq++; msgsend.msg_name = destaddr; msgsend.msg_namelen = destlen; msgsend.msg_iov = iovsend; msgsend.msg_iovlen = 2; iovsend[0].iov_base = &sendhdr; iovsend[0].iov_len = sizeof(struct hdr); iovsend[1].iov_base = outbuff; iovsend[1].iov_len = outbytes; msgrecv.msg_name = NULL; msgrecv.msg_namelen = 0; msgrecv.msg_iov = iovrecv; msgrecv.msg_iovlen = 2; iovrecv[0].iov_base = &recvhdr; iovrecv[0].iov_len = sizeof(struct hdr); iovrecv[1].iov_base = inbuff; iovrecv[1].iov_len = inbytes; rtt_newpack(&rttinfo); /* initialize for this packet */ sendagain: #ifdef RTT_DEBUG fprintf(stderr, "send %4d: ", sendhdr.seq); #endif sendhdr.ts = rtt_ts(&rttinfo); Sendmsg(fd, &msgsend, 0); alarm(rtt_start(&rttinfo)); /* calc timeout value & start timer */ #ifdef RTT_DEBUG rtt_debug(&rttinfo); #endif tv.tv_sec = rtt_start(&rttinfo); tv.tv_usec = 0; maxfdp1 = fd + 1; again: FD_ZERO(&rset); FD_SET(fd, &rset); nsel = select(maxfdp1, &rset, NULL, NULL, &tv); if ((nsel == -1) || (errno == EINTR)) goto again; else if (nsel == -1) err_msg("select error"); else if (nsel == 0) { if (rtt_timeout(&rttinfo) < 0) { err_msg("dg_send_recv: no response from server, giving up"); rttinit = 0; /* reinit in case we're called again */ errno = ETIMEDOUT; return(-1); } #ifdef RTT_DEBUG err_msg("dg_send_recv: timeout, retransmitting"); #endif goto sendagain; } if (FD_ISSET(fd, &rset)) { do { n = Recvmsg(fd, &msgrecv, 0); #ifdef RTT_DEBUG fprintf(stderr, "recv %4d\n", recvhdr.seq); #endif } while (n < sizeof(struct hdr) || recvhdr.seq != sendhdr.seq); } /* 4calculate & store new RTT estimator values */ rtt_stop(&rttinfo, rtt_ts(&rttinfo) - recvhdr.ts); return(n - sizeof(struct hdr)); /* return size of received datagram */ }
ssize_t jxclient_sendrecv(struct jxclient* cli, const struct sockaddr* servaddr, jxsocklen_t addrlen, mflag_t mflag) { char outbuf[MAX_MSG_LEN]; ssize_t recvbytes; jxsocklen_t sendlen; struct jxmsg_header* bufheader = NULL; if (s_rttinit == 0) { rtt_init(&s_rttinfo); s_rttinit = 1; #ifdef _DEBUG rtt_d_flag = 1; #endif } if (s_mutex_inited == 0) { s_sendrecv_init(); } bufheader = (struct jxmsg_header*)outbuf; bufheader->mflag = mflag; bufheader->header.seq = ++s_sendhdr.seq; rtt_newpack(&s_rttinfo); sendlen = sizeof(bufheader->addr); jxsock_getsockname(cli->hsock_sendrecv, &bufheader->addr, &sendlen); bufheader->addrlen = (uint8_t)sendlen; bufheader->numbytes = htonl(cli->len_senddata); if (jxmemcpy( outbuf + sizeof(struct jxmsg_header), sizeof(outbuf) - sizeof(struct jxmsg_header), cli->sendbuf, cli->len_senddata) != 0) { return 1; } s_recv_stat = RECV_RESEND; while (RECV_RESEND == s_recv_stat) { bufheader->header.ts = s_sendhdr.ts = rtt_ts(&s_rttinfo); if (SOCKET_ERROR == sendto( cli->hsock_sendrecv, outbuf, sizeof(struct jxmsg_header) + cli->len_senddata, 0, servaddr, (jxsocklen_t)addrlen)) { fprintf(stderr, "%s sendto() fail, error code: %d.\n", cli->prompt, jxsock_get_last_error()); return -2; } if (!JX_MFLAG_WAIT_RECV(mflag)) { return 0; } s_reset_recvtimer(); if ((recvbytes = s_recvmsg(cli->hsock_sendrecv, cli->recvbuf, sizeof(cli->recvbuf))) == -3) { return -3; } } if (s_recv_stat == RECV_TIMEOUT) { s_rttinit = 0; return -1; } rtt_stop(&s_rttinfo, rtt_ts(&s_rttinfo) - ((struct jxmsg_header*)cli->recvbuf)->header.ts); jxmsg_copyaddr((struct jxmsg_header*)cli->recvbuf, servaddr, addrlen); return recvbytes - sizeof(struct jxmsg_header); }