Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ 81c60962

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
/* debug varible: set to 1 if you want debug output  */
78
int verbose = 0;
79

    
80
int createSocket(const int port,const char *ipaddr)
81
{
82
  /* variables needed */
83
  struct sockaddr_in udpsrc, udpdst;
84

    
85
  int returnStatus = 0;
86
  debug(stderr,"X.CreateSock %s %d\n",ipaddr, port);
87

    
88
  //int udpSocket = 0;
89
  /*libevent2*/
90
  evutil_socket_t udpSocket;
91

    
92
  /* create a socket */
93
  udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
94

    
95
  /*libevent2*/
96
  evutil_make_socket_nonblocking(udpSocket);
97

    
98
  //This is debug code that checks if the socket was created
99
  if (udpSocket == -1)
100
    {
101
      error("Could not create an UDP socket! ERRNO %d\n",errno);
102
      return -1;
103
    }
104

    
105
  /* sets the standard server address and port */
106
  udpsrc.sin_family = AF_INET;
107
  udpsrc.sin_addr.s_addr = htonl(INADDR_ANY);
108
  udpsrc.sin_port = 0;
109

    
110
  /* sets a destinantion address  */
111
  udpdst.sin_family = AF_INET;
112
  udpdst.sin_addr.s_addr = htonl(INADDR_ANY);
113
  udpdst.sin_port = 0;
114

    
115
  /* set the address  */
116
  if (ipaddr == NULL)
117
    {
118
      udpsrc.sin_port = htons(port);
119
    }else{
120
      udpsrc.sin_addr.s_addr = inet_addr(ipaddr);
121
      udpsrc.sin_port = htons(port);
122
    }
123

    
124
  /* bind to the socket */
125
  returnStatus = bind(udpSocket,(struct sockaddr *)&udpsrc,sizeof(udpsrc));
126

    
127
  /* This is debug code */
128
  if (returnStatus) {
129
    error("Could not bind socketID to address! ERRNO %d\n",errno);
130
    return -2;
131
  }
132
#ifdef IP_MTU_DISCOVER
133

    
134
  int yes = 1;
135
  int size = sizeof(int);
136
  int pmtuopt = IP_PMTUDISC_DO;
137

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

    
144
  }
145

    
146
  /* This option writes the IP_TTL field into ancillary data */
147
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVTTL, &yes,size) < 0)
148
    {
149
      error("setsockopt: cannot set RECV_TTL. ERRNO %d\n",errno);
150
    }
151

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

    
154
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVERR, &yes,size) < 0) {
155
        error("setsockopt: cannot set RECV_ERROR. ERRNO %d\n",errno);
156
    }
157

    
158
#endif
159

    
160
  debug(stderr,"X.CreateSock\n");
161
  return udpSocket;
162

    
163
}
164

    
165
#ifndef WIN32
166
/* Information: read the standard TTL from a socket  */
167
int getTTL(const int udpSocket,uint8_t *ttl){
168
#ifdef MAC_OS
169
        return 0;
170
#else
171

    
172
        unsigned int value;
173
        unsigned int size = sizeof(value);
174

    
175
        if(getsockopt(udpSocket,SOL_IP,IP_TTL,&value,&size) == -1){
176
                error("get TTL did not work\n");
177
                return 0;
178
        }
179

    
180
        *ttl = value;
181
        if(verbose == 1) debug("TTL is %i\n",value);
182

    
183
        return 1;
184
#endif
185
}
186

    
187
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
188
{
189
        int error, ret;
190
        struct msghdr msgh;
191
        
192
        if(outputRateControl(len) != OK) return THROTTLE;
193

    
194
        msgh.msg_name = socketaddr;
195
        msgh.msg_namelen = sizeof(struct sockaddr_in);
196
        msgh.msg_iov = iov;
197
        msgh.msg_iovlen = len;
198
        msgh.msg_flags = 0;
199

    
200
        /* we do not send ancilliary data  */
201
        msgh.msg_control = 0;
202
        msgh.msg_controllen = 0;
203

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

    
219
/* A general error handling function on socket operations
220
 * that is called when sendmsg or recvmsg report an Error
221
 *
222
 */
223

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

    
229

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

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

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

    
253
        //set the size of the control data
254
        msgh.msg_control = errbuf;
255
        msgh.msg_controllen = sizeof(errbuf);
256
        //initialize pointer
257
        errptr = NULL;
258

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

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

    
295
                                /* raise the pmtu callback when an pmtu error occurred
296
                                *  -> icmp message type 3 code 4 icmp
297
                                */
298

    
299
                                if (type == 3 && code == 4){
300
                                        if(verbose == 1)
301
                                                debug("pmtu error message received\n");
302

    
303
                                        int mtusize = *bufsize;
304
                                        (icmpcb_value)(buf,mtusize);
305
                                }
306
                        }
307
                }
308
#endif
309
            ;
310
        } //end of for
311

    
312
        /* after the error is read from the socket error queue the
313
        * socket operation that was interrupeted by reading the error queue
314
        * has to be carried out
315
        */
316

    
317
        //error("socketErrorHandle: before iofunc loop \n");
318
/* @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
319
better error handling might be needed */
320
#if 0
321
        int transbuf;
322
        memcpy(&transbuf,bufsize,4);
323

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

    
344

    
345

    
346
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
347
{
348

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

    
379
        returnStatus = recvmsg(udpSocket,&msgh,0);
380
        msgh.msg_iov->iov_len = returnStatus;
381

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

    
397
        } else {
398
                /* debug code  */
399
                if(verbose == 1)
400
                        debug("udpSocket_recvPacket: Message received.\n");
401

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

    
415

    
416
int closeSocket(int udpSocket)
417
{
418

    
419
  /*cleanup */
420
  close(udpSocket);
421
  return 0;
422

    
423
}
424

    
425
const char *mlAutodetectIPAddress() {
426
        static char addr[128] = "";
427
#ifdef __linux__
428

    
429
        FILE *r = fopen("/proc/net/route", "r");
430
        if (!r) return NULL;
431

    
432
        char iface[IFNAMSIZ] = "";
433
        char line[128] = "x";
434
        while (1) {
435
                char dst[32];
436
                char ifc[IFNAMSIZ];
437

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

    
447
        struct ifaddrs *ifAddrStruct=NULL;
448
        if (getifaddrs(&ifAddrStruct)) return NULL;
449

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

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

    
485
  if(outputRateControl(total_len) != OK) return THROTTLE;
486

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

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

    
512
int getTTL(const int udpSocket,uint8_t *ttl){
513
  return 64;
514
}
515

    
516
const char *mlAutodetectIPAddress() {
517
  return NULL;
518
}
519

    
520

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