Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ a7fc92ab

History | View | Annotate | Download (11.5 KB)

1 a0a1f630 KristianBeckers
/*
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 6759fdd0 AlessandroRusso
#include <event2/event.h>
43 a0a1f630 KristianBeckers
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 4c2e6802 TivadarSzemethy
#ifdef __linux__
52
#include <linux/if.h>
53
#include <ifaddrs.h>
54
#endif
55 a0a1f630 KristianBeckers
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 2a4d6ca0 TivadarSzemethy
#define LOG_MODULE "[ml] "
71 11fce711 MarcoBiazzini
#include "ml_log.h"
72 a0a1f630 KristianBeckers
73
/* debug varible: set to 1 if you want debug output  */
74 351ad48b RobertBirke
int verbose = 0;
75 a0a1f630 KristianBeckers
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 281a37d0 CsabaKiraly
      error("Could not create an UDP socket! ERRNO %d\n",errno);
97
      return -1;
98 a0a1f630 KristianBeckers
    }
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 4c2e6802 TivadarSzemethy
  if (returnStatus) {
124 281a37d0 CsabaKiraly
    error("Could not bind socketID to address! ERRNO %d\n",errno);
125
    return -2;
126 a0a1f630 KristianBeckers
  }
127 4f4687b8 ArpadBakay
#ifdef IP_MTU_DISCOVER
128 a0a1f630 KristianBeckers
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 11fce711 MarcoBiazzini
    error("setsockopt: set IP_DONTFRAG did not work. ERRNO %d\n",errno);
138 a0a1f630 KristianBeckers
    
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 11fce711 MarcoBiazzini
      error("setsockopt: cannot set RECV_TTL. ERRNO %d\n",errno);
145 a0a1f630 KristianBeckers
    }
146
147
  /* This option writes received internal and external(icmp) error messages into ancillary data */
148
  
149 4c2e6802 TivadarSzemethy
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVERR, &yes,size) < 0) { 
150 11fce711 MarcoBiazzini
        error("setsockopt: cannot set RECV_ERROR. ERRNO %d\n",errno);
151 a0a1f630 KristianBeckers
    }
152
  
153 4f4687b8 ArpadBakay
#endif
154 a0a1f630 KristianBeckers
155
  return udpSocket;
156
157
}
158
159
/* Information: read the standard TTL from a socket  */
160 8601bccf RobertBirke
int getTTL(const int udpSocket,uint8_t *ttl){
161
        unsigned int value;
162
        unsigned int size = sizeof(value);
163 a0a1f630 KristianBeckers
164 8601bccf RobertBirke
        if(getsockopt(udpSocket,SOL_IP,IP_TTL,&value,&size) == -1){
165 11fce711 MarcoBiazzini
                error("get TTL did not work\n");
166 8601bccf RobertBirke
                return 0;
167
        }
168 a0a1f630 KristianBeckers
169 8601bccf RobertBirke
        *ttl = value;
170 11fce711 MarcoBiazzini
        if(verbose == 1) debug("TTL is %i\n",value);
171 a0a1f630 KristianBeckers
172 8601bccf RobertBirke
        return 1;
173 a0a1f630 KristianBeckers
}
174
175 1af63d85 RobertBirke
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
176 a0a1f630 KristianBeckers
{
177 a3fd121c RobertBirke
        int error, ret;
178 1af63d85 RobertBirke
        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 a3fd121c RobertBirke
        ret = sendmsg(udpSocket,&msgh,0);
192
        if (ret  < 0){
193 1af63d85 RobertBirke
                error = errno;
194 11fce711 MarcoBiazzini
                debug("ML: sendmsg failed errno %d: %s\n", error, strerror(error));
195 1af63d85 RobertBirke
                switch(error) {
196
                        case EMSGSIZE:
197
                                return MSGLEN;
198
                        default:
199
                                return FAILURE;
200
                }
201
        }
202
        return OK;
203 a0a1f630 KristianBeckers
}
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 8885ed28 RobertBirke
216 11fce711 MarcoBiazzini
        if(verbose == 1) debug("handle Socket error is called\n");
217 8601bccf RobertBirke
218
        /* variables  */
219
        struct msghdr msgh;
220
        struct cmsghdr *cmsg;
221
        struct sock_extended_err *errptr;
222
        struct iovec iov;
223 c6898c39 RobertBirke
        struct sockaddr_in sender_addr;
224 8601bccf RobertBirke
        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 c6898c39 RobertBirke
        msgh.msg_name = &sender_addr;
232 8601bccf RobertBirke
        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 a7fc92ab CsabaKiraly
        if (returnStatus <= 0) {
248
                return -1;
249
        }
