Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ 52f7925a

History | View | Annotate | Download (11.4 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 52f7925a TivadarSzemethy
#include "grapes_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 4c2e6802 TivadarSzemethy
      fatal("Could not create an UDP socket!");
97 a0a1f630 KristianBeckers
      exit(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 4c2e6802 TivadarSzemethy
  if (returnStatus) {
124
    fatal("Could not bind socketID to address!");
125 a0a1f630 KristianBeckers
  }
126 4f4687b8 ArpadBakay
#ifdef IP_MTU_DISCOVER
127 a0a1f630 KristianBeckers
128
  int yes = 1;
129
  int size = sizeof(int);
130
  int pmtuopt = IP_PMTUDISC_DO;
131
132
  /*Setting the automatic PMTU discoery function from the socket
133
   * This sets the DON'T FRAGMENT bit on the IP HEADER
134
   */
135
  if(setsockopt(udpSocket,IPPROTO_IP,IP_MTU_DISCOVER,&pmtuopt ,size) == -1){
136 4c2e6802 TivadarSzemethy
    error("setsockopt: set IP_DONTFRAG did not work. ERRNO %d",errno);
137 a0a1f630 KristianBeckers
    
138
  }
139
  
140
  /* This option writes the IP_TTL field into ancillary data */
141
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVTTL, &yes,size) < 0)
142
    {
143 4c2e6802 TivadarSzemethy
      error("setsockopt: cannot set RECV_TTL. ERRNO %d",errno);
144 a0a1f630 KristianBeckers
    }
145
146
  /* This option writes received internal and external(icmp) error messages into ancillary data */
147
  
148 4c2e6802 TivadarSzemethy
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVERR, &yes,size) < 0) { 
149
        error("setsockopt: cannot set RECV_ERROR. ERRNO %d",errno);
150 a0a1f630 KristianBeckers
    }
151
  
152 4f4687b8 ArpadBakay
#endif
153 a0a1f630 KristianBeckers
154
  return udpSocket;
155
156
}
157
158
/* Information: read the standard TTL from a socket  */
159 8601bccf RobertBirke
int getTTL(const int udpSocket,uint8_t *ttl){
160
        unsigned int value;
161
        unsigned int size = sizeof(value);
162 a0a1f630 KristianBeckers
163 8601bccf RobertBirke
        if(getsockopt(udpSocket,SOL_IP,IP_TTL,&value,&size) == -1){
164 4c2e6802 TivadarSzemethy
                error("get TTL did not work");
165 8601bccf RobertBirke
                return 0;
166
        }
167 a0a1f630 KristianBeckers
168 8601bccf RobertBirke
        *ttl = value;
169 4c2e6802 TivadarSzemethy
        if(verbose == 1) debug("TTL is %i",value);
170 a0a1f630 KristianBeckers
171 8601bccf RobertBirke
        return 1;
172 a0a1f630 KristianBeckers
}
173
174 1af63d85 RobertBirke
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
175 a0a1f630 KristianBeckers
{
176 a3fd121c RobertBirke
        int error, ret;
177 1af63d85 RobertBirke
        struct msghdr msgh;
178
179
        msgh.msg_name = socketaddr;
180
        msgh.msg_namelen = sizeof(struct sockaddr_in);
181
        msgh.msg_iov = iov;
182
        msgh.msg_iovlen = len;
183
        msgh.msg_flags = 0;
184
185
        /* we do not send ancilliary data  */
186
        msgh.msg_control = 0;
187
        msgh.msg_controllen = 0;
188
189
        /* send the message  */
190 a3fd121c RobertBirke
        ret = sendmsg(udpSocket,&msgh,0);
191
        if (ret  < 0){
192 1af63d85 RobertBirke
                error = errno;
193
                debug("ML: sendmsg failed errno %d: %s", error, strerror(error));
194
                switch(error) {
195
                        case EMSGSIZE:
196
                                return MSGLEN;
197
                        default:
198
                                return FAILURE;
199
                }
200
        }
201
        return OK;
202 a0a1f630 KristianBeckers
}
203
204
/* A general error handling function on socket operations
205
 * that is called when sendmsg or recvmsg report an Error
206
 *
207
 */
