Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ 08a4230a

History | View | Annotate | Download (12.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
/* 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
                                if(verbose == 1)
275
                                        debug("icmp error message received\n");
276

    
277
                                int type = errptr->ee_type;
278
                                int code = errptr->ee_code;
279
                                icmp = 1;
280
                                warn("icmp error message is type: %d code %d\n",
281
                                        errptr->ee_type,errptr->ee_code);
282

    
283
                                /* raise the pmtu callback when an pmtu error occurred
284
                                *  -> icmp message type 3 code 4 icmp
285
                                */
286

    
287
                                if (type == 3 && code == 4){
288
                                        if(verbose == 1)
289
                                                debug("pmtu error message received\n");
290

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

    
300
        /* after the error is read from the socket error queue the
301
        * socket operation that was interrupeted by reading the error queue
302
        * has to be carried out
303
        */
304

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

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

    
332

    
333

    
334
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
335
{
336

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

    
367
        returnStatus = recvmsg(udpSocket,&msgh,0);
368
        msgh.msg_iov->iov_len = returnStatus;
369

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

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

    
402

    
403
int closeSocket(int udpSocket)
404
{
405

    
406
  /*cleanup */
407
  close(udpSocket);
408
  return 0;
409

    
410
}
411

    
412
const char *mlAutodetectIPAddress() {
413
        static char addr[128] = "";
414
#ifdef __linux__
415

    
416
        FILE *r = fopen("/proc/net/route", "r");
417
        if (!r) return NULL;
418

    
419
        char iface[IFNAMSIZ] = "";
420
        char line[128] = "x";
421
        while (1) {
422
                char dst[32];
423
                char ifc[IFNAMSIZ];
424

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

    
434
        struct ifaddrs *ifAddrStruct=NULL;
435
        if (getifaddrs(&ifAddrStruct)) return NULL;
436

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