Statistics
| Branch: | Revision:

napa-baselibs / ml / util / udpSocket.c @ 7033967d

History | View | Annotate | Download (14.2 KB)

1 956892f0 ArpadBakay
/*
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 c1d7ce35 ArpadBakay
 /*
23 956892f0 ArpadBakay
 * 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 c1d7ce35 ArpadBakay
#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 956892f0 ArpadBakay
/* 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 c1d7ce35 ArpadBakay
#include <sys/uio.h>
51
#include <arpa/inet.h>
52
#include <resolv.h>
53 956892f0 ArpadBakay
#include <sys/socket.h>
54 c1d7ce35 ArpadBakay
#include <netdb.h>
55
56 956892f0 ArpadBakay
#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 c1d7ce35 ArpadBakay
#else
66
#include <winsock2.h>
67
#endif
68 956892f0 ArpadBakay
69
70
71
72
#include "udpSocket.h"
73 c1d7ce35 ArpadBakay
74 956892f0 ArpadBakay
#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 fa5e477b MarcoMellia
  debug("X.CreateSock %s %d\n",ipaddr, port);
87 956892f0 ArpadBakay
88 7033967d MarcoMellia
  bzero((char *)&udpsrc, sizeof udpsrc);
89
  bzero((char *)&udpdst, sizeof udpsrc);
90
91 956892f0 ArpadBakay
  //int udpSocket = 0;
92
  /*libevent2*/
93
  evutil_socket_t udpSocket;
94
95
  /* create a socket */
96
  udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
97
98
  /*libevent2*/
99
  evutil_make_socket_nonblocking(udpSocket);
100
101
  //This is debug code that checks if the socket was created
102
  if (udpSocket == -1)
103
    {
104
      error("Could not create an UDP socket! ERRNO %d\n",errno);
105
      return -1;
106
    }
107
108
  /* sets the standard server address and port */
109
  udpsrc.sin_family = AF_INET;
110
  udpsrc.sin_addr.s_addr = htonl(INADDR_ANY);
111
  udpsrc.sin_port = 0;
112
113
  /* sets a destinantion address  */
114
  udpdst.sin_family = AF_INET;
115
  udpdst.sin_addr.s_addr = htonl(INADDR_ANY);
116
  udpdst.sin_port = 0;
117
118
  /* set the address  */
119
  if (ipaddr == NULL)
120
    {
121
      udpsrc.sin_port = htons(port);
122
    }else{
123
      udpsrc.sin_addr.s_addr = inet_addr(ipaddr);
124
      udpsrc.sin_port = htons(port);
125
    }
126
127
  /* bind to the socket */
128
  returnStatus = bind(udpSocket,(struct sockaddr *)&udpsrc,sizeof(udpsrc));
129
130
  /* This is debug code */
131
  if (returnStatus) {
132
    error("Could not bind socketID to address! ERRNO %d\n",errno);
133
    return -2;
134
  }
135
#ifdef IP_MTU_DISCOVER
136
137
  int yes = 1;
138
  int size = sizeof(int);
139
  int pmtuopt = IP_PMTUDISC_DO;
140
141
  /*Setting the automatic PMTU discoery function from the socket
142
   * This sets the DON'T FRAGMENT bit on the IP HEADER
143
   */
144
  if(setsockopt(udpSocket,IPPROTO_IP,IP_MTU_DISCOVER,&pmtuopt ,size) == -1){
145
    error("setsockopt: set IP_DONTFRAG did not work. ERRNO %d\n",errno);
146
147
  }
148
149
  /* This option writes the IP_TTL field into ancillary data */
150
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVTTL, &yes,size) < 0)
151
    {
152
      error("setsockopt: cannot set RECV_TTL. ERRNO %d\n",errno);
153
    }
154
155
  /* This option writes received internal and external(icmp) error messages into ancillary data */
156
157
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVERR, &yes,size) < 0) {
158
        error("setsockopt: cannot set RECV_ERROR. ERRNO %d\n",errno);
159
    }
160
161
#endif
162
163 fa5e477b MarcoMellia
  debug("X.CreateSock\n");
164 956892f0 ArpadBakay
  return udpSocket;
