udpClient.cc 31.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/time.h>
#include <pcap.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/if_ether.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <vector>
#include <list>
#include <string>
#include <map>
#include <sstream>
#include <math.h>
29
#include <set>
30
31

#define REMOTE_SERVER_PORT 9831
Pramod R Sanaga's avatar
Pramod R Sanaga committed
32
33
//#define MAX_MSG 450000
#define MAX_MSG 1458
34
35
36


using namespace std;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
37

38
39
struct tcp_block{

Pramod R Sanaga's avatar
Pramod R Sanaga committed
40
41
42
43
44
45
46
    unsigned long HighData;
    unsigned long HighACK;
    unsigned long HighRxt;

    long pipe;
    unsigned long recoveryPoint;

47
48
49
50
51
52
53
54
55
    int dup_acks;

    double congWindow;
    int ssthresh;

    double rtt_est;
    double rtt_deviation_est;
    double rto_estimate;

Pramod R Sanaga's avatar
Pramod R Sanaga committed
56
    bool lossRecovery;
57

58
    set< pair<unsigned long, unsigned long> > sackRanges;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
59
    int congAvoidancePackets;
60
61
62
63
64
    unsigned long sackEdge;


    // Temp variables.
    unsigned long range_start, range_end;
65
66
};

Pramod R Sanaga's avatar
Pramod R Sanaga committed
67
pcap_t *pcapDescriptor = NULL;
68
69
70
71
72
73
74
75
76
77
78
79
80
struct tcp_block conn_info;
int clientSocket;
struct sockaddr_in remoteServAddr;
unsigned long long startTime;

map<unsigned long, unsigned long long> packetTimeMap;
map<unsigned long, bool> rexmitMap;
long long retransTimer;
list<unsigned long> unackedPackets;
list<unsigned long> rexmitPackets;
unsigned long reportedLost;
unsigned long highSeq;

Pramod R Sanaga's avatar
Pramod R Sanaga committed
81
82
83
void handleUDP(struct pcap_pkthdr const *pcap_info, struct udphdr const *udpHdr, u_char *const udpPacketStart, struct ip const *ipPacket);
int xmit_packet(char *message, int messageLen);
unsigned long long getTimeMilli();
84
85
86
87
88
89
90
91
92
93
94
95
96
static int ackCount = 0;

template <class T> class In_Range : public std::unary_function<T, bool>
{
    public:
        bool operator() (T& val)
        {
            if( (val >= conn_info.range_start) && (val <= conn_info.range_end) )
                return true;
            else
                return false;
        }
};
Pramod R Sanaga's avatar
Pramod R Sanaga committed
97
98
99
100
101

bool IsLost(unsigned long seq)
{
    // If this sequence number was acked by any of the SACKs, we wouldn't find
    // it in the unacked list.
102
103
    /*
    if(checkUnAcked)
Pramod R Sanaga's avatar
Pramod R Sanaga committed
104
    {
105
106
107
108
        if(find(unackedPackets.begin(),unackedPackets.end(),seq) == unackedPackets.end())
        {
            return false;
        }
Pramod R Sanaga's avatar
Pramod R Sanaga committed
109
    }
110
111
    */

Pramod R Sanaga's avatar
Pramod R Sanaga committed
112
113
    { // If the packet is still unacked, check that it is below the highest seq.
        // sacked to be considered lost.
114
115
        //if( (conn_info.sackRanges.size() > 0) && (seq < (*(conn_info.sackRanges.rbegin())).second ) )
        if(seq < conn_info.sackEdge)
Pramod R Sanaga's avatar
Pramod R Sanaga committed
116
117
118
119
120
121
122
123
124
125
126
127
128
            return true;
        else
            return false;
    }
}

// Returns the sequence number of the next segment to be transmitted.
unsigned long NextSeq(bool timeout)
{
    list<unsigned long>::iterator listIter = unackedPackets.begin();

    // Return the sequence number of the first unacked packet in case of a timeout.
    if(timeout)
129
    {
Pramod R Sanaga's avatar
Pramod R Sanaga committed
130
        return (*listIter);
131
    }
Pramod R Sanaga's avatar
Pramod R Sanaga committed
132
133
134
135
136
137
138

    while(listIter != unackedPackets.end())
    {
        if( IsLost(*listIter) ) 
        {
            if( (*listIter) > conn_info.HighRxt )
            {
139
140
                //if( (*listIter) < (*(conn_info.sackRanges.rbegin())).second )
                if( (*listIter) < conn_info.sackEdge )
Pramod R Sanaga's avatar
Pramod R Sanaga committed
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
                {
                    return (*listIter);
                }
            }
        }

        listIter++;
    }

    // else - no unacked packets were eligible for retransmission - send a new packet.
    return (conn_info.HighData+1);
}

