Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ 372c2c31

History | View | Annotate | Download (13.9 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 "../ml_all.h"
36

    
37
#ifdef __linux__
38
#include <linux/types.h>
39
#include <linux/errqueue.h>
40
#include <linux/if.h>
41
#include <ifaddrs.h>
42
#else
43
#define MSG_ERRQUEUE 0
44
#endif
45

    
46

    
47

    
48
/* debug varible: set to 1 if you want debug output  */
49
int verbose = 0;
50

    
51
int createSocket(const int port,const char *ipaddr)
52
{
53
  /* variables needed */
54
  struct sockaddr_in udpsrc, udpdst;
55

    
56
  int returnStatus = 0;
57
  debug("X.CreateSock %s %d\n",ipaddr, port);
58

    
59
  bzero((char *)&udpsrc, sizeof udpsrc);
60
  bzero((char *)&udpdst, sizeof udpsrc);
61

    
62
  //int udpSocket = 0;
63
  /*libevent2*/
64
  evutil_socket_t udpSocket;
65

    
66
  /* create a socket */
67
  udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
68

    
69
  /*libevent2*/
70
  evutil_make_socket_nonblocking(udpSocket);
71

    
72
  //This is debug code that checks if the socket was created
73
  if (udpSocket == -1)
74
    {
75
      error("Could not create an UDP socket! ERRNO %d\n",errno);
76
      return -1;
77
    }
78

    
79
  /* sets the standard server address and port */
80
  udpsrc.sin_family = AF_INET;
81
  udpsrc.sin_addr.s_addr = htonl(INADDR_ANY);
82
  udpsrc.sin_port = 0;
83

    
84
  /* sets a destinantion address  */
85
  udpdst.sin_family = AF_INET;
86
  udpdst.sin_addr.s_addr = htonl(INADDR_ANY);
87
  udpdst.sin_port = 0;
88

    
89
  /* set the address  */
90
  if (ipaddr == NULL)
91
    {
92
      udpsrc.sin_port = htons(port);
93
    }else{
94
      udpsrc.sin_addr.s_addr = inet_addr(ipaddr);
95
      udpsrc.sin_port = htons(port);
96
    }
97

    
98
  /* bind to the socket */
99
  returnStatus = bind(udpSocket,(struct sockaddr *)&udpsrc,sizeof(udpsrc));
100

    
101
  /* This is debug code */
102
  if (returnStatus) {
103
    error("Could not bind socketID to address! ERRNO %d\n",errno);
104
    return -2;
105
  }
106
#ifdef IP_MTU_DISCOVER
107

    
108
  int yes = 1;
109
  int size = sizeof(int);
110
  int pmtuopt = IP_PMTUDISC_DO;
111

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

    
118
  }
119

    
120
  /* This option writes the IP_TTL field into ancillary data */
121
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVTTL, &yes,size) < 0)
122
    {
123
      error("setsockopt: cannot set RECV_TTL. ERRNO %d\n",errno);
124
    }
125

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

    
128
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVERR, &yes,size) < 0) {
129
        error("setsockopt: cannot set RECV_ERROR. ERRNO %d\n",errno);
130
    }
131

    
132
#endif
133

    
134
  debug("X.CreateSock\n");
135
  return udpSocket;
