Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ e8e85bba

History | View | Annotate | Download (12.3 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
/* For sockaddr_in */
36
#include <netinet/in.h>
37
/* For socket functions */
38
#include <sys/socket.h>
39
/* For fcntl */
40
#include <fcntl.h>
41

    
42
#include <event2/event.h>
43

    
44
#include <stdio.h>
45
#include <stdlib.h>
46
#include <unistd.h>
47

    
48
#include <sys/socket.h>
49
#ifdef __linux__
50
#include <linux/types.h>
51
#include <linux/errqueue.h>
52
#include <linux/if.h>
53
#include <ifaddrs.h>
54
#else 
55
#define MSG_ERRQUEUE 0
56
#endif
57

    
58

    
59
#include <errno.h>
60
#include <string.h>
61
#include <netdb.h>
62
#include <netinet/in.h>
63

    
64
#include <resolv.h>
65
#include <sys/time.h>
66
#include <sys/uio.h>
67
#include <arpa/inet.h>
68

    
69
#include <unistd.h>
70
#include <stdlib.h>
71

    
72
#include "udpSocket.h"
73
#define LOG_MODULE "[ml] "
74
#include "ml_log.h"
75

    
76
/* debug varible: set to 1 if you want debug output  */
77
int verbose = 0;
78

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

    
84
  int returnStatus = 0;
85

    
86
  //int udpSocket = 0;
87
  /*libevent2*/
88
  evutil_socket_t udpSocket;
89

    
90
  /* create a socket */
91
  udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
92

    
93
  /*libevent2*/
94
  evutil_make_socket_nonblocking(udpSocket);
95

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

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

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

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

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

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

    
132
  int yes = 1;
133
  int size = sizeof(int);
134
  int pmtuopt = IP_PMTUDISC_DO;
135

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

    
142
  }
143

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

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

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

    
156
#endif
157

    
158
  return udpSocket;
159

    
160
}
161

    
162
/* Information: read the standard TTL from a socket  */
163
int getTTL(const int udpSocket,uint8_t *ttl){
164
        unsigned int value;
165
        unsigned int size = sizeof(value);
166

    
167
        if(getsockopt(udpSocket,SOL_IP,IP_TTL,&value,&size) == -1){
168
                error("get TTL did not work\n");
169
                return 0;
170
        }
171

    
172
        *ttl = value;
173
        if(verbose == 1) debug("TTL is %i\n",value);
174

    
175
        return 1;
176
}
177

    
178
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
179
{
180
        int error, ret;
181
        struct msghdr msgh;
182
        
183
        if(outputRateControl(len) != OK) return THROTTLE;
184

    
185
        msgh.msg_name = socketaddr;
186
        msgh.msg_namelen = sizeof(struct sockaddr_in);
187
        msgh.msg_iov = iov;
188
        msgh.msg_iovlen = len;
189
        msgh.msg_flags = 0;
190

    
191
        /* we do not send ancilliary data  */
192
        msgh.msg_control = 0;
193
        msgh.msg_controllen = 0;
194

    
195
        /* send the message  */
196
        ret = sendmsg(udpSocket,&msgh,0);
197
        if (ret  < 0){
198
                error = errno;
199
                info("ML: sendmsg failed errno %d: %s\n", error, strerror(error));
200
                switch(error) {
201
                        case EMSGSIZE:
202
                                return MSGLEN;
203
                        default:
204
                                return FAILURE;
205
                }
206
        }
207
        return OK;
208
}
209

    
210
/* A general error handling function on socket operations
211
 * that is called when sendmsg or recvmsg report an Error
212
 *
213
 */
214

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

    
220

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

    
223
        /* variables  */
224
        struct msghdr msgh;
225
        struct cmsghdr *cmsg;
226
        struct sock_extended_err *errptr;
227
        struct iovec iov;
228
        struct sockaddr_in sender_addr;
229
        int returnStatus;
230
        char errbuf[CMSG_SPACE(1024)];
231
        int recvbufsize = 1500;
232
        char recvbuf[recvbufsize];
233
        int icmp = 0;
234

    
235
        /* initialize recvmsg data  */
236
        msgh.msg_name = &sender_addr;
237
        msgh.msg_namelen = sizeof(struct sockaddr_in);
238
        msgh.msg_iov = &iov;
239
        msgh.msg_iovlen = 1;
240
        msgh.msg_iov->iov_base = recvbuf;
241
        msgh.msg_iov->iov_len = recvbufsize;
242
        msgh.msg_flags = 0;
243

    
244
        //set the size of the control data
245
        msgh.msg_control = errbuf;
246
        msgh.msg_controllen = sizeof(errbuf);
247
        //initialize pointer
248
        errptr = NULL;
249

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

    
278
                                int type = errptr->ee_type;
279
                                int code = errptr->ee_code;
280
                                icmp = 1;
281
                                inet_ntop(AF_INET, &(sender_addr.sin_addr.s_addr), sender_addr_str, INET_ADDRSTRLEN);
282
                                warn("icmp error message from %s:%d is type: %d code %d\n",
283
                                        sender_addr_str,ntohs(sender_addr.sin_port),
284
                                        errptr->ee_type,errptr->ee_code);