// Estimate of the number of packets outstanding in the network.
void SetPipe()
{
    unsigned long i;

    conn_info.pipe = 0;

161
162
163
164
165
166
    //for(i = conn_info.HighACK+1; i <= conn_info.HighData; i++)

    list<unsigned long>::iterator listIter = unackedPackets.begin();

    // Check only in the unacked list.
    while(listIter != unackedPackets.end())
Pramod R Sanaga's avatar
Pramod R Sanaga committed
167
    {
168
        if( ! IsLost((*listIter)) )
Pramod R Sanaga's avatar
Pramod R Sanaga committed
169
170
            conn_info.pipe++;

171
172
173
174
175
        //FIXME:
        //if((*listIter) <= conn_info.HighRxt)
         //   conn_info.pipe++;

        listIter++;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
176
177
178
179
    }
}


180
/*
Pramod R Sanaga's avatar
Pramod R Sanaga committed
181
182
183
184
185
186
187
188
bool sackCompare( pair<unsigned long, unsigned long> pair1, pair<unsigned long, unsigned long> pair2)
{
    if(pair1.second <= pair2.second)
        return true;
    else
        return false;
}

189
190
191
192
193
194
195
196
197
198
199
200
201
*/

struct sackCompare
{

    bool operator()( pair<unsigned long, unsigned long> pair1, pair<unsigned long, unsigned long> pair2)
    {
        if(pair1.second <= pair2.second)
            return true;
        else
            return false;
    }
};
Pramod R Sanaga's avatar
Pramod R Sanaga committed
202
203
204

void UpdateSACKs(int numSACKBlocks, u_char *dataPtr)
{
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    // Remove SACK ranges to the left side of packets which have been cumulatively acked.
    /*
    if(conn_info.HighACK >= (*(conn_info.sackRanges.begin())).second)
    {
        set<pair<unsigned long, unsigned long> >::iterator sackIter = conn_info.sackRanges.begin();

        while(sackIter != conn_info.sackRanges.end())
        {
            if(conn_info.HighACK >= (*sackIter).second)
                conn_info.sackRanges.erase(sackIter++);
            else
                sackIter++;
        }

    }
    */

Pramod R Sanaga's avatar
Pramod R Sanaga committed
222
223
    if(numSACKBlocks > 0)
    {
224
       // unsigned long lastSACKBlock = *(dataPtr + ((numSACKBlocks-1)*2 + 1 )*sizeof(unsigned long)); 
Pramod R Sanaga's avatar
Pramod R Sanaga committed
225
226
        pair<unsigned long, unsigned long> tmpRange;

227
228
                //printf("Received a SACK for seq = %u\n",conn_info.HighACK+1);

Pramod R Sanaga's avatar
Pramod R Sanaga committed
229
        // Erase packets acked by the SACK blocks from the unacked list.
230
231
        list<unsigned long>::iterator listIter;

Pramod R Sanaga's avatar
Pramod R Sanaga committed
232
233
        for(int i = 0;i < numSACKBlocks; i++)
        {
234
235
            tmpRange.first = *( (unsigned long *)(dataPtr + i*2*sizeof(unsigned long)));
            tmpRange.second = *( (unsigned long *)(dataPtr + (i*2+1)*sizeof(unsigned long)));
Pramod R Sanaga's avatar
Pramod R Sanaga committed
236

237
238
239
240
241
242
243
244
245
246
247
248
249
            /*
            if(conn_info.sackRanges.find(tmpRange) == conn_info.sackRanges.end())
            {
                conn_info.sackRanges.insert(tmpRange);
                cout << " Inserting "<<tmpRange.first<<", "<<tmpRange.second<<", size = "<<conn_info.sackRanges.size()<<endl;
            }
            */

            conn_info.range_start = tmpRange.first;
            conn_info.range_end = tmpRange.second;
            unackedPackets.remove_if( In_Range<unsigned long>() );

            /*
Pramod R Sanaga's avatar
Pramod R Sanaga committed
250
251
            for( unsigned long j = tmpRange.first; j <= tmpRange.second; j++)
            {
252
253
254
255
        //        listIter = find(unackedPackets.begin(),unackedPackets.end(),j);

         //       if(listIter != unackedPackets.end())
          //          unackedPackets.erase(listIter);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
256
257
258
259

                rexmitMap.erase(j);
                packetTimeMap.erase(j);
            }
260
261
262
263
264
            */

            // Remember the highest SACK number seen.
            if(tmpRange.second > conn_info.sackEdge)
                conn_info.sackEdge = tmpRange.second;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
265
266
267
268
269
        }

        // Update the SACK ranges.
        // It is not necessary to merge them - all that we care about is their
        // right most ( most recent ) edge.
270
        /*
Pramod R Sanaga's avatar
Pramod R Sanaga committed
271
272
273
        {
            for(int i = 0;i < numSACKBlocks; i++)
            {
274
275
                tmpRange.first = *( (unsigned long *)(dataPtr + i*2*sizeof(unsigned long)));
                tmpRange.second = *( (unsigned long *)(dataPtr + (i*2+1)*sizeof(unsigned long)));
Pramod R Sanaga's avatar
Pramod R Sanaga committed
276

277
278
                //cout<<"Adding range " << tmpRange.first << ", "<<tmpRange.second<<endl;
                conn_info.sackRanges.insert(tmpRange);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
279
280
            }
        }
281
        */
Pramod R Sanaga's avatar
Pramod R Sanaga committed
282

283
        //conn_info.sackRanges.sort(sackCompare);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
284

285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
        /*
        // Remove duplicate entries.
        list<pair<unsigned long, unsigned long> >::iterator sackIter = conn_info.sackRanges.begin();
        unsigned long range_start, range_end;
        range_start = (*sackIter).first;
        range_end = (*sackIter).second;
        sackIter++;
        while(sackIter != conn_info.sackRanges.end())
        {
            if( ( (*sackIter).first == range_start) && ((*sackIter).second == range_end) )
            {
                conn_info.sackRanges.erase(sackIter++);
            }
            else
            {
                range_start = (*sackIter).first;
                range_end = (*sackIter).second;
                sackIter++;
            }
        }
        */
Pramod R Sanaga's avatar
Pramod R Sanaga committed
306

307
308
309
310
311
312
        /*
        list<pair<unsigned long, unsigned long> >::iterator sackIter = conn_info.sackRanges.begin();
        printf("SACK Ranges:\n");
        while(sackIter != conn_info.sackRanges.end())
        {
            printf("%d %d : ", (*sackIter).first, (*sackIter).second);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
313
            sackIter++;
314
315
316
        }
        printf("\n");
        */
Pramod R Sanaga's avatar
Pramod R Sanaga committed
317
318
    }

319
320
321
322
323
324
325
326
327
328
329
    /*
        sackIter = conn_info.sackRanges.begin();
        printf("SACK Ranges after ( unacked = %d,front = %u, back = %u):\n",unackedPackets.size(), unackedPackets.front(), unackedPackets.back());
        while(sackIter != conn_info.sackRanges.end())
        {
            printf("%d %d :\n", (*sackIter).first, (*sackIter).second);
            sackIter++;
        }
        printf("\n");
        */

Pramod R Sanaga's avatar
Pramod R Sanaga committed
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
}

