Browse Source

Add IPv6 support for input and output.

Georgi Chorbadzhiyski 11 years ago
parent
commit
7e88477439
8 changed files with 229 additions and 120 deletions
  1. 5
    2
      ChangeLog
  2. 12
    8
      README
  3. 0
    1
      TODO
  4. 1
    3
      data.c
  5. 3
    2
      data.h
  6. 14
    7
      tsdecrypt.1
  7. 46
    41
      tsdecrypt.c
  8. 148
    56
      udp.c

+ 5
- 2
ChangeLog View File

@@ -8,11 +8,14 @@
8 8
  * Allow tsdecrypt to read ECM/EMM packet from text file. The added
9 9
    parameters are -n, -ecm-file <file> and -m --emm-file <file>.
10 10
  * Add support for CAMD server listening on IPv6.
11
- * Add support for forcing only IPv4 (-4, --ipv4) or IPv6 (-6, --ipv6)
12
-   server connections.
11
+ * Add support for input and output over IPv6.
12
+ * Add support for forcing only IPv4 (-4, --ipv4) or only IPv6 (-6, --ipv6).
13 13
  * Add support for multiple CAMD addresses returned when resolving CAMD
14 14
    server hostname. tsdecrypt would try each of the addresses and use
15 15
    the one that works.
16
+ * Change the way filenames are set in input/output options.
17
+   Now file:// prefix is must be added before the filename otherwise
18
+   the parameter is treated as network address.
16 19
  * Add --emm-filter (-a) option. This option implements EMM filtering.
17 20
 
18 21
 2012-04-19 : Version 8.1

+ 12
- 8
README View File

@@ -103,9 +103,10 @@ Main options:
103 103
 
104 104
 Input options:
105 105
  -I --input <source>        | Where to read from. File or multicast address.
106
-                            .    -I 224.0.0.1:5000 (multicast receive)
107
-                            .    -I file.ts        (read from file)
108
-                            .    -I -              (read from stdin) (default)
106
+                            .    -I 224.0.0.1:5000    (v4 multicast)
107
+                            .    -I [ff01::1111]:5000 (v6 multicast)
108
+                            .    -I file://in.ts      (read from file)
109
+                            . By default the input is stdin.
109 110
  -R --input-rtp             | Enable RTP input
110 111
  -z --input-ignore-disc     | Do not report discontinuty errors in input.
111 112
  -M --input-service <srvid> | Choose service id when input is MPTS.
@@ -114,10 +115,13 @@ Input options:
114 115
 
115 116
 Output options:
116 117
  -O --output <dest>         | Where to send output. File or multicast address.
117
-                            .    -O 239.0.0.1:5000 (multicast send)
118
-                            .    -O file.ts        (write to file)
119
-                            .    -O -              (write to stdout) (default)
120
- -o --output-intf <addr>    | Set multicast output interface. Default: 0.0.0.0
118
+                            .    -O 239.0.0.1:5000    (v4 multicast)
119
+                            .    -O [ff01::2222]:5000 (v6 multicast)
120
+                            .    -O file://out.ts     (write to file)
121
+                            . By default the output is stdout.
122
+ -o --output-intf <value>   | Set multicast output interface.
123
+                             . Default for IPv4: 0.0.0.0 (intf addr)
124
+                             . Default for IPv6: -1      (intf number)
121 125
  -t --output-ttl <ttl>      | Set multicast ttl. Default: 1
122 126
  -r --output-rtp            | Enable RTP output.
123 127
  -k --output-rtp-ssrc <id>  | Set RTP SSRC. Default: 0
@@ -249,7 +253,7 @@ Examples:
249 253
 
250 254
    # Decrypt file encypted with constant code word
251 255
    tsdecrypt --const-cw 0x00000000000000001111111111111111 \
252
-       --input encrypted-file.ts --output decrypted-file.ts
256
+       --input encrypted-file.ts --output file://decrypted-file.ts
253 257
 
254 258
    # Send ECM from file
255 259
    tsdecrypt --ecm-file ecm.txt --caid 0x5581 --input-service 12345 \

+ 0
- 1
TODO View File

@@ -1,2 +1 @@
1 1
 - Sort nanos of viaccess and cryptoworks emms.
2
-- Add ipv6 support (multicast send/recv).

+ 1
- 3
data.c View File

