Statistics
| Branch: | Revision:

ml / util / udpSocket.c @ 8885ed28

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

    
67
/* debug varible: set to 1 if you want debug output  */
68
int verbose = 1;
69

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

    
77
  //int udpSocket = 0;
78
  /*libevent2*/
79
  evutil_socket_t udpSocket;
80

    
81
  /* create a socket */
82
  udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
83

    
84
  /*libevent2*/
85
  evutil_make_socket_nonblocking(udpSocket);
86

    
87
  //This is debug code that checks if the socket was created 
88
  if (udpSocket == -1)
89
    {
90
      fprintf(stderr, "Could not create a socket!\n");
91
      exit(1);
92
    }
93
  else
94
    {
95
      if(verbose == 1){
96
      printf("Socket created.\n" );
97
      }
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 == 0) {
124
    if(verbose == 1){
125
    fprintf(stderr, "SocketID bind completed!\n");
126
    }
127
  }
128
  else{
129
    fprintf(stderr, "Could not bind socketID to address!\n");
130
    close(udpSocket);
131
    exit(1);
132
  }
133

    
134
  int yes = 1;
135
  int size = sizeof(int);
136
  int pmtuopt = IP_PMTUDISC_DO;
137

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

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

    
161
  return udpSocket;
162

    
163
}
164

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

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

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

    
179
        return 1;
180
}
181

    
182
void sendPacket(const int udpSocket,char *buffer,int bufferSize,struct sockaddr_in *socketaddr,icmp_error_cb icmpcb_value)
183
{
184
        /* check the pkg size  */
185
        if (bufferSize > MAXBUF)
186
      bufferSize = MAXBUF;
187

    
188
  int returnValue;
189
  int addrlen = 0;
190
  struct msghdr msgh = {0};
191
  struct iovec iov;
192

    
193
  /* set the sendmsg data  */
194
  addrlen = sizeof(struct sockaddr_in);
195
  msgh.msg_name = socketaddr;
196
  msgh.msg_namelen = addrlen;
197
  msgh.msg_iov = &iov;
198
  msgh.msg_iovlen = 1;
199
  msgh.msg_iov->iov_base = buffer;
200
  msgh.msg_iov->iov_len = bufferSize;
201
  msgh.msg_flags = 0;
202

    
203
  /* we do not send ancilliary data  */
204
  msgh.msg_control = 0;
205
  msgh.msg_controllen = 0;
206

    
207
  /* try sending the message
208
   * in case the socket error queue has an error 
209
   * this is given to the handle function
210
   */
211
  returnValue = sendmsg(udpSocket,&msgh,0);
212

    
213
  /* send the message  */
214
  if (returnValue  < 0){
215
    /* debug code */
216
    //printf( "sendmsg error %d %d  \n",errno,n);
217
    if(verbose == 1)
218
                printf("udpSocket:sendPacket: Read the error queue \n ");
219

    
220
    /* call the handle socket errors  */
221
    handleSocketError(udpSocket,1,buffer,&bufferSize,socketaddr,icmpcb_value,NULL);
222
  }else{
223
    /* debug code  */
224
    if(verbose == 1)
225
                printf("udpSocket_sendPacket: Message sent.\n");
226
  }
227
}
228

    
229
/* A general error handling function on socket operations
230
 * that is called when sendmsg or recvmsg report an Error
231
 *
232
 */
233

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

    
239

    
240
        if(verbose == 1)
241
                printf("handle Socket error is called \n");
242

    
243

    
244
        /* variables  */
245
        struct msghdr msgh;
246
        struct cmsghdr *cmsg;
247
        struct sock_extended_err *errptr;
248
        struct iovec iov;
249
        struct sockaddr_in *sender_addr;
250
        int returnStatus;
251
        char errbuf[CMSG_SPACE(1024)]; 
252
        int recvbufsize = 1500;
253
        char recvbuf[recvbufsize];
254
        int icmp = 0;
255
        
256
        /* initialize recvmsg data  */
257
        msgh.msg_name = sender_addr;
258
        msgh.msg_namelen = sizeof(struct sockaddr_in);
259
        msgh.msg_iov = &iov;
260
        msgh.msg_iovlen = 1;
261
        msgh.msg_iov->iov_base = recvbuf;
262
        msgh.msg_iov->iov_len = recvbufsize;
263
        msgh.msg_flags = 0;
264
        
265
        //set the size of the control data
266
        msgh.msg_control = errbuf;
267
        msgh.msg_controllen = sizeof(errbuf);
268
        //initialize pointer 
269
        errptr = NULL;
270

    
271
        /* get the error from the error que:  */
272
        returnStatus = recvmsg(udpSocket,&msgh,MSG_ERRQUEUE|MSG_DONTWAIT);
