1 /*****************************************************************************
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 *****************************************************************************/
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>
41 #include <bitstream/mpeg/ts.h>
42 #include <bitstream/ietf/rtp.h>
44 /*****************************************************************************
46 *****************************************************************************/
47 #define MAX_PACKETS 100
49 static struct ev_timer output_watcher
;
50 static mtime_t i_next_send
= INT64_MAX
;
54 struct packet_t
*p_next
;
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
);
91 char ipsrc_str
[16], ipdst_str
[16];
92 struct in_addr insrc
, indst
;
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
);
101 iph
->ihl
= 5; // ip header with no specific option
104 iph
->tot_len
= sizeof(struct udprawpkt
) + len
; // auto-htoned ?
105 iph
->id
= htons(0); // auto-generated if frag_off (flags) = 0 ?
108 iph
->protocol
= IPPROTO_UDP
;
114 udph
->source
= htons(portsrc
);
115 udph
->dest
= htons(portdst
);
116 udph
->len
= htons(sizeof(struct udpheader
) + len
);
119 // Compute ip header checksum. Computed by kernel when frag_off = 0 ?
120 //iph->check = csum((unsigned short *)iph, sizeof(struct iphdr));
123 /*****************************************************************************
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 /*****************************************************************************
136 *****************************************************************************/
137 packet_t
*output_PacketNew( output_t
*p_output
)
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
--;
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
;
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
)
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
;
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
)
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
];
205 if ( p_output
== NULL
)
207 p_output
= malloc( sizeof(output_t
) );
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 )
219 /* Init the mapped pids to unused */
220 void init_pid_mapping( output_t
*p_output
)
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
;
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
);
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
;
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
,
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
,
327 (void *)&p_config
->i_if_index_v6
,
328 sizeof(p_config
->i_if_index_v6
) );
332 msg_Warn( NULL
, "couldn't join multicast address (%s)",
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
;
345 p_output
->config
.i_config
|= OUTPUT_VALID
;
350 /*****************************************************************************
352 *****************************************************************************/
353 void output_Close( output_t
*p_output
)
355 packet_t
*p_packet
= p_output
->p_packets
;
356 while ( p_packet
!= NULL
)
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 /*****************************************************************************
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
);
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
);
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
;
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
;
452 if ( (p_output
->config
.i_config
& OUTPUT_RAW
) )
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
);
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
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
;
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
;
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
;
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 /*****************************************************************************
533 *****************************************************************************/
534 static void outputs_Send(struct ev_loop
*loop
, struct ev_timer
*w
, int revents
)
536 i_wallclock
= mdate();
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
) )
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 /*****************************************************************************
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
);
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
,
609 memcmp( &p_config
->bind_addr
, &p_output
->config
.bind_addr
,
613 if ( p_config
->i_family
== AF_INET6
&&
614 p_config
->i_if_index_v6
!= p_output
->config
.i_if_index_v6
)
617 if ( (p_config
->i_config
^ p_output
->config
.i_config
) & OUTPUT_RAW
) {
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
)
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
) );
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
;
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
) )
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
)
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
);