Browse Source

Add IPv6 support for input and output.

Georgi Chorbadzhiyski 12 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
  * Allow tsdecrypt to read ECM/EMM packet from text file. The added
8
  * Allow tsdecrypt to read ECM/EMM packet from text file. The added
9
    parameters are -n, -ecm-file <file> and -m --emm-file <file>.
9
    parameters are -n, -ecm-file <file> and -m --emm-file <file>.
10
  * Add support for CAMD server listening on IPv6.
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
  * Add support for multiple CAMD addresses returned when resolving CAMD
13
  * Add support for multiple CAMD addresses returned when resolving CAMD
14
    server hostname. tsdecrypt would try each of the addresses and use
14
    server hostname. tsdecrypt would try each of the addresses and use
15
    the one that works.
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
  * Add --emm-filter (-a) option. This option implements EMM filtering.
19
  * Add --emm-filter (-a) option. This option implements EMM filtering.
17
 
20
 
18
 2012-04-19 : Version 8.1
21
 2012-04-19 : Version 8.1

+ 12
- 8
README View File

103
 
103
 
104
 Input options:
104
 Input options:
105
  -I --input <source>        | Where to read from. File or multicast address.
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
  -R --input-rtp             | Enable RTP input
110
  -R --input-rtp             | Enable RTP input
110
  -z --input-ignore-disc     | Do not report discontinuty errors in input.
111
  -z --input-ignore-disc     | Do not report discontinuty errors in input.
111
  -M --input-service <srvid> | Choose service id when input is MPTS.
112
  -M --input-service <srvid> | Choose service id when input is MPTS.
114
 
115
 
115
 Output options:
116
 Output options:
116
  -O --output <dest>         | Where to send output. File or multicast address.
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
  -t --output-ttl <ttl>      | Set multicast ttl. Default: 1
125
  -t --output-ttl <ttl>      | Set multicast ttl. Default: 1
122
  -r --output-rtp            | Enable RTP output.
126
  -r --output-rtp            | Enable RTP output.
123
  -k --output-rtp-ssrc <id>  | Set RTP SSRC. Default: 0
127
  -k --output-rtp-ssrc <id>  | Set RTP SSRC. Default: 0
249
 
253
 
250
    # Decrypt file encypted with constant code word
254
    # Decrypt file encypted with constant code word
251
    tsdecrypt --const-cw 0x00000000000000001111111111111111 \
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
    # Send ECM from file
258
    # Send ECM from file
255
    tsdecrypt --ecm-file ecm.txt --caid 0x5581 --input-service 12345 \
259
    tsdecrypt --ecm-file ecm.txt --caid 0x5581 --input-service 12345 \

+ 0
- 1
TODO View File

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

+ 1
- 3
data.c View File

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

+ 3
- 2
data.h View File

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

+ 14
- 7
tsdecrypt.1 View File

68
 .PP
68
 .PP
69
 .TP
69
 .TP
70
 \fB\-I\fR, \fB\-\-input\fR <source>
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
 .TP
74
 .TP
74
 \fB\-R\fR, \fB\-\-input\-rtp\fR
75
 \fB\-R\fR, \fB\-\-input\-rtp\fR
75
 When reading from multicast assume the input is RTP stream. NOTE: No RTP
76
 When reading from multicast assume the input is RTP stream. NOTE: No RTP
105
 .PP
106
 .PP
106
 .TP
107
 .TP
107
 \fB\-O\fR, \fB\-\-output\fR <dest>
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
 .TP
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
 .TP
120
 .TP
114
 \fB\-t\fR, \fB\-\-output\-ttl\fR
121
 \fB\-t\fR, \fB\-\-output\-ttl\fR
115
 Set multicast ttl. The default value is \fB1\fR.
122
 Set multicast ttl. The default value is \fB1\fR.
366
 
373
 
367
    # Decrypt file encypted with constant code word
374
    # Decrypt file encypted with constant code word
368
    tsdecrypt --const-cw 0x00000000000000001111111111111111 \\
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
    # Send ECM from file
378
    # Send ECM from file
372
    tsdecrypt --ecm-file ecm.txt --caid 0x5581 --input-service 12345 \\