273
        for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)){
274
                //fill the error pointer
275
                errptr = (struct sock_extended_err *)CMSG_DATA(cmsg);
276
                if (errptr == NULL){
277
                        if(verbose == 1)
278
                                printf("no acillary error data \n");
279
             return -1;
280
                }
281
                /* check if the error originated locally */
282
                if (errptr->ee_origin == SO_EE_ORIGIN_LOCAL){
283
                        if (errptr->ee_errno != EMSGSIZE) {
284
                                if(verbose == 1)
285
                                        printf("local error: %s \n", strerror(errptr->ee_errno));
286
                        }
287
                }
288
                /* check if the error originated from an icmp message  */
289
                if (errptr->ee_origin == SO_EE_ORIGIN_ICMP){
290
                        if(verbose == 1)
291
                                printf("icmp error message received \n");
292

    
293
                        int type = errptr->ee_type;
294
                        int code = errptr->ee_code;
295
                        icmp = 1;
296
                        printf("icmp error message is type: %d code %d \n ",errptr->ee_type,errptr->ee_code);
297

    
298
                        /* raise the pmtu callback when an pmtu error occurred 
299
                        *  -> icmp message type 3 code 4 icmp
300
                        */
301

    
302
                        if (type == 3 && code == 4){
303
                                if(verbose == 1)
304
                                        printf("pmtu error message received \n");
305

    
306
                                int mtusize = bufsize;
307
                                (icmpcb_value)(buf,mtusize);
308
                        }
309
                }
310
        } //end of for
311

    
312
        /* after the error is read from the socket error queue the 
313
        * socket operation that was interrupeted by reading the error queue
314
        * has to be carried out
315
        */
316

    
317
        //printf("socketErrorHandle: before iofunc loop \n");
318
        int transbuf;
319
        memcpy(&transbuf,bufsize,4);
320
        
321
        if(iofunc == 1) {
322
                sendPacket(udpSocket,buf,transbuf,addr,icmpcb_value);
323
                if(verbose == 1)
324
                        printf("handle socket error: packetsize %i \n ",*bufsize );
325
        } else {
326
                if(iofunc == 2 && icmp == 1){
327
                        if(verbose == 1)
328
                                printf("handleSOcketError: recvPacket called \n ");
329
                        recvPacket(udpSocket,buf,bufsize,addr,icmpcb_value,ttl);
330
                } else {
331
                /* this is the case the socket has just an error message not related to anything of the messaging layer */
332
                        if(verbose == 1)
333
                                printf("handleSocketError: unrelated error \n");
334
                        *ttl = -1;
335
                }
336
        }
337
        return 0;
338
}
339

    
340

    
341

    
342
void recvPacket(const int udpSocket,char *buffer,int *recvSize,struct sockaddr_in *udpdst,icmp_error_cb icmpcb_value,int *ttl)
343
{
344

    
345
  /* variables  */
346
  struct msghdr msgh; 
347
  struct cmsghdr *cmsg;
348
  int *ttlptr;
349
  int received_ttl;
350
  struct iovec iov;
351
  //struct sockaddr_in sender_addr;
352
  //unsigned int sender_len;
353
  int returnStatus;
354

    
355
  /* initialize recvmsg data  */
356
  msgh.msg_name = udpdst;
357
  msgh.msg_namelen = sizeof(struct sockaddr_in);
358
  msgh.msg_iov = &iov;
359
  msgh.msg_iovlen = 1;
360
  msgh.msg_iov->iov_base = buffer;
361
  msgh.msg_iov->iov_len = 1500;
362
  msgh.msg_flags = 0;
363

    
364
  /*
365
   *  This shows the receiving of TTL within the ancillary data of recvmsg
366
   */
367
 
368
  // ancilliary data buffer 
369
  char ttlbuf[CMSG_SPACE(sizeof(int))];
370
 
371
  //set the size of the control data
372
  msgh.msg_control = ttlbuf;
373
  msgh.msg_controllen = sizeof(ttlbuf);
374
    
375
  returnStatus = recvmsg(udpSocket,&msgh,0);
376
  msgh.msg_iov->iov_len = returnStatus;
377

    
378
  *recvSize = returnStatus;
379
  /* receive the message */
380
  if ( returnStatus < 0){
381
    if(verbose == 1){
382

    
383
    printf("udpSocket:recvPacket: Read the error queue \n ");
384
    printf("recvmsg failed. errno %d \n",errno);
385
    }
386
    handleSocketError(udpSocket,2,buffer,recvSize,udpdst,icmpcb_value,ttl);
387
    
388
  }else
389

    
390
    {
391
  /* debug code  */
392
      if(verbose == 1){
393

    
394
  printf("udpSocket_recvPacket: Message received.\n");
395
      }  
396
           for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
397
               if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TTL)               { 
398
                 if(verbose == 1){
399

    
400
                    printf("ttl \n");
401
                 }
402
                    ttlptr = (int *) CMSG_DATA(cmsg);
403
                    received_ttl = *ttlptr;
404
                    memcpy(ttl,ttlptr,4);
405
                    if(verbose == 1){
406

    
407
                    printf("received ttl true: %i  \n ",received_ttl);
408
                    }
409
                    break;
410
               }
411

    
412
      }
413
 
414
  }
415

    
416
}
417

    
418

    
419
int closeSocket(int udpSocket)
420
{
421

    
422
  /*cleanup */
423
  close(udpSocket);
424
  return 0;
425
  
426
}