250 8601bccf RobertBirke
        for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)){
251
                //fill the error pointer
252 351ad48b RobertBirke
                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 fbb6e767 MarcoBiazzini
//                                error("no acillary error data \n");
257 351ad48b RobertBirke
//             return -1;
258
//                }
259 8601bccf RobertBirke
                /* check if the error originated locally */
260 351ad48b RobertBirke
                        if (errptr->ee_origin == SO_EE_ORIGIN_LOCAL){
261
                                if (errptr->ee_errno != EMSGSIZE) {
262
                                        if(verbose == 1)
263 11fce711 MarcoBiazzini
                                                error("local error: %s \n", strerror(errptr->ee_errno));
264 351ad48b RobertBirke
                                }
265 8601bccf RobertBirke
                        }
266 351ad48b RobertBirke
                        /* check if the error originated from an icmp message  */
267
                        if (errptr->ee_origin == SO_EE_ORIGIN_ICMP){
268
                                if(verbose == 1)
269 11fce711 MarcoBiazzini
                                        debug("icmp error message received\n");
270 8601bccf RobertBirke
271 351ad48b RobertBirke
                                int type = errptr->ee_type;
272
                                int code = errptr->ee_code;
273
                                icmp = 1;
274 11fce711 MarcoBiazzini
                                warn("icmp error message is type: %d code %d\n",
275 351ad48b RobertBirke
                                        errptr->ee_type,errptr->ee_code);
276 8601bccf RobertBirke
277 351ad48b RobertBirke
                                /* raise the pmtu callback when an pmtu error occurred 
278
                                *  -> icmp message type 3 code 4 icmp
279
                                */
280 8601bccf RobertBirke
281 351ad48b RobertBirke
                                if (type == 3 && code == 4){
282
                                        if(verbose == 1)
283 11fce711 MarcoBiazzini
                                                debug("pmtu error message received\n");
284 8601bccf RobertBirke
285 93a032eb TivadarSzemethy
                                        int mtusize = *bufsize;
286 351ad48b RobertBirke
                                        (icmpcb_value)(buf,mtusize);
287
                                }
288 8601bccf RobertBirke
                        }
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 11fce711 MarcoBiazzini
        //error("socketErrorHandle: before iofunc loop \n");
298 351ad48b RobertBirke
/* @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 e5a04498 CsabaKiraly
        int transbuf;
302
        memcpy(&transbuf,bufsize,4);
303
        
304 8601bccf RobertBirke
        if(iofunc == 1) {
305
                sendPacket(udpSocket,buf,transbuf,addr,icmpcb_value);
306
                if(verbose == 1)
307 11fce711 MarcoBiazzini
                        error("handle socket error: packetsize %i \n ",*bufsize );
308 8601bccf RobertBirke
        } else {
309
                if(iofunc == 2 && icmp == 1){
310
                        if(verbose == 1)
311 11fce711 MarcoBiazzini
                                error("handleSOcketError: recvPacket called \n ");
312 8601bccf RobertBirke
                        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 11fce711 MarcoBiazzini
                                error("handleSocketError: unrelated error \n");
317 8601bccf RobertBirke
                        *ttl = -1;
318
                }
319 a0a1f630 KristianBeckers
        }
320 351ad48b RobertBirke
#endif
321 8601bccf RobertBirke
        return 0;
322 a0a1f630 KristianBeckers
}
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 351ad48b RobertBirke
        
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 380cf1b9 RobertBirke
        msgh.msg_iov->iov_len = *recvSize;
346 351ad48b RobertBirke
        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 11fce711 MarcoBiazzini
                        error("udpSocket:recvPacket: Read the error queue \n ");
367
                        error("recvmsg failed. errno %d \n",errno);
368 351ad48b RobertBirke
                }
369
                // TODO debug code: delete afterwards start
370 e5a04498 CsabaKiraly
                if(errno == 11) {        //TODO: What is this 11, and why is it here with a NOP?
371 351ad48b RobertBirke
                        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 11fce711 MarcoBiazzini
                        debug("udpSocket_recvPacket: Message received.\n");
380 a0a1f630 KristianBeckers
381 351ad48b RobertBirke
                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 11fce711 MarcoBiazzini
                                        debug("received ttl true: %i  \n ",received_ttl);
388 351ad48b RobertBirke
                                break;
389
                        }
390
                }
391
        }
392 a0a1f630 KristianBeckers
}
393
394
395
int closeSocket(int udpSocket)
396
{
397
398
  /*cleanup */
399
  close(udpSocket);
400
  return 0;
401
  
402
}
403 4c2e6802 TivadarSzemethy
404 da5dade7 MarcoBiazzini
const char *mlAutodetectIPAddress() {
405 4c2e6802 TivadarSzemethy
#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 86f87418 TivadarSzemethy
                char *dummy = fgets(line, 127, r);
421 4c2e6802 TivadarSzemethy
                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
}