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