208
209
//This function has to deal with what to do when an icmp is received
210
//--check the connection array, look to which connection-establishment the icmp belongs
211
//--invoke a retransmission 
212
int handleSocketError(const int udpSocket,const int iofunc,char *buf,int *bufsize,struct sockaddr_in *addr,icmp_error_cb icmpcb_value,int *ttl){
213
214 8885ed28 RobertBirke
215 4c2e6802 TivadarSzemethy
        if(verbose == 1) debug("handle Socket error is called");
216 8601bccf RobertBirke
217
        /* variables  */
218
        struct msghdr msgh;
219
        struct cmsghdr *cmsg;
220
        struct sock_extended_err *errptr;
221
        struct iovec iov;
222
        struct sockaddr_in *sender_addr;
223
        int returnStatus;
224
        char errbuf[CMSG_SPACE(1024)]; 
225
        int recvbufsize = 1500;
226
        char recvbuf[recvbufsize];
227
        int icmp = 0;
228
        
229
        /* initialize recvmsg data  */
230
        msgh.msg_name = sender_addr;
231
        msgh.msg_namelen = sizeof(struct sockaddr_in);
232
        msgh.msg_iov = &iov;
233
        msgh.msg_iovlen = 1;
234
        msgh.msg_iov->iov_base = recvbuf;
235
        msgh.msg_iov->iov_len = recvbufsize;
236
        msgh.msg_flags = 0;
237
        
238
        //set the size of the control data
239
        msgh.msg_control = errbuf;
240
        msgh.msg_controllen = sizeof(errbuf);
241
        //initialize pointer 
242
        errptr = NULL;
243
244
        /* get the error from the error que:  */
245
        returnStatus = recvmsg(udpSocket,&msgh,MSG_ERRQUEUE|MSG_DONTWAIT);
246
        for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)){
247
                //fill the error pointer
248 351ad48b RobertBirke
                if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVERR) {
249
                        errptr = (struct sock_extended_err *)CMSG_DATA(cmsg);
250
//                        if (errptr == NULL){
251
//                        if(verbose == 1)
252
//                                printf("no acillary error data \n");
253
//             return -1;
254
//                }
255 8601bccf RobertBirke
                /* check if the error originated locally */
256 351ad48b RobertBirke
                        if (errptr->ee_origin == SO_EE_ORIGIN_LOCAL){
257
                                if (errptr->ee_errno != EMSGSIZE) {
258
                                        if(verbose == 1)
259
                                                printf("local error: %s \n", strerror(errptr->ee_errno));
260
                                }
261 8601bccf RobertBirke
                        }
262 351ad48b RobertBirke
                        /* check if the error originated from an icmp message  */
263
                        if (errptr->ee_origin == SO_EE_ORIGIN_ICMP){
264
                                if(verbose == 1)
265 81e17b78 TivadarSzemethy
                                        debug("icmp error message received");
266 8601bccf RobertBirke
267 351ad48b RobertBirke
                                int type = errptr->ee_type;
268
                                int code = errptr->ee_code;
269
                                icmp = 1;
270 81e17b78 TivadarSzemethy
                                warn("icmp error message is type: %d code %d",
271 351ad48b RobertBirke
                                        errptr->ee_type,errptr->ee_code);
272 8601bccf RobertBirke
273 351ad48b RobertBirke
                                /* raise the pmtu callback when an pmtu error occurred 
274
                                *  -> icmp message type 3 code 4 icmp
275
                                */
276 8601bccf RobertBirke
277 351ad48b RobertBirke
                                if (type == 3 && code == 4){
278
                                        if(verbose == 1)
279 81e17b78 TivadarSzemethy
                                                debug("pmtu error message received");
280 8601bccf RobertBirke
281 93a032eb TivadarSzemethy
                                        int mtusize = *bufsize;
282 351ad48b RobertBirke
                                        (icmpcb_value)(buf,mtusize);
283
                                }
284 8601bccf RobertBirke
                        }
285
                }
286
        } //end of for
287
288
        /* after the error is read from the socket error queue the 
289
        * socket operation that was interrupeted by reading the error queue
290
        * has to be carried out
291
        */
292
293
        //printf("socketErrorHandle: before iofunc loop \n");
294
        int transbuf;
295
        memcpy(&transbuf,bufsize,4);
296 a0a1f630 KristianBeckers
        
297 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
298
better error handling might be needed */
299
#if 0
300 8601bccf RobertBirke
        if(iofunc == 1) {
301
                sendPacket(udpSocket,buf,transbuf,addr,icmpcb_value);
302
                if(verbose == 1)
303
                        printf("handle socket error: packetsize %i \n ",*bufsize );
304
        } else {
305
                if(iofunc == 2 && icmp == 1){
306
                        if(verbose == 1)
307
                                printf("handleSOcketError: recvPacket called \n ");
308
                        recvPacket(udpSocket,buf,bufsize,addr,icmpcb_value,ttl);
309
                } else {
310
                /* this is the case the socket has just an error message not related to anything of the messaging layer */
311
                        if(verbose == 1)
312
                                printf("handleSocketError: unrelated error \n");
313
                        *ttl = -1;
314
                }
315 a0a1f630 KristianBeckers
        }
