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