Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ 52f7925a

History | View | Annotate | Download (11.4 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 "grapes_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
      fatal("Could not create an UDP socket!");
97
      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
  if (returnStatus) {
124
    fatal("Could not bind socketID to address!");
125
  }
126
#ifdef IP_MTU_DISCOVER
127

    
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
    error("setsockopt: set IP_DONTFRAG did not work. ERRNO %d",errno);
137
    
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
      error("setsockopt: cannot set RECV_TTL. ERRNO %d",errno);
144
    }
145

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

    
154
  return udpSocket;
155

    
156
}
157

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

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

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

    
171
        return 1;
172
}
173

    
174
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
175
{
176
        int error, ret;
177
        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
        ret = sendmsg(udpSocket,&msgh,0);
191
        if (ret  < 0){
192
                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
}
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

    
215
        if(verbose == 1) debug("handle Socket error is called");
216

    
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
                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
                /* check if the error originated locally */
256
                        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
                        }
262
                        /* check if the error originated from an icmp message  */
263
                        if (errptr->ee_origin == SO_EE_ORIGIN_ICMP){
264
                                if(verbose == 1)
265
                                        debug("icmp error message received");
266

    
267
                                int type = errptr->ee_type;
268
                                int code = errptr->ee_code;
269
                                icmp = 1;
270
                                warn("icmp error message is type: %d code %d",
271
                                        errptr->ee_type,errptr->ee_code);
272

    
273
                                /* raise the pmtu callback when an pmtu error occurred 
274
                                *  -> icmp message type 3 code 4 icmp
275
                                */
276

    
277
                                if (type == 3 && code == 4){
278
                                        if(verbose == 1)
279
                                                debug("pmtu error message received");
280

    
281
                                        int mtusize = *bufsize;
282
                                        (icmpcb_value)(buf,mtusize);
283
                                }
284
                        }
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
        
297
/* @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
        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
        }
316
#endif
317
        return 0;
318
}
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
        
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
        msgh.msg_iov->iov_len = *recvSize;
342
        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

    
377
                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
}
389

    
390

    
391
int closeSocket(int udpSocket)
392
{
393

    
394
  /*cleanup */
395
  close(udpSocket);
396
  return 0;
397
  
398
}
399

    
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
                char *dummy = fgets(line, 127, r);
417
                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
}
439