379
    tsdecrypt --ecm-file ecm.txt --caid 0x5581 --input-service 12345 \\

+ 46
- 41
tsdecrypt.c View File

160
 	printf("\n");
160
 	printf("\n");
161
 	printf("Input options:\n");
161
 	printf("Input options:\n");
162
 	printf(" -I --input <source>        | Where to read from. File or multicast address.\n");
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
 	printf(" -R --input-rtp             | Enable RTP input\n");
167
 	printf(" -R --input-rtp             | Enable RTP input\n");
167
 	printf(" -z --input-ignore-disc     | Do not report discontinuty errors in input.\n");
168
 	printf(" -z --input-ignore-disc     | Do not report discontinuty errors in input.\n");
168
 	printf(" -M --input-service <srvid> | Choose service id when input is MPTS.\n");
169
 	printf(" -M --input-service <srvid> | Choose service id when input is MPTS.\n");
171
 	printf("\n");
172
 	printf("\n");
172
 	printf("Output options:\n");
173
 	printf("Output options:\n");
173
 	printf(" -O --output <dest>         | Where to send output. File or multicast address.\n");
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
 	printf(" -t --output-ttl <ttl>      | Set multicast ttl. Default: %d\n", ts->output.ttl);
182
 	printf(" -t --output-ttl <ttl>      | Set multicast ttl. Default: %d\n", ts->output.ttl);
179
 	printf(" -r --output-rtp            | Enable RTP output.\n");
183
 	printf(" -r --output-rtp            | Enable RTP output.\n");
180
 	printf(" -k --output-rtp-ssrc <id>  | Set RTP SSRC. Default: %u\n", ts->rtp_ssrc);
184
 	printf(" -k --output-rtp-ssrc <id>  | Set RTP SSRC. Default: %u\n", ts->rtp_ssrc);
261
 }
265
 }
262
 
266
 
