diff --git a/src/descrambler/cwc.c b/src/descrambler/cwc.c index 63e3bb5d..6213684c 100755 --- a/src/descrambler/cwc.c +++ b/src/descrambler/cwc.c @@ -1169,7 +1169,7 @@ cwc_thread(void *aux) pthread_mutex_unlock(&cwc_mutex); - fd = tcp_connect(hostname, port, errbuf, sizeof(errbuf), 10); + fd = tcp_connect(hostname, port, NULL, errbuf, sizeof(errbuf), 10); pthread_mutex_lock(&cwc_mutex); diff --git a/src/http.h b/src/http.h index 5ba944bf..a8c99b21 100644 --- a/src/http.h +++ b/src/http.h @@ -222,6 +222,7 @@ struct http_client { char *hc_scheme; char *hc_host; int hc_port; + char *hc_bindaddr; tvhpoll_t *hc_efd; int hc_pevents; @@ -289,8 +290,8 @@ void http_client_init ( void ); void http_client_done ( void ); http_client_t* -http_client_connect ( void *aux, http_ver_t ver, - const char *scheme, const char *host, int port ); +http_client_connect ( void *aux, http_ver_t ver, const char *scheme, + const char *host, int port, const char *bindaddr ); void http_client_register ( http_client_t *hc ); void http_client_close ( http_client_t *hc ); diff --git a/src/httpc.c b/src/httpc.c index a2bbdcdd..8f9111ce 100644 --- a/src/httpc.c +++ b/src/httpc.c @@ -1164,7 +1164,7 @@ http_client_reconnect hc->hc_port = port; if (port < 0) return -EINVAL; - hc->hc_fd = tcp_connect(host, port, errbuf, sizeof(errbuf), -1); + hc->hc_fd = tcp_connect(host, port, hc->hc_bindaddr, errbuf, sizeof(errbuf), -1); if (hc->hc_fd < 0) { tvhlog(LOG_ERR, "httpc", "Unable to connect to %s:%i - %s", host, port, errbuf); return -EINVAL; @@ -1217,7 +1217,8 @@ err1: http_client_t * http_client_connect - ( void *aux, http_ver_t ver, const char *scheme, const char *host, int port ) + ( void *aux, http_ver_t ver, const char *scheme, + const char *host, int port, const char *bindaddr ) { http_client_t *hc; @@ -1226,6 +1227,7 @@ http_client_connect hc->hc_io_size = 1024; hc->hc_rtsp_stream_id = -1; hc->hc_verify_peer = -1; + hc->hc_bindaddr = bindaddr ? strdup(bindaddr) : NULL; TAILQ_INIT(&hc->hc_args); TAILQ_INIT(&hc->hc_wqueue); @@ -1280,6 +1282,7 @@ http_client_close ( http_client_t *hc ) free(hc->hc_data); free(hc->hc_host); free(hc->hc_scheme); + free(hc->hc_bindaddr); free(hc); } diff --git a/src/imagecache.c b/src/imagecache.c index cf17f01d..f9f40ef1 100644 --- a/src/imagecache.c +++ b/src/imagecache.c @@ -166,7 +166,7 @@ imagecache_image_fetch ( imagecache_image_t *img ) pthread_mutex_unlock(&global_lock); hc = http_client_connect(NULL, HTTP_VERSION_1_1, url.scheme, - url.host, url.port); + url.host, url.port, NULL); if (hc == NULL) goto error; diff --git a/src/input/mpegts/iptv/iptv_http.c b/src/input/mpegts/iptv/iptv_http.c index 660ece7d..e61b9ad5 100644 --- a/src/input/mpegts/iptv/iptv_http.c +++ b/src/input/mpegts/iptv/iptv_http.c @@ -68,7 +68,7 @@ iptv_http_start int r; if (!(hc = http_client_connect(im, HTTP_VERSION_1_1, u->scheme, - u->host, u->port))) + u->host, u->port, NULL))) return SM_CODE_TUNING_FAILED; hc->hc_hdr_received = iptv_http_header; hc->hc_data_received = iptv_http_data; diff --git a/src/input/mpegts/satip/satip.c b/src/input/mpegts/satip/satip.c index 9193b236..37234d8f 100644 --- a/src/input/mpegts/satip/satip.c +++ b/src/input/mpegts/satip/satip.c @@ -112,6 +112,13 @@ const idclass_t satip_device_class = .opts = PO_ADVANCED, .off = offsetof(satip_device_t, sd_pids0), }, + { + .type = PT_STR, + .id = "bindaddr", + .name = "Local bind IP address", + .opts = PO_ADVANCED, + .off = offsetof(satip_device_t, sd_bindaddr), + }, { .type = PT_STR, .id = "addr", @@ -227,7 +234,7 @@ const idclass_t satip_device_class = { .type = PT_STR, .id = "myaddr", - .name = "Local IP Address", + .name = "Local Discovery IP Address", .opts = PO_RDONLY | PO_NOSAVE, .off = offsetof(satip_device_t, sd_info.myaddr), }, @@ -455,6 +462,7 @@ satip_device_destroy( satip_device_t *sd ) FREEM(presentation); FREEM(tunercfg); #undef FREEM + free(sd->sd_bindaddr); tvh_hardware_delete((tvh_hardware_t*)sd); free(sd); @@ -573,10 +581,7 @@ satip_discovery_http_closed(http_client_t *hc, int errn) socklen_t addrlen = sizeof(ip); errbuf[0] = '\0'; getsockname(hc->hc_fd, (struct sockaddr *)&ip, &addrlen); - if (ip.ss_family == AF_INET6) - inet_ntop(AF_INET6, &IP_AS_V6(ip, addr), errbuf, sizeof(errbuf)); - else - inet_ntop(AF_INET, &IP_AS_V4(ip, addr), errbuf, sizeof(errbuf)); + inet_ntop(ip.ss_family, IP_IN_ADDR(ip), errbuf, sizeof(errbuf)); free(d->myaddr); d->myaddr = strdup(errbuf); } @@ -703,7 +708,7 @@ satip_discovery_timerq_cb(void *aux) } d->http_client = http_client_connect(d, HTTP_VERSION_1_1, d->url.scheme, - d->url.host, d->url.port); + d->url.host, d->url.port, NULL); if (d->http_client == NULL) satip_discovery_destroy(d, 1); else { @@ -803,7 +808,7 @@ satip_discovery_service_received /* Forward information to next layer */ d = calloc(1, sizeof(satip_discovery_t)); - if (inet_ntop(storage->ss_family, IP_IN_ADDR(conn->ip), + if (inet_ntop(conn->ip.ss_family, IP_IN_ADDR(conn->ip), sockbuf, sizeof(sockbuf)) == NULL) { satip_discovery_destroy(d, 0); return; diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c index d85423b2..5b8990ac 100644 --- a/src/input/mpegts/satip/satip_frontend.c +++ b/src/input/mpegts/satip/satip_frontend.c @@ -42,6 +42,15 @@ satip_frontend_find_by_number( satip_device_t *sd, int num ) return NULL; } +static char * +satip_frontend_bindaddr( satip_frontend_t *lfe ) +{ + char *bindaddr = lfe->sf_device->sd_bindaddr; + if (bindaddr == NULL || bindaddr[0] == '\0') + bindaddr = lfe->sf_device->sd_bindaddr; + return bindaddr; +} + /* ************************************************************************** * Class definition * *************************************************************************/ @@ -962,7 +971,8 @@ satip_frontend_input_thread ( void *aux ) pthread_mutex_unlock(&lfe->sf_device->sd_tune_mutex); rtsp = http_client_connect(lfe, RTSP_VERSION_1_0, "rstp", - lfe->sf_device->sd_info.addr, 554); + lfe->sf_device->sd_info.addr, 554, + satip_frontend_bindaddr(lfe)); if (rtsp == NULL) return NULL; @@ -1245,7 +1255,7 @@ satip_frontend_tune0 if (udp_bind_double(&lfe->sf_rtp, &lfe->sf_rtcp, "satip", "rtp", "rtpc", - lfe->sf_device->sd_info.myaddr, lfe->sf_udp_rtp_port, + satip_frontend_bindaddr(lfe), lfe->sf_udp_rtp_port, NULL, SATIP_BUF_SIZE, 16384) < 0) return SM_CODE_TUNING_FAILED; diff --git a/src/input/mpegts/satip/satip_private.h b/src/input/mpegts/satip/satip_private.h index 9972e7b8..1fe5b780 100644 --- a/src/input/mpegts/satip/satip_private.h +++ b/src/input/mpegts/satip/satip_private.h @@ -73,6 +73,7 @@ struct satip_device /* * RTSP */ + char *sd_bindaddr; int sd_fullmux_ok; int sd_pids_max; int sd_pids_len; diff --git a/src/tcp.c b/src/tcp.c index 0608abf2..c530d686 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -48,8 +48,8 @@ th_pipe_t tcp_server_pipe; * */ int -tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, - int timeout) +tcp_connect(const char *hostname, int port, const char *bindaddr, + char *errbuf, size_t errbufsize, int timeout) { int fd, r, res, err; struct addrinfo *ai; @@ -78,7 +78,19 @@ tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, */ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6)) { + if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) { + if (bindaddr && bindaddr[0] != '\0') { + struct sockaddr_storage ip; + memset(&ip, 0, sizeof(ip)); + ip.ss_family = ai->ai_family; + if (inet_pton(AF_INET, bindaddr, IP_IN_ADDR(ip)) <= 0 || + bind(fd, (struct sockaddr *)&ip, IP_IN_ADDRLEN(ip)) < 0) { + snprintf(errbuf, errbufsize, "Cannot bind to IPv%s addr '%s'", bindaddr, + ai->ai_family == AF_INET6 ? "6" : "4"); + return -1; + } + } + } else { snprintf(errbuf, errbufsize, "Invalid protocol family"); freeaddrinfo(ai); return -1; diff --git a/src/tcp.h b/src/tcp.h index 7006e4d2..7c4b8ead 100644 --- a/src/tcp.h +++ b/src/tcp.h @@ -22,6 +22,21 @@ #include "htsbuf.h" #include "htsmsg.h" +#define IP_AS_V4(storage, f) ((struct sockaddr_in *)&(storage))->sin_##f +#define IP_AS_V6(storage, f) ((struct sockaddr_in6 *)&(storage))->sin6_##f +#define IP_IN_ADDR(storage) \ + ((storage).ss_family == AF_INET6 ? \ + &((struct sockaddr_in6 *)&(storage))->sin6_addr : \ + (void *)&((struct sockaddr_in *)&(storage))->sin_addr) +#define IP_IN_ADDRLEN(storage) \ + ((storage).ss_family == AF_INET6 ? \ + sizeof(struct sockaddr_in6) : \ + sizeof(struct sockaddr_in)) +#define IP_PORT(storage) \ + ((storage).ss_family == AF_INET6 ? \ + ((struct sockaddr_in6 *)&(storage))->sin6_port : \ + ((struct sockaddr_in *)&(storage))->sin_port) + typedef struct tcp_server_ops { void (*start) (int fd, void **opaque, @@ -37,8 +52,8 @@ extern int tcp_preferred_address_family; void tcp_server_init(int opt_ipv6); void tcp_server_done(void); -int tcp_connect(const char *hostname, int port, char *errbuf, - size_t errbufsize, int timeout); +int tcp_connect(const char *hostname, int port, const char *bindaddr, + char *errbuf, size_t errbufsize, int timeout); typedef void (tcp_server_callback_t)(int fd, void *opaque, struct sockaddr_storage *peer, diff --git a/src/udp.h b/src/udp.h index c5fa2eef..be6f062c 100644 --- a/src/udp.h +++ b/src/udp.h @@ -25,17 +25,6 @@ #define UDP_FATAL_ERROR ((void *)-1) -#define IP_AS_V4(storage, f) ((struct sockaddr_in *)&(storage))->sin_##f -#define IP_AS_V6(storage, f) ((struct sockaddr_in6 *)&(storage))->sin6_##f -#define IP_IN_ADDR(storage) \ - ((storage).ss_family == AF_INET6 ? \ - &((struct sockaddr_in6 *)&(storage))->sin6_addr : \ - (void *)&((struct sockaddr_in *)&(storage))->sin_addr) -#define IP_PORT(storage) \ - ((storage).ss_family == AF_INET6 ? \ - ((struct sockaddr_in6 *)&(storage))->sin6_port : \ - ((struct sockaddr_in *)&(storage))->sin_port) - typedef struct udp_connection { char *host; int port;