Statistics
| Branch: | Revision:

napa-baselibs / ml / util / udpSocket.c @ 612e856d

History | View | Annotate | Download (14.1 KB)

1
/*
2
 *          Policy Management
3
 *
4
 *          NEC Europe Ltd. PROPRIETARY INFORMATION
5
 *
6
 * This software is supplied under the terms of a license agreement
7
 * or nondisclosure agreement with NEC Europe Ltd. and may not be
8
 * copied or disclosed except in accordance with the terms of that
9
 * agreement.
10
 *
11
 *      Copyright (c) 2009 NEC Europe Ltd. All Rights Reserved.
12
 *
13
 * Authors: Kristian Beckers  <beckers@nw.neclab.eu>
14
 *          Sebastian Kiesel  <kiesel@nw.neclab.eu>
15
 *          
16
 *
17
 * NEC Europe Ltd. DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED,
18
 * INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY
19
 * AND FITNESS FOR A PARTICULAR PURPOSE AND THE WARRANTY AGAINST LATENT
20
 * DEFECTS, WITH RESPECT TO THE PROGRAM AND THE ACCOMPANYING
21
 * DOCUMENTATION.
22
 *
23
 * No Liability For Consequential Damages IN NO EVENT SHALL NEC Europe
24
 * Ltd., NEC Corporation OR ANY OF ITS SUBSIDIARIES BE LIABLE FOR ANY
25
 * DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS
26
 * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF INFORMATION, OR
27
 * OTHER PECUNIARY LOSS AND INDIRECT, CONSEQUENTIAL, INCIDENTAL,
28
 * ECONOMIC OR PUNITIVE DAMAGES) ARISING OUT OF THE USE OF OR INABILITY
29
 * TO USE THIS PROGRAM, EVEN IF NEC Europe Ltd. HAS BEEN ADVISED OF THE
30
 * POSSIBILITY OF SUCH DAMAGES.
31
 *
32
 *     THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
33
 */
34

    
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <unistd.h>
38
#include <errno.h>
39
#include <string.h>
40
#include <sys/time.h>
41

    
42
#include <event2/event.h>
43
#ifndef WIN32
44
/* For sockaddr_in */
45
#include <netinet/in.h>
46
/* For socket functions */
47
#include <sys/socket.h>
48
/* For fcntl */
49
#include <fcntl.h>
50
#include <sys/uio.h>
51
#include <arpa/inet.h>
52
#include <resolv.h>
53
#include <sys/socket.h>
54
#include <netdb.h>
55

    
56
#ifdef __linux__
57
#include <linux/types.h>
58
#include <linux/errqueue.h>
59
#include <linux/if.h>
60
#include <ifaddrs.h>
61
#else 
62
#define MSG_ERRQUEUE 0
63
#endif
64

    
65
#else
66
#include <winsock2.h>
67
#endif
68

    
69

    
70

    
71

    
72
#include "udpSocket.h"
73

    
74
#define LOG_MODULE "[ml] "
75
#include "ml_log.h"
76

    
77
#include "rateLimiter.h"
78
#include "queueManagement.h"
79

    
80
/* debug varible: set to 1 if you want debug output  */
81
int verbose = 0;
82

    
83
int createSocket(const int port,const char *ipaddr)
84
{
85
  /* variables needed */
86
  struct sockaddr_in udpsrc, udpdst;
87

    
88
  int returnStatus = 0;
89
  debug("X.CreateSock %s %d\n",ipaddr, port);
90

    
91
  bzero((char *)&udpsrc, sizeof udpsrc);
92
  bzero((char *)&udpdst, sizeof udpsrc);
93

    
94
  //int udpSocket = 0;
95
  /*libevent2*/
96
  evutil_socket_t udpSocket;
97

    
98
  /* create a socket */
99
  udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
100

    
101
  /*libevent2*/
102
  evutil_make_socket_nonblocking(udpSocket);
103

    
104
  //This is debug code that checks if the socket was created
105
  if (udpSocket == -1)
106
    {
107
      error("Could not create an UDP socket! ERRNO %d\n",errno);
108
      return -1;
109
    }
110

    
111
  /* sets the standard server address and port */
112
  udpsrc.sin_family = AF_INET;
113
  udpsrc.sin_addr.s_addr = htonl(INADDR_ANY);
114
  udpsrc.sin_port = 0;
115

    
116
  /* sets a destinantion address  */
117
  udpdst.sin_family = AF_INET;
118
  udpdst.sin_addr.s_addr = htonl(INADDR_ANY);
119
  udpdst.sin_port = 0;
120

    
121
  /* set the address  */
122
  if (ipaddr == NULL)
123
    {
124
      udpsrc.sin_port = htons(port);
125
    }else{
126
      udpsrc.sin_addr.s_addr = inet_addr(ipaddr);
127
      udpsrc.sin_port = htons(port);
128
    }
129

    
130
  /* bind to the socket */
131
  returnStatus = bind(udpSocket,(struct sockaddr *)&udpsrc,sizeof(udpsrc));
132

    
133
  /* This is debug code */
134
  if (returnStatus) {
135
    error("Could not bind socketID to address! ERRNO %d\n",errno);
136
    return -2;
137
  }
138
#ifdef IP_MTU_DISCOVER
139

    
140
  int yes = 1;
141
  int size = sizeof(int);
142
  int pmtuopt = IP_PMTUDISC_DO;
143

    
144
  /*Setting the automatic PMTU discoery function from the socket
145
   * This sets the DON'T FRAGMENT bit on the IP HEADER
146
   */
147
  if(setsockopt(udpSocket,IPPROTO_IP,IP_MTU_DISCOVER,&pmtuopt ,size) == -1){
148
    error("setsockopt: set IP_DONTFRAG did not work. ERRNO %d\n",errno);
149

    
150
  }
151

    
152
  /* This option writes the IP_TTL field into ancillary data */
153
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVTTL, &yes,size) < 0)
154
    {
155
      error("setsockopt: cannot set RECV_TTL. ERRNO %d\n",errno);
156
    }
