Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ 2a4d6ca0

History | View | Annotate | Download (10.7 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

    
52
#include <errno.h>
53
#include <string.h>
54
#include <netdb.h>
55
#include <netinet/in.h>
56

    
57
#include <resolv.h>
58
#include <sys/time.h>
59
#include <sys/uio.h>
60
#include <arpa/inet.h>
61

    
62
#include <unistd.h>
63
#include <stdlib.h>
64

    
65
#include "udpSocket.h"
66
#define LOG_MODULE "[ml] "
67
#include "pulse_log.h"
68

    
69
/* debug varible: set to 1 if you want debug output  */
70
int verbose = 0;
71

    
72
int createSocket(const int port,const char *ipaddr)
73
{
74
  /* variables needed */
75
  struct sockaddr_in udpsrc, udpdst;
76
  
77
  int returnStatus = 0;
78

    
79
  //int udpSocket = 0;
80
  /*libevent2*/
81
  evutil_socket_t udpSocket;
82

    
83
  /* create a socket */
84
  udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
85

    
86
  /*libevent2*/
87
  evutil_make_socket_nonblocking(udpSocket);
88

    
89
  //This is debug code that checks if the socket was created 
90
  if (udpSocket == -1)
91
    {
92
      fprintf(stderr, "Could not create a socket!\n");
93
      exit(1);
94
    }
95
  else
96
    {
97
      if(verbose == 1){
98
      printf("Socket created.\n" );
99
      }
100
    }
101

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

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

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

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

    
124
  /* This is debug code */
125
  if (returnStatus == 0) {
126
    if(verbose == 1){
127
    fprintf(stderr, "SocketID bind completed!\n");
128
    }
129
  }
130
  else{
131
    fprintf(stderr, "Could not bind socketID to address!\n");
132
    close(udpSocket);
133
    exit(1);
134
  }
135

    
136
  int yes = 1;
137
  int size = sizeof(int);
138
  int pmtuopt = IP_PMTUDISC_DO;
139

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

    
155
  /* This option writes received internal and external(icmp) error messages into ancillary data */
156
  
157
  if(setsockopt(udpSocket,IPPROTO_IP, IP_RECVERR, &yes,size) < 0)
158
    {
159
      printf("setsockopt: cannot set RECV_ERROR. ERRNO %d \n",errno);
160
    }
161
  
162

    
163
  return udpSocket;
164

    
165
}
166

    
167
/* Information: read the standard TTL from a socket  */
168
int getTTL(const int udpSocket,uint8_t *ttl){
169
        unsigned int value;
170
        unsigned int size = sizeof(value);
171

    
172
        if(getsockopt(udpSocket,SOL_IP,IP_TTL,&value,&size) == -1){
173
                printf("get TTL did not work \n ");
174
                return 0;
175
        }
176

    
177
        *ttl = value;
178
        if(verbose == 1)
179
                printf("TTL is %i \n",value);
180

    
181
        return 1;
182
}
183

    
184
int sendPacket(const int udpSocket, struct iovec *iov, int len, struct sockaddr_in *socketaddr)
185
{
186
        int error, ret;
187
        struct msghdr msgh;
188

    
189
        msgh.msg_name = socketaddr;
190
        msgh.msg_namelen = sizeof(struct sockaddr_in);
191
        msgh.msg_iov = iov;
192
        msgh.msg_iovlen = len;
193
        msgh.msg_flags = 0;
194

    
195
        /* we do not send ancilliary data  */
196
        msgh.msg_control = 0;
197
        msgh.msg_controllen = 0;
198

    
199
        /* send the message  */
200
        ret = sendmsg(udpSocket,&msgh,0);
201
        if (ret  < 0){
202
                error = errno;
203
                debug("ML: sendmsg failed errno %d: %s", error, strerror(error));
204
                switch(error) {
205
                        case EMSGSIZE:
206
                                return MSGLEN;
207
                        default:
208
                                return FAILURE;
209
                }
210
        }
211
        return OK;
212
}
213

    
214
/* A general error handling function on socket operations
215
 * that is called when sendmsg or recvmsg report an Error
216
 *
217
 */
218

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

    
224

    
225
        if(verbose == 1)
226
                printf("handle Socket error is called \n");
227

    
228
        /* variables  */
229
        struct msghdr msgh;
230
        struct cmsghdr *cmsg;
231
        struct sock_extended_err *errptr;
232
        struct iovec iov;
233
        struct sockaddr_in *sender_addr;
234
        int returnStatus;
235
        char errbuf[CMSG_SPACE(1024)]; 
236
        int recvbufsize = 1500;
237
        char recvbuf[recvbufsize];
238
        int icmp = 0;
239
        
240
        /* initialize recvmsg data  */
241
        msgh.msg_name = sender_addr;
242
        msgh.msg_namelen = sizeof(struct sockaddr_in);
243
        msgh.msg_iov = &iov;
244
        msgh.msg_iovlen = 1;
245
        msgh.msg_iov->iov_base = recvbuf;
246
        msgh.msg_iov->iov_len = recvbufsize;
247
        msgh.msg_flags = 0;
248
        
249
        //set the size of the control data
250
        msgh.msg_control = errbuf;
251
        msgh.msg_controllen = sizeof(errbuf);
252
        //initialize pointer 
253
        errptr = NULL;
254

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

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

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

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

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

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

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

    
331

    
332

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

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

    
401

    
402
int closeSocket(int udpSocket)
403
{
404

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