@@ -93,6 +93,7 @@ void data_init(struct ts *ts) {
93 93
 	ts->output.type = FILE_IO;
94 94
 	ts->output.ttl  = 1;
95 95
 	ts->output.tos  = -1;
96
+	ts->output.v6_if_index = -1;
96 97
 
97 98
 	ts->decode_buf  = cbuf_init((7 * csa_get_batch_size() * 188) * 16, "decode"); // ~658Kb
98 99
 	ts->write_buf   = cbuf_init((7 * csa_get_batch_size() * 188) *  8, "write");  // ~324Kb
@@ -128,9 +129,6 @@ void data_free(struct ts *ts) {
128 129
 	cbuf_free(&ts->decode_buf);
129 130
 	cbuf_free(&ts->write_buf);
130 131
 
131
-	FREE(ts->input.fname);
132
-	FREE(ts->output.fname);
133
-
134 132
 	list_free(&ts->input_buffer, free, NULL);
135 133
 
136 134
 	// glibc's crypt function allocates static buffer on first crypt() call.

+ 3
- 2
data.h View File

@@ -172,12 +172,13 @@ struct io {
172 172
 	int					fd;
173 173
 	enum io_type		type;
174 174
 	char				*fname;
175
-	struct in_addr		addr;
176
-	unsigned int		port;
175
+	char				*hostname;
176
+	char				*service;
177 177
 	// Used only for output
178 178
 	int					ttl;
179 179
 	int					tos;
180 180
 	struct in_addr		intf;
181
+	int					v6_if_index;
181 182
 };
182 183
 
183 184
 struct packet_buf {

+ 14
- 7
tsdecrypt.1 View File

@@ -68,8 +68,9 @@ Show program help.
68 68
 .PP
69 69
 .TP
70 70
 \fB\-I\fR, \fB\-\-input\fR <source>
71
-Where to read from. tsdecrypt supports input from files (\-I file.ts or \-I \-)
72
-or multicast (\-I 224.0.0.1:5000). By default tsdecrypt reads from \fBstdin\fR.
71
+Where to read from. tsdecrypt supports input from file (\-I file://file.ts),
72
+IPv4 multicast/unicast addresses (\-I 224.0.0.1:5000) or IPv6 multicast/unicast
73
+addresses (\-I [ff01::1111]:5000). By default tsdecrypt reads from \fBstdin\fR.
73 74
 .TP
74 75
 \fB\-R\fR, \fB\-\-input\-rtp\fR
75 76
 When reading from multicast assume the input is RTP stream. NOTE: No RTP
@@ -105,11 +106,17 @@ tsdecrypt \-I 239.78.78.78:5000 \-O /dev/null \-s 0.0.0.0 \-W file.ts
105 106
 .PP
106 107
 .TP
107 108
 \fB\-O\fR, \fB\-\-output\fR <dest>
108
-Output decrypted stream to <dest>. Destination can be multicast address
109
-(\-O 239.0.0.1:5000) or a file (\-O file.ts). The default output is \fBstdout\fR.
109
+Output decrypted stream to <dest>. The destination can be IPv4 multicast
110
+address (\-O 239.0.0.1:5000), IPv6 mulicast address (\-O [ff01::2222]:5000),
111
+hostname that resolves to IPv4/IPv6 address (\-O example.com:5000) or file.
112
+When the output is file, the file name should be prefixed with file://
113
+(\-O file://out.ts)if it doesn't contain / symbol. The default output
114
+is \fBstdout\fR.
110 115
 .TP
111
-\fB\-o\fR, \fB\-\-output\-intf\fR <addr>
112
-Set multicast output interface.
116
+\fB\-o\fR, \fB\-\-output\-intf\fR <value>
117
+Set multicast output interface. The value can be IPv4 address of the output
118
+interface  (default: 0.0.0.0 /any/) or in the case of IPv6 the interface
119
+number (default: -1 /any/).
113 120
 .TP
114 121
 \fB\-t\fR, \fB\-\-output\-ttl\fR
115 122
 Set multicast ttl. The default value is \fB1\fR.
@@ -366,7 +373,7 @@ CA system is set to CONAX, you can change it using \fB\-\-ca-system\fR parameter
366 373
 
367 374
    # Decrypt file encypted with constant code word
368 375
    tsdecrypt --const-cw 0x00000000000000001111111111111111 \\
369
-       --input encrypted-file.ts --output decrypted-file.ts
376
+       --input encrypted-file.ts --output file://decrypted-file.ts
370 377
 
371 378
    # Send ECM from file
372 379
    tsdecrypt --ecm-file ecm.txt --caid 0x5581 --input-service 12345 \\

+ 46
- 41
tsdecrypt.c View File

@@ -160,9 +160,10 @@ static void show_help(struct ts *ts) {
160 160
 	printf("\n");
161 161
 	printf("Input options:\n");
162 162
 	printf(" -I --input <source>        | Where to read from. File or multicast address.\n");
163
-	printf("                            .    -I 224.0.0.1:5000 (multicast receive)\n");
164
-	printf("                            .    -I file.ts        (read from file)\n");
165
-	printf("                            .    -I -              (read from stdin) (default)\n");
163
+	printf("                            .    -I 224.0.0.1:5000    (v4 multicast)\n");
164
+	printf("                            .    -I [ff01::1111]:5000 (v6 multicast)\n");
165
+	printf("                            .    -I file://in.ts      (read from file)\n");
166
+	printf("                            . By default the input is stdin.\n");
166 167
 	printf(" -R --input-rtp             | Enable RTP input\n");
167 168
 	printf(" -z --input-ignore-disc     | Do not report discontinuty errors in input.\n");
168 169
 	printf(" -M --input-service <srvid> | Choose service id when input is MPTS.\n");
@@ -171,10 +172,13 @@ static void show_help(struct ts *ts) {
171 172
 	printf("\n");
172 173
 	printf("Output options:\n");
173 174
 	printf(" -O --output <dest>         | Where to send output. File or multicast address.\n");
174
-	printf("                            .    -O 239.0.0.1:5000 (multicast send)\n");
175
-	printf("                            .    -O file.ts        (write to file)\n");
176
-	printf("                            .    -O -              (write to stdout) (default)\n");
177
-	printf(" -o --output-intf <addr>    | Set multicast output interface. Default: %s\n", inet_ntoa(ts->output.intf));
175
+	printf("                            .    -O 239.0.0.1:5000    (v4 multicast)\n");
176
+	printf("                            .    -O [ff01::2222]:5000 (v6 multicast)\n");
177
+	printf("                            .    -O file://out.ts     (write to file)\n");
178
+	printf("                            . By default the output is stdout.\n");
179
+	printf(" -o --output-intf <value>   | Set multicast output interface.\n");
180
+	printf("                            . Default for IPv4: 0.0.0.0 (intf addr)\n");
181
+	printf("                            . Default for IPv6: -1      (intf number)\n");
178 182
 	printf(" -t --output-ttl <ttl>      | Set multicast ttl. Default: %d\n", ts->output.ttl);
179 183
 	printf(" -r --output-rtp            | Enable RTP output.\n");
180 184
 	printf(" -k --output-rtp-ssrc <id>  | Set RTP SSRC. Default: %u\n", ts->rtp_ssrc);
@@ -261,33 +265,33 @@ static void show_help(struct ts *ts) {
261 265
 }
262 266
 
263 267
 static int parse_io_param(struct io *io, char *opt, int open_flags, mode_t open_mode) {
268
+	int port_set = 0, host_set;
264 269
 	io->type = WTF_IO;
265
-	char *p = strrchr(opt, ':');
266
-	if (!p) {
270
+	if (strstr(opt, "file://") == opt) {
271
+		io->fname = opt + 7; // strlen("file://")
272
+		io->type = FILE_IO;
273
+	} else if (strchr(opt, '/')) {
274
+		io->fname = opt;
267 275
 		io->type = FILE_IO;
268
-		if (strcmp(opt, "-") != 0) {
269
-			io->fd = open(opt, open_flags, open_mode);
270
-			if (io->fd < 0) {
271
-				fprintf(stderr, "ERROR: Can not open file (%s): %s\n", opt, strerror(errno));
272
-				exit(EXIT_FAILURE);
273
-			}
274
-		}
275
-		io->fname = strdup(opt);
276
-		return 0;
277 276
 	}
278
-	*p = 0x00;
279
-	io->type = NET_IO;
280
-	io->port = atoi(p + 1);
281
-	if (inet_aton(opt, &io->addr) == 0)
277
+	if (io->type == FILE_IO) {
278
+		io->fd = open(io->fname, open_flags, open_mode);
279
+		if (io->fd < 0) {
280
+			fprintf(stderr, "ERROR: Can not open file (%s): %s\n", io->fname, strerror(errno));
281
+			exit(EXIT_FAILURE);
282
+		}
282 283
 		return 1;
283
-	return 0;
284
+	}
285
+	io->type = NET_IO;
286
+	host_set = parse_host_and_port(opt, &io->hostname, &io->service, &port_set);
287
+	return !(!port_set || !host_set);
284 288
 }
285 289
 
286 290
 extern char *optarg;
287 291
 extern int optind, opterr, optopt;
288 292
 
289 293
 static void parse_options(struct ts *ts, int argc, char **argv) {
290
-	int j, i, ca_err = 0, server_err = 1, input_addr_err = 0, output_addr_err = 0, output_intf_err = 0, ident_err = 0, port_set = 0;
294
+	int j, i, ca_err = 0, server_err = 1, input_addr_err = 0, output_addr_err = 0, ident_err = 0, port_set = 0;
291 295
 	opterr = 0; // Prevent printing of error messages for unknown options in getopt()
292 296
 	while ((j = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
293 297
 		if (j == '?') {
@@ -322,7 +326,7 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
322 326
 				break;
323 327
 
324 328
 			case 'I': // --input
325
-				input_addr_err = parse_io_param(&ts->input, optarg, O_RDONLY, 0);
329
+				input_addr_err = !parse_io_param(&ts->input, optarg, O_RDONLY, 0);
326 330
 				break;
327 331
 			case 'R': // --input-rtp
328 332
 				ts->rtp_input = !ts->rtp_input;
@@ -341,13 +345,15 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
341 345
 				break;
342 346
 
343 347
 			case 'O': // --output
344
-				output_addr_err = parse_io_param(&ts->output, optarg,
348
+				output_addr_err = !parse_io_param(&ts->output, optarg,
345 349
 					O_CREAT | O_WRONLY | O_TRUNC,
346 350
 					S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
347 351
 				break;
348 352
 			case 'o': // --output-intf
349
-				if (inet_aton(optarg, &ts->output.intf) == 0)
350
-					output_intf_err = 1;
353
+				if (strchr(optarg, '.'))
354
+					inet_aton(optarg, &ts->output.intf);
355
+				else
356
+					ts->output.v6_if_index = atoi(optarg);
351 357
 				break;
352 358
 			case 't': // --output-ttl
353 359
 				ts->output.ttl = atoi(optarg);
@@ -624,11 +630,9 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
624 630
 		if (server_err)
625 631
 			fprintf(stderr, "ERROR: CAMD server address is not set or it is invalid.\n");
626 632
 		if (input_addr_err)
627
-			fprintf(stderr, "ERROR: Input IP address is invalid.\n");
633
+			fprintf(stderr, "ERROR: Input address is invalid.\n");
628 634
 		if (output_addr_err)
629
-			fprintf(stderr, "ERROR: Output IP address is invalid.\n");
630
-		if (output_intf_err)
631
-			fprintf(stderr, "ERROR: Output interface address is invalid.\n");
635
+			fprintf(stderr, "ERROR: Output address is invalid.\n");
632 636
 		exit(EXIT_FAILURE);
633 637
 	}
634 638
 	if (decode_hex_string(ts->camd.newcamd.hex_des_key, ts->camd.newcamd.bin_des_key, DESKEY_LENGTH) < 0) {
@@ -682,9 +686,9 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
682 686
 	}
683 687
 
684 688
 	if (ts->input.type == NET_IO) {
685
-		ts_LOGf("Input addr : %s://%s:%u/\n",
689
+		ts_LOGf("Input addr : %s://%s:%s/\n",
686 690
 			ts->rtp_input ? "rtp" : "udp",
687
-			inet_ntoa(ts->input.addr), ts->input.port);
691
+			ts->input.hostname, ts->input.service);
688 692
 		if (ts->input_buffer_time) {
689 693
 			ts_LOGf("Input buff : %u ms\n", ts->input_buffer_time);
690 694
 		}
@@ -708,10 +712,11 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
708 712
 	if (!ts->emm_only)
709 713
 	{
710 714
 		if (ts->output.type == NET_IO) {
711
-			ts_LOGf("Output addr: %s://%s:%u/\n",
715
+			ts_LOGf("Output addr: %s://%s:%s/\n",
712 716
 				ts->rtp_output ? "rtp" : "udp",
713
-				inet_ntoa(ts->output.addr), ts->output.port);
714
-			ts_LOGf("Output intf: %s\n", inet_ntoa(ts->output.intf));
717
+				ts->output.hostname, ts->output.service);
718
+			ts_LOGf("Output intf: %s (IPv6 intf index:%d)\n",
719
+				inet_ntoa(ts->output.intf), ts->output.v6_if_index);
715 720
 			ts_LOGf("Output ttl : %d\n", ts->output.ttl);
716 721
 			if (ts->output.tos > -1)
717 722
 				ts_LOGf("Output TOS : %u (0x%02x)\n", ts->output.tos, ts->output.tos);
@@ -1000,16 +1005,16 @@ int main(int argc, char **argv) {
1000 1005
 				ts_LOGf("--- | Input read timeout.\n");
1001 1006
 				if (!ntimeouts) {
1002 1007
 					timeout_start = time(NULL);
1003
-					notify(&ts, "INPUT_TIMEOUT", "Read timeout on input %s://%s:%u/",
1008
+					notify(&ts, "INPUT_TIMEOUT", "Read timeout on input %s://%s:%s/",
1004 1009
 							ts.rtp_input ? "rtp" : "udp",
1005
-							inet_ntoa(ts.input.addr), ts.input.port);
1010
+							ts.input.hostname, ts.input.service);
1006 1011
 				}
1007 1012
 				ntimeouts++;
1008 1013
 			} else {
1009 1014
 				if (ntimeouts && readen > 0) {
1010
-					notify(&ts, "INPUT_OK", "Data is available on input %s://%s:%u/ after %ld seconds timeout.",
1015
+					notify(&ts, "INPUT_OK", "Data is available on input %s://%s:%s/ after %ld seconds timeout.",
1011 1016
 							ts.rtp_input ? "rtp" : "udp",
1012
-							inet_ntoa(ts.input.addr), ts.input.port,
1017
+							ts.input.hostname, ts.input.service,
1013 1018
 							(time(NULL) - timeout_start) + 2); // Timeout is detected when ~2 seconds there is no incoming data
1014 1019
 					ntimeouts = 0;
1015 1020
 				}

+ 148
- 56
udp.c View File

@@ -24,43 +24,135 @@
24 24
 #include <arpa/inet.h>
25 25
 #include <errno.h>
26 26
 
27
+#include "util.h"
27 28
 #include "udp.h"
28 29
 
30
+#ifndef IPV6_ADD_MEMBERSHIP
31
+#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
32
+#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
33
+#endif
34
+
35
+static int is_multicast(struct sockaddr_storage *addr) {
36
+	int ret = 0;
37
+	switch (addr->ss_family) {
38
+	case AF_INET: {
39
+		struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
40
+		ret = IN_MULTICAST(ntohl(addr4->sin_addr.s_addr));
41
+		break;
42
+	}
43
+	case AF_INET6: {
44
+		struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
45
+		ret = IN6_IS_ADDR_MULTICAST(&addr6->sin6_addr);
46
+		break;
47
+	} }
48
+	return ret;
49
+}
50
+
51
+extern int ai_family;
52
+
53
+static int bind_addr(const char *hostname, const char *service, int socktype, struct sockaddr_storage *addr, int *addrlen, int *sock) {
54
+	struct addrinfo hints, *res, *ressave;
55
+	int n, ret = -1;
56
+
57
+	memset(&hints, 0, sizeof(struct addrinfo));
58
+	hints.ai_family = ai_family;
59
+	hints.ai_socktype = socktype;
60
+
61
+	n = getaddrinfo(hostname, service, &hints, &res);
62
+	if (n < 0) {
63
+		ts_LOGf("ERROR: getaddrinfo(%s): %s\n", hostname, gai_strerror(n));
64
+		return ret;
65
+	}
66
+
67
+	ressave = res;
68
+	while (res) {
69
+		*sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
70
+		if (*sock > -1) {
71
+			if (bind(*sock, res->ai_addr, res->ai_addrlen) == 0) {
72
+				memcpy(addr, res->ai_addr, sizeof(*addr));
73
+				*addrlen = res->ai_addrlen;
74
+				ret = 0;
75
+				goto OUT;
76
+			} else {
77
+				char str_addr[INET6_ADDRSTRLEN];
78
+				my_inet_ntop(res->ai_family, res->ai_addr, str_addr, sizeof(str_addr));
79
+				ts_LOGf("ERROR: bind: %s:%s (%s): %s\n",
80
+					hostname, service, str_addr, strerror(errno));
81
+			}
82
+			close(*sock);
83
+			*sock = -1;
84
+		}
85
+		res = res->ai_next;
86
+	}
87
+OUT:
88
+	freeaddrinfo(ressave);
89
+
90
+	if (*sock > -1) {
91
+		int on = 1;
92
+		setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
93
+		set_sock_nonblock(*sock);
94
+	}
95
+
96
+	return ret;
97
+}
98
+
99
+static int join_multicast_group(int sock, int ttl, struct sockaddr_storage *addr) {
100
+	switch (addr->ss_family) {
101
+	case AF_INET: {
102
+		struct ip_mreq mreq;
103
+		mreq.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
104
+		mreq.imr_interface.s_addr = INADDR_ANY;
105
+
106
+		if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) {
107
+			ts_LOGf("ERROR: setsockopt(IP_ADD_MEMBERSHIP): %s\n", strerror(errno));
108
+			return -1;
109
+		}
110
+		if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
111
+			ts_LOGf("ERROR: setsockopt(IP_MULTICAST_TTL %d): %s\n", ttl, strerror(errno));
112
+		}
113
+		break;
114
+	}
115
+
116
+	case AF_INET6: {
117
+		struct ipv6_mreq mreq6;
118
+		memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
119
+		mreq6.ipv6mr_interface = 0; // interface index, will be set later
120
+
121
+		if (setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
122
+			ts_LOGf("ERROR: setsockopt(IPV6_ADD_MEMBERSHIP): %s\n", strerror(errno));
123
+			return -1;
124
+		}
125
+		if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
126
+			ts_LOGf("ERROR: setsockopt(IPV6_MULTICAST_HOPS %d): %s\n", ttl, strerror(errno));
127
+		}
128
+		break;
129
+	}
130
+	}
131
+
132
+	return 0;
133
+}
134
+
29 135
 int udp_connect_input(struct io *io) {
30
-	int sock = socket(AF_INET, SOCK_DGRAM, 0);
31
-	if (sock < 0) {
32
-		ts_LOGf("socket(SOCK_DGRAM): %s\n", strerror(errno));
136
+	struct sockaddr_storage addr;
137
+	int addrlen = sizeof(addr);
138
+	int sock = -1;
139
+
140
+	memset(&addr, 0, sizeof(addr));
141
+
142
+	ts_LOGf("Connecting input to %s port %s\n", io->hostname, io->service);
143
+	if (bind_addr(io->hostname, io->service, SOCK_DGRAM, &addr, &addrlen, &sock) < 0)
33 144
 		return -1;
34
-	}
35
-
36
-	ts_LOGf("Connecting input to udp://%s:%d/\n", inet_ntoa(io->addr), io->port);
37
-	int on = 1;
38
-	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
39 145
 
40 146
 	/* Set receive buffer size to ~2.0MB */
41 147
 	int bufsize = (2000000 / 1316) * 1316;
42 148
 	setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&bufsize, sizeof(bufsize));
43 149
 
44
-	// subscribe to multicast group
45
-	if (IN_MULTICAST(ntohl(io->addr.s_addr))) {
46
-		struct ip_mreq mreq;
47
-		memcpy(&mreq.imr_multiaddr, &io->addr, sizeof(struct in_addr));
48
-		mreq.imr_interface.s_addr = htonl(INADDR_ANY);
49
-		if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
50
-			ts_LOGf("setsockopt(IP_ADD_MEMBERSHIP %s): %s\n", inet_ntoa(io->addr), strerror(errno));
150
+	if (is_multicast(&addr)) {
151
+		if (join_multicast_group(sock, io->ttl, &addr) < 0) {
152
+			close(sock);
51 153
 			return -1;
52 154
 		}
53 155
 	}
54
-	// bind to the socket so data can be read
55
-	struct sockaddr_in receiving_from;
56
-	memset(&receiving_from, 0, sizeof(receiving_from));
57
-	receiving_from.sin_family = AF_INET;
58
-	receiving_from.sin_addr   = io->addr;
59
-	receiving_from.sin_port   = htons(io->port);
60
-	if (bind(sock, (struct sockaddr *) &receiving_from, sizeof(receiving_from)) < 0) {
61
-		ts_LOGf("bind(): %s\n", strerror(errno));
62
-		return -1;
63
-	}
64 156
 
65 157
 	io->fd = sock;
66 158
 	ts_LOGf("Input connected to fd:%d\n", io->fd);
@@ -69,51 +161,51 @@ int udp_connect_input(struct io *io) {
69 161
 }
70 162
 
71 163
 int udp_connect_output(struct io *io) {
72
-	int sock = socket(AF_INET, SOCK_DGRAM, 0);
73
-	if (sock < 0) {
74
-		ts_LOGf("socket(SOCK_DGRAM): %s\n", strerror(errno));
164
+	struct sockaddr_storage addr;
165
+	int addrlen = sizeof(addr);
166
+	int sock = -1;
167
+
168
+	memset(&addr, 0, sizeof(addr));
169
+
170
+	ts_LOGf("Connecting output to %s port %s ttl: %d\n",
171
+		io->hostname, io->service, io->ttl);
172
+	if (bind_addr(io->hostname, io->service, SOCK_DGRAM, &addr, &addrlen, &sock) < 0)
75 173
 		return -1;
76
-	}
77 174
 
78
-	ts_LOGf("Connecting output to udp://%s:%d ttl:%d\n",
79
-		inet_ntoa(io->addr), io->port, io->ttl);
80
-
81
-	int on = 1;
82
-	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
83
-	set_sock_nonblock(sock);
84
-
85
-	/* Set receive buffer size to ~2.0MB */
175
+	/* Set send buffer size to ~2.0MB */
86 176
 	int bufsize = (2000000 / 1316) * 1316;
87 177
 	setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&bufsize, sizeof(bufsize));
88 178
 
89
-	// subscribe to multicast group
90
-	if (IN_MULTICAST(ntohl(io->addr.s_addr))) {
91
-		int ttl = io->ttl;
92
-		if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
93
-			ts_LOGf("setsockopt(IP_MUTICAST_TTL): %s\n", strerror(errno));
94
-			close(sock);
95
-			return -1;
96
-		}
97
-		if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &io->intf, sizeof(io->intf)) < 0) {
98
-			ts_LOGf("setsockopt(IP_MUTICAST_IF %s): %s\n", inet_ntoa(io->intf), strerror(errno));
179
+	if (is_multicast(&addr)) {
180
+		if (join_multicast_group(sock, io->ttl, &addr) < 0) {
99 181
 			close(sock);
100 182
 			return -1;
183
+		} else {
184
+			if (addr.ss_family == AF_INET) {
185
+				if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &io->intf, sizeof(io->intf)) < 0) {
186
+					ts_LOGf("ERROR: setsockopt(IP_MUTICAST_IF %s): %s\n", inet_ntoa(io->intf), strerror(errno));
187
+					close(sock);
188
+					return -1;
189
+				}
190
+			}
191
+			if (addr.ss_family == AF_INET6 && io->v6_if_index > -1) {
192
+				if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (void *)&io->v6_if_index, sizeof(io->v6_if_index)) < 0) {
193
+					ts_LOGf("ERROR: setsockopt(IPV6_MUTICAST_IF %d): %s\n", io->v6_if_index, strerror(errno));
194
+					close(sock);
195
+					return -1;
196
+				}
197
+			}
101 198
 		}
102 199
 	}
103 200
 
104
-	if (io->tos > -1) {
201
+	if (addr.ss_family == AF_INET && io->tos > -1) {
105 202
 		if (setsockopt(sock, IPPROTO_IP, IP_TOS, &io->tos, sizeof(io->tos)) < 0) {
106
-			ts_LOGf("setsockopt(IP_TOS 0x%02x): %s\n", io->tos, strerror(errno));
203
+			ts_LOGf("ERROR: setsockopt(IP_TOS 0x%02x): %s\n", io->tos, strerror(errno));
107 204
 		}
108 205
 	}
109 206
 
110
-	struct sockaddr_in sockaddr;
111
-	memset(&sockaddr, 0, sizeof(sockaddr));
112
-	sockaddr.sin_family			= AF_INET;
113
-	sockaddr.sin_addr.s_addr	= io->addr.s_addr;
114
-	sockaddr.sin_port			= htons(io->port);
115
-	if (connect(sock, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
116
-		ts_LOGf("udp_connect() error: %s\n", strerror(errno));
207
+	if (connect(sock, (struct sockaddr *)&addr, addrlen) < 0) {
208
+		ts_LOGf("ERROR: udp_connect(): %s\n", strerror(errno));
117 209
 		close(sock);
118 210
 		return -1;
119 211
 	}

Loading…
Cancel
Save