157

    
158
  /* This option writes received internal and external(icmp) error messages into ancillary data */
159

    
160
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVERR, &yes,size) < 0) {
161
        error("setsockopt: cannot set RECV_ERROR. ERRNO %d\n",errno);
162
    }
163

    
164
#endif
165

    
166
  debug("X.CreateSock\n");
167
  return udpSocket;
168

    
169
}
170

    
171
#ifndef WIN32
172
/* Information: read the standard TTL from a socket  */
173
int getTTL(const int udpSocket,uint8_t *ttl){
174
#ifdef MAC_OS
175
        return 0;
176
#else
177

    
178
        unsigned int value;
179
        unsigned int size = sizeof(value);
180

    
181
        if(getsockopt(udpSocket,SOL_IP,IP_TTL,&value,&size) == -1){
182
                error("get TTL did not work\n");
183
                return 0;
184
        }
185

    
186
        *ttl = value;
187
        if(verbose == 1) debug("TTL is %i\n",value);
188

    
189
        return 1;
190
#endif
191
}
192

    
193
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
194
{
195
        int error, ret;
196
        struct msghdr msgh;
197

    
198
        msgh.msg_name = socketaddr;
199
        msgh.msg_namelen = sizeof(struct sockaddr_in);
200
        msgh.msg_iov = iov;
201
        msgh.msg_iovlen = len;
202
        msgh.msg_flags = 0;
203

    
204
        /* we do not send ancilliary data  */
205
        msgh.msg_control = 0;
206
        msgh.msg_controllen = 0;
207

    
208
        /* send the message  */
209
        ret = sendmsg(udpSocket,&msgh,0);
210
        if (ret  < 0){
211
                error = errno;
212
                info("ML: sendmsg failed errno %d: %s\n", error, strerror(error));
213
                switch(error) {
214
                        case EMSGSIZE:
215
                                return MSGLEN;
216
                        default:
217
                                return FAILURE;
218
                }
219
        }
220
        return OK;
221
}
222

    
223
/* A general error handling function on socket operations
224
 * that is called when sendmsg or recvmsg report an Error
225
 *
226
 */