// Updates all the state variables.
//void Update(unsigned long seqNum, int numSACKBlocks, u_char *dataPtr, struct pcap_pkthdr const *pcap_info)
void Update(unsigned long seqNum, int numSACKBlocks, u_char *dataPtr, unsigned long long recvTime)
{
    unsigned long numPacketsAcked = 0;

    //printf("ACK for seq # = %u\n", seqNum);
    if((seqNum-1) > conn_info.HighACK)
    {
        numPacketsAcked = seqNum - conn_info.HighACK - 1;

        // Update the RTT estimates.
        // Only include non retransmitted packets in our calculations.
        if(! rexmitMap[seqNum-1] )
        {
            // Count only the packets that have been individually acked.
            // ie. only the single packet at the left most position in the
            // window. Do not take cumulatively acked packets into account.
            if((seqNum-1) == conn_info.HighACK+1)
            {
                //unsigned long long secVal = pcap_info->ts.tv_sec;
                //unsigned long long usecVal = pcap_info->ts.tv_usec;

                //long rtt_val = (secVal*1000 + usecVal/1000 - packetTimeMap[seqNum-1]);
                long rtt_val = (recvTime - packetTimeMap[seqNum-1]);

                // Use an exponential moving avg.
                conn_info.rtt_est = conn_info.rtt_est*(1-0.125) + rtt_val*0.125;
                conn_info.rtt_deviation_est = conn_info.rtt_deviation_est*(1-0.25) + fabs(rtt_val - conn_info.rtt_est)*0.25;

                conn_info.rto_estimate = conn_info.rtt_est + 4.0*conn_info.rtt_deviation_est;

                // Never allow the timeout timer to be below 1 second, to avoid
                // spurious timeouts.(RFC 2988)
                if(conn_info.rto_estimate < 1000)
                    conn_info.rto_estimate = 1000;
            }
        }

371
        list<unsigned long>::iterator listIter;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
372
        // Remove all cumulatively acked packets from the unacked list.
373
374
375
376
377
        conn_info.range_start = conn_info.HighACK;
        conn_info.range_end = seqNum - 1;

        unackedPackets.remove_if( In_Range<unsigned long>() );

Pramod R Sanaga's avatar
Pramod R Sanaga committed
378
379
        for(unsigned long i = conn_info.HighACK; i < seqNum; i++)
        {
380
381
382
383
384
            
        //    listIter = find(unackedPackets.begin(),unackedPackets.end(),i);

         //   if(listIter != unackedPackets.end())
          //      unackedPackets.erase(listIter);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
385
386
387
388
389
390
391
392
393
394

            rexmitMap.erase(i);
            packetTimeMap.erase(i);
        }

        conn_info.HighACK = seqNum - 1;

        // If all packets upto the loss recovery point have been acked, 
        // terminate loss recovery.
        if( ( conn_info.lossRecovery ) && ( seqNum >= conn_info.recoveryPoint ) )
395
396
        {
//            printf("Exiting loss recovery at %u\n", seqNum);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
397
            conn_info.lossRecovery = false;
398
399
            conn_info.dup_acks = 0;
        }
Pramod R Sanaga's avatar
Pramod R Sanaga committed
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

        // Reset the timout value - because this ACK is acknowledging new data.
        unsigned long long currTime = getTimeMilli();
        retransTimer = currTime + (int)conn_info.rto_estimate;
    }
    else
    {
        numPacketsAcked = 1;

        if(! conn_info.lossRecovery )
        {
            conn_info.dup_acks++;

            // We received three duplicate ACKS - enter the loss recovery stage.
            if(conn_info.dup_acks == 3)
            {
416
                //printf("Entering loss recovery for seq = %u\n", seqNum);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
417
418
419
420
421
422
423
424
425
                conn_info.lossRecovery = true;

                // Set the recovery point - multiple losses upto this point
                // will NOT result in multiple cong. window reductions.
                conn_info.recoveryPoint = conn_info.HighData;

                // Decrease the congestion window and slow start threshold.
                conn_info.ssthresh = unackedPackets.size() / 2;
                conn_info.congWindow = unackedPackets.size() / 2;
426
427
428
429
430
431
432
                if(conn_info.ssthresh < 2)
                {
                    conn_info.ssthresh = 2;
                    conn_info.congWindow = 2;
                }

                //printf("Setting ssthresh = %d\n", conn_info.ssthresh);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
433
434
435
436
            }
        }
    }

437
438
    unsigned long long measure1, measure2;
                 //       measure1 = getTimeMilli();
Pramod R Sanaga's avatar
Pramod R Sanaga committed
439
    UpdateSACKs(numSACKBlocks, dataPtr);
440
441
442
443
444
    /*
                        measure2 = getTimeMilli();
        if(measure2 - measure1 > 2)
            cout << " Spent " << measure2 - measure1 << " ms in select\n";
            */
Pramod R Sanaga's avatar
Pramod R Sanaga committed
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464

    SetPipe();

    // Congestion avoidance.
    if(conn_info.congWindow >= conn_info.ssthresh)
    {
        conn_info.congAvoidancePackets += numPacketsAcked;

        if(conn_info.congAvoidancePackets >= conn_info.congWindow)
        {
            conn_info.congWindow += 1.0;
            conn_info.congAvoidancePackets = 0;
        }
    }
    else // Slow Start
    {
//        printf("For seq # = %u,packets = %d, window before = %f ", seqNum,numPacketsAcked, conn_info.congWindow);
        conn_info.congWindow += numPacketsAcked;
  //      printf(", window after = %f\n", conn_info.congWindow);
    }
465
//    cout << "CongWin: " << conn_info.congWindow<< " "<< conn_info.ssthresh << " , outstanding=" <<conn_info.pipe << ", last Range = "<<conn_info.sackRanges.back().second<<endl;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
466
467
468
}


