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