Commit 227d4e2d authored by Andy Gatward's avatar Andy Gatward Committed by Christophe Massiot

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

parent f447c22a
......@@ -7,14 +7,15 @@
# 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).
N: Marian Ďurkovič
N: Marian Durkovic
E: md AT bts DOT sk
C: md
D: numerous bug fixes
N: Andy Gatward
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
E: massiot AT via DOT ecp DOT fr
......
......@@ -40,6 +40,17 @@ For instance :
The configuration file can be reloaded by sending "HUP" to the program, or
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
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,
......@@ -114,12 +125,18 @@ Advanced features
=================
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).
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 [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
unused ones, can be output. With -e, dvblast also streams EIT and SDT packets
......
$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:
----------------------------
......
......@@ -6,7 +6,7 @@
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* 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
* 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 )
pp_outputs[j]->i_nb_errors = 0;
msg_Warn( NULL,
"too many errors for stream %s:%d, resetting",
inet_ntoa( p_output->maddr.sin_addr ), p_output->maddr.sin_port );
"too many errors for stream %s, resetting",
p_output->psz_displayname );
en50221_Reset();
}
}
......
......@@ -28,6 +28,7 @@
#include <stdint.h>
#include <string.h>
#include <pthread.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
......@@ -41,7 +42,7 @@
*****************************************************************************/
output_t **pp_outputs = NULL;
int i_nb_outputs = 0;
output_t output_dup = {{ 0 }};
output_t output_dup = { 0 };
static char *psz_conf_file = NULL;
char *psz_srv_socket = NULL;
int i_ttl = 64;
......@@ -98,13 +99,19 @@ static void ReadConfiguration( char *psz_file )
{
output_t *p_output = NULL;
char *psz_parser, *psz_token, *psz_token2, *psz_token3;
struct in_addr maddr;
uint16_t i_port = DEFAULT_PORT;
struct addrinfo *p_addr;
struct addrinfo ai_hints;
char sz_port[5];
char *psz_displayname;
uint16_t i_sid = 0;
uint16_t *pi_pids = NULL;
int i_nb_pids = 0;
int b_rawudp = 0;
int b_watch;
uint8_t i_config = 0;
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 );
if ( psz_token == NULL )
......@@ -113,20 +120,81 @@ static void ReadConfiguration( char *psz_file )
if ( (psz_token3 = strrchr( psz_token, '/' )) != NULL )
{
*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';
i_port = atoi( psz_token2 + 1 );
if ( (psz_token2 = strchr( psz_token, ']' ) ) == NULL )
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 );
if ( psz_token == NULL )
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 );
if ( psz_token == NULL )
......@@ -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...",
inet_ntoa( maddr ), i_port, b_watch, i_sid, i_nb_pids,
msg_Dbg( NULL, "conf: %s w=%d sid=%d pids[%d]=%d,%d,%d,%d,%d...",
psz_displayname,
( i_config & OUTPUT_WATCH ) ? 1 : 0, i_sid, i_nb_pids,
i_nb_pids < 1 ? -1 : pi_pids[0],
i_nb_pids < 2 ? -1 : pi_pids[1],
i_nb_pids < 3 ? -1 : pi_pids[2],
......@@ -159,34 +228,48 @@ static void ReadConfiguration( char *psz_file )
for ( i = 0; i < i_nb_outputs; i++ )
{
if ( pp_outputs[i]->maddr.sin_addr.s_addr == maddr.s_addr
&& ntohs( pp_outputs[i]->maddr.sin_port ) == i_port )
if ( pp_outputs[i]->p_addr->ss_family == AF_INET )
{
p_output = pp_outputs[i];
break;
struct sockaddr_in *p_esad = (struct sockaddr_in *)pp_outputs[i]->p_addr;
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 )
p_output = output_Create( maddr.s_addr, i_port );
p_output = output_Create( i_config, psz_displayname, (void *)p_addr );
if ( p_output != NULL )
{
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;
}
free( pi_pids );
freeaddrinfo( p_addr );
}
fclose( p_file );
......@@ -196,8 +279,7 @@ static void ReadConfiguration( char *psz_file )
if ( ( pp_outputs[i]->i_config & OUTPUT_VALID ) &&
!( pp_outputs[i]->i_config & OUTPUT_STILL_PRESENT ) )
{
msg_Dbg( NULL, "closing %s:%u", inet_ntoa( pp_outputs[i]->maddr.sin_addr ),
ntohs( pp_outputs[i]->maddr.sin_port ) );
msg_Dbg( NULL, "closing %s", pp_outputs[i]->psz_displayname );
demux_Change( pp_outputs[i], 0, NULL, 0 );
output_Close( pp_outputs[i] );
}
......@@ -373,17 +455,92 @@ int main( int i_argc, char **pp_argv )
case 'd':
{
char *psz_token;
uint16_t i_port = DEFAULT_PORT;
struct in_addr maddr;
if ( (psz_token = strrchr( optarg, ':' )) != NULL )
char *psz_token, *psz_displayname;
char sz_port[5];
struct addrinfo *p_daddr;
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';
i_port = atoi( psz_token + 1 );
if ( (psz_token = strchr( optarg, ']' ) ) == NULL )
{
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 ) )
usage();
output_Init( &output_dup, maddr.s_addr, i_port );
else
{
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;
}
......
......@@ -5,6 +5,7 @@
* $Id$
*
* 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
* it under the terms of the GNU General Public License as published by
......@@ -25,9 +26,13 @@
#include <dvbpsi/descriptor.h>
#include <dvbpsi/pmt.h>
#include "netdb.h"
#include "sys/socket.h"
#define DEFAULT_PORT 3001
#define TS_SIZE 188
#define NB_BLOCKS 7
#define NB_BLOCKS_IPV6 6 // assume MTU of 1280 bytes for IPv6
#define RTP_SIZE 12
#define EMPTY_PID 8192
#define PADDING_PID 8191
......@@ -41,16 +46,14 @@
* Bit 1 : Set output still present
* 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 4 : Set for IPv6, unset for IPv4 (future use)
* Bit 5 : Set for file / FIFO output, unset for network (future use)
* Bit 4 : Set for file / FIFO output, unset for network (future use)
*****************************************************************************/
#define OUTPUT_WATCH 0x01
#define OUTPUT_STILL_PRESENT 0x02
#define OUTPUT_VALID 0x04
#define OUTPUT_UDP 0x08
#define OUTPUT_IPV6 0x10
#define OUTPUT_FILE 0x20
#define OUTPUT_FILE 0x10
typedef int64_t mtime_t;
......@@ -63,7 +66,12 @@ typedef struct block_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 */
int i_handle;
......@@ -161,8 +169,8 @@ void demux_Change( output_t *p_output, uint16_t i_sid,
void demux_ResendCAPMTs( void );
int PIDIsSelected( uint16_t i_pid );
output_t *output_Create( in_addr_t i_maddr, uint16_t i_port );
int output_Init( output_t *p_output, 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, uint8_t i_config, char *psz_displayname, void *p_init_data );
void output_Close( output_t *p_output );
void output_Put( output_t *p_output, block_t *p_block );
......
......@@ -5,6 +5,7 @@
* $Id$
*
* 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
* it under the terms of the GNU General Public License as published by
......@@ -25,6 +26,7 @@
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
......@@ -44,7 +46,7 @@ static void rtp_SetHdr( output_t *p_output, uint8_t *p_hdr );
/*****************************************************************************
* 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;
output_t *p_output = NULL;
......@@ -67,7 +69,7 @@ output_t *output_Create( in_addr_t i_maddr, uint16_t i_port )
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 p_output;
......@@ -76,7 +78,7 @@ output_t *output_Create( in_addr_t i_maddr, uint16_t i_port )
/*****************************************************************************
* 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_depth = 0;
......@@ -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_wallclock = 0;
p_output->maddr.sin_family = AF_INET;
p_output->maddr.sin_addr.s_addr = i_maddr;
p_output->maddr.sin_port = htons(i_port);
if ( (p_output->i_handle = net_Open(p_output)) < 0 )
p_output->i_config = i_config;
p_output->psz_displayname = psz_displayname;
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;
return -1;
......@@ -141,7 +149,9 @@ static void output_Flush( output_t *p_output )
struct iovec p_iov[NB_BLOCKS + 1];
uint8_t p_rtp_hdr[RTP_SIZE];
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) )
{
......@@ -149,7 +159,7 @@ static void output_Flush( output_t *p_output )
p_iov[0].iov_len = sizeof(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_len = TS_SIZE;
......@@ -159,7 +169,7 @@ static void output_Flush( output_t *p_output )
}
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_len = TS_SIZE;
......@@ -168,11 +178,11 @@ static void output_Flush( output_t *p_output )
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 ),
p_output->maddr.sin_port, strerror(errno) );
msg_Err( NULL, "couldn't writev to %s (%s)",
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--;
if ( !p_output->pp_blocks[i]->i_refcount )
......@@ -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->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 );
}
......@@ -200,21 +213,42 @@ void output_Put( output_t *p_output, block_t *p_block )
*****************************************************************************/
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 ),
p_output->maddr.sin_port, strerror(errno) );
close( i_handle );
return -1;
msg_Err( NULL, "couldn't create socket for %s (%s)",
p_output->psz_displayname, strerror(errno) );
return -errno;
}
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;
setsockopt( i_handle, IPPROTO_IP, IP_MULTICAST_TTL,
(void *)&i, sizeof(i) );
msg_Err( NULL, "couldn't connect socket to %s (%s)",
p_output->psz_displayname, strerror(errno) );
close( i_handle );
return -errno;
}
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