Merge branch 'nto-signal-stats'
[dvblast.git] / output.c
blobbbedcface4af77661a1fb5f50f52c317fd2599f4
1 /*****************************************************************************
2 * output.c
3 *****************************************************************************
4 * Copyright (C) 2004, 2008-2010, 2015-2016 VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7 * Andy Gatward <a.j.gatward@reading.ac.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <stdint.h>
27 #include <stdbool.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/uio.h>
36 #include <errno.h>
37 #include <ev.h>
39 #include "dvblast.h"
41 #include <bitstream/mpeg/ts.h>
42 #include <bitstream/ietf/rtp.h>
44 /*****************************************************************************
45 * Local declarations
46 *****************************************************************************/
47 #define MAX_PACKETS 100
49 static struct ev_timer output_watcher;
50 static mtime_t i_next_send = INT64_MAX;
52 struct packet_t
54 struct packet_t *p_next;
55 mtime_t i_dts;
56 int i_depth;
57 block_t *pp_blocks[];
60 static uint8_t p_pad_ts[TS_SIZE] = {
61 0x47, 0x1f, 0xff, 0x10, 0xff, 0xff, 0xff, 0xff,
62 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
63 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
64 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
65 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
66 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
67 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
68 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
69 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
70 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
71 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
72 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
73 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
74 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
75 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
76 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
79 /*****************************************************************************
80 * RawFillHeaders - fill ipv4/udp headers for RAW socket
81 *****************************************************************************/
82 static void RawFillHeaders(struct udprawpkt *dgram,
83 in_addr_t ipsrc, in_addr_t ipdst,
84 uint16_t portsrc, uint16_t portdst,
85 uint8_t ttl, uint8_t tos, uint16_t len)
87 struct iphdr *iph = &(dgram->iph);
88 struct udpheader *udph = &(dgram->udph);
90 #ifdef DEBUG_SOCKET
91 char ipsrc_str[16], ipdst_str[16];
92 struct in_addr insrc, indst;
93 insrc.s_addr = ipsrc;
94 indst.s_addr = ipdst;
95 strncpy(ipsrc_str, inet_ntoa(insrc), 16);
96 strncpy(ipdst_str, inet_ntoa(indst), 16);
97 printf("Filling raw header (%p) (%s:%u -> %s:%u)\n", dgram, ipsrc_str, portsrc, ipdst_str, portdst);
98 #endif
100 // Fill ip header
101 iph->ihl = 5; // ip header with no specific option
102 iph->version = 4;
103 iph->tos = tos;
104 iph->tot_len = sizeof(struct udprawpkt) + len; // auto-htoned ?
105 iph->id = htons(0); // auto-generated if frag_off (flags) = 0 ?
106 iph->frag_off = 0;
107 iph->ttl = ttl;
108 iph->protocol = IPPROTO_UDP;
109 iph->check = 0;
110 iph->saddr = ipsrc;
111 iph->daddr = ipdst;
113 // Fill udp header
114 udph->source = htons(portsrc);
115 udph->dest = htons(portdst);
116 udph->len = htons(sizeof(struct udpheader) + len);
117 udph->check = 0;
119 // Compute ip header checksum. Computed by kernel when frag_off = 0 ?
120 //iph->check = csum((unsigned short *)iph, sizeof(struct iphdr));
123 /*****************************************************************************
124 * output_BlockCount
125 *****************************************************************************/
126 static int output_BlockCount( output_t *p_output )
128 int i_mtu = p_output->config.i_mtu;
129 if ( !(p_output->config.i_config & OUTPUT_UDP) )
130 i_mtu -= RTP_HEADER_SIZE;
131 return i_mtu / TS_SIZE;
134 /*****************************************************************************
135 * output_PacketNew
136 *****************************************************************************/
137 packet_t *output_PacketNew( output_t *p_output )
139 packet_t *p_packet;
141 if (p_output->i_packet_count)
143 p_packet = p_output->p_packet_lifo;
144 p_output->p_packet_lifo = p_packet->p_next;
145 p_output->i_packet_count--;
147 else
149 p_packet = malloc(sizeof(packet_t) +
150 output_BlockCount(p_output) * sizeof(block_t *) );
153 p_packet->i_depth = 0;
154 p_packet->p_next = NULL;
155 return p_packet;
158 /*****************************************************************************
159 * output_PacketDelete
160 *****************************************************************************/
161 void output_PacketDelete( output_t *p_output, packet_t *p_packet )
163 if (p_output->i_packet_count >= MAX_PACKETS )
165 free( p_packet );
166 return;
169 p_packet->p_next = p_output->p_packet_lifo;
170 p_output->p_packet_lifo = p_packet;
171 p_output->i_packet_count++;
174 /*****************************************************************************
175 * output_PacketVacuum
176 *****************************************************************************/
177 void output_PacketVacuum( output_t *p_output )
179 while (p_output->i_packet_count)
181 packet_t *p_packet = p_output->p_packet_lifo;
182 p_output->p_packet_lifo = p_packet->p_next;
183 free(p_packet);
184 p_output->i_packet_count--;
188 /*****************************************************************************
189 * output_Create : create and insert the output_t structure
190 *****************************************************************************/
191 output_t *output_Create( const output_config_t *p_config )
193 int i;
194 output_t *p_output = NULL;
196 for ( i = 0; i < i_nb_outputs; i++ )
198 if ( !( pp_outputs[i]->config.i_config & OUTPUT_VALID ) )
200 p_output = pp_outputs[i];
201 break;
205 if ( p_output == NULL )
207 p_output = malloc( sizeof(output_t) );
208 i_nb_outputs++;
209 pp_outputs = realloc( pp_outputs, i_nb_outputs * sizeof(output_t *) );
210 pp_outputs[i] = p_output;
213 if ( output_Init( p_output, p_config ) < 0 )
214 return NULL;
216 return p_output;
219 /* Init the mapped pids to unused */
220 void init_pid_mapping( output_t *p_output )
222 unsigned int i;
223 for ( i = 0; i < MAX_PIDS; i++ ) {
224 p_output->pi_newpids[i] = UNUSED_PID;
225 p_output->pi_freepids[i] = UNUSED_PID;
229 /*****************************************************************************
230 * output_Init : set up the output initial config
231 *****************************************************************************/
232 int output_Init( output_t *p_output, const output_config_t *p_config )
234 socklen_t i_sockaddr_len = (p_config->i_family == AF_INET) ?
235 sizeof(struct sockaddr_in) :
236 sizeof(struct sockaddr_in6);
238 memset( p_output, 0, sizeof(output_t) );
239 config_Init( &p_output->config );
241 /* Init run-time values */
242 p_output->p_packets = p_output->p_last_packet = NULL;
243 p_output->p_packet_lifo = NULL;
244 p_output->i_packet_count = 0;
245 p_output->i_seqnum = rand() & 0xffff;
246 p_output->i_pat_cc = rand() & 0xf;
247 p_output->i_pmt_cc = rand() & 0xf;
248 p_output->i_nit_cc = rand() & 0xf;
249 p_output->i_sdt_cc = rand() & 0xf;
250 p_output->i_eit_cc = rand() & 0xf;
251 p_output->i_pat_version = rand() & 0xff;
252 p_output->i_pmt_version = rand() & 0xff;
253 p_output->i_nit_version = rand() & 0xff;
254 p_output->i_sdt_version = rand() & 0xff;
255 p_output->p_pat_section = NULL;
256 p_output->p_pmt_section = NULL;
257 p_output->p_nit_section = NULL;
258 p_output->p_sdt_section = NULL;
259 p_output->p_eit_ts_buffer = NULL;
260 if ( b_random_tsid )
261 p_output->i_tsid = rand() & 0xffff;
262 p_output->i_pcr_pid = 0;
264 /* Init the mapped pids to unused */
265 init_pid_mapping( p_output );
267 /* Init socket-related fields */
268 p_output->config.i_family = p_config->i_family;
269 memcpy( &p_output->config.connect_addr, &p_config->connect_addr,
270 sizeof(struct sockaddr_storage) );
271 memcpy( &p_output->config.bind_addr, &p_config->bind_addr,
272 sizeof(struct sockaddr_storage) );
273 p_output->config.i_if_index_v6 = p_config->i_if_index_v6;
275 if ( (p_config->i_config & OUTPUT_RAW) ) {
276 p_output->config.i_config |= OUTPUT_RAW;
277 p_output->i_handle = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );
278 } else {
279 p_output->i_handle = socket( p_config->i_family, SOCK_DGRAM, IPPROTO_UDP );
281 if ( p_output->i_handle < 0 )
283 msg_Err( NULL, "couldn't create socket (%s)", strerror(errno) );
284 p_output->config.i_config &= ~OUTPUT_VALID;
285 return -errno;
288 int ret = 0;
289 if ( p_config->bind_addr.ss_family != AF_UNSPEC )
291 if ( bind( p_output->i_handle, (struct sockaddr *)&p_config->bind_addr,
292 i_sockaddr_len ) < 0 )
293 msg_Warn( NULL, "couldn't bind socket (%s)", strerror(errno) );
295 if ( p_config->i_family == AF_INET )
297 struct sockaddr_in *p_connect_addr =
298 (struct sockaddr_in *)&p_output->config.connect_addr;
299 struct sockaddr_in *p_bind_addr =
300 (struct sockaddr_in *)&p_output->config.bind_addr;
302 if ( IN_MULTICAST( ntohl( p_connect_addr->sin_addr.s_addr ) ) )
303 ret = setsockopt( p_output->i_handle, IPPROTO_IP,
304 IP_MULTICAST_IF,
305 (void *)&p_bind_addr->sin_addr.s_addr,
306 sizeof(p_bind_addr->sin_addr.s_addr) );
310 if ( (p_config->i_config & OUTPUT_RAW) )
312 struct sockaddr_in *p_connect_addr =
313 (struct sockaddr_in *)&p_output->config.connect_addr;
314 RawFillHeaders(&p_output->raw_pkt_header, inet_addr(p_config->psz_srcaddr),
315 p_connect_addr->sin_addr.s_addr,
316 (uint16_t) p_config->i_srcport, ntohs(p_connect_addr->sin_port),
317 p_config->i_ttl, p_config->i_tos, 0);
320 if ( p_config->i_family == AF_INET6 && p_config->i_if_index_v6 != -1 )
322 struct sockaddr_in6 *p_addr =
323 (struct sockaddr_in6 *)&p_output->config.connect_addr;
324 if ( IN6_IS_ADDR_MULTICAST( &p_addr->sin6_addr ) )
325 ret = setsockopt( p_output->i_handle, IPPROTO_IPV6,
326 IPV6_MULTICAST_IF,
327 (void *)&p_config->i_if_index_v6,
328 sizeof(p_config->i_if_index_v6) );
331 if (ret == -1)
332 msg_Warn( NULL, "couldn't join multicast address (%s)",
333 strerror(errno) );
335 if ( connect( p_output->i_handle,
336 (struct sockaddr *)&p_output->config.connect_addr,
337 i_sockaddr_len ) < 0 )
339 msg_Err( NULL, "couldn't connect socket (%s)", strerror(errno) );
340 close( p_output->i_handle );
341 p_output->config.i_config &= ~OUTPUT_VALID;
342 return -errno;
345 p_output->config.i_config |= OUTPUT_VALID;
347 return 0;
350 /*****************************************************************************
351 * output_Close
352 *****************************************************************************/
353 void output_Close( output_t *p_output )
355 packet_t *p_packet = p_output->p_packets;
356 while ( p_packet != NULL )
358 int i;
360 for ( i = 0; i < p_packet->i_depth; i++ )
362 p_packet->pp_blocks[i]->i_refcount--;
363 if ( !p_packet->pp_blocks[i]->i_refcount )
364 block_Delete( p_packet->pp_blocks[i] );
366 p_output->p_packets = p_packet->p_next;
367 output_PacketDelete( p_output, p_packet );
368 p_packet = p_output->p_packets;
370 output_PacketVacuum( p_output );
372 p_output->p_packets = p_output->p_last_packet = NULL;
373 free( p_output->p_pat_section );
374 free( p_output->p_pmt_section );
375 free( p_output->p_nit_section );
376 free( p_output->p_sdt_section );
377 free( p_output->p_eit_ts_buffer );
378 p_output->config.i_config &= ~OUTPUT_VALID;
380 close( p_output->i_handle );
382 config_Free( &p_output->config );
385 /*****************************************************************************
386 * output_Flush
387 *****************************************************************************/
388 static void output_Flush( output_t *p_output )
390 packet_t *p_packet = p_output->p_packets;
391 int i_block_cnt = output_BlockCount( p_output );
392 struct iovec p_iov[i_block_cnt + 2];
393 uint8_t p_rtp_hdr[RTP_HEADER_SIZE];
394 int i_iov = 0, i_payload_len, i_block;
396 if ( (p_output->config.i_config & OUTPUT_RAW) )
398 p_iov[i_iov].iov_base = &p_output->raw_pkt_header;
399 p_iov[i_iov].iov_len = sizeof(struct udprawpkt);
400 i_iov++;
403 if ( !(p_output->config.i_config & OUTPUT_UDP) )
405 p_iov[i_iov].iov_base = p_rtp_hdr;
406 p_iov[i_iov].iov_len = sizeof(p_rtp_hdr);
408 rtp_set_hdr( p_rtp_hdr );
409 rtp_set_type( p_rtp_hdr, RTP_TYPE_TS );
410 rtp_set_seqnum( p_rtp_hdr, p_output->i_seqnum++ );
411 /* New timestamp based only on local time when sent */
412 /* 90 kHz clock = 90000 counts per second */
413 rtp_set_timestamp( p_rtp_hdr, i_wallclock * 9 / 100);
414 rtp_set_ssrc( p_rtp_hdr, p_output->config.pi_ssrc );
416 i_iov++;
419 for ( i_block = 0; i_block < p_packet->i_depth; i_block++ )
421 /* Do pid mapping here if needed.
422 * save the original pid in the block.
423 * set the pid to the new pid
424 * later we re-instate the old pid for the next output
426 if ( b_do_remap || p_output->config.b_do_remap ) {
427 block_t *p_block = p_packet->pp_blocks[i_block];
428 uint16_t i_pid = ts_get_pid( p_block->p_ts );
429 p_block->tmp_pid = UNUSED_PID;
430 if ( p_output->pi_newpids[i_pid] != UNUSED_PID )
432 uint16_t i_newpid = p_output->pi_newpids[i_pid];
433 /* Need to map this pid to the new pid */
434 ts_set_pid( p_block->p_ts, i_newpid );
435 p_block->tmp_pid = i_pid;
439 p_iov[i_iov].iov_base = p_packet->pp_blocks[i_block]->p_ts;
440 p_iov[i_iov].iov_len = TS_SIZE;
441 i_iov++;
444 for ( ; i_block < i_block_cnt; i_block++ )
446 p_iov[i_iov].iov_base = p_pad_ts;
447 p_iov[i_iov].iov_len = TS_SIZE;
448 i_iov++;
452 if ( (p_output->config.i_config & OUTPUT_RAW) )
454 i_payload_len = 0;
455 for ( i_block = 1; i_block < i_iov; i_block++ ) {
456 i_payload_len += p_iov[i_block].iov_len;
458 p_output->raw_pkt_header.udph.len = htons(sizeof(struct udpheader) + i_payload_len);
461 if ( writev( p_output->i_handle, p_iov, i_iov ) < 0 )
463 msg_Err( NULL, "couldn't writev to %s (%s)",
464 p_output->config.psz_displayname, strerror(errno) );
466 /* Update the wallclock because writev() can take some time. */
467 i_wallclock = mdate();
469 for ( i_block = 0; i_block < p_packet->i_depth; i_block++ )
471 p_packet->pp_blocks[i_block]->i_refcount--;
472 if ( !p_packet->pp_blocks[i_block]->i_refcount )
473 block_Delete( p_packet->pp_blocks[i_block] );
474 else if ( b_do_remap || p_output->config.b_do_remap ) {
475 /* still referenced so re-instate the orignial pid if remapped */
476 block_t * p_block = p_packet->pp_blocks[i_block];
477 if (p_block->tmp_pid != UNUSED_PID)
478 ts_set_pid( p_block->p_ts, p_block->tmp_pid );
481 p_output->p_packets = p_packet->p_next;
482 output_PacketDelete( p_output, p_packet );
483 if ( p_output->p_packets == NULL )
484 p_output->p_last_packet = NULL;
487 /*****************************************************************************
488 * output_Put : called from demux
489 *****************************************************************************/
490 void output_Put( output_t *p_output, block_t *p_block )
492 int i_block_cnt = output_BlockCount( p_output );
493 packet_t *p_packet;
495 p_block->i_refcount++;
497 if ( p_output->p_last_packet != NULL
498 && p_output->p_last_packet->i_depth < i_block_cnt
499 && p_output->p_last_packet->i_dts + p_output->config.i_max_retention
500 > p_block->i_dts )
502 p_packet = p_output->p_last_packet;
503 if ( ts_has_adaptation( p_block->p_ts )
504 && ts_get_adaptation( p_block->p_ts )
505 && tsaf_has_pcr( p_block->p_ts ) )
506 p_packet->i_dts = p_block->i_dts;
508 else
510 p_packet = output_PacketNew( p_output );
511 p_packet->i_dts = p_block->i_dts;
512 if ( p_output->p_last_packet != NULL )
513 p_output->p_last_packet->p_next = p_packet;
514 else
515 p_output->p_packets = p_packet;
516 p_output->p_last_packet = p_packet;
519 p_packet->pp_blocks[p_packet->i_depth] = p_block;
520 p_packet->i_depth++;
522 if (i_next_send > p_packet->i_dts + p_output->config.i_output_latency)
524 i_next_send = p_packet->i_dts + p_output->config.i_output_latency;
525 ev_timer_stop(event_loop, &output_watcher);
526 ev_timer_set(&output_watcher, (i_next_send - i_wallclock) / 1000000., 0);
527 ev_timer_start(event_loop, &output_watcher);
531 /*****************************************************************************
532 * outputs_Send :
533 *****************************************************************************/
534 static void outputs_Send(struct ev_loop *loop, struct ev_timer *w, int revents)
536 i_wallclock = mdate();
540 int i;
541 i_next_send = INT64_MAX;
543 if ( output_dup.config.i_config & OUTPUT_VALID )
545 while ( output_dup.p_packets != NULL
546 && output_dup.p_packets->i_dts
547 + output_dup.config.i_output_latency <= i_wallclock )
548 output_Flush( &output_dup );
550 if ( output_dup.p_packets != NULL )
551 i_next_send = output_dup.p_packets->i_dts
552 + output_dup.config.i_output_latency;
555 for ( i = 0; i < i_nb_outputs; i++ )
557 output_t *p_output = pp_outputs[i];
558 if ( !( p_output->config.i_config & OUTPUT_VALID ) )
559 continue;
561 while ( p_output->p_packets != NULL
562 && p_output->p_packets->i_dts
563 + p_output->config.i_output_latency <= i_wallclock )
564 output_Flush( p_output );
566 if ( p_output->p_packets != NULL
567 && (p_output->p_packets->i_dts
568 + p_output->config.i_output_latency < i_next_send) )
569 i_next_send = p_output->p_packets->i_dts
570 + p_output->config.i_output_latency;
573 while (i_next_send <= i_wallclock);
575 if (i_next_send < INT64_MAX)
577 ev_timer_set(&output_watcher, (i_next_send - i_wallclock) / 1000000., 0);
578 ev_timer_start(loop, &output_watcher);
582 /*****************************************************************************
583 * outputs_Init :
584 *****************************************************************************/
585 void outputs_Init( void )
587 ev_timer_init(&output_watcher, outputs_Send, 0, 0);
590 /*****************************************************************************
591 * output_Find : find an existing output from a given output_config_t
592 *****************************************************************************/
593 output_t *output_Find( const output_config_t *p_config )
595 socklen_t i_sockaddr_len = (p_config->i_family == AF_INET) ?
596 sizeof(struct sockaddr_in) :
597 sizeof(struct sockaddr_in6);
598 int i;
600 for ( i = 0; i < i_nb_outputs; i++ )
602 output_t *p_output = pp_outputs[i];
604 if ( !(p_output->config.i_config & OUTPUT_VALID) ) continue;
606 if ( p_config->i_family != p_output->config.i_family ||
607 memcmp( &p_config->connect_addr, &p_output->config.connect_addr,
608 i_sockaddr_len ) ||
609 memcmp( &p_config->bind_addr, &p_output->config.bind_addr,
610 i_sockaddr_len ) )
611 continue;
613 if ( p_config->i_family == AF_INET6 &&
614 p_config->i_if_index_v6 != p_output->config.i_if_index_v6 )
615 continue;
617 if ( (p_config->i_config ^ p_output->config.i_config) & OUTPUT_RAW ) {
618 continue;
621 return p_output;
624 return NULL;
627 /*****************************************************************************
628 * output_Change : get changes from a new output_config_t
629 *****************************************************************************/
630 void output_Change( output_t *p_output, const output_config_t *p_config )
632 int ret = 0;
633 memcpy( p_output->config.pi_ssrc, p_config->pi_ssrc, 4 * sizeof(uint8_t) );
634 p_output->config.i_output_latency = p_config->i_output_latency;
635 p_output->config.i_max_retention = p_config->i_max_retention;
637 if ( p_output->config.i_ttl != p_config->i_ttl )
639 if ( p_output->config.i_family == AF_INET6 )
641 struct sockaddr_in6 *p_addr =
642 (struct sockaddr_in6 *)&p_output->config.connect_addr;
643 if ( IN6_IS_ADDR_MULTICAST( &p_addr->sin6_addr ) )
644 ret = setsockopt( p_output->i_handle, IPPROTO_IPV6,
645 IPV6_MULTICAST_HOPS, (void *)&p_config->i_ttl,
646 sizeof(p_config->i_ttl) );
648 else
650 struct sockaddr_in *p_addr =
651 (struct sockaddr_in *)&p_output->config.connect_addr;
652 if ( IN_MULTICAST( ntohl( p_addr->sin_addr.s_addr ) ) )
653 ret = setsockopt( p_output->i_handle, IPPROTO_IP,
654 IP_MULTICAST_TTL, (void *)&p_config->i_ttl,
655 sizeof(p_config->i_ttl) );
657 p_output->config.i_ttl = p_config->i_ttl;
658 p_output->raw_pkt_header.iph.ttl = p_config->i_ttl;
661 if ( p_output->config.i_tos != p_config->i_tos )
663 if ( p_output->config.i_family == AF_INET )
664 ret = setsockopt( p_output->i_handle, IPPROTO_IP, IP_TOS,
665 (void *)&p_config->i_tos,
666 sizeof(p_config->i_tos) );
667 p_output->config.i_tos = p_config->i_tos;
668 p_output->raw_pkt_header.iph.tos = p_config->i_tos;
671 if (ret == -1)
672 msg_Warn( NULL, "couldn't change socket (%s)", strerror(errno) );
674 if ( p_output->config.i_mtu != p_config->i_mtu
675 || ((p_output->config.i_config ^ p_config->i_config) & OUTPUT_UDP) )
677 int i_block_cnt;
678 packet_t *p_packet = p_output->p_last_packet;
679 p_output->config.i_config &= ~OUTPUT_UDP;
680 p_output->config.i_config |= p_config->i_config & OUTPUT_UDP;
681 p_output->config.i_mtu = p_config->i_mtu;
683 output_PacketVacuum( p_output );
685 i_block_cnt = output_BlockCount( p_output );
686 if ( p_packet != NULL && p_packet->i_depth < i_block_cnt )
688 p_packet = realloc( p_packet, sizeof(packet_t *)
689 + i_block_cnt * sizeof(block_t *) );
690 p_output->p_last_packet = p_packet;
694 if ( p_config->i_config & OUTPUT_RAW ) {
695 p_output->raw_pkt_header.iph.saddr = inet_addr(p_config->psz_srcaddr);
696 p_output->raw_pkt_header.udph.source = htons(p_config->i_srcport);
700 /*****************************************************************************
701 * outputs_Close : Close all outputs and free allocated memory
702 *****************************************************************************/
703 void outputs_Close( int i_num_outputs )
705 int i;
707 for ( i = 0; i < i_num_outputs; i++ )
709 output_t *p_output = pp_outputs[i];
711 if ( p_output->config.i_config & OUTPUT_VALID )
713 msg_Dbg( NULL, "removing %s", p_output->config.psz_displayname );
715 if ( p_output->p_packets )
716 output_Flush( p_output );
717 output_Close( p_output );
720 free( p_output );
723 free( pp_outputs );