136

    
137
}
138

    
139
#ifndef _WIN32
140
/* Information: read the standard TTL from a socket  */
141
int getTTL(const int udpSocket,uint8_t *ttl){
142
#ifdef MAC_OS
143
        return 0;
144
#else
145

    
146
        unsigned int value;
147
        unsigned int size = sizeof(value);
148

    
149
        if(getsockopt(udpSocket,SOL_IP,IP_TTL,&value,&size) == -1){
150
                error("get TTL did not work\n");
151
                return 0;
152
        }
153

    
154
        *ttl = value;
155
        if(verbose == 1) debug("TTL is %i\n",value);
156

    
157
        return 1;
158
#endif
159
}
160

    
161
int sendPacketFinal(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
162
{
163
        int error, ret;
164
        struct msghdr msgh;
165

    
166
        msgh.msg_name = socketaddr;
167
        msgh.msg_namelen = sizeof(struct sockaddr_in);
168
        msgh.msg_iov = iov;
169
        msgh.msg_iovlen = len;
170
        msgh.msg_flags = 0;
171

    
172
        /* we do not send ancilliary data  */
173
        msgh.msg_control = 0;
174
        msgh.msg_controllen = 0;
175

    
176
        /* send the message  */
177
        ret = sendmsg(udpSocket,&msgh,0);
178
        if (ret  < 0){
179
                error = errno;
180
                info("ML: sendmsg failed errno %d: %s\n", error, strerror(error));
181
                switch(error) {
182
                        case EMSGSIZE:
183
                                return MSGLEN;
184
                        default:
185
                                return FAILURE;
186
                }
187
        }
188
        return OK;
189
}
190

    
191
/* A general error handling function on socket operations
192
 * that is called when sendmsg or recvmsg report an Error
193
 *
194
 */
195

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

    
201

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

    
204
        /* variables  */
205
        struct msghdr msgh;
206
        struct cmsghdr *cmsg;
207
        struct sock_extended_err *errptr;
208
        struct iovec iov;
209
        struct sockaddr_in sender_addr;
210
        int returnStatus;
211
        char errbuf[CMSG_SPACE(1024)];
212
        int recvbufsize = 1500;
213
        char recvbuf[recvbufsize];
214
        int icmp = 0;
215

    
216
        /* initialize recvmsg data  */
217
        msgh.msg_name = &sender_addr;
218
        msgh.msg_namelen = sizeof(struct sockaddr_in);
219
        msgh.msg_iov = &iov;
220
        msgh.msg_iovlen = 1;
221
        msgh.msg_iov->iov_base = recvbuf;
222
        msgh.msg_iov->iov_len = recvbufsize;
223
        msgh.msg_flags = 0;
224

    
225
        //set the size of the control data
226
        msgh.msg_control = errbuf;
227
        msgh.msg_controllen = sizeof(errbuf);
228
        //initialize pointer
229
        errptr = NULL;
230

    
231
        /* get the error from the error que:  */
232
        returnStatus = recvmsg(udpSocket,&msgh,MSG_ERRQUEUE|MSG_DONTWAIT);
233
        if (returnStatus <= 0) {
234
                return -1;
235
        }
236
        for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)){
237
#ifdef __linux__
238
                //fill the error pointer
239
                if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVERR) {
240
                        errptr = (struct sock_extended_err *)CMSG_DATA(cmsg);
241
//                        if (errptr == NULL){
242
//                        if(verbose == 1)
243
//                                error("no acillary error data \n");
244
//             return -1;
245
//                }
246
                /* check if the error originated locally */
247
                        if (errptr->ee_origin == SO_EE_ORIGIN_LOCAL){
248
                                if (errptr->ee_errno != EMSGSIZE) {
249
                                        if(verbose == 1)
250
                                                error("local error: %s \n", strerror(errptr->ee_errno));
251
                                }
252
                        }
253
                        /* check if the error originated from an icmp message  */
254
                        if (errptr->ee_origin == SO_EE_ORIGIN_ICMP){
255
                                char sender_addr_str[INET_ADDRSTRLEN];
256
                                if(verbose == 1)
257
                                        debug("icmp error message received\n");
258

    
259
                                int type = errptr->ee_type;
260
                                int code = errptr->ee_code;
261
                                icmp = 1;
262
                                inet_ntop(AF_INET, &(sender_addr.sin_addr.s_addr), sender_addr_str, INET_ADDRSTRLEN);
263
                                warn("icmp error message from %s:%d is type: %d code %d\n",
264
                                        sender_addr_str,ntohs(sender_addr.sin_port),
265
                                        errptr->ee_type,errptr->ee_code);
266

    
267
                                /* raise the pmtu callback when an pmtu error occurred
268
                                *  -> icmp message type 3 code 4 icmp
269
                                */
270

    
271
                                if (type == 3 && code == 4){
272
                                        if(verbose == 1)
273
                                                debug("pmtu error message received\n");
274

    
275
                                        int mtusize = *bufsize;
276
                                        (icmpcb_value)(buf,mtusize);
277
                                }
278
                        }
279
                }
280
#endif
281
            ;
282
        } //end of for
283

    
284
        /* after the error is read from the socket error queue the
285
        * socket operation that was interrupeted by reading the error queue
286
        * has to be carried out
287
        */
