Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ a7fc92ab

History | View | Annotate | Download (11.5 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
#include <linux/types.h>
50
#include <linux/errqueue.h>
51
#ifdef __linux__
52
#include <linux/if.h>
53
#include <ifaddrs.h>
54
#endif
55

    
56
#include <errno.h>
57
#include <string.h>
58
#include <netdb.h>
59
#include <netinet/in.h>
60

    
61
#include <resolv.h>
62
#include <sys/time.h>
63
#include <sys/uio.h>
64
#include <arpa/inet.h>
65

    
66
#include <unistd.h>
67
#include <stdlib.h>
68

    
69
#include "udpSocket.h"
70
#define LOG_MODULE "[ml] "
71
#include "ml_log.h"
72

    
73
/* debug varible: set to 1 if you want debug output  */
74
int verbose = 0;
75

    
76
int createSocket(const int port,const char *ipaddr)
77
{
78
  /* variables needed */
79
  struct sockaddr_in udpsrc, udpdst;
80
  
81
  int returnStatus = 0;
82

    
83
  //int udpSocket = 0;
84
  /*libevent2*/
85
  evutil_socket_t udpSocket;
86

    
87
  /* create a socket */
88
  udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
89

    
90
  /*libevent2*/
91
  evutil_make_socket_nonblocking(udpSocket);
92

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

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

    
105
  /* sets a destinantion address  */
106
  udpdst.sin_family = AF_INET;
107
  udpdst.sin_addr.s_addr = htonl(INADDR_ANY);
108
  udpdst.sin_port = 0;
109

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

    
119
  /* bind to the socket */
120
  returnStatus = bind(udpSocket,(struct sockaddr *)&udpsrc,sizeof(udpsrc));
121

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

    
129
  int yes = 1;
130
  int size = sizeof(int);
131
  int pmtuopt = IP_PMTUDISC_DO;
132

    
133
  /*Setting the automatic PMTU discoery function from the socket
134
   * This sets the DON'T FRAGMENT bit on the IP HEADER
135
   */
136
  if(setsockopt(udpSocket,IPPROTO_IP,IP_MTU_DISCOVER,&pmtuopt ,size) == -1){
137
    error("setsockopt: set IP_DONTFRAG did not work. ERRNO %d\n",errno);
138
    
139
  }
140
  
141
  /* This option writes the IP_TTL field into ancillary data */
142
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVTTL, &yes,size) < 0)
143
    {
144
      error("setsockopt: cannot set RECV_TTL. ERRNO %d\n",errno);
145
    }
146

    
147
  /* This option writes received internal and external(icmp) error messages into ancillary data */
148
  
149
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVERR, &yes,size) < 0) { 
150
        error("setsockopt: cannot set RECV_ERROR. ERRNO %d\n",errno);
151
    }
152
  
153
#endif
154

    
155
  return udpSocket;
156

    
157
}
158

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

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

    
169
        *ttl = value;
170
        if(verbose == 1) debug("TTL is %i\n",value);
171

    
172
        return 1;
173
}
174

    
175
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
176
{
177
        int error, ret;
178
        struct msghdr msgh;
179

    
180
        msgh.msg_name = socketaddr;
181
        msgh.msg_namelen = sizeof(struct sockaddr_in);
182
        msgh.msg_iov = iov;
183
        msgh.msg_iovlen = len;
184
        msgh.msg_flags = 0;
185

    
186
        /* we do not send ancilliary data  */
187
        msgh.msg_control = 0;
188
        msgh.msg_controllen = 0;
189

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

    
205
/* A general error handling function on socket operations
206
 * that is called when sendmsg or recvmsg report an Error
207
 *
208
 */
209

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

    
215

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

    
218
        /* variables  */
219
        struct msghdr msgh;
220
        struct cmsghdr *cmsg;
221
        struct sock_extended_err *errptr;
222
        struct iovec iov;
223
        struct sockaddr_in sender_addr;
224
        int returnStatus;
225
        char errbuf[CMSG_SPACE(1024)]; 
226
        int recvbufsize = 1500;
227
        char recvbuf[recvbufsize];
228
        int icmp = 0;
229
        
230
        /* initialize recvmsg data  */
231
        msgh.msg_name = &sender_addr;
232
        msgh.msg_namelen = sizeof(struct sockaddr_in);
233
        msgh.msg_iov = &iov;
234
        msgh.msg_iovlen = 1;
235
        msgh.msg_iov->iov_base = recvbuf;
236
        msgh.msg_iov->iov_len = recvbufsize;
237
        msgh.msg_flags = 0;
238
        
239
        //set the size of the control data
240
        msgh.msg_control = errbuf;
241
        msgh.msg_controllen = sizeof(errbuf);
242
        //initialize pointer 
243
        errptr = NULL;
244

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

    
271
                                int type = errptr->ee_type;
272
                                int code = errptr->ee_code;
273
                                icmp = 1;
274
                                warn("icmp error message is type: %d code %d\n",
275
                                        errptr->ee_type,errptr->ee_code);
276

    
277
                                /* raise the pmtu callback when an pmtu error occurred 
278
                                *  -> icmp message type 3 code 4 icmp
279
                                */
280

    
281
                                if (type == 3 && code == 4){
282
                                        if(verbose == 1)
283
                                                debug("pmtu error message received\n");
284

    
285
                                        int mtusize = *bufsize;
286
                                        (icmpcb_value)(buf,mtusize);
287
                                }
288
                        }