263
 static int parse_io_param(struct io *io, char *opt, int open_flags, mode_t open_mode) {
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
 	io->type = WTF_IO;
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
 		io->type = FILE_IO;
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
 		return 1;
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
 extern char *optarg;
290
 extern char *optarg;
287
 extern int optind, opterr, optopt;
291
 extern int optind, opterr, optopt;
288
 
292
 
289
 static void parse_options(struct ts *ts, int argc, char **argv) {
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
 	opterr = 0; // Prevent printing of error messages for unknown options in getopt()
295
 	opterr = 0; // Prevent printing of error messages for unknown options in getopt()
292
 	while ((j = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
296
 	while ((j = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
293
 		if (j == '?') {
297
 		if (j == '?') {
322
 				break;
326
 				break;
323
 
327
 
324
 			case 'I': // --input
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
 				break;
330
 				break;
327
 			case 'R': // --input-rtp
331
 			case 'R': // --input-rtp
328
 				ts->rtp_input = !ts->rtp_input;
332
 				ts->rtp_input = !ts->rtp_input;
341
 				break;
345
 				break;
342
 
346
 
343
 			case 'O': // --output
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
 					O_CREAT | O_WRONLY | O_TRUNC,
349
 					O_CREAT | O_WRONLY | O_TRUNC,
346
 					S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
350
 					S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
347
 				break;
351
 				break;
348
 			case 'o': // --output-intf
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
 				break;
357
 				break;
352
 			case 't': // --output-ttl
358
 			case 't': // --output-ttl
353
 				ts->output.ttl = atoi(optarg);
359
 				ts->output.ttl = atoi(optarg);
624
 		if (server_err)
630
 		if (server_err)
625
 			fprintf(stderr, "ERROR: CAMD server address is not set or it is invalid.\n");
631
 			fprintf(stderr, "ERROR: CAMD server address is not set or it is invalid.\n");
626
 		if (input_addr_err)
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
 		if (output_addr_err)
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
 		exit(EXIT_FAILURE);
636
 		exit(EXIT_FAILURE);
633
 	}
637
 	}
634
 	if (decode_hex_string(ts->camd.newcamd.hex_des_key, ts->camd.newcamd.bin_des_key, DESKEY_LENGTH) < 0) {
638
 	if (decode_hex_string(ts->camd.newcamd.hex_des_key, ts->camd.newcamd.bin_des_key, DESKEY_LENGTH) < 0) {
682
 	}
686
 	}
683
 
687
 
684
 	if (ts->input.type == NET_IO) {
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
 			ts->rtp_input ? "rtp" : "udp",
690
 			ts->rtp_input ? "rtp" : "udp",
687
-			inet_ntoa(ts->input.addr), ts->input.port);
691
+			ts->input.hostname, ts->input.service);
688
 		if (ts->input_buffer_time) {
692
 		if (ts->input_buffer_time) {
689
 			ts_LOGf("Input buff : %u ms\n", ts->input_buffer_time);
693
 			ts_LOGf("Input buff : %u ms\n", ts->input_buffer_time);
690
 		}
694
 		}
708
 	if (!ts->emm_only)
712
 	if (!ts->emm_only)
709
 	{
713
 	{
710
 		if (ts->output.type == NET_IO) {
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
 				ts->rtp_output ? "rtp" : "udp",
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
 			ts_LOGf("Output ttl : %d\n", ts->output.ttl);
720
 			ts_LOGf("Output ttl : %d\n", ts->output.ttl);
716
 			if (ts->output.tos > -1)
721
 			if (ts->output.tos > -1)
717
 				ts_LOGf("Output TOS : %u (0x%02x)\n", ts->output.tos, ts->output.tos);
722
 				ts_LOGf("Output TOS : %u (0x%02x)\n", ts->output.tos, ts->output.tos);
1000
 				ts_LOGf("--- | Input read timeout.\n");
1005
 				ts_LOGf("--- | Input read timeout.\n");
1001
 				if (!ntimeouts) {
1006
 				if (!ntimeouts) {
1002
 					timeout_start = time(NULL);
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
 							ts.rtp_input ? "rtp" : "udp",
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
 				ntimeouts++;
1012
 				ntimeouts++;
1008
 			} else {
1013
 			} else {
1009
 				if (ntimeouts && readen > 0) {
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
 							ts.rtp_input ? "rtp" : "udp",
1016
 							ts.rtp_input ? "rtp" : "udp",
1012
-							inet_ntoa(ts.input.addr), ts.input.port,
1017
+							ts.input.hostname, ts.input.service,
1013
 							(time(NULL) - timeout_start) + 2); // Timeout is detected when ~2 seconds there is no incoming data
1018
 							(time(NULL) - timeout_start) + 2); // Timeout is detected when ~2 seconds there is no incoming data
1014
 					ntimeouts = 0;
1019
 					ntimeouts = 0;
1015
 				}
1020
 				}

+ 148
- 56
udp.c View File

24
 #include <arpa/inet.h>
24
 #include <arpa/inet.h>
25
 #include <errno.h>
25
 #include <errno.h>
26
 
26
 
27
+#include "util.h"
27
 #include "udp.h"
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
 int udp_connect_input(struct io *io) {
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
 		return -1;
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
 	/* Set receive buffer size to ~2.0MB */
146
 	/* Set receive buffer size to ~2.0MB */
41
 	int bufsize = (2000000 / 1316) * 1316;
147
 	int bufsize = (2000000 / 1316) * 1316;
42
 	setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *)&bufsize, sizeof(bufsize));
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
 			return -1;
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
 	io->fd = sock;
157
 	io->fd = sock;
66
 	ts_LOGf("Input connected to fd:%d\n", io->fd);
158
 	ts_LOGf("Input connected to fd:%d\n", io->fd);
69
 }
161
 }
70
 
162
 
71
 int udp_connect_output(struct io *io) {
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
 		return -1;
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
 	int bufsize = (2000000 / 1316) * 1316;
176
 	int bufsize = (2000000 / 1316) * 1316;
87
 	setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *)&bufsize, sizeof(bufsize));
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
 			close(sock);
181
 			close(sock);
100
 			return -1;
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
 		if (setsockopt(sock, IPPROTO_IP, IP_TOS, &io->tos, sizeof(io->tos)) < 0) {
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
 		close(sock);
209
 		close(sock);
118
 		return -1;
210
 		return -1;
119
 	}
211
 	}

Loading…
Cancel
Save