285

    
286
                                /* raise the pmtu callback when an pmtu error occurred
287
                                *  -> icmp message type 3 code 4 icmp
288
                                */
289

    
290
                                if (type == 3 && code == 4){
291
                                        if(verbose == 1)
292
                                                debug("pmtu error message received\n");
293

    
294
                                        int mtusize = *bufsize;
295
                                        (icmpcb_value)(buf,mtusize);
296
                                }
297
                        }
298
                }
299
#endif
300
            ;
301
        } //end of for
302

    
303
        /* after the error is read from the socket error queue the
304
        * socket operation that was interrupeted by reading the error queue
305
        * has to be carried out
306
        */
307

    
308
        //error("socketErrorHandle: before iofunc loop \n");
309
/* @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
310
better error handling might be needed */
311
#if 0
312
        int transbuf;
313
        memcpy(&transbuf,bufsize,4);
314

315
        if(iofunc == 1) {
316
                sendPacket(udpSocket,buf,transbuf,addr,icmpcb_value);
317
                if(verbose == 1)
318
                        error("handle socket error: packetsize %i \n ",*bufsize );
319
        } else {
320
                if(iofunc == 2 && icmp == 1){
321
                        if(verbose == 1)
322
                                error("handleSOcketError: recvPacket called \n ");
323
                        recvPacket(udpSocket,buf,bufsize,addr,icmpcb_value,ttl);
324
                } else {
325
                /* this is the case the socket has just an error message not related to anything of the messaging layer */
326
                        if(verbose == 1)
327
                                error("handleSocketError: unrelated error \n");
328
                        *ttl = -1;
329
                }
330
        }
331
#endif
332
        return 0;
333
}
334

    
335

    
336

    
337
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
338
{
339

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

    
370
        returnStatus = recvmsg(udpSocket,&msgh,0);
371
        msgh.msg_iov->iov_len = returnStatus;
372

    
373
        *recvSize = returnStatus;
374
        /* receive the message */
375
        if (returnStatus < 0) {
376
                if(verbose == 1) {
377
                        error("udpSocket:recvPacket: Read the error queue \n ");
378
                        error("recvmsg failed. errno %d \n",errno);
379
                }
380
                // TODO debug code: delete afterwards start
381
                if(errno == 11) {        //TODO: What is this 11, and why is it here with a NOP?
382
                        int a;
383
                        a++;
384
                };
385
                // end
386
                handleSocketError(udpSocket,2,buffer,recvSize,udpdst,icmpcb_value,ttl);
387

    
388
        } else {
389
                /* debug code  */
390
                if(verbose == 1)
391
                        debug("udpSocket_recvPacket: Message received.\n");
392

    
393
                for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
394
                        if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) {
395
                                ttlptr = (int *) CMSG_DATA(cmsg);
396
                                received_ttl = *ttlptr;
397
                                memcpy(ttl,ttlptr,4);
398
                                if(verbose == 1)
399
                                        debug("received ttl true: %i  \n ",received_ttl);
400
                                break;
401
                        }
402
                }
403
        }
404
}
405

    
406

    
407
int closeSocket(int udpSocket)
408
{
409

    
410
  /*cleanup */
411
  close(udpSocket);
412
  return 0;
413

    
414
}
415

    
416
const char *mlAutodetectIPAddress() {
417
        static char addr[128] = "";
418
#ifdef __linux__
419

    
420
        FILE *r = fopen("/proc/net/route", "r");
421
        if (!r) return NULL;
422

    
423
        char iface[IFNAMSIZ] = "";
424
        char line[128] = "x";
425
        while (1) {
426
                char dst[32];
427
                char ifc[IFNAMSIZ];
428

    
429
                char *dummy = fgets(line, 127, r);
430
                if (feof(r)) break;
431
                if ((sscanf(line, "%s\t%s", iface, dst) == 2) && !strcpy(dst, "00000000")) {
432
                        strcpy(iface, ifc);
433
                         break;
434
                }
435
        }
436
        if (iface[0] == 0) return NULL;
437

    
438
        struct ifaddrs *ifAddrStruct=NULL;
439
        if (getifaddrs(&ifAddrStruct)) return NULL;
440

    
441
        while (ifAddrStruct) {
442
                if (ifAddrStruct->ifa_addr && ifAddrStruct->ifa_addr->sa_family == AF_INET &&
443
                        ifAddrStruct->ifa_name && !strcmp(ifAddrStruct->ifa_name, iface))  {
444
                        void *tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
445
                        return inet_ntop(AF_INET, tmpAddrPtr, addr, 127);
446
                }
447
        ifAddrStruct=ifAddrStruct->ifa_next;
448
        }
449
#else
450
       {
451
                char namebuf[256];
452
                if(gethostname(namebuf, sizeof(namebuf))) {
453
                  perror("Error getting hostname");
454
                  return NULL;
455
                }
456
printf("Hostname is %s\n", namebuf);
457
                struct hostent *he = gethostbyname(namebuf);
458
                if(he == NULL) return NULL;
459
printf("Hostaddr: %x\n", *((unsigned int *)(he->h_addr)));
460
                return inet_ntop(AF_INET, he->h_addr, addr, 127);
461
       }
462
#endif
463
        return NULL;
464
}
465