288

    
289
        //error("socketErrorHandle: before iofunc loop \n");
290
/* @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
291
better error handling might be needed */
292
#if 0
293
        int transbuf;
294
        memcpy(&transbuf,bufsize,4);
295

296
        if(iofunc == 1) {
297
                sendPacket(udpSocket,buf,transbuf,addr,icmpcb_value);
298
                if(verbose == 1)
299
                        error("handle socket error: packetsize %i \n ",*bufsize );
300
        } else {
301
                if(iofunc == 2 && icmp == 1){
302
                        if(verbose == 1)
303
                                error("handleSOcketError: recvPacket called \n ");
304
                        recvPacket(udpSocket,buf,bufsize,addr,icmpcb_value,ttl);
305
                } else {
306
                /* this is the case the socket has just an error message not related to anything of the messaging layer */
307
                        if(verbose == 1)
308
                                error("handleSocketError: unrelated error \n");
309
                        *ttl = -1;
310
                }
311
        }
312
#endif
313
        return 0;
314
}
315

    
316

    
317

    
318
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
319
{
320

    
321
        /* variables  */
322
        struct msghdr msgh; 
323
        struct cmsghdr *cmsg;
324
        int *ttlptr;
325
        int received_ttl;
326
        struct iovec iov;
327
        //struct sockaddr_in sender_addr;
328
        //unsigned int sender_len;
329
        int returnStatus;
330
        
331
        /* initialize recvmsg data  */
332
        msgh.msg_name = udpdst;
333
        msgh.msg_namelen = sizeof(struct sockaddr_in);
334
        msgh.msg_iov = &iov;
335
        msgh.msg_iovlen = 1;
336
        msgh.msg_iov->iov_base = buffer;
337
        msgh.msg_iov->iov_len = *recvSize;
338
        msgh.msg_flags = 0;
339
        
340
        /*
341
        *  This shows the receiving of TTL within the ancillary data of recvmsg
342
        */
343
        
344
        // ancilliary data buffer 
345
        char ttlbuf[CMSG_SPACE(sizeof(int))];
346
        
347
        //set the size of the control data
348
        msgh.msg_control = ttlbuf;
349
        msgh.msg_controllen = sizeof(ttlbuf);
350

    
351
        returnStatus = recvmsg(udpSocket,&msgh,0);
352
        msgh.msg_iov->iov_len = returnStatus;
353

    
354
        *recvSize = returnStatus;
355
        /* receive the message */
356
        if (returnStatus < 0) {
357
                if(verbose == 1) {
358
                        error("udpSocket:recvPacket: Read the error queue \n ");
359
                        error("recvmsg failed. errno %d \n",errno);
360
                }
361
                // TODO debug code: delete afterwards start
362
                if(errno == 11) {        //TODO: What is this 11, and why is it here with a NOP?
363
                        int a;
364
                        a++;
365
                };
366
                // end
367
                handleSocketError(udpSocket,2,buffer,recvSize,udpdst,icmpcb_value,ttl);
368

    
369
        } else {
370
                /* debug code  */
371
                if(verbose == 1)
372
                        debug("udpSocket_recvPacket: Message received.\n");
373

    
374
                for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
375
                        if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) {
376
                                ttlptr = (int *) CMSG_DATA(cmsg);
377
                                received_ttl = *ttlptr;
378
                                memcpy(ttl,ttlptr,4);
379
                                if(verbose == 1)
380
                                        debug("received ttl true: %i  \n ",received_ttl);
381
                                break;
382
                        }
383
                }
384
        }