227

    
228
//This function has to deal with what to do when an icmp is received
229
//--check the connection array, look to which connection-establishment the icmp belongs
230
//--invoke a retransmission
231
int handleSocketError(const int udpSocket,const int iofunc,char *buf,int *bufsize,struct sockaddr_in *addr,icmp_error_cb icmpcb_value,int *ttl){
232

    
233

    
234
        if(verbose == 1) debug("handle Socket error is called\n");
235

    
236
        /* variables  */
237
        struct msghdr msgh;
238
        struct cmsghdr *cmsg;
239
        struct sock_extended_err *errptr;
240
        struct iovec iov;
241
        struct sockaddr_in sender_addr;
242
        int returnStatus;
243
        char errbuf[CMSG_SPACE(1024)];
244
        int recvbufsize = 1500;
245
        char recvbuf[recvbufsize];
246
        int icmp = 0;
247

    
248
        /* initialize recvmsg data  */
249
        msgh.msg_name = &sender_addr;
250
        msgh.msg_namelen = sizeof(struct sockaddr_in);
251
        msgh.msg_iov = &iov;
252
        msgh.msg_iovlen = 1;
253
        msgh.msg_iov->iov_base = recvbuf;
254
        msgh.msg_iov->iov_len = recvbufsize;
255
        msgh.msg_flags = 0;
256

    
257
        //set the size of the control data
258
        msgh.msg_control = errbuf;
259
        msgh.msg_controllen = sizeof(errbuf);
260
        //initialize pointer
261
        errptr = NULL;
262

    
263
        /* get the error from the error que:  */
264
        returnStatus = recvmsg(udpSocket,&msgh,MSG_ERRQUEUE|MSG_DONTWAIT);
265
        if (returnStatus <= 0) {
266
                return -1;
267
        }
268
        for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)){
269
#ifdef __linux__
270
                //fill the error pointer
271
                if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVERR) {
272
                        errptr = (struct sock_extended_err *)CMSG_DATA(cmsg);
273
//                        if (errptr == NULL){
274
//                        if(verbose == 1)
275
//                                error("no acillary error data \n");
276
//             return -1;
277
//                }
278
                /* check if the error originated locally */
279
                        if (errptr->ee_origin == SO_EE_ORIGIN_LOCAL){
280
                                if (errptr->ee_errno != EMSGSIZE) {
281
                                        if(verbose == 1)
282
                                                error("local error: %s \n", strerror(errptr->ee_errno));
283
                                }
284
                        }
285
                        /* check if the error originated from an icmp message  */
286
                        if (errptr->ee_origin == SO_EE_ORIGIN_ICMP){
287
                                char sender_addr_str[INET_ADDRSTRLEN];
288
                                if(verbose == 1)
289
                                        debug("icmp error message received\n");
290

    
291
                                int type = errptr->ee_type;
292
                                int code = errptr->ee_code;
293
                                icmp = 1;
294
                                inet_ntop(AF_INET, &(sender_addr.sin_addr.s_addr), sender_addr_str, INET_ADDRSTRLEN);
295
                                warn("icmp error message from %s:%d is type: %d code %d\n",
296
                                        sender_addr_str,ntohs(sender_addr.sin_port),
297
                                        errptr->ee_type,errptr->ee_code);
298

    
299
                                /* raise the pmtu callback when an pmtu error occurred
300
                                *  -> icmp message type 3 code 4 icmp
301
                                */
302

    
303
                                if (type == 3 && code == 4){
304
                                        if(verbose == 1)
305
                                                debug("pmtu error message received\n");
306

    
307
                                        int mtusize = *bufsize;
308
                                        (icmpcb_value)(buf,mtusize);
309
                                }
310
                        }
311
                }
312
#endif
313
            ;
314
        } //end of for
315

    
316
        /* after the error is read from the socket error queue the
317
        * socket operation that was interrupeted by reading the error queue
318
        * has to be carried out
319
        */
320

    
321
        //error("socketErrorHandle: before iofunc loop \n");