165
166
}
167
168 c1d7ce35 ArpadBakay
#ifndef WIN32
169 956892f0 ArpadBakay
/* Information: read the standard TTL from a socket  */
170
int getTTL(const int udpSocket,uint8_t *ttl){
171 df44d3c0 RobertBirke
#ifdef MAC_OS
172 53213af7 RobertBirke
        return 0;
173 df44d3c0 RobertBirke
#else
174
175 956892f0 ArpadBakay
        unsigned int value;
176
        unsigned int size = sizeof(value);
177
178
        if(getsockopt(udpSocket,SOL_IP,IP_TTL,&value,&size) == -1){
179
                error("get TTL did not work\n");
180
                return 0;
181
        }
182
183
        *ttl = value;
184
        if(verbose == 1) debug("TTL is %i\n",value);
185
186
        return 1;
187 df44d3c0 RobertBirke
#endif
188 956892f0 ArpadBakay
}
189
190
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
191
{
192
        int error, ret;
193
        struct msghdr msgh;
194 4f047c4f ArpadBakay
        
195
        if(outputRateControl(len) != OK) return THROTTLE;
196 956892f0 ArpadBakay
197
        msgh.msg_name = socketaddr;
198
        msgh.msg_namelen = sizeof(struct sockaddr_in);
199
        msgh.msg_iov = iov;
200
        msgh.msg_iovlen = len;
201
        msgh.msg_flags = 0;
202
203
        /* we do not send ancilliary data  */
204
        msgh.msg_control = 0;
205
        msgh.msg_controllen = 0;
206
207
        /* send the message  */
208
        ret = sendmsg(udpSocket,&msgh,0);
209
        if (ret  < 0){
210
                error = errno;
211
                info("ML: sendmsg failed errno %d: %s\n", error, strerror(error));
212
                switch(error) {
213
                        case EMSGSIZE:
214
                                return MSGLEN;
215
                        default:
216
                                return FAILURE;
217
                }
218
        }
219
        return OK;
220
}
221
222
/* A general error handling function on socket operations
223
 * that is called when sendmsg or recvmsg report an Error
224
 *
225
 */
226
227
//This function has to deal with what to do when an icmp is received
228
//--check the connection array, look to which connection-establishment the icmp belongs
229
//--invoke a retransmission
230
int handleSocketError(const int udpSocket,const int iofunc,char *buf,int *bufsize,struct sockaddr_in *addr,icmp_error_cb icmpcb_value,int *ttl){
231
232
233
        if(verbose == 1) debug("handle Socket error is called\n");
234
235
        /* variables  */
236
        struct msghdr msgh;
237
        struct cmsghdr *cmsg;
238
        struct sock_extended_err *errptr;
239
        struct iovec iov;
240
        struct sockaddr_in sender_addr;
241
        int returnStatus;
242
        char errbuf[CMSG_SPACE(1024)];
243
        int recvbufsize = 1500;
244
        char recvbuf[recvbufsize];
245
        int icmp = 0;
246
247
        /* initialize recvmsg data  */
248
        msgh.msg_name = &sender_addr;
249
        msgh.msg_namelen = sizeof(struct sockaddr_in);
250
        msgh.msg_iov = &iov;
251
        msgh.msg_iovlen = 1;
252
        msgh.msg_iov->iov_base = recvbuf;
253
        msgh.msg_iov->iov_len = recvbufsize;
254
        msgh.msg_flags = 0;
255
256
        //set the size of the control data
257
        msgh.msg_control = errbuf;
258
        msgh.msg_controllen = sizeof(errbuf);
259
        //initialize pointer
260
        errptr = NULL;
261
262
        /* get the error from the error que:  */
263
        returnStatus = recvmsg(udpSocket,&msgh,MSG_ERRQUEUE|MSG_DONTWAIT);
264
        if (returnStatus <= 0) {
265
                return -1;
266
        }
267
        for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)){
268
#ifdef __linux__
269
                //fill the error pointer
270
                if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVERR) {
271
                        errptr = (struct sock_extended_err *)CMSG_DATA(cmsg);
272
//                        if (errptr == NULL){
273
//                        if(verbose == 1)
274
//                                error("no acillary error data \n");
275
//             return -1;
276
//                }
277
                /* check if the error originated locally */
278
                        if (errptr->ee_origin == SO_EE_ORIGIN_LOCAL){
279
                                if (errptr->ee_errno != EMSGSIZE) {
280
                                        if(verbose == 1)
281
                                                error("local error: %s \n", strerror(errptr->ee_errno));
282
                                }
283
                        }
284
                        /* check if the error originated from an icmp message  */
285
                        if (errptr->ee_origin == SO_EE_ORIGIN_ICMP){
286 b0be061a CsabaKiraly
                                char sender_addr_str[INET_ADDRSTRLEN];
287 956892f0 ArpadBakay
                                if(verbose == 1)
288
                                        debug("icmp error message received\n");
289
290
                                int type = errptr->ee_type;
291
                                int code = errptr->ee_code;
292
                                icmp = 1;
293 b0be061a CsabaKiraly
                                inet_ntop(AF_INET, &(sender_addr.sin_addr.s_addr), sender_addr_str, INET_ADDRSTRLEN);
294
                                warn("icmp error message from %s:%d is type: %d code %d\n",
295
                                        sender_addr_str,ntohs(sender_addr.sin_port),
296 956892f0 ArpadBakay
                                        errptr->ee_type,errptr->ee_code);
297
298
                                /* raise the pmtu callback when an pmtu error occurred
299
                                *  -> icmp message type 3 code 4 icmp
300
                                */
301
302
                                if (type == 3 && code == 4){
303
                                        if(verbose == 1)
304
                                                debug("pmtu error message received\n");
305
306
                                        int mtusize = *bufsize;
307
                                        (icmpcb_value)(buf,mtusize);
308
                                }
309
                        }
310
                }