316 351ad48b RobertBirke
#endif
317 8601bccf RobertBirke
        return 0;
318 a0a1f630 KristianBeckers
}
319
320
321
322
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
323
{
324 351ad48b RobertBirke
        
325
        /* variables  */
326
        struct msghdr msgh; 
327
        struct cmsghdr *cmsg;
328
        int *ttlptr;
329
        int received_ttl;
330
        struct iovec iov;
331
        //struct sockaddr_in sender_addr;
332
        //unsigned int sender_len;
333
        int returnStatus;
334
        
335
        /* initialize recvmsg data  */
336
        msgh.msg_name = udpdst;
337
        msgh.msg_namelen = sizeof(struct sockaddr_in);
338
        msgh.msg_iov = &iov;
339
        msgh.msg_iovlen = 1;
340
        msgh.msg_iov->iov_base = buffer;
341 380cf1b9 RobertBirke
        msgh.msg_iov->iov_len = *recvSize;
342 351ad48b RobertBirke
        msgh.msg_flags = 0;
343
        
344
        /*
345
        *  This shows the receiving of TTL within the ancillary data of recvmsg
346
        */
347
        
348
        // ancilliary data buffer 
349
        char ttlbuf[CMSG_SPACE(sizeof(int))];
350
        
351
        //set the size of the control data
352
        msgh.msg_control = ttlbuf;
353
        msgh.msg_controllen = sizeof(ttlbuf);
354
                
355
        returnStatus = recvmsg(udpSocket,&msgh,0);
356
        msgh.msg_iov->iov_len = returnStatus;
357
        
358
        *recvSize = returnStatus;
359
        /* receive the message */
360
        if (returnStatus < 0) {
361
                if(verbose == 1) {
362
                        printf("udpSocket:recvPacket: Read the error queue \n ");
363
                        printf("recvmsg failed. errno %d \n",errno);
364
                }
365
                // TODO debug code: delete afterwards start
366
                if(errno == 11) {
367
                        int a;
368
                        a++; 
369
                };
370
                // end
371
                handleSocketError(udpSocket,2,buffer,recvSize,udpdst,icmpcb_value,ttl);
372
        } else {
373
                /* debug code  */
374
                if(verbose == 1)
375
                        printf("udpSocket_recvPacket: Message received.\n");
376 a0a1f630 KristianBeckers
377 351ad48b RobertBirke
                for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
378
                        if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL) {
379
                                ttlptr = (int *) CMSG_DATA(cmsg);
380
                                received_ttl = *ttlptr;
381
                                memcpy(ttl,ttlptr,4);
382
                                if(verbose == 1)
383
                                        printf("received ttl true: %i  \n ",received_ttl);
384
                                break;
385
                        }
386
                }
387
        }
388 a0a1f630 KristianBeckers
}
389
390
391
int closeSocket(int udpSocket)
392
{
393
394
  /*cleanup */
395
  close(udpSocket);
396
  return 0;
397
  
398
}
399 4c2e6802 TivadarSzemethy
400
const char *autodetect_ipaddress() {
401
#ifndef __linux__
402
        return NULL;
403
#endif
404
405
        static char addr[128] = "";
406
407
        FILE *r = fopen("/proc/net/route", "r");
408
        if (!r) return NULL;
409
410
        char iface[IFNAMSIZ] = "";
411
        char line[128] = "x";
412
        while (1) {
413
                char dst[32];
414
                char ifc[IFNAMSIZ];
415
416 86f87418 TivadarSzemethy
                char *dummy = fgets(line, 127, r);
417 4c2e6802 TivadarSzemethy
                if (feof(r)) break;
418
                if ((sscanf(line, "%s\t%s", iface, dst) == 2) && !strcpy(dst, "00000000")) {
419
                        strcpy(iface, ifc);
420
                         break;
421
                }
422
        }
423
        if (iface[0] == 0) return NULL;
424
425
        struct ifaddrs *ifAddrStruct=NULL;
426
        if (getifaddrs(&ifAddrStruct)) return NULL;
427
428
        while (ifAddrStruct) {
429
                if (ifAddrStruct->ifa_addr && ifAddrStruct->ifa_addr->sa_family == AF_INET && 
430
                        ifAddrStruct->ifa_name && !strcmp(ifAddrStruct->ifa_name, iface))  {
431
                        void *tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
432
                        return inet_ntop(AF_INET, tmpAddrPtr, addr, 127);
433
                }
434
        ifAddrStruct=ifAddrStruct->ifa_next;
435
        }
436
437
        return NULL;
438
}