/* * New incoming feedback */ void ScreamTx::incomingFeedback(guint64 time_us, guint32 ssrc, guint32 timestamp, guint16 highestSeqNr, guint8 nLoss, gboolean qBit) { /* fix -Werror=unused-parameter */ (void) qBit; if (!isInitialized) initialize(time_us); Stream *stream = getStream(ssrc); accBytesInFlightMax += bytesInFlight(); nAccBytesInFlightMax++; for (int n=0; n < kMaxTxPackets; n++) { /* * Loop through TX packets with matching SSRC */ Transmitted *tmp = &txPackets[n]; if (tmp->isUsed == TRUE) { /* * RTP packet is in flight */ if (stream->isMatch(tmp->ssrc)) { if (tmp->seqNr == highestSeqNr) { ackedOwd = timestamp - tmp->timestamp; guint64 rtt = time_us - tmp->timeTx_us; sRttSh_us = (7 * sRttSh_us + rtt) / 8; if (time_us - lastSRttUpdateT_us > sRttSh_us) { sRtt_us = (7 * sRtt_us + sRttSh_us) / 8; lastSRttUpdateT_us = time_us; } } /* * Wrap-around safety net */ guint32 seqNrExt = tmp->seqNr; guint32 highestSeqNrExt = highestSeqNr; if (seqNrExt < highestSeqNrExt && highestSeqNrExt-seqNrExt > 20000) seqNrExt += 65536; else if (seqNrExt > highestSeqNrExt && seqNrExt - highestSeqNrExt > 20000) highestSeqNrExt += 65536; /* * RTP packets with a sequence number lower * than or equal to the highest received sequence number * are treated as received even though they are not * This advances the send window, similar to what * SACK does in TCP */ if (seqNrExt <= highestSeqNrExt) { bytesNewlyAcked += tmp->size; stream->bytesAcked += tmp->size; tmp->isUsed = FALSE; } } } } /* * Determine if a loss event has occurred */ if (stream->nLoss != nLoss) { /* * The loss counter has increased */ stream->nLoss = nLoss; if (time_us - lastLossEventT_us > sRtt_us) { /* * The loss counter has increased and it is more than one RTT since last * time loss was detected */ lossEvent = TRUE; lastLossEventT_us = time_us; } } if (lossEvent) { cerr << "LOSS " << (int)nLoss << endl; lastLossEventT_us = time_us; for (int n=0; n < nStreams; n++) { Stream *tmp = streams[n]; tmp->lossEventFlag = TRUE; } } updateCwnd(time_us); }
int main(int argc, char **argv) { int sockfd; /* socket */ int portno; /* port to listen on */ struct sockaddr_in clientaddr; /* client addr */ socklen_t clientlen; /* byte size of client's address */ struct sockaddr_in serveraddr; /* server's addr */ int optval; /* flag value for setsockopt */ int fd; long file_size; long total_read = 0; unsigned char file_buf[MAX_SEQ_NUM_HALF]; unsigned long lastbyteSent, lastbyteAcked, maxbyte; unsigned char *lastbyteSentPtr, *lastbyteAckedPtr, *maxbytePtr; clock_t clock_start, clock_end; bool eof = false; int dupAck = 0; map<uint16_t, clock_t> time_map; /* check command line arguments */ if (argc != 3) error("Usage: ./server PORT-NUMBER FILE-NAME"); portno = atoi(argv[1]); /* socket: create the parent socket */ sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) error("ERROR opening socket"); optval = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval , sizeof(int)) == -1){ perror("setsockopt"); return 1; }; /* build the server's Internet address */ bzero((char *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = htons((unsigned short)portno); /* bind: associate the parent socket with a port */ if (::bind(sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) == -1){ perror("bind"); return 2; } clientlen = sizeof(clientaddr); if (handshake(sockfd, clientaddr, clientlen) == USHRT_MAX) return 3; if ((fd = open(argv[2], O_RDONLY, 0644)) == -1){ perror("open"); return 4; } if ((file_size = lseek(fd, 0, SEEK_END)) == -1){ perror("lseek"); return 5; } if (lseek(fd, 0, SEEK_SET) == -1){ perror("lseek"); return 6; } maxbyte = lastbyteSent = lastbyteAcked = 0; maxbytePtr = lastbyteSentPtr = lastbyteAckedPtr = file_buf; clock_start = clock_end = clock(); bool firstRTT = true; while (!(eof && lastbyteAcked == maxbyte)) { for ( ; (lastbyteSent < maxbyte) && (unackedPackets < cwndPackets); (lastbyteSent += BUFSIZE) && (unackedPackets++)) { segment seg; seg.setSeqnum(server_seq); int send_size; if ((maxbyte-lastbyteSent)/BUFSIZE >= 1) send_size = BUFSIZE; else send_size = (int)(maxbyte - lastbyteSent); if (lastbyteSentPtr + send_size > file_buf + MAX_SEQ_NUM_HALF) { unsigned char temp[BUFSIZE]; long send_part2 = (lastbyteSentPtr + send_size) - (file_buf + MAX_SEQ_NUM_HALF); long send_part1 = send_size - send_part2; memcpy((char*)temp, (char*)lastbyteSentPtr, send_part1); memcpy((char*)(temp+send_part1), (char*)file_buf, send_part2); unsigned char *send_buf = seg.encode(temp, send_size); sendto(sockfd, send_buf, send_size+HEADERSIZE, 0, (struct sockaddr *)&clientaddr, clientlen); lastbyteSentPtr = lastbyteSentPtr + send_size - MAX_SEQ_NUM_HALF; } else { unsigned char *send_buf = seg.encode(lastbyteSentPtr, send_size); sendto(sockfd, send_buf, send_size+HEADERSIZE, 0, (struct sockaddr *)&clientaddr, clientlen); lastbyteSentPtr = lastbyteSentPtr + send_size; } clock_t now = clock(); time_map[server_seq] = now; cout << "Sending packet " << server_seq << " " << cwnd << " " << ssthresh << endl; server_seq = (server_seq + send_size) % MAX_SEQ_NUM; } while (true) { unsigned char recv_buf[HEADERSIZE]; long recv_len; if ((recv_len = recvfrom(sockfd, recv_buf, HEADERSIZE, MSG_DONTWAIT, (struct sockaddr *) &clientaddr, &clientlen)) == -1) { if (errno != EWOULDBLOCK && errno != EAGAIN) perror("recvfrom"); break; } segment ack; ack.decode(recv_buf, HEADERSIZE); if (ack.getFlagack()) { cout << "Receiving packet " << ack.getAcknum() << endl; if (ack.getAcknum() != server_ack) { map<uint16_t, clock_t>::iterator it = time_map.find(server_ack); if (it != time_map.end()) { clock_t now, then; now = clock(); then = it->second; time_map.erase(server_ack); double sampleRTT = double(now - then) / CLOCKS_PER_SEC; if (firstRTT) { estimatedRTT = sampleRTT; devRTT = sampleRTT / 2; adaptiveRTO = estimatedRTT + 4 * devRTT; timeout = adaptiveRTO; firstRTT = false; } else { double difference = sampleRTT - estimatedRTT >= 0 ? sampleRTT - estimatedRTT : estimatedRTT - sampleRTT; estimatedRTT = 0.875 * estimatedRTT + 0.125 * sampleRTT; devRTT = 0.75 * devRTT + 0.25 * difference; adaptiveRTO = estimatedRTT + 4 * devRTT; timeout = adaptiveRTO; } } uint16_t diff; if (ack.getAcknum() > server_ack) diff = ack.getAcknum() - server_ack; else diff = MAX_SEQ_NUM - server_ack + ack.getAcknum(); lastbyteAcked += diff; if (lastbyteAckedPtr + diff > file_buf + MAX_SEQ_NUM_HALF) lastbyteAckedPtr = lastbyteAckedPtr + diff - MAX_SEQ_NUM_HALF; else lastbyteAckedPtr = lastbyteAckedPtr + diff; server_ack = ack.getAcknum(); int num_acked = diff/BUFSIZE; unackedPackets -= num_acked; for (int i = 0; i < num_acked; i++) updateCwnd(); clock_start = clock_end = clock(); dupAck = 0; } else { if (state != FASTRECOVERY) { dupAck++; if (dupAck == 3) { state = FASTRECOVERY; dupAck = 0; ssthresh = cwnd/2 < BUFSIZE ? BUFSIZE : cwnd/2; ssthreshPackets = ssthresh / BUFSIZE; cwnd = ssthresh + BUFSIZE*3; cwndPackets = cwnd / BUFSIZE; segment seg; seg.setSeqnum(server_ack); int send_size; if ((maxbyte-lastbyteAcked)/BUFSIZE >= 1) send_size = BUFSIZE; else send_size = (int)(maxbyte - lastbyteAcked); if (lastbyteAckedPtr + send_size > file_buf + MAX_SEQ_NUM_HALF) { unsigned char temp[BUFSIZE]; long send_part2 = (lastbyteAckedPtr + send_size) - (file_buf + MAX_SEQ_NUM_HALF); long send_part1 = send_size - send_part2; memcpy((char*)temp, (char*)lastbyteAckedPtr, send_part1); memcpy((char*)(temp+send_part1), (char*)file_buf, send_part2); unsigned char *send_buf = seg.encode(temp, send_size); sendto(sockfd, send_buf, send_size+8, 0, (struct sockaddr *) &clientaddr, clientlen); } else { unsigned char *send_buf = seg.encode(lastbyteAckedPtr, send_size); sendto(sockfd, send_buf, send_size+8, 0, (struct sockaddr *) &clientaddr, clientlen); } cout << "Sending packet " << server_ack << " " << cwnd << " " << ssthresh << " Retransmission" << endl; clock_start = clock_end = clock(); time_map.erase(server_ack); } } else { cwnd += BUFSIZE; cwndPackets += 1; } } } } clock_end = clock(); double elapsed_secs = double(clock_end - clock_start) / CLOCKS_PER_SEC; if (elapsed_secs >= timeout) { state = SLOWSTART; dupAck = 0; ssthresh = cwnd/2 < BUFSIZE ? BUFSIZE : cwnd/2; ssthreshPackets = ssthresh / BUFSIZE; cwnd = BUFSIZE; cwndPackets = 1; segment seg; seg.setSeqnum(server_ack); int send_size; if ((maxbyte-lastbyteAcked)/BUFSIZE >= 1) send_size = BUFSIZE; else send_size = (int)(maxbyte - lastbyteAcked); if (lastbyteAckedPtr + send_size > file_buf + MAX_SEQ_NUM_HALF) { unsigned char temp[BUFSIZE]; long send_part2 = (lastbyteAckedPtr + send_size) - (file_buf + MAX_SEQ_NUM_HALF); long send_part1 = send_size - send_part2; memcpy((char*)temp, (char*)lastbyteAckedPtr, send_part1); memcpy((char*)(temp+send_part1), (char*)file_buf, send_part2); unsigned char *send_buf = seg.encode(temp, send_size); sendto(sockfd, send_buf, send_size+8, 0, (struct sockaddr *) &clientaddr, clientlen); } else { unsigned char *send_buf = seg.encode(lastbyteAckedPtr, send_size); sendto(sockfd, send_buf, send_size+8, 0, (struct sockaddr *) &clientaddr, clientlen); } cout << "Sending packet " << server_ack << " " << cwnd << " " << ssthresh << " Retransmission" << endl; clock_start = clock_end = clock(); timeout *= 2; time_map.erase(server_ack); } if (maxbyte - lastbyteAcked <= MAX_SEQ_NUM_HALF) { long bytes_left = MAX_SEQ_NUM_HALF - (maxbyte - lastbyteAcked); long bytes_read = 0; long read_len; if (MAX_SEQ_NUM_HALF-(maxbytePtr-file_buf) < (bytes_left)) { unsigned long part1 = MAX_SEQ_NUM_HALF - (maxbytePtr - file_buf); unsigned long part2 = bytes_left - part1; read_len = read(fd, maxbytePtr, part1); bytes_read += read_len; read_len = read(fd, file_buf, part2); bytes_read += read_len; } else { read_len = read(fd, maxbytePtr, bytes_left); bytes_read += read_len; } maxbyte += bytes_read; if (maxbytePtr + bytes_read > file_buf + MAX_SEQ_NUM_HALF) maxbytePtr = maxbytePtr + bytes_read - MAX_SEQ_NUM_HALF; else maxbytePtr = maxbytePtr + bytes_read; total_read += bytes_read; if (total_read == file_size) eof = true; } } teardown(sockfd, clientaddr, clientlen, 0, server_seq); }