469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
unsigned long long getTimeMilli()
{
    struct timeval tp;
    gettimeofday(&tp, NULL);

    long long tmpSecVal = tp.tv_sec;
    long long tmpUsecVal = tp.tv_usec;

    return (tmpSecVal*1000 + tmpUsecVal/1000);
}

int getLinkLayer(struct pcap_pkthdr const *pcap_info, const u_char *pkt_data)
{
    unsigned int caplen = pcap_info->caplen;

    if (caplen < sizeof(struct ether_header))
    {
        printf("A captured packet was too short to contain "
                "an ethernet header");
        return -1;
    }
    else
    {
        struct ether_header * etherPacket = (struct ether_header *) pkt_data;
        return ntohs(etherPacket->ether_type);
    }
}

void pcapCallback(u_char *user, const struct pcap_pkthdr *pcap_info, const u_char *pkt_data)
{
    int packetType = getLinkLayer(pcap_info, pkt_data);

    if(packetType != ETHERTYPE_IP)
    {
        printf("Unknown link layer type: %d\n", packetType);
        return;
    }

    struct ip const *ipPacket;
    size_t bytesLeft = pcap_info->caplen - sizeof(struct ether_header);

    if(bytesLeft < sizeof(struct ip))
    {
        printf("Captured packet was too short to contain an IP header.\n");
        return;
    }

    ipPacket = (struct ip const *)(pkt_data + sizeof(struct ether_header));
    int ipHeaderLength = ipPacket->ip_hl;
    int ipVersion = ipPacket->ip_v;


    if(ipVersion != 4)
    {
        printf("Captured IP packet is not IPV4.\n");
        return;
    }

    if(ipHeaderLength < 5)
    {
        printf("Captured IP packet has header less than the minimum 20 bytes.\n");
        return;
    }

    if(ipPacket->ip_p != IPPROTO_UDP)
    {
        printf("Captured packet is not a UDP packet.\n");
        return;
    }

    // Ignore the IP options for now - but count their length.
    /////////////////////////////////////////////////////////
    u_char *udpPacketStart = (u_char *)(pkt_data + sizeof(struct ether_header) + ipHeaderLength*4);

    struct udphdr const *udpPacket;

    udpPacket = (struct udphdr const *)(udpPacketStart);

    bytesLeft -= ipHeaderLength*4;

    if(bytesLeft < sizeof(struct udphdr))
    {
        printf("Captured packet is too small to contain a UDP header.\n");
        return;
    }

    handleUDP(pcap_info,udpPacket,udpPacketStart, ipPacket);
}