311
#endif
312
            ;
313
        } //end of for
314
315
        /* after the error is read from the socket error queue the
316
        * socket operation that was interrupeted by reading the error queue
317
        * has to be carried out
318
        */
319
320
        //error("socketErrorHandle: before iofunc loop \n");
321
/* @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
322
better error handling might be needed */
323
#if 0
324
        int transbuf;
325
        memcpy(&transbuf,bufsize,4);
326

327
        if(iofunc == 1) {
328
                sendPacket(udpSocket,buf,transbuf,addr,icmpcb_value);
329
                if(verbose == 1)
330
                        error("handle socket error: packetsize %i \n ",*bufsize );
331
        } else {
332
                if(iofunc == 2 && icmp == 1){
333
                        if(verbose == 1)
334
                                error("handleSOcketError: recvPacket called \n ");
335
                        recvPacket(udpSocket,buf,bufsize,addr,icmpcb_value,ttl);
336
                } else {
337
                /* this is the case the socket has just an error message not related to anything of the messaging layer */
338
                        if(verbose == 1)
339
                                error("handleSocketError: unrelated error \n");
340
                        *ttl = -1;
341
                }
342
        }
343
#endif
344
        return 0;
345
}
346
347
348
349
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
350
{
351
352
        /* variables  */
353
        struct msghdr msgh; 
354
        struct cmsghdr *cmsg;
355
        int *ttlptr;
356
        int received_ttl;
357
        struct iovec iov;
358
        //struct sockaddr_in sender_addr;
359
        //unsigned int sender_len;
360
        int returnStatus;
361
        
362
        /* initialize recvmsg data  */
363
        msgh.msg_name = udpdst;
364
        msgh.msg_namelen = sizeof(struct sockaddr_in);
365
        msgh.msg_iov = &iov;
366
        msgh.msg_iovlen = 1;
367
        msgh.msg_iov->iov_base = buffer;
368
        msgh.msg_iov->iov_len = *recvSize;
369
        msgh.msg_flags = 0;
370
        
371
        /*
372
        *  This shows the receiving of TTL within the ancillary data of recvmsg
373
        */
374
        
375
        // ancilliary data buffer 
376
        char ttlbuf[CMSG_SPACE(sizeof(int))];
377
        
378
        //set the size of the control data
379
        msgh.msg_control = ttlbuf;
380
        msgh.msg_controllen = sizeof(ttlbuf);
381
382
        returnStatus = recvmsg(udpSocket,&msgh,0);
383
        msgh.msg_iov->iov_len = returnStatus;
384
385
        *recvSize = returnStatus;
386
        /* receive the message */
387
        if (returnStatus < 0) {
388
                if(verbose == 1) {
389
                        error("udpSocket:recvPacket: Read the error queue \n ");
390
                        error("recvmsg failed. errno %d \n",errno);
391
                }
392
                // TODO debug code: delete afterwards start
393
                if(errno == 11) {        //TODO: What is this 11, and why is it here with a NOP?
394
                        int a;
395
                        a++;
396
                };
397
                // end
398
                handleSocketError(udpSocket,2,buffer,recvSize,udpdst,icmpcb_value,ttl);
399 b0be061a CsabaKiraly
400 956892f0 ArpadBakay
        } else {
401
                /* debug code  */
402
                if(verbose == 1)
403
                        debug("udpSocket_recvPacket: Message received.\n");
404
405
                for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
406
                        if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) {
407
                                ttlptr = (int *) CMSG_DATA(cmsg);
408
                                received_ttl = *ttlptr;
409
                                memcpy(ttl,ttlptr,4);
410
                                if(verbose == 1)
411
                                        debug("received ttl true: %i  \n ",received_ttl);
412
                                break;
413
                        }
414
                }
