/***************************************************************************** * udp_Open *****************************************************************************/ void udp_Open( void ) { int i_family; struct addrinfo *p_connect_ai = NULL, *p_bind_ai; int i_if_index = 0; in_addr_t i_if_addr = INADDR_ANY; int i_mtu = 0; char *psz_bind, *psz_string = strdup( psz_udp_src ); char *psz_save = psz_string; int i = 1; /* Parse configuration. */ if ( (psz_bind = strchr( psz_string, '@' )) != NULL ) { *psz_bind++ = '\0'; p_connect_ai = ParseNodeService( psz_string, NULL, 0 ); } else psz_bind = psz_string; p_bind_ai = ParseNodeService( psz_bind, &psz_string, DEFAULT_PORT ); if ( p_bind_ai == NULL ) { msg_Err( NULL, "couldn't parse %s", psz_bind ); exit(EXIT_FAILURE); } i_family = p_bind_ai->ai_family; if ( p_connect_ai != NULL && p_connect_ai->ai_family != i_family ) { msg_Warn( NULL, "invalid connect address" ); freeaddrinfo( p_connect_ai ); p_connect_ai = NULL; } while ( (psz_string = strchr( psz_string, '/' )) != NULL ) { *psz_string++ = '\0'; #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) )) #define ARG_OPTION( option ) (psz_string + strlen(option)) if ( IS_OPTION("udp") ) b_udp = true; else if ( IS_OPTION("mtu=") ) i_mtu = strtol( ARG_OPTION("mtu="), NULL, 0 ); else if ( IS_OPTION("ifindex=") ) i_if_index = strtol( ARG_OPTION("ifindex="), NULL, 0 ); else if ( IS_OPTION("ifaddr=") ) i_if_addr = inet_addr( ARG_OPTION("ifaddr=") ); else msg_Warn( NULL, "unrecognized option %s", psz_string ); #undef IS_OPTION #undef ARG_OPTION } if ( !i_mtu ) i_mtu = i_family == AF_INET6 ? DEFAULT_IPV6_MTU : DEFAULT_IPV4_MTU; i_block_cnt = (i_mtu - (b_udp ? 0 : RTP_HEADER_SIZE)) / TS_SIZE; /* Do stuff. */ if ( (i_handle = socket( i_family, SOCK_DGRAM, IPPROTO_UDP )) < 0 ) { msg_Err( NULL, "couldn't create socket (%s)", strerror(errno) ); exit(EXIT_FAILURE); } setsockopt( i_handle, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof( i ) ); /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid * packet loss caused by scheduling problems */ i = 0x80000; setsockopt( i_handle, SOL_SOCKET, SO_RCVBUF, (void *) &i, sizeof( i ) ); if ( bind( i_handle, p_bind_ai->ai_addr, p_bind_ai->ai_addrlen ) < 0 ) { msg_Err( NULL, "couldn't bind (%s)", strerror(errno) ); close( i_handle ); exit(EXIT_FAILURE); } if ( p_connect_ai != NULL ) { uint16_t i_port; if ( i_family == AF_INET6 ) i_port = ((struct sockaddr_in6 *)p_connect_ai->ai_addr)->sin6_port; else i_port = ((struct sockaddr_in *)p_connect_ai->ai_addr)->sin_port; if ( i_port != 0 && connect( i_handle, p_connect_ai->ai_addr, p_connect_ai->ai_addrlen ) < 0 ) msg_Warn( NULL, "couldn't connect socket (%s)", strerror(errno) ); } /* Join the multicast group if the socket is a multicast address */ if ( i_family == AF_INET6 ) { struct sockaddr_in6 *p_addr = (struct sockaddr_in6 *)p_bind_ai->ai_addr; if ( IN6_IS_ADDR_MULTICAST( &p_addr->sin6_addr ) ) { struct ipv6_mreq imr; imr.ipv6mr_multiaddr = p_addr->sin6_addr; imr.ipv6mr_interface = i_if_index; if ( i_if_addr != INADDR_ANY ) msg_Warn( NULL, "ignoring ifaddr option in IPv6" ); if ( setsockopt( i_handle, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&imr, sizeof(struct ipv6_mreq) ) < 0 ) msg_Warn( NULL, "couldn't join multicast group (%s)", strerror(errno) ); } } else { struct sockaddr_in *p_addr = (struct sockaddr_in *)p_bind_ai->ai_addr; if ( IN_MULTICAST( ntohl(p_addr->sin_addr.s_addr)) ) { if ( p_connect_ai != NULL ) { #ifndef IP_ADD_SOURCE_MEMBERSHIP msg_Err( NULL, "IP_ADD_SOURCE_MEMBERSHIP is unsupported." ); #else /* Source-specific multicast */ struct sockaddr_in *p_src = (struct sockaddr_in *)&p_connect_ai->ai_addr; struct ip_mreq_source imr; imr.imr_multiaddr = p_addr->sin_addr; imr.imr_interface.s_addr = i_if_addr; imr.imr_sourceaddr = p_src->sin_addr; if ( i_if_index ) msg_Warn( NULL, "ignoring ifindex option in SSM" ); if ( setsockopt( i_handle, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (char *)&imr, sizeof(struct ip_mreq_source) ) < 0 ) msg_Warn( NULL, "couldn't join multicast group (%s)", strerror(errno) ); #endif } else if ( i_if_index ) { /* Linux-specific interface-bound multicast */ struct ip_mreqn imr; imr.imr_multiaddr = p_addr->sin_addr; #if defined(__linux__) imr.imr_address.s_addr = i_if_addr; imr.imr_ifindex = i_if_index; #endif if ( setsockopt( i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(struct ip_mreqn) ) < 0 ) msg_Warn( NULL, "couldn't join multicast group (%s)", strerror(errno) ); } else { /* Regular multicast */ struct ip_mreq imr; imr.imr_multiaddr = p_addr->sin_addr; imr.imr_interface.s_addr = i_if_addr; if ( setsockopt( i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, sizeof(struct ip_mreq) ) == -1 ) msg_Warn( NULL, "couldn't join multicast group (%s)", strerror(errno) ); } } } freeaddrinfo( p_bind_ai ); if ( p_connect_ai != NULL ) freeaddrinfo( p_connect_ai ); free( psz_save ); msg_Dbg( NULL, "binding socket to %s", psz_udp_src ); }
static bool config_ParseHost( output_config_t *p_config, char *psz_string ) { struct addrinfo *p_ai; int i_mtu; p_config->psz_displayname = strdup( psz_string ); p_ai = ParseNodeService( psz_string, &psz_string, DEFAULT_PORT ); if ( p_ai == NULL ) return false; memcpy( &p_config->connect_addr, p_ai->ai_addr, p_ai->ai_addrlen ); freeaddrinfo( p_ai ); p_config->i_family = p_config->connect_addr.ss_family; if ( p_config->i_family == AF_UNSPEC ) return false; if ( psz_string == NULL || !*psz_string ) goto end; if ( *psz_string == '@' ) { psz_string++; p_ai = ParseNodeService( psz_string, &psz_string, 0 ); if ( p_ai == NULL || p_ai->ai_family != p_config->i_family ) msg_Warn( NULL, "invalid bind address" ); else memcpy( &p_config->bind_addr, p_ai->ai_addr, p_ai->ai_addrlen ); freeaddrinfo( p_ai ); } while ( (psz_string = strchr( psz_string, '/' )) != NULL ) { *psz_string++ = '\0'; #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) )) #define ARG_OPTION( option ) (psz_string + strlen(option)) if ( IS_OPTION("udp") ) p_config->i_config |= OUTPUT_UDP; else if ( IS_OPTION("dvb") ) p_config->i_config |= OUTPUT_DVB; else if ( IS_OPTION("epg") ) p_config->i_config |= OUTPUT_EPG; else if ( IS_OPTION("tsid=") ) p_config->i_tsid = strtol( ARG_OPTION("tsid="), NULL, 0 ); else if ( IS_OPTION("retention=") ) p_config->i_max_retention = strtoll( ARG_OPTION("retention="), NULL, 0 ) * 1000; else if ( IS_OPTION("latency=") ) p_config->i_output_latency = strtoll( ARG_OPTION("latency="), NULL, 0 ) * 1000; else if ( IS_OPTION("ttl=") ) p_config->i_ttl = strtol( ARG_OPTION("ttl="), NULL, 0 ); else if ( IS_OPTION("tos=") ) p_config->i_tos = strtol( ARG_OPTION("tos="), NULL, 0 ); else if ( IS_OPTION("mtu=") ) p_config->i_mtu = strtol( ARG_OPTION("mtu="), NULL, 0 ); else if ( IS_OPTION("ifindex=") ) p_config->i_if_index_v6 = strtol( ARG_OPTION("ifindex="), NULL, 0 ); else if ( IS_OPTION("networkid=") ) p_config->i_network_id = strtol( ARG_OPTION("networkid="), NULL, 0 ); else if ( IS_OPTION("networkname=") ) { config_strdvb( &p_config->network_name, ARG_OPTION("networkname=") ); } else if ( IS_OPTION("srvname=") ) { config_strdvb( &p_config->service_name, ARG_OPTION("srvname=") ); } else if ( IS_OPTION("srvprovider=") ) { config_strdvb( &p_config->provider_name, ARG_OPTION("srvprovider=") ); } else if ( IS_OPTION("srcaddr=") ) { if ( p_config->i_family != AF_INET ) { msg_Err( NULL, "RAW sockets currently implemented for ipv4 only"); return false; } free( p_config->psz_srcaddr ); p_config->psz_srcaddr = config_stropt( ARG_OPTION("srcaddr=") ); p_config->i_config |= OUTPUT_RAW; } else if ( IS_OPTION("srcport=") ) p_config->i_srcport = strtol( ARG_OPTION("srcport="), NULL, 0 ); else if ( IS_OPTION("ssrc=") ) { in_addr_t i_addr = inet_addr( ARG_OPTION("ssrc=") ); memcpy( p_config->pi_ssrc, &i_addr, 4 * sizeof(uint8_t) ); } else if ( IS_OPTION("pidmap=") ) { char *str1; char *saveptr = NULL; char *tok = NULL; int i, i_newpid; for (i = 0, str1 = config_stropt( (ARG_OPTION("pidmap="))); i < N_MAP_PIDS; i++, str1 = NULL) { tok = strtok_r(str1, ",", &saveptr); if ( !tok ) break; i_newpid = strtoul(tok, NULL, 0); p_config->pi_confpids[i] = i_newpid; } p_config->b_do_remap = true; } else if ( IS_OPTION("newsid=") ) p_config->i_new_sid = strtol( ARG_OPTION("newsid="), NULL, 0 ); else msg_Warn( NULL, "unrecognized option %s", psz_string ); #undef IS_OPTION #undef ARG_OPTION } end: i_mtu = p_config->i_family == AF_INET6 ? DEFAULT_IPV6_MTU : DEFAULT_IPV4_MTU; if ( !p_config->i_mtu ) p_config->i_mtu = i_mtu; else if ( p_config->i_mtu < TS_SIZE + RTP_HEADER_SIZE ) { msg_Warn( NULL, "invalid MTU %d, setting %d", p_config->i_mtu, i_mtu ); p_config->i_mtu = i_mtu; } return true; }
bool config_ParseHost( output_config_t *p_config, char *psz_string ) { struct addrinfo *p_ai; int i_mtu; p_config->psz_displayname = strdup( psz_string ); p_ai = ParseNodeService( psz_string, &psz_string, DEFAULT_PORT ); if ( p_ai == NULL ) return false; memcpy( &p_config->connect_addr, p_ai->ai_addr, p_ai->ai_addrlen ); freeaddrinfo( p_ai ); p_config->i_family = p_config->connect_addr.ss_family; if ( p_config->i_family == AF_UNSPEC ) return false; if ( psz_string == NULL || !*psz_string ) goto end; if ( *psz_string == '@' ) { psz_string++; p_ai = ParseNodeService( psz_string, &psz_string, 0 ); if ( p_ai == NULL || p_ai->ai_family != p_config->i_family ) msg_Warn( NULL, "invalid bind address" ); else memcpy( &p_config->bind_addr, p_ai->ai_addr, p_ai->ai_addrlen ); freeaddrinfo( p_ai ); } while ( (psz_string = strchr( psz_string, '/' )) != NULL ) { *psz_string++ = '\0'; #define IS_OPTION( option ) (!strncasecmp( psz_string, option, strlen(option) )) #define ARG_OPTION( option ) (psz_string + strlen(option)) if ( IS_OPTION("udp") ) p_config->i_config |= OUTPUT_UDP; else if ( IS_OPTION("dvb") ) p_config->i_config |= OUTPUT_DVB; else if ( IS_OPTION("epg") ) p_config->i_config |= OUTPUT_EPG; else if ( IS_OPTION("tsid=") ) p_config->i_tsid = strtol( ARG_OPTION("tsid="), NULL, 0 ); else if ( IS_OPTION("retention=") ) p_config->i_max_retention = strtoll( ARG_OPTION("retention="), NULL, 0 ) * 1000; else if ( IS_OPTION("latency=") ) p_config->i_output_latency = strtoll( ARG_OPTION("latency="), NULL, 0 ) * 1000; else if ( IS_OPTION("ttl=") ) p_config->i_ttl = strtol( ARG_OPTION("ttl="), NULL, 0 ); else if ( IS_OPTION("tos=") ) p_config->i_tos = strtol( ARG_OPTION("tos="), NULL, 0 ); else if ( IS_OPTION("mtu=") ) p_config->i_mtu = strtol( ARG_OPTION("mtu="), NULL, 0 ); else if ( IS_OPTION("ifindex=") ) p_config->i_if_index_v6 = strtol( ARG_OPTION("ifindex="), NULL, 0 ); else if ( IS_OPTION("srvname=") ) { if ( p_config->psz_service_name ) free( p_config->psz_service_name ); p_config->psz_service_name = config_stropt( ARG_OPTION("srvname=") ); } else if ( IS_OPTION("srvprovider=") ) { if ( !p_config->psz_service_provider ) free( p_config->psz_service_provider ); p_config->psz_service_provider = config_stropt( ARG_OPTION("srvprovider=") ); } else if ( IS_OPTION("ssrc=") ) { in_addr_t i_addr = inet_addr( ARG_OPTION("ssrc=") ); memcpy( p_config->pi_ssrc, &i_addr, 4 * sizeof(uint8_t) ); } else msg_Warn( NULL, "unrecognized option %s", psz_string ); #undef IS_OPTION #undef ARG_OPTION } if ( !p_config->psz_service_provider && psz_provider_name ) p_config->psz_service_provider = strdup( psz_provider_name ); end: i_mtu = p_config->i_family == AF_INET6 ? DEFAULT_IPV6_MTU : DEFAULT_IPV4_MTU; if ( !p_config->i_mtu ) p_config->i_mtu = i_mtu; else if ( p_config->i_mtu < TS_SIZE + RTP_HEADER_SIZE ) { msg_Warn( NULL, "invalid MTU %d, setting %d", p_config->i_mtu, i_mtu ); p_config->i_mtu = i_mtu; } return true; }