Pramod R Sanaga's avatar
Pramod R Sanaga committed
558
void init_pcap( char *ipAddress, bool WriteFlag)
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
{
    char interface[] = "eth4";
    struct bpf_program bpfProg;
    char errBuf[PCAP_ERRBUF_SIZE];
    char filter[128] = " udp ";

    // IP Address and sub net mask.
    bpf_u_int32 maskp, netp;
    struct in_addr localAddress;

    pcapDescriptor = pcap_open_live(interface, 120, 0, 0, errBuf);

    if(pcapDescriptor == NULL)
    {
        printf("Error opening device %s with libpcap = %s\n", interface, errBuf);
        exit(1);
    }

Pramod R Sanaga's avatar
Pramod R Sanaga committed
577
578
579
580
581
582
    pcap_lookupnet(interface, &netp, &maskp, errBuf);
    localAddress.s_addr = netp;
    //printf("IP addr = %s\n", ipAddress);

    sprintf(filter," udp and ( (dst host %s and src port 9831 )) ", ipAddress);

583
584
585
586
587
588
589
590
591
592
593
594
595
596
    pcap_compile(pcapDescriptor, &bpfProg, filter, 1, netp);
    pcap_setfilter(pcapDescriptor, &bpfProg);
    pcap_setnonblock(pcapDescriptor, 1, errBuf);

}

void handleUDP(struct pcap_pkthdr const *pcap_info, struct udphdr const *udpHdr, u_char *const udpPacketStart, struct ip const *ipPacket)
{
    u_char *dataPtr = udpPacketStart + 8;

    char packetType = *(char *)(dataPtr);

    if(packetType == '0')
    {
Pramod R Sanaga's avatar
Pramod R Sanaga committed
597
        /*
598
599
600
601
602
603
604
605
606
607
608
609
610
611
        unsigned long seqNum = ( *(unsigned long *)(dataPtr + 1));
        unsigned long long currTime = getTimeMilli();

        unsigned long long secVal = pcap_info->ts.tv_sec;
        unsigned long long usecVal = pcap_info->ts.tv_usec;

        packetTimeMap[seqNum] = (unsigned long long)(secVal*1000 + usecVal/1000);

        // Set the retransmission timer.
        retransTimer = currTime + (unsigned long long)conn_info.rto_estimate;

        //cout<<"Sending seqNum "<<seqNum<<endl;

        unackedPackets.push_back(seqNum);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
612
        */
613
614
615
616
617
618
619
620
621
622

    }
    else if(packetType == '1')
    {
        // We received an ACK.
        int sackBlocks = (int)(*(char *)(dataPtr + 1));
        unsigned long seqNum = ( *(unsigned long *)(dataPtr + 2));
        reportedLost = ( *(unsigned long *)(dataPtr + 2 + sizeof(unsigned long)));
        highSeq = ( *(unsigned long *)(dataPtr + 2 + 2*sizeof(unsigned long)));

Pramod R Sanaga's avatar
Pramod R Sanaga committed
623
        int sackStart = 2 + 3*sizeof(unsigned long);
624

Pramod R Sanaga's avatar
Pramod R Sanaga committed
625
626
627
628
        unsigned long long recvTime = pcap_info->ts.tv_sec*1000 + pcap_info->ts.tv_usec/1000;
        //cout << "Received an ACK for "<<seqNum<<endl;
        Update(seqNum, sackBlocks, (dataPtr + sackStart), recvTime);
    //    Update(seqNum, sackBlocks, (dataPtr + sackStart), pcap_info);
629

Pramod R Sanaga's avatar
Pramod R Sanaga committed
630
631
632
633
634
635
636
    }
    else
    {
        printf("ERROR: Unknown UDP packet received from remote agent\n");
        return;
    }
}
637

