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 */ }
int dg_retransmit( int fd, int ack_recieved ) { ssize_t n; struct iovec iovsend[2], iovrecv[2]; char outbuff[MAXLINE]; memset( &msgsend, '\0', sizeof( msgsend ) ); memset( &sendhdr, '\0', sizeof( sendhdr ) ); if( ack_recieved > -1 ) strcpy( outbuff, swnd1[ ack_recieved%sender_window_size ].data ); sendhdr.seq = ack_recieved; msgsend.msg_name = NULL; msgsend.msg_namelen = 0; msgsend.msg_iov = iovsend; msgsend.msg_iovlen = 2; iovsend[0].iov_base = &sendhdr; iovsend[0].iov_len = sizeof(struct hdr); iovsend[1].iov_base = (void *)outbuff; iovsend[1].iov_len = sizeof(outbuff); int n1; sendhdr.ts = rtt_ts(&rttinfo); n1 = sendmsg( fd, &msgsend, 0 ); if( ack_recieved > -3 ) { struct itimerval value, ovalue, pvalue; value=rtt_start(&rttinfo); setitimer( ITIMER_REAL, &value, &ovalue ); } if( n1 > 0 ) { printf( "Completed sending packet..\n" ); } else { printf("Failed to send..\n"); } return( ack_recieved ); }
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 ); } }
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 */ }
void child(int index, struct sockaddr_in* ptr_connaddr, struct datagram* ptr_conn_gram) { struct datagram recv_gram; struct datagram send_gram; struct datagram* sendbuf; uint32_t* sendtv; char *tmp; int sockfd; int nready; int i; fd_set rset, allset; int maxfdp1 = 0; struct sockaddr_in servaddr, cliaddr; int local = 0; int on = 1; int len; //int filepos = -1; int filesize = 0; int servsockclosed = 0; int recv_seq; int last_ack; int last_ack_times; int recv_ack; int send_seq; int send_flag; int seq = 2568; int newport = 0; int recv_lock = 0; int eof = 0; int send_exist = 0; int buf_to_send = 0; int ssth = 0; float congestion_size = 1; int max_size = 0; uint32_t ts; FILE* file; char* payload; char* filename; struct rtt_info rttinfo; rtt_init(&rttinfo); for (i=0;i<count;i++) { if (i != index) { Close(sockfds[i]); continue; } } // todo: file not exist // todo: pipeline payload = get_payload_ptr(ptr_conn_gram); recv_windowsize = *(int*)payload; filename = payload+sizeof(int); printf("Client [%s:%d] request %s\n", inet_ntoa(ptr_connaddr->sin_addr), ntohs(ptr_connaddr->sin_port), filename); file = fopen(filename, "r"); if (!file) { printf("File not exist: %s\n", filename); Close(sockfd); return; } fseek(file, 0, SEEK_END); filesize = ftell(file); fseek(file, 0, SEEK_SET); local = is_local(addrs[index], ptr_connaddr, 0); sockfd = Socket(AF_INET, SOCK_DGRAM, 0); Setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = ((struct sockaddr_in*)addrs[index]->ifi_addr)->sin_addr.s_addr; servaddr.sin_port = 0; Bind(sockfd, (SA *) &servaddr, sizeof(servaddr)); len = sizeof(servaddr); getsockname(sockfd, (SA *) &servaddr, &len); if (local == 0) { printf("Client [%s:%d] is not LOCAL\n", inet_ntoa(ptr_connaddr->sin_addr), ntohs(ptr_connaddr->sin_port)); } else if (local == 1) { printf("Client [%s:%d] is LOCAL\n", inet_ntoa(ptr_connaddr->sin_addr), ntohs(ptr_connaddr->sin_port)); } else if (local == 2) { printf("Client [%s:%d] is LOOPBACK\n", inet_ntoa(ptr_connaddr->sin_addr), ntohs(ptr_connaddr->sin_port)); } if (local) Setsockopt(sockfd, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on)); //Connect(sockfd, (SA*)ptr_connaddr, sizeof(struct sockaddr_in)); // init // todo: fail sendbuf = (struct datagram*)malloc(windowsize*sizeof(struct datagram)); memset(sendbuf, 0, windowsize*sizeof(struct datagram)); sendtv = (uint32_t*)malloc(windowsize*sizeof(uint32_t)); memset(sendtv, 0, windowsize*sizeof(uint32_t)); send_exist = 0; last_ack = 0; last_ack_times = 0; newport = (int)ntohs(servaddr.sin_port); printf("New port for client [%s:%d] is %d\n", inet_ntoa(ptr_connaddr->sin_addr), ntohs(ptr_connaddr->sin_port), newport); get_header(ptr_conn_gram, 0, &recv_seq, 0, &ts); make_datagram(&sendbuf[0], SYN | ACK, seq, recv_seq+1, ts, (char*)&newport, sizeof(newport)); sendtv[0] = rtt_ts(&rttinfo) + rtt_start(&rttinfo); send_to(sockfd, &sendbuf[0], ptr_connaddr, sizeof(struct sockaddr_in)); send_exist++; FD_ZERO(&allset); FD_ZERO(&rset); FD_SET(sockfd, &allset); maxfdp1 = sockfd+1; for(;;) { rset = allset; // handle timeout // todo: rtt, recv_lock ts = rtt_start(&rttinfo); struct timeval tv; tv.tv_sec = ts/1000; tv.tv_usec = (ts % 1000)*1000; nready = select(maxfdp1, &rset, NULL, NULL, &tv); if (nready < 0) { if (errno == EINTR) continue; /* back to for() */ else err_sys("select error"); } else if (nready == 0) { // timeout if (recv_lock) { ts = rtt_ts(&rttinfo); make_datagram(&send_gram, ACK, 0, 0, ts, NULL, 0); send_to(sockfd, &send_gram, ptr_connaddr, sizeof(*ptr_connaddr)); continue; } // resend for (i=0;i<windowsize;i++) { if (0 == sendtv[i]) continue; ts = rtt_ts(&rttinfo); if (ts >= sendtv[i]) { set_ts(&sendbuf[i], ts); send_to(sockfd, &sendbuf[i], ptr_connaddr, sizeof(*ptr_connaddr)); sendtv[i] = ts + rtt_start(&rttinfo); } } if (rtt_timeout(&rttinfo) < 0) { if (!servsockclosed) { Close(sockfds[index]); servsockclosed = 1; } Close(sockfd); fclose(file); printf("Too many timeouts for Client [%s:%d]\n", inet_ntoa(ptr_connaddr->sin_addr), ntohs(ptr_connaddr->sin_port)); return; } ssth = (int)congestion_size/2; if (ssth < 1) ssth = 1; congestion_size = 1; printf("Timeout slow start\n"); continue; } if (FD_ISSET(sockfd, &rset)) { len = sizeof(cliaddr); recv_from(sockfd, &recv_gram, &cliaddr, &len); get_header(&recv_gram, 0, 0, &recv_ack, &ts); rtt_stop(&rttinfo, rtt_ts(&rttinfo)-ts); payload = get_payload_ptr(&recv_gram); recv_lock = (*(int*)payload == 0)?1:0; if (!servsockclosed) { Close(sockfds[index]); servsockclosed = 1; } for (i=0;i<windowsize;i++) { get_header(&sendbuf[i], &send_flag, &send_seq, 0, 0); if (!send_flag) continue; if (send_seq < recv_ack) { set_flag(&sendbuf[i], 0); sendtv[i] = 0; send_exist--; } } if ((recv_ack > seq) && eof) { Close(sockfd); fclose(file); printf("Client [%s:%d] end\n", inet_ntoa(ptr_connaddr->sin_addr), ntohs(ptr_connaddr->sin_port)); return; } if (last_ack == recv_ack) { last_ack_times++; } else { last_ack = recv_ack; last_ack_times=1; } if (last_ack_times >= 3) { last_ack = 0; for (i=0;i<windowsize;i++) { get_header(&sendbuf[i], &send_flag, &send_seq, 0, 0); if (!send_flag) continue; if (send_seq == recv_ack) break; } ts = rtt_ts(&rttinfo); set_ts(&sendbuf[i], ts); send_to(sockfd, &sendbuf[i], ptr_connaddr, sizeof(*ptr_connaddr)); // todo: congestion printf("Fast recvory\n"); congestion_size = ssth; if (congestion_size <= 0) congestion_size = 1; continue; } // todo: congestion max_size = windowsize; if (recv_windowsize < max_size) max_size = recv_windowsize; if (congestion_size < ssth) { congestion_size++; if (congestion_size >= ssth) { printf("Reach slow start threshold\n"); } } else { congestion_size += (max_size > 0)? 1.0/max_size:1.0; } if (congestion_size < max_size) max_size = (int)congestion_size; if (eof || recv_lock) { buf_to_send = 0; } else if (send_exist < max_size) { buf_to_send = max_size - send_exist; } else if (send_exist >= max_size) { buf_to_send = 0; } //printf("buf_to_send %d\n", buf_to_send); for (;buf_to_send > 0;buf_to_send--) { for (i=0;i<windowsize;i++) { get_header(&sendbuf[i], &send_flag, &send_seq, 0, 0); if (!send_flag) break; } seq++; ts = rtt_ts(&rttinfo); make_datagram(&sendbuf[i], DAT, seq, 0, ts, NULL, 0); payload = get_payload_ptr(&sendbuf[i]); //len = fread(payload+4, BUFFER_SIZE-HEADER_SIZE-4, 1, file); len = fread(payload+4, 1, BUFFER_SIZE-HEADER_SIZE-4, file); *(int*)payload = len; //printf("f %d %s\n", len, payload+4); if (ftell(file) >= filesize) { eof = 1; set_fin_flag(&sendbuf[i]); } sendtv[i] = ts + rtt_start(&rttinfo); send_to(sockfd, &sendbuf[i], ptr_connaddr, sizeof(*ptr_connaddr)); send_exist++; if (eof) break; } } } }
void s_reset_recvtimer(void) { jxtimelong_cur(&s_recvbegin); s_recvtimer = rtt_start(&s_rttinfo); }