322
/* @TODO commented the next section because some errors are not rcoverable. ie error code EAGAIN means no dtata is available and even if you retry the eroor most probably persists (no dtata arrived in the mena time) causing recorsive callings and subsequent seg fault probably due to stack overflow
323
better error handling might be needed */
324
#if 0
325
        int transbuf;
326
        memcpy(&transbuf,bufsize,4);
327

328
        if(iofunc == 1) {
329
                sendPacket(udpSocket,buf,transbuf,addr,icmpcb_value);
330
                if(verbose == 1)
331
                        error("handle socket error: packetsize %i \n ",*bufsize );
332
        } else {
333
                if(iofunc == 2 && icmp == 1){
334
                        if(verbose == 1)
335
                                error("handleSOcketError: recvPacket called \n ");
336
                        recvPacket(udpSocket,buf,bufsize,addr,icmpcb_value,ttl);
337
                } else {
338
                /* this is the case the socket has just an error message not related to anything of the messaging layer */
339
                        if(verbose == 1)
340
                                error("handleSocketError: unrelated error \n");
341
                        *ttl = -1;
342
                }
343
        }
344
#endif
345
        return 0;
346
}
347

    
348

    
349

    
350
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
351
{
352

    
353
        /* variables  */
354
        struct msghdr msgh; 
355
        struct cmsghdr *cmsg;
356
        int *ttlptr;
357
        int received_ttl;
358
        struct iovec iov;
359
        //struct sockaddr_in sender_addr;
360
        //unsigned int sender_len;
361
        int returnStatus;
362
        
363
        /* initialize recvmsg data  */
364
        msgh.msg_name = udpdst;
365
        msgh.msg_namelen = sizeof(struct sockaddr_in);
366
        msgh.msg_iov = &iov;
367
        msgh.msg_iovlen = 1;
368
        msgh.msg_iov->iov_base = buffer;
369
        msgh.msg_iov->iov_len = *recvSize;
370
        msgh.msg_flags = 0;
371
        
372
        /*
373
        *  This shows the receiving of TTL within the ancillary data of recvmsg
374
        */
375
        
376
        // ancilliary data buffer 
377
        char ttlbuf[CMSG_SPACE(sizeof(int))];
378
        
379
        //set the size of the control data
380
        msgh.msg_control = ttlbuf;
381
        msgh.msg_controllen = sizeof(ttlbuf);
382

    
383
        returnStatus = recvmsg(udpSocket,&msgh,0);
384
        msgh.msg_iov->iov_len = returnStatus;
385

    
386
        *recvSize = returnStatus;
387
        /* receive the message */
388
        if (returnStatus < 0) {
389
                if(verbose == 1) {
390
                        error("udpSocket:recvPacket: Read the error queue \n ");
391
                        error("recvmsg failed. errno %d \n",errno);
392
                }
393
                // TODO debug code: delete afterwards start
394
                if(errno == 11) {        //TODO: What is this 11, and why is it here with a NOP?
395
                        int a;
396
                        a++;
397
                };
398
                // end
399
                handleSocketError(udpSocket,2,buffer,recvSize,udpdst,icmpcb_value,ttl);
400

    
401
        } else {
402
                /* debug code  */
403
                if(verbose == 1)
404
                        debug("udpSocket_recvPacket: Message received.\n");
405

    
406
                for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
407
                        if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) {
408
                                ttlptr = (int *) CMSG_DATA(cmsg);
409
                                received_ttl = *ttlptr;
410
                                memcpy(ttl,ttlptr,4);
411
                                if(verbose == 1)
412
                                        debug("received ttl true: %i  \n ",received_ttl);
413
                                break;
414
                        }
415
                }
416
        }