638
void handlePacket(u_char *const dataPtr, unsigned long long recvTime, bool newPacketTx)
Pramod R Sanaga's avatar
Pramod R Sanaga committed
639
640
{
    char packetType = *(char *)(dataPtr);
641

Pramod R Sanaga's avatar
Pramod R Sanaga committed
642
643
644
645
    if(packetType == '0')
    {
        unsigned long seqNum = ( *(unsigned long *)(dataPtr + 1));
       // unsigned long long currTime = getTimeMilli();
646

Pramod R Sanaga's avatar
Pramod R Sanaga committed
647
648
     //   unsigned long long secVal = pcap_info->ts.tv_sec;
      //  unsigned long long usecVal = pcap_info->ts.tv_usec;
649

Pramod R Sanaga's avatar
Pramod R Sanaga committed
650
       // packetTimeMap[seqNum] = (unsigned long long)(secVal*1000 + usecVal/1000);
651

Pramod R Sanaga's avatar
Pramod R Sanaga committed
652
653
        // Set the retransmission timer.
        //retransTimer = currTime + (unsigned long long)conn_info.rto_estimate;
654

655
      //  cout<<"Sending seqNum "<<seqNum<<endl;
656

657
658
        if(newPacketTx)
            unackedPackets.push_back(seqNum);
659

Pramod R Sanaga's avatar
Pramod R Sanaga committed
660
661
662
663
    }
    else if(packetType == '1')
    {
        // We received an ACK.
664
        ackCount++;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
665
666
667
668
        int sackBlocks = (int)(*(char *)(dataPtr + 1));
        unsigned long seqNum = ( *(unsigned long *)(dataPtr + 2));
        reportedLost = ( *(unsigned long *)(dataPtr + 2 + sizeof(unsigned long)));
        highSeq = ( *(unsigned long *)(dataPtr + 2 + 2*sizeof(unsigned long)));
669

670
671
672
673
674
675
676
677
        /*
        if(sackBlocks == 0)
            cout << "Received an ACK for "<<seqNum<<endl;
        else
            cout << "HigSeq = "<<highSeq<<endl;
            */
        highSeq = ( *(unsigned long *)(dataPtr + 2 + 2*sizeof(unsigned long)));

Pramod R Sanaga's avatar
Pramod R Sanaga committed
678
        int sackStart = 2 + 3*sizeof(unsigned long);
679

Pramod R Sanaga's avatar
Pramod R Sanaga committed
680
        Update(seqNum, sackBlocks, (dataPtr + sackStart), recvTime);
681

682

683
684
685
686
687
688
689
    }
    else
    {
        printf("ERROR: Unknown UDP packet received from remote agent\n");
        return;
    }
}
Pramod R Sanaga's avatar
Pramod R Sanaga committed
690
int xmit_packet(u_char *message, int messageLen)
691
692
693
694
695
696
697
698
699
700
701
702
{

    int flags = 0;

    return sendto(clientSocket, message, messageLen, flags,
            (struct sockaddr *) &remoteServAddr,
            sizeof(remoteServAddr));
}