385
}
386

    
387

    
388
int closeSocket(int udpSocket)
389
{
390

    
391
  /*cleanup */
392
  close(udpSocket);
393
  return 0;
394

    
395
}
396

    
397
const char *mlAutodetectIPAddress() {
398
        static char addr[128] = "";
399
#ifdef __linux__
400

    
401
        FILE *r = fopen("/proc/net/route", "r");
402
        if (!r) return NULL;
403

    
404
        char iface[IFNAMSIZ] = "";
405
        char line[128] = "x";
406
        while (1) {
407
                char dst[32];
408
                char ifc[IFNAMSIZ];
409

    
410
                char *dummy = fgets(line, 127, r);
411
                if (feof(r)) break;
412
                if ((sscanf(line, "%s\t%s", iface, dst) == 2) && !strcpy(dst, "00000000")) {
413
                        strcpy(iface, ifc);
414
                         break;
415
                }
416
        }
417
        if (iface[0] == 0) return NULL;
418

    
419
        struct ifaddrs *ifAddrStruct=NULL;
420
        if (getifaddrs(&ifAddrStruct)) return NULL;
421

    
422
        while (ifAddrStruct) {
423
                if (ifAddrStruct->ifa_addr && ifAddrStruct->ifa_addr->sa_family == AF_INET &&
424
                        ifAddrStruct->ifa_name && !strcmp(ifAddrStruct->ifa_name, iface))  {
425
                        void *tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
426
                        return inet_ntop(AF_INET, tmpAddrPtr, addr, 127);
427
                }
428
        ifAddrStruct=ifAddrStruct->ifa_next;
429
        }
430
#else
431
       {
432
                char namebuf[256];
433
                if(gethostname(namebuf, sizeof(namebuf))) {
434
                  perror("Error getting hostname");
435
                  return NULL;
436
                }
437
printf("Hostname is %s\n", namebuf);
438
                struct hostent *he = gethostbyname(namebuf);
439
                if(he == NULL) return NULL;
440
printf("Hostaddr: %x\n", *((unsigned int *)(he->h_addr)));
441
                return inet_ntop(AF_INET, he->h_addr, addr, 127);
442
       }
443
#endif
444
        return NULL;
445
}
446
#else  // WINDOWS
447

    
448
int sendPacketFinal(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
449
{
450
  char stack_buffer[1600];
451
  char *buf = stack_buffer;
452
  int i;
453
  int total_len = 0;
454
  int ret;
455
  for(i = 0; i < len; i++) total_len += iov[i].iov_len;
456

    
457
  if(outputRateControl(total_len) != OK) return THROTTLE;
458

    
459
  if(total_len > sizeof(stack_buffer)) {
460
     warn("sendPacket total_length %d requires dynamically allocated buffer", total_len);
461
     buf = malloc(total_len);
462
  }
463
  total_len = 0;
464
  for(i = 0; i < len; i++) {
465
     memcpy(buf+total_len, iov[i].iov_base, iov[i].iov_len);
466
     total_len += iov[i].iov_len;
467
  } 
468
  ret = sendto(udpSocket, buf, total_len, 0, (struct sockaddr *)socketaddr, sizeof(*socketaddr));
469
debug("Sent %d bytes (%d) to %d\n",ret, WSAGetLastError(), udpSocket);
470
  if(buf != stack_buffer) free(buf);
471
  return ret == total_len ? OK:FAILURE; 
472
}
473

    
474
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
475
{
476
  debug("recvPacket");
477
  int salen = sizeof(struct sockaddr_in);
478
  int ret;
479
  ret = recvfrom(udpSocket, buffer, *recvSize, 0, (struct sockaddr *)udpdst, &salen);
480
  *recvSize = ret;
481
  if(ret == SOCKET_ERROR) {
482
      int err = WSAGetLastError();
483
      if(err = WSAECONNRESET) {
484
           warn("RECVPACKET detected ICMP Unreachable  for %s:%d", inet_ntoa(udpdst->sin_addr), udpdst->sin_port);
485
      }
486
      else {
487
           warn("RECVPACKET unclassified error %d", err);
488
      }
489
      *recvSize = -1;
490
      return;
491
  }
492
  *ttl=10;
493
}
494

    
495
int getTTL(const int udpSocket,uint8_t *ttl){
496
  return 64;
497
}
498

    
499
const char *mlAutodetectIPAddress() {
500
  return NULL;
501
}
502

    
503

    
504
const char *inet_ntop(int af, const void *src,
505
       char *dst, size_t size) {
506
    char *c = inet_ntoa(*(struct in_addr *)src);
507
    if(strlen(c) >= size) return NULL;
508
    return strcpy(dst, c);
509
}
510
int inet_pton(int af, const char * src, void *dst) {
511
    unsigned long l = inet_addr(src);
512
    if(l == INADDR_NONE) return 0;
513
    *(unsigned long *)dst = l;
514
    return 1;
515
}
516
#endif