add .gitignore
[swift-upb.git] / tests / ledbattest2.cpp
1 #include <stdio.h>
2 #include <stdlib.h>
3 #ifdef _MSC_VER
4         #include "compat/stdint.h"
5     #include <winsock2.h>
6 #else
7    #include <sys/socket.h>
8    #include <netinet/in.h>
9    #include <arpa/inet.h>
10 #endif
11 #include <vector>
12 #include <deque>
13 #include "datagram.h"
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 unsigned long dest_addr;
29 int send_port = 10001;
30 int ack_port = 10002;
31
32 TEST(Datagram,LedbatTest) {
33
34     int MAX_REORDERING = 3;
35     tint TARGET = 25*TINT_MSEC;
36     float GAIN = 1.0/TARGET;
37     int seq_off = 0;
38     float cwnd = 1;
39     tint DELAY_BIN = TINT_SEC*30;
40     tint min_delay = TINT_NEVER;
41     tint rtt_avg = TINT_NEVER>>4, dev_avg = TINT_NEVER>>4;
42     tint last_bin_time = 0;
43     tint last_drop_time = 0;
44     int delay_bin = 0;
45     deque<tint> history, delay_history;
46     tint min_delay_bins[4] = {TINT_NEVER,TINT_NEVER,
47         TINT_NEVER,TINT_NEVER};
48     tint cur_delays[4] = {TINT_NEVER,TINT_NEVER,
49         TINT_NEVER,TINT_NEVER};
50     tint last_sec = 0;
51     int sec_ackd = 0;
52
53     // bind sending socket
54     SOCKET send_sock = Datagram::Bind(Address(INADDR_ANY,send_port));
55     // bind receiving socket
56     SOCKET ack_sock = Datagram::Bind(Address(INADDR_ANY,ack_port));
57     struct sockaddr_in send_to, ack_to;
58     memset(&send_to, 0, sizeof(struct sockaddr_in));
59     memset(&ack_to, 0, sizeof(struct sockaddr_in));
60     send_to.sin_family = AF_INET;
61     send_to.sin_port = htons(ack_port);
62     send_to.sin_addr.s_addr = dest_addr;
63     ack_to.sin_family = AF_INET;
64     ack_to.sin_port = htons(send_port);
65     ack_to.sin_addr.s_addr = dest_addr;
66     uint8_t* garbage = (uint8_t*) malloc(1024);
67     SOCKET socks[2] = {send_sock,ack_sock};
68     SOCKET sock2read;
69     tint wait_time = 100*TINT_MSEC;
70
71     while (sock2read = Datagram::Wait(2,socks,wait_time)) {
72         tint now = Datagram::Time();
73         if (sock2read==ack_sock) {
74             Datagram data(ack_sock); // send an acknowledgement
75             data.Recv();
76             int seq = data.Pull32();
77             Datagram ack(ack_sock,ack_to);
78             ack.Push32(seq);
79             ack.Push64(now);
80             if (4+8!=ack.Send())
81                 fprintf(stderr,"short write\n");
82             fprintf(stderr,"%lli rcvd%i\n",now/TINT_SEC,seq);
83             // TODO: peer cwnd !!!
84             continue;
85         }
86         if (sock2read==send_sock) {        // process an acknowledgement
87             Datagram ack(send_sock);
88             ack.Recv();
89             int seq = ack.Pull32();
90             tint arrival_time = ack.Pull64();
91             seq -= seq_off;
92             if (seq<0)
93                 continue;
94             if (seq>=history.size())
95                 continue;
96             if (history[seq]==0)
97                 continue;
98             tint send_time = history[seq];
99             history[seq] = 0;
100             if (seq>MAX_REORDERING*2) { //loss
101                 if (last_drop_time<now-rtt_avg) {
102                     cwnd /= 2;
103                     last_drop_time = now;
104                 }
105                 fprintf(stderr,"got %i. LOSS, cwnd drop: %f\n",seq,cwnd);
106                 for(int i=0; i<MAX_REORDERING*2 && history.size(); i++) {
107                     seq_off++;
108                     history.pop_front();
109                 }
110                 continue;
111             }
112             tint delay = arrival_time - send_time;
113             if (seq==0 && seq_off==0) { // FIXME
114                 rtt_avg = now - send_time;
115                 dev_avg = rtt_avg;
116             }
117             if (send_time/DELAY_BIN != last_bin_time) {
118                 last_bin_time = send_time/DELAY_BIN;
119                 delay_bin = (delay_bin+1) % 4;
120                 min_delay_bins[delay_bin] = TINT_NEVER;
121                 min_delay = TINT_NEVER;
122                 for(int i=0;i<4;i++)
123                     if (min_delay_bins[i]<min_delay)
124                         min_delay = min_delay_bins[i];
125             }
126             if (min_delay_bins[delay_bin] > delay)
127                 min_delay_bins[delay_bin] = delay;
128             if (delay < min_delay)
129                 min_delay = delay;
130             cur_delays[(seq_off+seq)%4] = delay;
131             tint current_delay = TINT_NEVER;
132             for(int i=0; i<4; i++)
133                 if (current_delay > cur_delays[i])
134                     current_delay = cur_delays[i];  // FIXME avg
135             tint queueing_delay = current_delay - min_delay;
136             // adjust cwnd
137             tint off_target = TARGET - queueing_delay;
138             //cerr<<"\t"<<cwnd<<"+="<<GAIN<<"*"<<off_target<<"/"<<cwnd<<endl;
139             cwnd += GAIN * off_target / cwnd;
140             fprintf(stderr,"ackd cwnd%f cur%lli min%lli seq%i off%i\n",
141                     cwnd,current_delay,min_delay,seq_off+seq,seq);
142
143             if (now/TINT_SEC!=last_sec/TINT_SEC) {
144                 fprintf(stderr,"%i KB/sec\n",sec_ackd);
145                 sec_ackd = 0;
146                 last_sec = now; // FIXME
147             } else
148                 sec_ackd++;
149
150         } // if
151         while (history[0]==0 && history.size()) {
152             history.pop_front();
153             seq_off++;
154         }
155         if (history.size() && history[0]<now-rtt_avg-5*dev_avg) {
156             if (last_drop_time<now-rtt_avg) {
157                 cwnd /= 2;
158                 last_drop_time = now;
159             }
160             fprintf(stderr,"TIMEOUT LOSS, cwnd drop: %f\n",cwnd);
161             seq_off++;
162             history.pop_front();
163         }
164         // fill cwnd
165         if (history.size()<cwnd) {
166             int sendseq = history.size() + seq_off;
167             Datagram send(send_sock,send_to);
168             send.Push32(sendseq);
169             send.Push(garbage,1024);
170             history.push_back(now);
171             fprintf(stderr,"sent%i\n",sendseq);
172             if (4+1024!=send.Send())
173                 fprintf(stderr,"short data write\n");
174         }
175         if (cwnd<1)
176             cwnd = 1;
177         if (history.size()<cwnd)
178             wait_time = rtt_avg/cwnd;
179         else
180             wait_time = 100*TINT_MSEC;
181     } // while
182 }
183
184 int main (int argc, char** argv) {
185
186     int opt;
187     swift::LibraryInit();
188     printf("Warning: use the script to set up dummynet!\n");
189     testing::InitGoogleTest(&argc, argv);
190     dest_addr = htonl(INADDR_LOOPBACK);
191     while ((opt = getopt(argc, argv, "a:d:s:h")) != -1)
192         switch (opt) {
193         case 'd':
194             if (!inet_aton(optarg, (struct in_addr *)&dest_addr)) {
195                 fprintf(stderr, "inet_aton failed for addr: %s\n", optarg);
196                 return -1;
197             }
198             break;
199         case 'a':
200             ack_port = (int)strtol(optarg, NULL, 10);
201             break;
202         case 's':
203             send_port = (int)strtol(optarg, NULL, 10);
204             break;
205         case 'h':
206         default:
207             printf("\nledbattest2 usage:\n"
208                    "  -d Destination IP-address (default: 127.0.0.1)\n"
209                    "  -s Send port (default: 10001)\n"
210                    "  -a Ack port (default: 10002)\n");
211             break;
212         }
213     return RUN_ALL_TESTS();
214 }