Add files for swift over UDP.
[swifty.git] / src / libswift_udp / tests / ledbattest.cpp
1 /*
2  *  ledbattest.cpp
3  *
4  *  BROKEN: Arno: must be rewritten to libevent
5  *
6  *  Created by Victor Grishchenko on 3/22/09.
7  *  Copyright 2009-2012 TECHNISCHE UNIVERSITEIT DELFT. All rights reserved.
8  *
9  */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <vector>
13 #include <deque>
14 #include "swift.h"
15 #include <gtest/gtest.h>
16
17 using namespace swift;
18 using namespace std;
19
20 /**
21   TODO
22   * losses
23   * smooth rate
24   * seq 12345 stop
25   * busy pipe => negative cwnd
26 */
27
28 TEST(Datagram,LedbatTest) {
29
30     int MAX_REORDERING = 3;
31     tint TARGET = 25*TINT_MSEC;
32     float GAIN = 1.0/TARGET;
33     int seq_off = 0;
34     float cwnd = 1;
35     tint DELAY_BIN = TINT_SEC*30;
36     tint min_delay = TINT_NEVER;
37     tint rtt_avg = TINT_NEVER>>4, dev_avg = TINT_NEVER>>4;
38     tint last_bin_time = 0;
39     tint last_drop_time = 0;
40     int delay_bin = 0;
41     deque<tint> history, delay_history;
42     tint min_delay_bins[4] = {TINT_NEVER,TINT_NEVER,
43         TINT_NEVER,TINT_NEVER};
44     tint cur_delays[4] = {TINT_NEVER,TINT_NEVER,
45         TINT_NEVER,TINT_NEVER};
46     tint last_sec = 0;
47     int sec_ackd = 0;
48
49     evutil_socket_t send_sock = Datagram::Bind(10001); // bind sending socket
50     evutil_socket_t ack_sock = Datagram::Bind(10002);  // bind receiving socket
51     struct sockaddr_in send_to, ack_to;
52     send_to.sin_family = AF_INET;
53     send_to.sin_port = htons(10002);
54     send_to.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
55     ack_to.sin_family = AF_INET;
56     ack_to.sin_port = htons(10001);
57     ack_to.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
58     uint8_t* garbage = (uint8_t*) malloc(1024);
59     evutil_socket_t socks[2] = {send_sock,ack_sock};
60     evutil_socket_t sock2read;
61     tint wait_time = 100*TINT_MSEC;
62
63     while (sock2read = Datagram::Wait(2,socks,wait_time)) {
64         tint now = Datagram::Time();
65         if (sock2read==ack_sock) {
66             Datagram data(ack_sock); // send an acknowledgement
67             data.Recv();
68             int seq = data.Pull32();
69             Datagram ack(ack_sock,ack_to);
70             ack.Push32(seq);
71             ack.Push64(now);
72             if (4+8!=ack.Send())
73                 fprintf(stderr,"short write\n");
74             fprintf(stderr,"%lli rcvd%i\n",now/TINT_SEC,seq);
75             //cc->OnDataRecv(bin64_t(0,seq));
76             // TODO: peer cwnd !!!
77             continue;
78         }
79         if (sock2read==send_sock) {        // process an acknowledgement
80             Datagram ack(send_sock);
81             ack.Recv();
82             int seq = ack.Pull32();
83             tint arrival_time = ack.Pull64();
84             seq -= seq_off;
85             if (seq<0)
86                 continue;
87             if (seq>=history.size())
88                 continue;
89             if (history[seq]==0)
90                 continue;
91             tint send_time = history[seq];
92             history[seq] = 0;
93             if (seq>MAX_REORDERING*2) { //loss
94                 if (last_drop_time<now-rtt_avg) {
95                     cwnd /= 2;
96                     last_drop_time = now;
97                 }
98                 fprintf(stderr,"got %i. LOSS, cwnd drop: %f\n",seq,cwnd);
99                 for(int i=0; i<MAX_REORDERING*2 && history.size(); i++) {
100                     seq_off++;
101                     history.pop_front();
102                 }
103                 continue;
104             }
105             tint delay = arrival_time - send_time;
106             if (seq==0 && seq_off==0) { // FIXME
107                 rtt_avg = now - send_time;
108                 dev_avg = rtt_avg;
109             }
110             if (send_time/DELAY_BIN != last_bin_time) {
111                 last_bin_time = send_time/DELAY_BIN;
112                 delay_bin = (delay_bin+1) % 4;
113                 min_delay_bins[delay_bin] = TINT_NEVER;
114                 min_delay = TINT_NEVER;
115                 for(int i=0;i<4;i++)
116                     if (min_delay_bins[i]<min_delay)
117                         min_delay = min_delay_bins[i];
118             }
119             if (min_delay_bins[delay_bin] > delay)
120                 min_delay_bins[delay_bin] = delay;
121             if (delay < min_delay)
122                 min_delay = delay;
123             cur_delays[(seq_off+seq)%4] = delay;
124             tint current_delay = TINT_NEVER;
125             for(int i=0; i<4; i++)
126                 if (current_delay > cur_delays[i])
127                     current_delay = cur_delays[i];  // FIXME avg
128             tint queueing_delay = current_delay - min_delay;
129             // adjust cwnd
130             tint off_target = TARGET - queueing_delay;
131             //cerr<<"\t"<<cwnd<<"+="<<GAIN<<"*"<<off_target<<"/"<<cwnd<<endl;
132             cwnd += GAIN * off_target / cwnd;
133             fprintf(stderr,"ackd cwnd%f cur%lli min%lli seq%i off%i\n",
134                     cwnd,current_delay,min_delay,seq_off+seq,seq);
135
136             if (now/TINT_SEC!=last_sec/TINT_SEC) {
137                 fprintf(stderr,"%i KB/sec\n",sec_ackd);
138                 sec_ackd = 0;
139                 last_sec = now; // FIXME
140             } else
141                 sec_ackd++;
142
143         } // if
144         while (history[0]==0 && history.size()) {
145             history.pop_front();
146             seq_off++;
147         }
148         if (history.size() && history[0]<now-rtt_avg-5*dev_avg) {
149             if (last_drop_time<now-rtt_avg) {
150                 cwnd /= 2;
151                 last_drop_time = now;
152             }
153             fprintf(stderr,"TIMEOUT LOSS, cwnd drop: %f\n",cwnd);
154             seq_off++;
155             history.pop_front();
156         }
157         // fill cwnd
158         if (history.size()<cwnd) {
159             int sendseq = history.size() + seq_off;
160             Datagram send(send_sock,send_to);
161             send.Push32(sendseq);
162             send.Push(garbage,1024);
163             history.push_back(now);
164             fprintf(stderr,"sent%i\n",sendseq);
165             if (4+1024!=send.Send())
166                 fprintf(stderr,"short data write\n");
167         }
168         if (cwnd<1)
169             cwnd = 1;
170         if (history.size()<cwnd)
171             wait_time = rtt_avg/cwnd;
172         else
173             wait_time = 100*TINT_MSEC;
174     } // while
175 }
176
177 int main (int argc, char** argv) {
178     printf("Warning: use the script to set up dummynet!\n");
179
180     swift::LibraryInit();
181     testing::InitGoogleTest(&argc, argv);
182     return RUN_ALL_TESTS();
183
184 }