int main(int argc, char **argv)
{
    int rc, i, n, flags = 0;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
703
    socklen_t echoLen = 0;
704
705
    struct sockaddr_in servAddr, localHostAddr;
    struct hostent *host1, *localhostEnt;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
706
    u_char msg[2000];
707
708
709
710
711
712
713
714
715
716

    string localHostName = argv[1];
    string hostName = argv[2];
    int portNum = atoi(argv[3]);
    unsigned long long connDuration = atoi(argv[4]); 

    localhostEnt = gethostbyname(argv[1]);
    memcpy((char *) &localHostAddr.sin_addr.s_addr,
            localhostEnt->h_addr_list[0], localhostEnt->h_length);

717
    /*
Pramod R Sanaga's avatar
Pramod R Sanaga committed
718
719
    init_pcap(inet_ntoa(localHostAddr.sin_addr), true);
    int pcapfd = pcap_get_selectable_fd(pcapDescriptor);
720
721
722
    */


Pramod R Sanaga's avatar
Pramod R Sanaga committed
723
724
725
726
727
    /*
    init_pcap(inet_ntoa(localHostAddr.sin_addr), false);
    int pcapfd_read = pcap_get_selectable_fd(pcapDescriptor_Read);
    int pcapfd_write = pcap_get_selectable_fd(pcapDescriptor_Write);
    */
728

729
    clientSocket = socket(PF_INET, SOCK_DGRAM, 0);
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748

    fcntl(clientSocket, F_SETFL, flags | O_NONBLOCK);

    host1 = NULL;
    host1 = gethostbyname(hostName.c_str());
    if(host1 == NULL)
    {
        printf("ERROR: Unknown host %s\n", hostName.c_str());
        exit(1);
    }

    remoteServAddr.sin_family = host1->h_addrtype;
    memcpy((char *) &remoteServAddr.sin_addr.s_addr,
            host1->h_addr_list[0], host1->h_length);
    remoteServAddr.sin_port = htons(REMOTE_SERVER_PORT);

    startTime = getTimeMilli();
    unsigned long long lastSentTime = startTime;
    unsigned long long lastPrintTime = startTime;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
749
    u_char messageString[1458];
750
751
752
753
754
    fd_set socketReadSet, socketWriteSet;

    // Initialize the congestion window and slow start threshold.
    conn_info.congWindow = 2.0;
    conn_info.ssthresh = 65000;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
755
756
757
758
    conn_info.HighACK = 0;
    conn_info.HighData = 0;
    conn_info.pipe = 0;
    conn_info.dup_acks = 0;
759
760

    // Initialize the timeout value to be one second.
761
762
    conn_info.rto_estimate = 3000;
    conn_info.rtt_est = 3000;
763
764
    conn_info.rtt_deviation_est = 0;
    retransTimer = 0;
765
    conn_info.sackEdge = 0;
766
767
768
769
770
771
772
773
774
775
776

    connDuration *= 1000;
    rexmitMap.clear();
    packetTimeMap.clear();

    // Used for passing along the timeout information to the retransmission part of the code.
    bool timeoutFlag = false;

    reportedLost = 0;
    highSeq = 0;

Pramod R Sanaga's avatar
Pramod R Sanaga committed
777
    /*
778
779
780
781
    struct pcap_stat pcapStatObj;
    {
        int bufferSize = 0;
        socklen_t buflen = sizeof(bufferSize);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
782
        int retVal = getsockopt( pcapfd_read, SOL_SOCKET, SO_RCVBUF, 
783
784
785
786
                &bufferSize, &buflen);
        printf("Retval = %d, Recv buffer size = %d bytes\n", retVal, bufferSize);

    }
Pramod R Sanaga's avatar
Pramod R Sanaga committed
787
788
    */

789
    struct timeval timeoutStruct, writeTimeout;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
790
791

    timeoutStruct.tv_sec = 0;
792
793
794
795
    timeoutStruct.tv_usec = 20000;

    writeTimeout.tv_sec = 0;
    writeTimeout.tv_usec = 2000;
796

797
798
799
800
    unsigned long long measure1, measure2;
    unsigned long long recvTime = getTimeMilli();

    while ( ( ( lastSentTime - startTime) < connDuration) && (( recvTime - startTime) < connDuration))
801
802
803
    {
        FD_ZERO(&socketReadSet);
        FD_SET(clientSocket,&socketReadSet);
804
        //FD_SET(pcapfd,&socketReadSet);
805

Pramod R Sanaga's avatar
Pramod R Sanaga committed
806
        //select(clientSocket+pcapfd_read+pcapfd_write+1,&socketReadSet,&socketWriteSet,0,&timeoutStruct);
807
808
809
        //select(clientSocket+1,&socketReadSet,&socketWriteSet,0,&timeoutStruct);
        select(clientSocket+1,&socketReadSet,NULL,0,&timeoutStruct);

Pramod R Sanaga's avatar
Pramod R Sanaga committed
810
        //select(pcapfd+clientSocket+1,&socketReadSet,&socketWriteSet,0,&timeoutStruct);
811

Pramod R Sanaga's avatar
Pramod R Sanaga committed
812
        /*
813
814
        if (FD_ISSET(pcapfd,&socketReadSet) )
        {
Pramod R Sanaga's avatar
Pramod R Sanaga committed
815
816
817
818
819
820
821
822
823
          //  while(pcap_dispatch(pcapDescriptor, 100, pcapCallback, NULL) != 0);
            pcap_dispatch(pcapDescriptor, 10000, pcapCallback, NULL);
        }
        */
        /*
        if (FD_ISSET(pcapfd_write,&socketReadSet) )
        {
            //while(pcap_dispatch(pcapDescriptor, 10000, pcapCallback, NULL) != 0);
            pcap_dispatch(pcapDescriptor_Write, 10000, pcapCallback, NULL);
824
        }
Pramod R Sanaga's avatar
Pramod R Sanaga committed
825
        */
826
827
828

        if (FD_ISSET(clientSocket,&socketReadSet) )
        {
829
830
            recvTime = getTimeMilli();
            //cout << recvTime - startTime << " " << conn_info.congWindow<< " "<< conn_info.ssthresh << " , outstanding=" <<conn_info.pipe <<", reportedLost = "<<reportedLost<<endl;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
831
832
            //memset(msg, 0x0, 100);
            int retval = 1;
833
            flags = 0;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
834

835
       //     cout<<"Into recv at "<<recvTime - startTime<<endl;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
836
            //while( (retval = recvfrom(clientSocket, (void *)msg, MAX_MSG, flags,(struct sockaddr *) &servAddr, &echoLen) ) > 0)
837
838
         //   do
            {
Pramod R Sanaga's avatar
Pramod R Sanaga committed
839
840
                retval = recvfrom(clientSocket, (void *)msg, 75, flags,(struct sockaddr *) &servAddr, &echoLen) ;
                if(retval > 0)
841
                {
842
                    /*
Pramod R Sanaga's avatar
Pramod R Sanaga committed
843
844
845
846
847
                    if(retval > 120)
                    {
                        printf("ERROR, packet size = %d\n",retval);
                        exit(1);
                    }
848
849
                    */
                    handlePacket(msg, recvTime,false);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
850
                    //memset(msg, 0x0, 100);
851
                }
852
                /*
853
                else
Pramod R Sanaga's avatar
Pramod R Sanaga committed
854
855
856
857
858
                {
                 //   printf("Retval = %d\n",retval);
                  //  printf("ERRNO = %d\n", errno);
                }
                //pcap_dispatch(pcapDescriptor, 300, pcapCallback, NULL);
859
                */
860
            }
861
862
863
864
        //    while(retval > 0);

        //    recvTime = getTimeMilli();
         //   cout<<"Out of recv at "<<recvTime - startTime<<endl;
Pramod R Sanaga's avatar
Pramod R Sanaga committed
865

866
867
        }

868
        if( (conn_info.congWindow - conn_info.pipe >= 1.0) || timeoutFlag ) 
869
        {
870
871
            FD_ZERO(&socketWriteSet);
            FD_SET(clientSocket,&socketWriteSet);
872

873
            select(clientSocket+1,NULL,&socketWriteSet,0,&writeTimeout);
874

875
876
877
878
            if (FD_ISSET(clientSocket,&socketWriteSet) != 0)
            {
                unsigned long long currTime;
                unsigned long nextSeq;
879

880
                currTime = getTimeMilli();
881

882
883
                // Send a packet as long as the oustanding data is less than cong. window
                while( (conn_info.congWindow - conn_info.pipe >= 1.0) || timeoutFlag ) 
884
                {
885
                    nextSeq = NextSeq(timeoutFlag);
886
887


888
889
890
                    memset(messageString, 0x0, 100);
                    // Data packet.
                    messageString[0] = '0';
891

892
893
                    // Copy the sequence number into the packet data.
                    memcpy(&messageString[1], &nextSeq, sizeof(unsigned long));
894

895
                    rc = xmit_packet(messageString, 1458);
Pramod R Sanaga's avatar
Pramod R Sanaga committed
896

897
898
899
                    if(rc <= 0)
                        break;
                    else
900
                    {
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
                        //Record a timestamp for the packet. This is less accurate than
                        // the libpcap timestamp, but serves as a backup if we fail to
                        // catch this packet on the way out due to libpcap buffer overflow.

                        // In the most common case, this is going to be revised when the
                        // packet is recorded by the libpcap filter function.
                        packetTimeMap[conn_info.HighData] = currTime;

                        retransTimer = currTime + (long long)conn_info.rto_estimate;

                        // Reduce the congestion window to '1' on a timeout.
                        if(timeoutFlag)
                        {
                            conn_info.ssthresh = unackedPackets.size()/2;
                            if(conn_info.ssthresh < 2)
                                conn_info.ssthresh = 2;

                            conn_info.congWindow = 1;

                            timeoutFlag = false;
                            printf("Timed out\n");

                            conn_info.rto_estimate *= 2;

                            if(conn_info.rto_estimate > 60)
                                conn_info.rto_estimate = 60;
                        }

                        //cout << "Transmitting # "<<conn_info.HighData<<", Time = "<<currTime - startTime<<endl;
                        // This is a new packet, increment the sequence number.
                        if(nextSeq > conn_info.HighData)
                        {
                            conn_info.HighData = nextSeq;
                            conn_info.pipe++;
                            handlePacket(messageString, currTime,true);
                        }
                        else if( (nextSeq > conn_info.HighRxt) && conn_info.lossRecovery )
                        {
                            conn_info.HighRxt = nextSeq;

                            // Mark this as a retransmitted packet - doesn't count
                            // towards RTT/RTO calculation.
                            rexmitMap[nextSeq] = true;
                            handlePacket(messageString, currTime,false);
                        }

                        // Recalculate the number of outstanding packets.
                        //    SetPipe();
949
950
951
                    }
                }

952
953
                //////////////////////////
                //pcap_dispatch(pcapDescriptor, 10000, pcapCallback, NULL);
954
955
956



957
                //cout << "Last sent at time = "<<lastSentTime - startTime<<endl;
958
            }
959
960
961
962
963
964
965
        }

        lastSentTime = getTimeMilli();
        // Check the retransmission timer.
        if(retransTimer < lastSentTime || retransTimer < recvTime)
        {
            timeoutFlag = true;
966

967
968
            // Start retransmitting from the first unacked packet.
            conn_info.HighRxt = conn_info.HighACK;
969
970
        }

971
        /*
Pramod R Sanaga's avatar
Pramod R Sanaga committed
972
        if( (lastSentTime - lastPrintTime) >= 100)
973
        {
Pramod R Sanaga's avatar
Pramod R Sanaga committed
974
975
976
            cout << lastSentTime - startTime << " " << conn_info.congWindow<< " "<< conn_info.ssthresh << " , outstanding=" <<conn_info.pipe <<", reportedLost = "<<reportedLost<<endl;
            //pcap_stats(pcapDescriptor_Read, &pcapStatObj);
            //if(pcapStatObj.ps_drop > 0)
977
            //   printf("pcap: Packets received %d, dropped %d\n", pcapStatObj.ps_recv, pcapStatObj.ps_drop);
978
979
            lastPrintTime = lastSentTime;
        }
980
981
982
983
984
985
986
987
988
989
990
        */
        /*
        if( (recvTime - lastPrintTime) >= 100)
        {
//            cout << recvTime - startTime << " " << conn_info.congWindow<< " "<< conn_info.ssthresh << " , outstanding=" <<conn_info.pipe <<", reportedLost = "<<reportedLost<<endl;
            //pcap_stats(pcapDescriptor_Read, &pcapStatObj);
            //if(pcapStatObj.ps_drop > 0)
            //   printf("pcap: Packets received %d, dropped %d\n", pcapStatObj.ps_recv, pcapStatObj.ps_drop);
            lastPrintTime = recvTime;
        }
        */
Pramod R Sanaga's avatar
Pramod R Sanaga committed
991

992
993
994
995
    }

    close(clientSocket);

Pramod R Sanaga's avatar
Pramod R Sanaga committed
996
    //double tput = (double)conn_info.HighACK/(double)connDuration;
997
998
    //double tput = (double)(conn_info.HighACK - reportedLost)/(double)connDuration;
    double tput = (double)(conn_info.HighData - unackedPackets.size())/(double)connDuration;
999
1000
    tput *= (1500*8);

For faster browsing, not all history is shown. View entire blame