417
}
418

    
419

    
420
int closeSocket(int udpSocket)
421
{
422

    
423
  /*cleanup */
424
  close(udpSocket);
425
  return 0;
426

    
427
}
428

    
429
const char *mlAutodetectIPAddress() {
430
        static char addr[128] = "";
431
#ifdef __linux__
432

    
433
        FILE *r = fopen("/proc/net/route", "r");
434
        if (!r) return NULL;
435

    
436
        char iface[IFNAMSIZ] = "";
437
        char line[128] = "x";
438
        while (1) {
439
                char dst[32];
440
                char ifc[IFNAMSIZ];
441

    
442
                char *dummy = fgets(line, 127, r);
443
                if (feof(r)) break;
444
                if ((sscanf(line, "%s\t%s", iface, dst) == 2) && !strcpy(dst, "00000000")) {
445
                        strcpy(iface, ifc);
446
                         break;
447
                }
448
        }
449
        if (iface[0] == 0) return NULL;
450

    
451
        struct ifaddrs *ifAddrStruct=NULL;
452
        if (getifaddrs(&ifAddrStruct)) return NULL;
453

    
454
        while (ifAddrStruct) {
455
                if (ifAddrStruct->ifa_addr && ifAddrStruct->ifa_addr->sa_family == AF_INET &&
456
                        ifAddrStruct->ifa_name && !strcmp(ifAddrStruct->ifa_name, iface))  {
457
                        void *tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
458
                        return inet_ntop(AF_INET, tmpAddrPtr, addr, 127);
459
                }
460
        ifAddrStruct=ifAddrStruct->ifa_next;
461
        }
462
#else
463
       {
464
                char namebuf[256];
465
                if(gethostname(namebuf, sizeof(namebuf))) {
466
                  perror("Error getting hostname");
467
                  return NULL;
468
                }
469
printf("Hostname is %s\n", namebuf);
470
                struct hostent *he = gethostbyname(namebuf);
471
                if(he == NULL) return NULL;
472
printf("Hostaddr: %x\n", *((unsigned int *)(he->h_addr)));
473
                return inet_ntop(AF_INET, he->h_addr, addr, 127);
474
       }
475
#endif
476
        return NULL;
477
}
478
#else  // WINDOWS
479

    
480
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
481
{
482
  char stack_buffer[1600];
483
  char *buf = stack_buffer;
484
  int i;
485
  int total_len = 0;
486
  int ret;
487
  for(i = 0; i < len; i++) total_len += iov[i].iov_len;
488

    
489
  if(outputRateControl(total_len) != OK) return THROTTLE;
490

    
491
  if(total_len > sizeof(stack_buffer)) {
492
     warn("sendPacket total_length %d requires dynamically allocated buffer", total_len);
493
     buf = malloc(total_len);
494
  }
495
  total_len = 0;
496
  for(i = 0; i < len; i++) {
497
     memcpy(buf+total_len, iov[i].iov_base, iov[i].iov_len);
498
     total_len += iov[i].iov_len;
499
  } 
500
  ret = sendto(udpSocket, buf, total_len, 0, (struct sockaddr *)socketaddr, sizeof(*socketaddr));
501
debug("Sent %d bytes (%d) to %d\n",ret, WSAGetLastError(), udpSocket);
502
  if(buf != stack_buffer) free(buf);
503
  return ret == total_len ? OK:FAILURE; 
504
}
505

    
506
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
507
{
508
fprintf(stderr,"X.RECV\n");
509
  int salen = sizeof(struct sockaddr_in);
510
  int ret;
511
  ret = recvfrom(udpSocket, buffer, *recvSize, 0, (struct sockaddr *)udpdst, &salen);
512
  if(ret > 0) *recvSize = ret;
513
  *ttl=10;
514
}
515

    
516
int getTTL(const int udpSocket,uint8_t *ttl){
517
  return 64;
518
}
519

    
520
const char *mlAutodetectIPAddress() {
521
  return NULL;
522
}
523

    
524

    
525
const char *inet_ntop(int af, const void *src,
526
       char *dst, size_t size) {
527
    char *c = inet_ntoa(*(struct in_addr *)src);
528
    if(strlen(c) >= size) return NULL;
529
    return strcpy(dst, c);
530
}
531
int inet_pton(int af, const char * src, void *dst) {
532
    unsigned long l = inet_addr(src);
533
    if(l == INADDR_NONE) return 0;
534
    *(unsigned long *)dst = l;
535
    return 1;
536
}
537
#endif