289
                }
290
        } //end of for
291

    
292
        /* after the error is read from the socket error queue the 
293
        * socket operation that was interrupeted by reading the error queue
294
        * has to be carried out
295
        */
296

    
297
        //error("socketErrorHandle: before iofunc loop \n");
298
/* @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
299
better error handling might be needed */
300
#if 0
301
        int transbuf;
302
        memcpy(&transbuf,bufsize,4);
303
        
304
        if(iofunc == 1) {
305
                sendPacket(udpSocket,buf,transbuf,addr,icmpcb_value);
306
                if(verbose == 1)
307
                        error("handle socket error: packetsize %i \n ",*bufsize );
308
        } else {
309
                if(iofunc == 2 && icmp == 1){
310
                        if(verbose == 1)
311
                                error("handleSOcketError: recvPacket called \n ");
312
                        recvPacket(udpSocket,buf,bufsize,addr,icmpcb_value,ttl);
313
                } else {
314
                /* this is the case the socket has just an error message not related to anything of the messaging layer */
315
                        if(verbose == 1)
316
                                error("handleSocketError: unrelated error \n");
317
                        *ttl = -1;
318
                }
319
        }
320
#endif
321
        return 0;
322
}
323

    
324

    
325

    
326
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
327
{
328
        
329
        /* variables  */
330
        struct msghdr msgh; 
331
        struct cmsghdr *cmsg;
332
        int *ttlptr;
333
        int received_ttl;
334
        struct iovec iov;
335
        //struct sockaddr_in sender_addr;
336
        //unsigned int sender_len;
337
        int returnStatus;
338
        
339
        /* initialize recvmsg data  */
340
        msgh.msg_name = udpdst;
341
        msgh.msg_namelen = sizeof(struct sockaddr_in);
342
        msgh.msg_iov = &iov;
343
        msgh.msg_iovlen = 1;
344
        msgh.msg_iov->iov_base = buffer;
345
        msgh.msg_iov->iov_len = *recvSize;
346
        msgh.msg_flags = 0;
347
        
348
        /*
349
        *  This shows the receiving of TTL within the ancillary data of recvmsg
350
        */
351
        
352
        // ancilliary data buffer 
353
        char ttlbuf[CMSG_SPACE(sizeof(int))];
354
        
355
        //set the size of the control data
356
        msgh.msg_control = ttlbuf;
357
        msgh.msg_controllen = sizeof(ttlbuf);
358
                
359
        returnStatus = recvmsg(udpSocket,&msgh,0);
360
        msgh.msg_iov->iov_len = returnStatus;
361
        
362
        *recvSize = returnStatus;
363
        /* receive the message */
364
        if (returnStatus < 0) {
365
                if(verbose == 1) {
366
                        error("udpSocket:recvPacket: Read the error queue \n ");
367
                        error("recvmsg failed. errno %d \n",errno);
368
                }
369
                // TODO debug code: delete afterwards start
370
                if(errno == 11) {        //TODO: What is this 11, and why is it here with a NOP?
371
                        int a;
372
                        a++; 
373
                };
374
                // end
375
                handleSocketError(udpSocket,2,buffer,recvSize,udpdst,icmpcb_value,ttl);
376
        } else {
377
                /* debug code  */
378
                if(verbose == 1)
379
                        debug("udpSocket_recvPacket: Message received.\n");
380

    
381
                for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
382
                        if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) {
383
                                ttlptr = (int *) CMSG_DATA(cmsg);
384
                                received_ttl = *ttlptr;
385
                                memcpy(ttl,ttlptr,4);
386
                                if(verbose == 1)
387
                                        debug("received ttl true: %i  \n ",received_ttl);
388
                                break;
389
                        }
390
                }
391
        }
392
}
393

    
394

    
395
int closeSocket(int udpSocket)
396
{
397

    
398
  /*cleanup */
399
  close(udpSocket);
400
  return 0;
401
  
402
}
403

    
404
const char *mlAutodetectIPAddress() {
405
#ifndef __linux__
406
        return NULL;
407
#endif
408

    
409
        static char addr[128] = "";
410

    
411
        FILE *r = fopen("/proc/net/route", "r");
412
        if (!r) return NULL;
413

    
414
        char iface[IFNAMSIZ] = "";
415
        char line[128] = "x";
416
        while (1) {
417
                char dst[32];
418
                char ifc[IFNAMSIZ];
419

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

    
429
        struct ifaddrs *ifAddrStruct=NULL;
430
        if (getifaddrs(&ifAddrStruct)) return NULL;
431

    
432
        while (ifAddrStruct) {
433
                if (ifAddrStruct->ifa_addr && ifAddrStruct->ifa_addr->sa_family == AF_INET && 
434
                        ifAddrStruct->ifa_name && !strcmp(ifAddrStruct->ifa_name, iface))  {
435
                        void *tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
436
                        return inet_ntop(AF_INET, tmpAddrPtr, addr, 127);
437
                }
438
        ifAddrStruct=ifAddrStruct->ifa_next;
439
        }
440

    
441
        return NULL;
442
}
443