415
        }
416
}
417
418
419
int closeSocket(int udpSocket)
420
{
421
422
  /*cleanup */
423
  close(udpSocket);
424
  return 0;
425
426
}
427
428
const char *mlAutodetectIPAddress() {
429
        static char addr[128] = "";
430
#ifdef __linux__
431
432
        FILE *r = fopen("/proc/net/route", "r");
433
        if (!r) return NULL;
434
435
        char iface[IFNAMSIZ] = "";
436
        char line[128] = "x";
437
        while (1) {
438
                char dst[32];
439
                char ifc[IFNAMSIZ];
440
441
                char *dummy = fgets(line, 127, r);
442
                if (feof(r)) break;
443
                if ((sscanf(line, "%s\t%s", iface, dst) == 2) && !strcpy(dst, "00000000")) {
444
                        strcpy(iface, ifc);
445
                         break;
446
                }
447
        }
448
        if (iface[0] == 0) return NULL;
449
450
        struct ifaddrs *ifAddrStruct=NULL;
451
        if (getifaddrs(&ifAddrStruct)) return NULL;
452
453
        while (ifAddrStruct) {
454
                if (ifAddrStruct->ifa_addr && ifAddrStruct->ifa_addr->sa_family == AF_INET &&
455
                        ifAddrStruct->ifa_name && !strcmp(ifAddrStruct->ifa_name, iface))  {
456
                        void *tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
457
                        return inet_ntop(AF_INET, tmpAddrPtr, addr, 127);
458
                }
459
        ifAddrStruct=ifAddrStruct->ifa_next;
460
        }
461
#else
462
       {
463
                char namebuf[256];
464
                if(gethostname(namebuf, sizeof(namebuf))) {
465
                  perror("Error getting hostname");
466
                  return NULL;
467
                }
468
printf("Hostname is %s\n", namebuf);
469
                struct hostent *he = gethostbyname(namebuf);
470
                if(he == NULL) return NULL;
471
printf("Hostaddr: %x\n", *((unsigned int *)(he->h_addr)));
472
                return inet_ntop(AF_INET, he->h_addr, addr, 127);
473
       }
474
#endif
475
        return NULL;
476
}
477 c1d7ce35 ArpadBakay
#else  // WINDOWS
478 956892f0 ArpadBakay
479 c1d7ce35 ArpadBakay
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
480
{
481
  char stack_buffer[1600];
482
  char *buf = stack_buffer;
483
  int i;
484
  int total_len = 0;
485
  int ret;
486
  for(i = 0; i < len; i++) total_len += iov[i].iov_len;
487
488
  if(outputRateControl(total_len) != OK) return THROTTLE;
489
490
  if(total_len > sizeof(stack_buffer)) {
491
     warn("sendPacket total_length %d requires dynamically allocated buffer", total_len);
492
     buf = malloc(total_len);
493
  }
494
  total_len = 0;
495
  for(i = 0; i < len; i++) {
496
     memcpy(buf+total_len, iov[i].iov_base, iov[i].iov_len);
497
     total_len += iov[i].iov_len;
498
  } 
499
  ret = sendto(udpSocket, buf, total_len, 0, (struct sockaddr *)socketaddr, sizeof(*socketaddr));
500
debug("Sent %d bytes (%d) to %d\n",ret, WSAGetLastError(), udpSocket);
501
  if(buf != stack_buffer) free(buf);
502
  return ret == total_len ? OK:FAILURE; 
503
}
504
505
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
506
{
507
fprintf(stderr,"X.RECV\n");
508
  int salen = sizeof(struct sockaddr_in);
509
  int ret;
510
  ret = recvfrom(udpSocket, buffer, *recvSize, 0, (struct sockaddr *)udpdst, &salen);
511
  if(ret > 0) *recvSize = ret;
512
  *ttl=10;
513
}
514
515
int getTTL(const int udpSocket,uint8_t *ttl){
516
  return 64;
517
}
518
519
const char *mlAutodetectIPAddress() {
520
  return NULL;
521
}
522
523
524
const char *inet_ntop(int af, const void *src,
525
       char *dst, size_t size) {
526
    char *c = inet_ntoa(*(struct in_addr *)src);
527
    if(strlen(c) >= size) return NULL;
528
    return strcpy(dst, c);
529
}
530
int inet_pton(int af, const char * src, void *dst) {
531
    unsigned long l = inet_addr(src);
532
    if(l == INADDR_NONE) return 0;
533
    *(unsigned long *)dst = l;
534
    return 1;
535
}
536
#endif