Commit 103b7ff0 authored by gatty's avatar gatty

Added IPv6 support for output and duplicate (-d) targets. See INSTALL file for usage info.

git-svn-id: svn://svn.videolan.org/dvblast/trunk@93 55d3f8b6-4a41-4d2d-a900-313d1436a5b8
parent ebfd5297
...@@ -7,14 +7,15 @@ ...@@ -7,14 +7,15 @@
# The fields are: name (N), email (E), web-address (W), CVS account login (C), # The fields are: name (N), email (E), web-address (W), CVS account login (C),
# PGP key ID and fingerprint (P), description (D), and snail-mail address (S). # PGP key ID and fingerprint (P), description (D), and snail-mail address (S).
N: Marian Ďurkovič N: Marian Durkovic
E: md AT bts DOT sk E: md AT bts DOT sk
C: md C: md
D: numerous bug fixes D: numerous bug fixes
N: Andy Gatward N: Andy Gatward
E: a DOT j DOT gatward AT reading DOT ac DOT uk E: a DOT j DOT gatward AT reading DOT ac DOT uk
D: EIT pass-through mode and misc fixes C: gatty
D: EIT pass-through, IPv6 support, various bug fixes
N: Christophe Massiot N: Christophe Massiot
E: massiot AT via DOT ecp DOT fr E: massiot AT via DOT ecp DOT fr
......
...@@ -40,6 +40,17 @@ For instance : ...@@ -40,6 +40,17 @@ For instance :
The configuration file can be reloaded by sending "HUP" to the program, or The configuration file can be reloaded by sending "HUP" to the program, or
via the dvblastctl program. via the dvblastctl program.
IPv6 is supported, the destination address must be specified in the format
described by RFC2732. When using link-local scope addresses, it is
mandatory to include the interface name in the address, as shown in the
example below. If you do not include the interface name, you will see an
"invalid argument" error. The interface name is optional for site-local and
global scope addresses.
For example :
[ff12::1%eth0]:1234 1 10750
[ff15::abcd]:1234 1 10750
The "always on" flag tells DVBlast whether the channel is expected to The "always on" flag tells DVBlast whether the channel is expected to
be on at all times or if it may break. If set to "1", then DVBlast will be on at all times or if it may break. If set to "1", then DVBlast will
regularly reset the CAM module if it fails to descramble the service, regularly reset the CAM module if it fails to descramble the service,
...@@ -114,12 +125,18 @@ Advanced features ...@@ -114,12 +125,18 @@ Advanced features
================= =================
DVBlast may handle several DVB adapters in the same machine with the -a switch: DVBlast may handle several DVB adapters in the same machine with the -a switch:
-a 3 will use /dev/dvb/adapter3. -a 3 will use /dev/dvb/adapter3. Additionally, selecting between frontends on
a single card is supported with the -n switch. This is useful for hybrid
DVB/S + DVB/T cards.
For better latency, run DVBlast in real-time priority (-i 1). For better latency, run DVBlast in real-time priority (-i 1).
DVBlast can also stream the entire transponder to an address : DVBlast can also stream the entire transponder to an IPv4 or IPv6 address :
dvblast -u -d 172.16.42.42:1235 -f 11570000 -s 27500000 -v 18 dvblast -u -d 172.16.42.42:1235 -f 11570000 -s 27500000 -v 18
dvblast -u -d [fe80::0ca:feff:fec0:ffee]:1235 -f 11570000 -s 27500000 -v 18
Note that IPv6 addresses specified on command line may need to have the square
brackets escaped (\[ and \]), depending on your shell.
The -u switch disables the PID filters, so that all PIDs, even the The -u switch disables the PID filters, so that all PIDs, even the
unused ones, can be output. With -e, dvblast also streams EIT and SDT packets unused ones, can be output. With -e, dvblast also streams EIT and SDT packets
......
$Id$ $Id$
Changes between 1.1 and 1.2-svn:
--------------------------------
* Support for IPv6 output and duplicate
* Support input from ASI card
* Support input from (IPv4) RTP / UDP stream
* Miscellaneous CAM and demux fixes
Changes between 1.0 and 1.1: Changes between 1.0 and 1.1:
---------------------------- ----------------------------
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Andy Gatward <a.j.gatward@reading.ac.uk> * Andy Gatward <a.j.gatward@reading.ac.uk>
* Marian Ďurkovič <md@bts.sk> * Marian Durkovic <md@bts.sk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -280,8 +280,8 @@ static void demux_Handle( block_t *p_ts ) ...@@ -280,8 +280,8 @@ static void demux_Handle( block_t *p_ts )
pp_outputs[j]->i_nb_errors = 0; pp_outputs[j]->i_nb_errors = 0;
msg_Warn( NULL, msg_Warn( NULL,
"too many errors for stream %s:%d, resetting", "too many errors for stream %s, resetting",
inet_ntoa( p_output->maddr.sin_addr ), p_output->maddr.sin_port ); p_output->psz_displayname );
en50221_Reset(); en50221_Reset();
} }
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <pthread.h> #include <pthread.h>
#include <netdb.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
...@@ -41,7 +42,7 @@ ...@@ -41,7 +42,7 @@
*****************************************************************************/ *****************************************************************************/
output_t **pp_outputs = NULL; output_t **pp_outputs = NULL;
int i_nb_outputs = 0; int i_nb_outputs = 0;
output_t output_dup = {{ 0 }}; output_t output_dup = { 0 };
static char *psz_conf_file = NULL; static char *psz_conf_file = NULL;
char *psz_srv_socket = NULL; char *psz_srv_socket = NULL;
int i_ttl = 64; int i_ttl = 64;
...@@ -98,13 +99,19 @@ static void ReadConfiguration( char *psz_file ) ...@@ -98,13 +99,19 @@ static void ReadConfiguration( char *psz_file )
{ {
output_t *p_output = NULL; output_t *p_output = NULL;
char *psz_parser, *psz_token, *psz_token2, *psz_token3; char *psz_parser, *psz_token, *psz_token2, *psz_token3;
struct in_addr maddr; struct addrinfo *p_addr;
uint16_t i_port = DEFAULT_PORT; struct addrinfo ai_hints;
char sz_port[5];
char *psz_displayname;
uint16_t i_sid = 0; uint16_t i_sid = 0;
uint16_t *pi_pids = NULL; uint16_t *pi_pids = NULL;
int i_nb_pids = 0; int i_nb_pids = 0;
int b_rawudp = 0; uint8_t i_config = 0;
int b_watch;
snprintf( sz_port, sizeof( sz_port ), "%d", DEFAULT_PORT );
if ( !strncmp( psz_line, "#", 1 ) )
continue;
psz_token = strtok_r( psz_line, "\t\n ", &psz_parser ); psz_token = strtok_r( psz_line, "\t\n ", &psz_parser );
if ( psz_token == NULL ) if ( psz_token == NULL )
...@@ -113,20 +120,81 @@ static void ReadConfiguration( char *psz_file ) ...@@ -113,20 +120,81 @@ static void ReadConfiguration( char *psz_file )
if ( (psz_token3 = strrchr( psz_token, '/' )) != NULL ) if ( (psz_token3 = strrchr( psz_token, '/' )) != NULL )
{ {
*psz_token3 = '\0'; *psz_token3 = '\0';
b_rawudp = ( strncasecmp( psz_token3 + 1, "udp", 3 ) == 0 ); if( strncasecmp( psz_token3 + 1, "udp", 3 ) == 0 )
i_config |= OUTPUT_UDP;
} }
if ( (psz_token2 = strrchr( psz_token, ':' )) != NULL )
if ( !strncmp( psz_token, "[", 1 ) )
{ {
*psz_token2 = '\0'; if ( (psz_token2 = strchr( psz_token, ']' ) ) == NULL )
i_port = atoi( psz_token2 + 1 ); continue;
char *psz_maddr = malloc( psz_token2 - psz_token );
memset( psz_maddr, '\0', ( psz_token2 - psz_token ) );
strncpy( psz_maddr, psz_token + 1, ( psz_token2 - psz_token - 1 ));
if ( (psz_token2 = strchr( psz_token2, ':' )) != NULL )
{
*psz_token2 = '\0';
snprintf( sz_port, sizeof( sz_port ), "%d", atoi( psz_token2 + 1 ) );
}
p_addr = malloc( sizeof( p_addr ) );
memset( &ai_hints, 0, sizeof( ai_hints ) );
ai_hints.ai_socktype = SOCK_DGRAM;
ai_hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV;
ai_hints.ai_family = AF_INET6;
int i_ai = getaddrinfo( psz_maddr, sz_port, &ai_hints, &p_addr );
if ( i_ai != 0 )
{
msg_Err( NULL, "Cannot configure output [%s]:%s: %s", psz_maddr,
sz_port, gai_strerror( i_ai ) );
continue;
}
psz_displayname = malloc( INET6_ADDRSTRLEN + 8 );
snprintf( psz_displayname, ( INET6_ADDRSTRLEN + 8 ), "[%s]:%s",
psz_maddr, sz_port );
free( psz_maddr );
}
else
{
if ( (psz_token2 = strrchr( psz_token, ':' )) != NULL )
{
*psz_token2 = '\0';
snprintf( sz_port, sizeof( sz_port ), "%d", atoi( psz_token2 + 1 ) );
}
p_addr = malloc( sizeof( p_addr ) );
memset( &ai_hints, 0, sizeof( ai_hints ) );
ai_hints.ai_socktype = SOCK_DGRAM;
ai_hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV;
ai_hints.ai_family = AF_INET;
int i_ai = getaddrinfo( psz_token, sz_port, &ai_hints, &p_addr );
if ( i_ai != 0 )
{
msg_Err( NULL, "Cannot configure output %s:%s: %s", psz_token,
sz_port, gai_strerror( i_ai ) );
continue;
}
psz_displayname = malloc( INET_ADDRSTRLEN + 6 );
snprintf( psz_displayname, ( INET_ADDRSTRLEN + 6 ), "%s:%s",
psz_token, sz_port );
} }
if ( !inet_aton( psz_token, &maddr ) )
continue;
psz_token = strtok_r( NULL, "\t\n ", &psz_parser ); psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
if ( psz_token == NULL ) if ( psz_token == NULL )
continue; continue;
b_watch = atoi( psz_token ); if( atoi( psz_token ) )
i_config |= OUTPUT_WATCH;
else
i_config &= ~OUTPUT_WATCH;
psz_token = strtok_r( NULL, "\t\n ", &psz_parser ); psz_token = strtok_r( NULL, "\t\n ", &psz_parser );
if ( psz_token == NULL ) if ( psz_token == NULL )
...@@ -149,8 +217,9 @@ static void ReadConfiguration( char *psz_file ) ...@@ -149,8 +217,9 @@ static void ReadConfiguration( char *psz_file )
} }
} }
msg_Dbg( NULL, "conf: %s:%u w=%d sid=%d pids[%d]=%d,%d,%d,%d,%d...", msg_Dbg( NULL, "conf: %s w=%d sid=%d pids[%d]=%d,%d,%d,%d,%d...",
inet_ntoa( maddr ), i_port, b_watch, i_sid, i_nb_pids, psz_displayname,
( i_config & OUTPUT_WATCH ) ? 1 : 0, i_sid, i_nb_pids,
i_nb_pids < 1 ? -1 : pi_pids[0], i_nb_pids < 1 ? -1 : pi_pids[0],
i_nb_pids < 2 ? -1 : pi_pids[1], i_nb_pids < 2 ? -1 : pi_pids[1],
i_nb_pids < 3 ? -1 : pi_pids[2], i_nb_pids < 3 ? -1 : pi_pids[2],
...@@ -159,34 +228,48 @@ static void ReadConfiguration( char *psz_file ) ...@@ -159,34 +228,48 @@ static void ReadConfiguration( char *psz_file )
for ( i = 0; i < i_nb_outputs; i++ ) for ( i = 0; i < i_nb_outputs; i++ )
{ {
if ( pp_outputs[i]->maddr.sin_addr.s_addr == maddr.s_addr if ( pp_outputs[i]->p_addr->ss_family == AF_INET )
&& ntohs( pp_outputs[i]->maddr.sin_port ) == i_port )
{ {
p_output = pp_outputs[i]; struct sockaddr_in *p_esad = (struct sockaddr_in *)pp_outputs[i]->p_addr;
break; struct sockaddr_in *p_nsad = (struct sockaddr_in *)p_addr->ai_addr;
if ( ( p_esad->sin_addr.s_addr == p_nsad->sin_addr.s_addr ) &&
( p_esad->sin_port == p_nsad->sin_port ) )
{
p_output = pp_outputs[i];
output_Init( p_output, i_config, psz_displayname, (void *)p_addr );
break;
}
}
else if ( pp_outputs[i]->p_addr->ss_family == AF_INET6 )
{
struct sockaddr_in6 *p_esad = (struct sockaddr_in6 *)pp_outputs[i]->p_addr;
struct sockaddr_in6 *p_nsad = (struct sockaddr_in6 *)p_addr->ai_addr;
if ( ( p_esad->sin6_addr.s6_addr32[0] == p_nsad->sin6_addr.s6_addr32[0] ) &&
( p_esad->sin6_addr.s6_addr32[1] == p_nsad->sin6_addr.s6_addr32[1] ) &&
( p_esad->sin6_addr.s6_addr32[2] == p_nsad->sin6_addr.s6_addr32[2] ) &&
( p_esad->sin6_addr.s6_addr32[3] == p_nsad->sin6_addr.s6_addr32[3] ) &&
( p_esad->sin6_port == p_nsad->sin6_port ) )
{
p_output = pp_outputs[i];
output_Init( p_output, i_config, psz_displayname, (void *)p_addr );
break;
}
} }
} }
if ( i == i_nb_outputs ) if ( i == i_nb_outputs )
p_output = output_Create( maddr.s_addr, i_port ); p_output = output_Create( i_config, psz_displayname, (void *)p_addr );
if ( p_output != NULL ) if ( p_output != NULL )
{ {
demux_Change( p_output, i_sid, pi_pids, i_nb_pids ); demux_Change( p_output, i_sid, pi_pids, i_nb_pids );
if( b_rawudp )
p_output->i_config |= OUTPUT_UDP;
else
p_output->i_config &= ~OUTPUT_UDP;
if( b_watch == 1)
p_output->i_config |= OUTPUT_WATCH;
else
p_output->i_config &= ~OUTPUT_WATCH;
p_output->i_config |= OUTPUT_STILL_PRESENT; p_output->i_config |= OUTPUT_STILL_PRESENT;
} }
free( pi_pids ); free( pi_pids );
freeaddrinfo( p_addr );
} }
fclose( p_file ); fclose( p_file );
...@@ -196,8 +279,7 @@ static void ReadConfiguration( char *psz_file ) ...@@ -196,8 +279,7 @@ static void ReadConfiguration( char *psz_file )
if ( ( pp_outputs[i]->i_config & OUTPUT_VALID ) && if ( ( pp_outputs[i]->i_config & OUTPUT_VALID ) &&
!( pp_outputs[i]->i_config & OUTPUT_STILL_PRESENT ) ) !( pp_outputs[i]->i_config & OUTPUT_STILL_PRESENT ) )
{ {
msg_Dbg( NULL, "closing %s:%u", inet_ntoa( pp_outputs[i]->maddr.sin_addr ), msg_Dbg( NULL, "closing %s", pp_outputs[i]->psz_displayname );
ntohs( pp_outputs[i]->maddr.sin_port ) );
demux_Change( pp_outputs[i], 0, NULL, 0 ); demux_Change( pp_outputs[i], 0, NULL, 0 );
output_Close( pp_outputs[i] ); output_Close( pp_outputs[i] );
} }
...@@ -373,17 +455,92 @@ int main( int i_argc, char **pp_argv ) ...@@ -373,17 +455,92 @@ int main( int i_argc, char **pp_argv )
case 'd': case 'd':
{ {
char *psz_token; char *psz_token, *psz_displayname;
uint16_t i_port = DEFAULT_PORT; char sz_port[5];
struct in_addr maddr; struct addrinfo *p_daddr;
if ( (psz_token = strrchr( optarg, ':' )) != NULL ) struct addrinfo ai_hints;
int i_dup_config = 0;
snprintf( sz_port, sizeof( sz_port ), "%d", DEFAULT_PORT );
p_daddr = malloc( sizeof( p_daddr ) );
memset( p_daddr, '\0', sizeof( p_daddr ) );
if ( !strncmp( optarg, "[", 1 ) )
{ {
*psz_token = '\0'; if ( (psz_token = strchr( optarg, ']' ) ) == NULL )
i_port = atoi( psz_token + 1 ); {
msg_Err(NULL, "Invalid target address for -d switch");
break;
}
char *psz_maddr = malloc( psz_token - optarg );
memset( psz_maddr, '\0', ( psz_token - optarg ) );
strncpy( psz_maddr, optarg + 1, ( psz_token - optarg - 1 ));
if ( (psz_token = strchr( psz_token, ':' )) != NULL )
{
*psz_token = '\0';
snprintf( sz_port, sizeof( sz_port ), "%d", atoi( psz_token + 1 ) );
}
memset( &ai_hints, 0, sizeof( ai_hints ) );
ai_hints.ai_socktype = SOCK_DGRAM;
ai_hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV;
ai_hints.ai_family = AF_INET6;
int i_ai = getaddrinfo( psz_maddr, sz_port, &ai_hints, &p_daddr );
if ( i_ai != 0 )
{
msg_Err( NULL, "Cannot duplicate to [%s]:%s: %s", psz_maddr,
sz_port, gai_strerror( i_ai ) );
break;
}
psz_displayname = malloc( INET6_ADDRSTRLEN + 20 );
snprintf( psz_displayname, ( INET6_ADDRSTRLEN + 20 ),
"duplicate ([%s]:%s)", psz_maddr, sz_port );
i_dup_config |= OUTPUT_VALID;
free( psz_maddr );
} }
if ( !inet_aton( optarg, &maddr ) ) else
usage(); {
output_Init( &output_dup, maddr.s_addr, i_port ); if ( (psz_token = strrchr( optarg, ':' )) != NULL )
{
*psz_token = '\0';
snprintf( sz_port, sizeof( sz_port ), "%d", atoi( psz_token + 1 ) );
}
memset( &ai_hints, 0, sizeof( ai_hints ) );
ai_hints.ai_socktype = SOCK_DGRAM;
ai_hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV;
ai_hints.ai_family = AF_INET;
int i_ai = getaddrinfo( optarg, sz_port, &ai_hints, &p_daddr );
if ( i_ai != 0 )
{
msg_Err( NULL, "Cannot duplicate to %s:%s: %s", optarg,
sz_port, gai_strerror( i_ai ) );
break;
}
psz_displayname = malloc( INET_ADDRSTRLEN + 18 );
snprintf( psz_displayname, ( INET6_ADDRSTRLEN + 18 ),
"duplicate (%s:%s)", optarg, sz_port );
i_dup_config |= OUTPUT_VALID;
}
if ( i_dup_config &= OUTPUT_VALID ) {
output_Init( &output_dup, i_dup_config, psz_displayname, p_daddr );
}
else
msg_Err( NULL, "Invalid configuration for -d switch: %s" , optarg);
freeaddrinfo( p_daddr );
break; break;
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* $Id$ * $Id$
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Andy Gatward <a.j.gatward@reading.ac.uk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -25,9 +26,13 @@ ...@@ -25,9 +26,13 @@
#include <dvbpsi/descriptor.h> #include <dvbpsi/descriptor.h>
#include <dvbpsi/pmt.h> #include <dvbpsi/pmt.h>
#include "netdb.h"
#include "sys/socket.h"
#define DEFAULT_PORT 3001 #define DEFAULT_PORT 3001
#define TS_SIZE 188 #define TS_SIZE 188
#define NB_BLOCKS 7 #define NB_BLOCKS 7
#define NB_BLOCKS_IPV6 6 // assume MTU of 1280 bytes for IPv6
#define RTP_SIZE 12 #define RTP_SIZE 12
#define EMPTY_PID 8192 #define EMPTY_PID 8192
#define PADDING_PID 8191 #define PADDING_PID 8191
...@@ -41,16 +46,14 @@ ...@@ -41,16 +46,14 @@
* Bit 1 : Set output still present * Bit 1 : Set output still present
* Bit 2 : Set if output is valid (replaces m_addr != 0 tests) * Bit 2 : Set if output is valid (replaces m_addr != 0 tests)
* Bit 3 : Set for UDP, otherwise use RTP if a network stream * Bit 3 : Set for UDP, otherwise use RTP if a network stream
* Bit 4 : Set for IPv6, unset for IPv4 (future use) * Bit 4 : Set for file / FIFO output, unset for network (future use)
* Bit 5 : Set for file / FIFO output, unset for network (future use)
*****************************************************************************/ *****************************************************************************/
#define OUTPUT_WATCH 0x01 #define OUTPUT_WATCH 0x01
#define OUTPUT_STILL_PRESENT 0x02 #define OUTPUT_STILL_PRESENT 0x02
#define OUTPUT_VALID 0x04 #define OUTPUT_VALID 0x04
#define OUTPUT_UDP 0x08 #define OUTPUT_UDP 0x08
#define OUTPUT_IPV6 0x10 #define OUTPUT_FILE 0x10
#define OUTPUT_FILE 0x20
typedef int64_t mtime_t; typedef int64_t mtime_t;
...@@ -63,7 +66,12 @@ typedef struct block_t ...@@ -63,7 +66,12 @@ typedef struct block_t
typedef struct output_t typedef struct output_t
{ {
struct sockaddr_in maddr; /* address information, protocol agnostic */
struct sockaddr_storage *p_addr;
socklen_t i_addrlen;
/* display string */
char *psz_displayname;
/* output */ /* output */
int i_handle; int i_handle;
...@@ -161,8 +169,8 @@ void demux_Change( output_t *p_output, uint16_t i_sid, ...@@ -161,8 +169,8 @@ void demux_Change( output_t *p_output, uint16_t i_sid,
void demux_ResendCAPMTs( void ); void demux_ResendCAPMTs( void );
int PIDIsSelected( uint16_t i_pid ); int PIDIsSelected( uint16_t i_pid );
output_t *output_Create( in_addr_t i_maddr, uint16_t i_port ); output_t *output_Create( uint8_t i_config, char *psz_displayname, void *p_init_data );
int output_Init( output_t *p_output, in_addr_t i_maddr, uint16_t i_port ); int output_Init( output_t *p_output, uint8_t i_config, char *psz_displayname, void *p_init_data );
void output_Close( output_t *p_output ); void output_Close( output_t *p_output );
void output_Put( output_t *p_output, block_t *p_block ); void output_Put( output_t *p_output, block_t *p_block );
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* $Id$ * $Id$
* *
* Authors: Christophe Massiot <massiot@via.ecp.fr> * Authors: Christophe Massiot <massiot@via.ecp.fr>
* Andy Gatward <a.j.gatward@reading.ac.uk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
...@@ -44,7 +46,7 @@ static void rtp_SetHdr( output_t *p_output, uint8_t *p_hdr ); ...@@ -44,7 +46,7 @@ static void rtp_SetHdr( output_t *p_output, uint8_t *p_hdr );
/***************************************************************************** /*****************************************************************************
* output_Create : called from main thread * output_Create : called from main thread
*****************************************************************************/ *****************************************************************************/
output_t *output_Create( in_addr_t i_maddr, uint16_t i_port ) output_t *output_Create( uint8_t i_config, char *psz_displayname, void *p_init_data )
{ {
int i; int i;
output_t *p_output = NULL; output_t *p_output = NULL;
...@@ -67,7 +69,7 @@ output_t *output_Create( in_addr_t i_maddr, uint16_t i_port ) ...@@ -67,7 +69,7 @@ output_t *output_Create( in_addr_t i_maddr, uint16_t i_port )
pp_outputs[i] = p_output; pp_outputs[i] = p_output;
} }
if ( output_Init( p_output, i_maddr, i_port ) < 0 ) if ( output_Init( p_output, i_config, psz_displayname, p_init_data ) < 0 )
return NULL; return NULL;
return p_output; return p_output;
...@@ -76,7 +78,7 @@ output_t *output_Create( in_addr_t i_maddr, uint16_t i_port ) ...@@ -76,7 +78,7 @@ output_t *output_Create( in_addr_t i_maddr, uint16_t i_port )
/***************************************************************************** /*****************************************************************************
* output_Init * output_Init
*****************************************************************************/ *****************************************************************************/
int output_Init( output_t *p_output, in_addr_t i_maddr, uint16_t i_port ) int output_Init( output_t *p_output, uint8_t i_config, char *psz_displayname, void *p_init_data )
{ {
p_output->i_sid = 0; p_output->i_sid = 0;
p_output->i_depth = 0; p_output->i_depth = 0;
...@@ -100,10 +102,16 @@ int output_Init( output_t *p_output, in_addr_t i_maddr, uint16_t i_port ) ...@@ -100,10 +102,16 @@ int output_Init( output_t *p_output, in_addr_t i_maddr, uint16_t i_port )
p_output->i_ref_timestamp = 0; p_output->i_ref_timestamp = 0;
p_output->i_ref_wallclock = 0; p_output->i_ref_wallclock = 0;
p_output->maddr.sin_family = AF_INET; p_output->i_config = i_config;
p_output->maddr.sin_addr.s_addr = i_maddr; p_output->psz_displayname = psz_displayname;
p_output->maddr.sin_port = htons(i_port);
if ( (p_output->i_handle = net_Open(p_output)) < 0 ) struct addrinfo *p_ai = (struct addrinfo *)p_init_data;
p_output->i_addrlen = p_ai->ai_addrlen;
p_output->p_addr = malloc( p_output->i_addrlen );
memcpy( p_output->p_addr, p_ai->ai_addr,
p_output->i_addrlen );
if ( ( p_output->i_handle = net_Open( p_output ) ) < 0 )
{ {
p_output->i_config &= ~OUTPUT_VALID; p_output->i_config &= ~OUTPUT_VALID;
return -1; return -1;
...@@ -141,7 +149,9 @@ static void output_Flush( output_t *p_output ) ...@@ -141,7 +149,9 @@ static void output_Flush( output_t *p_output )
struct iovec p_iov[NB_BLOCKS + 1]; struct iovec p_iov[NB_BLOCKS + 1];
uint8_t p_rtp_hdr[RTP_SIZE]; uint8_t p_rtp_hdr[RTP_SIZE];
int i; int i;
int i_outblocks = NB_BLOCKS;
int i_block_cnt = ( p_output->p_addr->ss_family == AF_INET6 ) ? NB_BLOCKS_IPV6 : NB_BLOCKS;
int i_outblocks = i_block_cnt;
if ( !b_output_udp && !(p_output->i_config & OUTPUT_UDP) ) if ( !b_output_udp && !(p_output->i_config & OUTPUT_UDP) )
{ {
...@@ -149,7 +159,7 @@ static void output_Flush( output_t *p_output ) ...@@ -149,7 +159,7 @@ static void output_Flush( output_t *p_output )
p_iov[0].iov_len = sizeof(p_rtp_hdr); p_iov[0].iov_len = sizeof(p_rtp_hdr);
rtp_SetHdr( p_output, p_rtp_hdr ); rtp_SetHdr( p_output, p_rtp_hdr );
for ( i = 1; i < NB_BLOCKS + 1; i++ ) for ( i = 1; i < i_block_cnt + 1; i++ )
{ {
p_iov[i].iov_base = p_output->pp_blocks[i - 1]->p_ts; p_iov[i].iov_base = p_output->pp_blocks[i - 1]->p_ts;
p_iov[i].iov_len = TS_SIZE; p_iov[i].iov_len = TS_SIZE;
...@@ -159,7 +169,7 @@ static void output_Flush( output_t *p_output ) ...@@ -159,7 +169,7 @@ static void output_Flush( output_t *p_output )
} }
else else
{ {
for ( i = 0; i < NB_BLOCKS; i++ ) for ( i = 0; i < i_block_cnt; i++ )
{ {
p_iov[i].iov_base = p_output->pp_blocks[i]->p_ts; p_iov[i].iov_base = p_output->pp_blocks[i]->p_ts;
p_iov[i].iov_len = TS_SIZE; p_iov[i].iov_len = TS_SIZE;
...@@ -168,11 +178,11 @@ static void output_Flush( output_t *p_output ) ...@@ -168,11 +178,11 @@ static void output_Flush( output_t *p_output )
if ( writev( p_output->i_handle, p_iov, i_outblocks ) < 0 ) if ( writev( p_output->i_handle, p_iov, i_outblocks ) < 0 )
{ {
msg_Err( NULL, "couldn't writev to %s:%u (%s)", inet_ntoa( p_output->maddr.sin_addr ), msg_Err( NULL, "couldn't writev to %s (%s)",
p_output->maddr.sin_port, strerror(errno) ); p_output->psz_displayname, strerror(errno) );
} }
for ( i = 0; i < NB_BLOCKS; i++ ) for ( i = 0; i < i_block_cnt; i++ )
{ {
p_output->pp_blocks[i]->i_refcount--; p_output->pp_blocks[i]->i_refcount--;
if ( !p_output->pp_blocks[i]->i_refcount ) if ( !p_output->pp_blocks[i]->i_refcount )
...@@ -191,7 +201,10 @@ void output_Put( output_t *p_output, block_t *p_block ) ...@@ -191,7 +201,10 @@ void output_Put( output_t *p_output, block_t *p_block )
p_output->pp_blocks[p_output->i_depth] = p_block; p_output->pp_blocks[p_output->i_depth] = p_block;
p_output->i_depth++; p_output->i_depth++;
if ( p_output->i_depth >= NB_BLOCKS ) if ( ( ( p_output->p_addr->ss_family == AF_INET6 ) &&
( p_output->i_depth >= NB_BLOCKS_IPV6 ) ) ||
( ( p_output->p_addr->ss_family == AF_INET ) &&
( p_output->i_depth >= NB_BLOCKS ) ) )
output_Flush( p_output ); output_Flush( p_output );
} }
...@@ -200,21 +213,42 @@ void output_Put( output_t *p_output, block_t *p_block ) ...@@ -200,21 +213,42 @@ void output_Put( output_t *p_output, block_t *p_block )
*****************************************************************************/ *****************************************************************************/
static int net_Open( output_t *p_output ) static int net_Open( output_t *p_output )
{ {
int i_handle = socket( AF_INET, SOCK_DGRAM, 0 ); int i_handle = socket( p_output->p_addr->ss_family, SOCK_DGRAM, IPPROTO_UDP );
if ( connect( i_handle, (struct sockaddr *)&p_output->maddr, sizeof( p_output->maddr ) ) < 0 ) if ( i_handle < 0 )
{ {
msg_Err( NULL, "couldn't connect to %s:%u (%s)", inet_ntoa( p_output->maddr.sin_addr ), msg_Err( NULL, "couldn't create socket for %s (%s)",
p_output->maddr.sin_port, strerror(errno) ); p_output->psz_displayname, strerror(errno) );
close( i_handle ); return -errno;
return -1; }
if ( p_output->p_addr->ss_family == AF_INET6 )
{
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p_output->p_addr;
if ( IN6_IS_ADDR_MULTICAST( addr->sin6_addr.s6_addr ) )
{
int i = i_ttl;
setsockopt( i_handle, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
(void *)&i, sizeof(i) );
}
}
else if ( p_output->p_addr->ss_family == AF_INET )
{
struct sockaddr_in *addr = (struct sockaddr_in *)p_output->p_addr;
if ( IN_MULTICAST( ntohl( addr->sin_addr.s_addr ) ) )
{
int i = i_ttl;
setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL,
(void *)&i, sizeof(i) );
}
} }
if ( IN_MULTICAST( ntohl(p_output->maddr.sin_addr.s_addr ) ) ) if ( connect( i_handle, (struct sockaddr *)p_output->p_addr, p_output->i_addrlen ) < 0 )
{ {
int i = i_ttl; msg_Err( NULL, "couldn't connect socket to %s (%s)",
setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL, p_output->psz_displayname, strerror(errno) );
(void *)&i, sizeof(i) ); close( i_handle );
return -errno;
} }
return i_handle; return i_handle;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment