1 /** \file alc_socket.c \brief Socket functions
2  *
3  *  $Author: peltotal $ $Date: 2007/02/28 08:58:00 $ $Revision: 1.49 $
4  *
5  *  MAD-ALCLIB: Implementation of ALC/LCT protocols, Compact No-Code FEC,
6  *  Simple XOR FEC, Reed-Solomon FEC, and RLC Congestion Control protocol.
7  *  Copyright (c) 2003-2007 TUT - Tampere University of Technology
8  *  main authors/contacts: jani.peltotalo@tut.fi and sami.peltotalo@tut.fi
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  *  In addition, as a special exception, TUT - Tampere University of Technology
25  *  gives permission to link the code of this program with the OpenSSL library (or
26  *  with modified versions of OpenSSL that use the same license as OpenSSL), and
27  *  distribute linked combinations including the two. You must obey the GNU
28  *  General Public License in all respects for all of the code used other than
29  *  OpenSSL. If you modify this file, you may extend this exception to your version
30  *  of the file, but you are not obligated to do so. If you do not wish to do so,
31  *  delete this exception statement from your version.
32  */
33 
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <sys/types.h>
39 
40 #ifdef _MSC_VER
41 #include <io.h>
42 #else
43 #include <sys/socket.h>
44 #include <netdb.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <net/if.h>
48 #include <unistd.h>
49 #endif
50 
51 #include "alc_socket.h"
52 
53 /**
54 * This is a private function which reports the error
55 *
56 * @return the code error
57 *
58 */
59 
error_socket()60 int error_socket() {
61 #ifdef _MSC_VER
62     return WSAGetLastError();
63 #else
64     return errno;
65 #endif
66 }
67 
68 /**
69 * This is a private function which closes the socket
70 *
71 * @param a_socket socket to be closed
72 *
73 * @return 0 in success, -1 otherwise
74 *
75 */
76 
77 #ifdef _MSC_VER
close_socket(SOCKET a_socket)78 int close_socket(SOCKET a_socket) {
79     return closesocket(a_socket);
80 #else
81 int close_socket(int a_socket) {
82     return close(a_socket);
83 #endif
84 }
85 
86 int init_alc_socket(alc_channel_t *ch) {
87 
88   int receiver_socket_buffer_size = RECEIVER_SOCKET_BUFFER_SIZE;
89   int ttl;
90   int loop;
91   int reuse;
92   int mode;
93   int addr_type;
94   struct addrinfo hints, *local;
95   struct in_addr if_addr;	/* interface IP address for IPv4 multicast */
96   int return_value;
97 
98 #if defined(LINUX) && defined(SSM)
99   struct sockaddr_in6 source;
100 #endif
101 
102   local = NULL;
103   mode = ch->s->mode;
104   addr_type = ch->s->addr_type;
105 
106   if(mode == SENDER) {
107 
108     if((ch->tx_sock  = socket(ch->s->addr_family, SOCK_DGRAM, 0)) < 0) {
109 	  printf("socket failed with: %d\n", error_socket());
110       fflush(stdout);
111       return -1;
112     }
113 
114     memset(&hints, 0, sizeof(hints));
115     hints.ai_family = ch->s->addr_family;
116     hints.ai_socktype = SOCK_DGRAM;
117 
118     /* ch->addrinfo is used in sendto function */
119 
120     if((return_value = getaddrinfo(ch->addr, ch->port, &hints, &ch->addrinfo)) != 0) {
121 #ifdef _MSC_VER
122       printf("getaddrinfo failed: %d\n", error_socket());
123 #else
124       if(return_value == EAI_SYSTEM) {
125 		printf("getaddrinfo failed: %d\n", error_socket());
126       }
127 	  else{
128 		printf("getaddrinfo failed: %d %s\n", return_value, gai_strerror(return_value));
129       }
130 #endif
131 	  fflush(stdout);
132       close_socket(ch->tx_sock);
133       return -1;
134     }
135 
136     /* Bind the socket to right interface */
137 
138     if(ch->intface != NULL) {
139 
140       if((((ch->s->addr_family == PF_INET6)) || (addr_type == 1))) {
141 
142 		if((return_value = getaddrinfo(ch->intface, 0, &hints, &local)) != 0) {
143 #ifdef _MSC_VER
144 			printf("getaddrinfo failed: %d\n", error_socket());
145 #else
146 			if(return_value == EAI_SYSTEM) {
147 				printf("getaddrinfo failed: %d\n", error_socket());
148 			}
149 			else{
150 				printf("getaddrinfo failed: %d %s\n", return_value, gai_strerror(return_value));
151 			}
152 #endif
153 			fflush(stdout);
154 			close_socket(ch->tx_sock);
155 			return -1;
156 		}
157 
158 		if(bind(ch->tx_sock, local->ai_addr, local->ai_addrlen) < 0) {
159 			printf("bind failed: %d\n", error_socket());
160 			fflush(stdout);
161 			close_socket(ch->tx_sock);
162 			return -1;
163 		}
164       }
165       else if(((ch->s->addr_family == PF_INET) && (addr_type == 0))) {
166 		/* does not work without this interface setting */
167 		if_addr.s_addr = inet_addr(ch->intface);
168 
169 		/* specify multicast interface */
170 		if(setsockopt(ch->tx_sock, IPPROTO_IP, IP_MULTICAST_IF,
171 		      (char*)&if_addr.s_addr, sizeof(if_addr.s_addr)) < 0 ) {
172 
173 			printf("setsockopt (IP_MULTICAST_IF) failed: %d\n", error_socket());
174 			fflush(stdout);
175 			close_socket(ch->tx_sock);
176 			return -1;
177 		}
178       }
179     }
180 
181     if(addr_type == 0) {
182 
183       /* TTL */
184       ttl = min(ch->s->def_ttl, 255);
185 
186       if(ch->s->addr_family == PF_INET) {
187 
188 		if(setsockopt(ch->tx_sock, IPPROTO_IP, IP_MULTICAST_TTL,
189 		      (char *)&ttl, sizeof(ttl)) < 0 ) {
190 			printf("setsockopt (IP_MULTICAST_TTL) failed: %d\n", error_socket());
191 			fflush(stdout);
192 			close_socket(ch->tx_sock);
193 			return -1;
194 		}
195       }
196       else if(ch->s->addr_family == PF_INET6) {
197 
198 		if(setsockopt(ch->tx_sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
199 		      (char *)&ttl, sizeof(ttl)) < 0 ) {
200 			printf("setsockopt (IPV6_MULTICAST_HOPS) failed: %d\n", error_socket());
201 			fflush(stdout);
202 			close_socket(ch->tx_sock);
203 			return -1;
204 		}
205       }
206 
207       /* Loopback (doesn't work in Windows, even if loop = 0, data is looped back) */
208       /* set to 0, when you don't have to do testing any more */
209       loop = 1;
210 
211       if(ch->s->addr_family == PF_INET) {
212 
213 		if(setsockopt(ch->tx_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
214 		      (char *)&loop, sizeof(loop)) != 0) {
215 			printf("setsockopt (IP_MULTICAST_LOOP) failed: %d\n", error_socket());
216 			fflush(stdout);
217 			close_socket(ch->tx_sock);
218 			return -1;
219 		}
220       }
221       else if(ch->s->addr_family == PF_INET6) {
222 
223 		if(setsockopt(ch->tx_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
224 		      (char *)&loop, sizeof(loop)) != 0) {
225 			printf("setsockopt (IPV6_MULTICAST_LOOP) failed: %d\n", error_socket());
226 			fflush(stdout);
227 			close_socket(ch->tx_sock);
228 			return -1;
229 		}
230       }
231     }
232 
233     if(local != NULL) {
234       freeaddrinfo(local);
235     }
236   }
237 
238   if(mode == RECEIVER) {
239 
240     if((ch->rx_sock = socket(ch->s->addr_family, SOCK_DGRAM, 0)) < 0) {
241       printf("socket failed with: %d\n", error_socket());
242       fflush(stdout);
243       return -1;
244     }
245 
246     memset(&hints, 0, sizeof(hints));
247     hints.ai_family = ch->s->addr_family;
248     hints.ai_socktype = SOCK_DGRAM;
249     hints.ai_flags = AI_PASSIVE;
250 
251 #ifdef _MSC_VER
252 	if((return_value = getaddrinfo(ch->intface, ch->port, &hints, &ch->addrinfo)) != 0) {
253 #else
254 	if((return_value = getaddrinfo(ch->addr, ch->port, &hints, &ch->addrinfo)) != 0) {
255 #endif
256 
257 #ifdef _MSC_VER
258       printf("getaddrinfo failed: %d\n", error_socket());
259 #else
260       if(return_value == EAI_SYSTEM) {
261 		printf("getaddrinfo failed: %d\n", error_socket());
262       }
263 	  else{
264 		printf("getaddrinfo failed: %d %s\n", return_value, gai_strerror(return_value));
265       }
266 
267 #endif
268 	  fflush(stdout);
269 	  close_socket(ch->rx_sock);
270       return -1;
271 	}
272 
273 	reuse = 1;
274 
275     if(setsockopt(ch->rx_sock, SOL_SOCKET, SO_REUSEADDR,
276                   (char *)&reuse, sizeof(reuse)) < 0 ) {
277       printf("setsockopt (SO_REUSEADDR) failed: %d\n", error_socket());
278 	  fflush(stdout);
279       close_socket(ch->rx_sock);
280       return -1;
281     }
282 
283     if(setsockopt(ch->rx_sock, SOL_SOCKET, SO_RCVBUF, (char *)&receiver_socket_buffer_size, sizeof(int))) {
284       printf("setsockopt (SO_RCVBUF) failed: %d\n", error_socket());
285 	  fflush(stdout);
286       close_socket(ch->rx_sock);
287       return -1;
288     }
289 
290     if(bind(ch->rx_sock, ch->addrinfo->ai_addr, ch->addrinfo->ai_addrlen) < 0) {
291 
292       printf("bind failed: %d\n", error_socket());
293 	  fflush(stdout);
294       close_socket(ch->rx_sock);
295       return -1;
296     }
297 
298     if(addr_type == 0) {
299       if(ch->s->addr_family == PF_INET) {
300 
301 		memset((void *)&ch->remote, 0, sizeof(ch->remote));
302 
303 		ch->remote.sin_addr.s_addr = inet_addr(ch->addr);
304 		ch->remote.sin_port = (unsigned short)atoi(ch->port);
305 		ch->remote.sin_family = ch->s->addr_family;
306       }
307       else if(ch->s->addr_family == PF_INET6) {
308 
309 		memset((void *)&ch->remote6, 0, sizeof(ch->remote6));
310 #ifdef _MSC_VER
311 		WSAStringToAddress((char*)ch->addr, PF_INET6, NULL, (struct sockaddr*)&ch->remote6,
312 			   &ch->addrinfo->ai_addrlen);
313 #else
314 		inet_pton(PF_INET6, ch->addr, &ch->remote6.sin6_addr);
315 #endif
316 		ch->remote6.sin6_port = (unsigned short)atoi(ch->port);
317 		ch->remote6.sin6_family = ch->s->addr_family;
318       }
319     }
320 
321     if(addr_type == 0) {
322 
323       /* Join the multicast group */
324 
325       if(ch->s->addr_family == PF_INET) {
326 
327 #ifdef SSM
328 	if(ch->s->ssm) {
329 	  ch->source_imr.imr_multiaddr.s_addr = ch->remote.sin_addr.s_addr;
330 
331 	  if(ch->intface == NULL) {
332 	    ch->source_imr.imr_interface.s_addr = htonl(INADDR_ANY);
333 	  }
334 	  else {
335 	    ch->source_imr.imr_interface.s_addr = inet_addr(ch->intface);
336 	  }
337 
338 	  ch->source_imr.imr_sourceaddr.s_addr = inet_addr(ch->s->src_addr);
339 
340 	  if(setsockopt(ch->rx_sock, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
341 			(char *)&ch->source_imr, sizeof(ch->source_imr)) < 0) {
342 	    printf("setsockopt (IP_ADD_SOURCE_MEMBERSHIP) failed: %d\n", error_socket());
343 	    fflush(stdout);
344 		close_socket(ch->rx_sock);
345 	    return -1;
346 	  }
347 	}
348 	else {
349 	  ch->imr.imr_multiaddr.s_addr = ch->remote.sin_addr.s_addr;
350 
351 	  if(ch->intface == NULL) {
352 	    ch->imr.imr_interface.s_addr = htonl(INADDR_ANY);
353 	  }
354 	  else {
355 	    ch->imr.imr_interface.s_addr = inet_addr(ch->intface);
356 	  }
357 
358 	  if(setsockopt(ch->rx_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
359 			(char *)&ch->imr, sizeof(ch->imr)) < 0) {
360 	    printf("setsockopt (IP_ADD_MEMBERSHIP) failed: %d\n", error_socket());
361 	    fflush(stdout);
362 		close_socket(ch->rx_sock);
363 	    return -1;
364 	  }
365 	}
366 #else
367 	ch->imr.imr_multiaddr.s_addr = ch->remote.sin_addr.s_addr;
368 
369 	if(ch->intface == NULL) {
370 	  ch->imr.imr_interface.s_addr = htonl(INADDR_ANY);
371 	}
372 	else {
373 	  ch->imr.imr_interface.s_addr = inet_addr(ch->intface);
374 	}
375 
376 	if(setsockopt(ch->rx_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
377 		      (char *)&ch->imr, sizeof(ch->imr)) < 0) {
378 	  printf("setsockopt (IP_ADD_MEMBERSHIP) failed: %d\n", error_socket());
379 	  fflush(stdout);
380 	  close_socket(ch->rx_sock);
381 	  return -1;
382 	}
383 #endif
384       }
385       else if(ch->s->addr_family == PF_INET6) {
386 
387 #if defined(LINUX) && defined(SSM)
388 	if(ch->s->ssm) {
389 
390 	  if(ch->intface_name == NULL) {
391 	    ch->greqs.gsr_interface = 0;
392 	  }
393 	  else {
394 	    ch->greqs.gsr_interface = if_nametoindex(ch->intface_name);
395 	  }
396 
397 	  memcpy(&ch->greqs.gsr_group, &ch->remote6, sizeof(ch->remote6));
398 	  source.sin6_family = AF_INET6;
399 
400 	  inet_pton(AF_INET6, ch->s->src_addr, &source.sin6_addr);
401 	  memcpy(&ch->greqs.gsr_source, &source, sizeof(source));
402 
403 	  if(setsockopt(ch->rx_sock, IPPROTO_IPV6, MCAST_JOIN_SOURCE_GROUP,
404 			(char *)&ch->greqs, sizeof(ch->greqs)) < 0) {
405 
406 	    printf("setsockopt (MCAST_JOIN_SOURCE_GROUP) failed: %d\n", error_socket());
407 	    fflush(stdout);
408 	    close_socket(ch->rx_sock);
409 	    return -1;
410 	  }
411 	}
412 	else {
413 	  ch->imr6.ipv6mr_multiaddr = ch->remote6.sin6_addr;
414 
415 	  if(ch->intface_name == NULL) {
416 	    ch->imr6.ipv6mr_interface = 0;
417 	  }
418 	  else {
419 	    ch->imr6.ipv6mr_interface = if_nametoindex(ch->intface_name);
420 	  }
421 
422 	  if(setsockopt(ch->rx_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
423 			(char *)&ch->imr6, sizeof(ch->imr6)) < 0) {
424 
425 	    printf("setsockopt (IPV6_JOIN_GROUP) failed: %d\n", error_socket());
426 	    fflush(stdout);
427 	    close_socket(ch->rx_sock);
428 	    return -1;
429 	  }
430 	}
431 #else
432 	ch->imr6.ipv6mr_multiaddr = ch->remote6.sin6_addr;
433 
434 #ifdef LINUX
435 	if(ch->intface_name == NULL) {
436 	  ch->imr6.ipv6mr_interface = 0;
437 	}
438 	else {
439 	  ch->imr6.ipv6mr_interface = if_nametoindex(ch->intface_name);
440 	}
441 #else
442 	if(ch->intface_name == NULL) {
443 	  ch->imr6.ipv6mr_interface = 0;
444 	}
445 	else {
446 	  ch->imr6.ipv6mr_interface = atoi(ch->intface_name);
447 	}
448 
449 #endif
450 	if(setsockopt(ch->rx_sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
451 		      (char *)&ch->imr6, sizeof(ch->imr6)) < 0) {
452 	  printf("setsockopt (IPV6_JOIN_GROUP) failed: %d\n", error_socket());
453 	  fflush(stdout);
454 	  close_socket(ch->rx_sock);
455 	  return -1;
456 	}
457 #endif
458       }
459     }
460   }
461 
462   return 0;
463 }
464 
465 int close_alc_socket(alc_channel_t *ch) {
466 
467   int mode;
468   int addr_type;
469   mode = ch->s->mode;
470   addr_type = ch->s->addr_type;
471 
472   if(mode == SENDER) {
473     close_socket(ch->tx_sock);
474   }
475 
476   if(mode == RECEIVER) {
477 
478     if(addr_type == 0) {
479 
480       if(ch->s->addr_family == PF_INET) {
481 
482 #ifdef SSM
483 	if(ch->s->ssm) {
484 
485 	  if(setsockopt(ch->rx_sock, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP,
486 			(char *)&ch->source_imr, sizeof(ch->source_imr)) < 0) {
487 	    printf("setsockopt (IP_DROP_SOURCE_MEMBERSHIP) failed: %d\n", error_socket());
488 	    fflush(stdout);
489 		close_socket(ch->rx_sock);
490 	    return -1;
491 	  }
492 	}
493 	else {
494 	  if(setsockopt(ch->rx_sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
495 			(char *)&ch->imr, sizeof(ch->imr)) < 0) {
496 	    printf("setsockopt (IP_DROP_MEMBERSHIP) failed: %d\n", error_socket());
497 	    fflush(stdout);
498 		close_socket(ch->rx_sock);
499 	    return -1;
500 	  }
501 	}
502 #else
503 	if(setsockopt(ch->rx_sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
504 		      (char *)&ch->imr, sizeof(ch->imr)) < 0) {
505 	  printf("setsockopt (IP_DROP_MEMBERSHIP) failed: %d\n", error_socket());
506 	  fflush(stdout);
507 	  close_socket(ch->rx_sock);
508 	  return -1;
509 	}
510 #endif
511       }
512       else if(ch->s->addr_family == PF_INET6) {
513 
514 #if defined(LINUX) && defined(SSM)
515 	if(ch->s->ssm) {
516 	  if(setsockopt(ch->rx_sock, IPPROTO_IPV6, MCAST_LEAVE_SOURCE_GROUP,
517 			(char *)&ch->greqs, sizeof(ch->greqs)) < 0) {
518 
519 	    printf("setsockopt (MCAST_LEAVE_SOURCE_GROUP) failed: %d\n", error_socket());
520 	    fflush(stdout);
521 	    close(ch->rx_sock);
522 	    return -1;
523 	  }
524 	}
525 	else {
526 	  if(setsockopt(ch->rx_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
527 			(char *)&ch->imr6, sizeof(ch->imr6)) < 0) {
528 
529 	    printf("setsockopt (IPV6_LEAVE_GROUP) failed: %d\n", error_socket());
530 	    fflush(stdout);
531 	    close(ch->rx_sock);
532 	    return -1;
533 	  }
534 	}
535 #else
536 	if(setsockopt(ch->rx_sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
537 		      (char *)&ch->imr6, sizeof(ch->imr6)) < 0) {
538 	  printf("setsockopt (IPV6_LEAVE_GROUP) failed: %d\n", error_socket());
539 	  fflush(stdout);
540 	  close_socket(ch->rx_sock);
541 	  return -1;
542 	}
543 #endif
544       }
545     }
546 
547     close_socket(ch->rx_sock);
548   }
549 
550   return 0;
551 }
552 
553