Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable multicast reception and binding to a specific interface #32

Merged
merged 8 commits into from
Feb 9, 2017
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ AM_COND_IF([DVBPSIBUILD], [
])

# Checks for header files.
AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h netdb.h stdint.h stdlib.h string.h sys/ioctl.h sys/time.h sys/timeb.h unistd.h sys/poll.h sys/socket.h linux/dvb/frontend.h])
AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h netdb.h stdint.h stdlib.h string.h sys/ioctl.h sys/time.h sys/timeb.h unistd.h ifaddrs.h sys/poll.h sys/socket.h linux/dvb/frontend.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_C_INLINE
Expand Down
12 changes: 10 additions & 2 deletions dvbtee/dvbtee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ int main(int argc, char **argv)
bool b_json = false;
bool b_bitrate_stats = false;
bool b_hdhr = false;
bool b_network_interface = false;

context.server = NULL;

Expand Down Expand Up @@ -387,6 +388,9 @@ int main(int argc, char **argv)
char tcpipfeedurl[2048];
memset(&tcpipfeedurl, 0, sizeof(tcpipfeedurl));

char network_interface[2048];
memset(&network_interface, 0, sizeof(network_interface));

char service_ids[64];
memset(&service_ids, 0, sizeof(service_ids));

Expand All @@ -396,7 +400,7 @@ int main(int argc, char **argv)
char hdhrname[256];
memset(&hdhrname, 0, sizeof(hdhrname));

while ((opt = getopt(argc, argv, "a:A:bc:C:f:F:t:T:i:I:js::S::E::o::O:d::H::h?")) != -1) {
while ((opt = getopt(argc, argv, "a:A:bc:C:f:F:t:n:T:i:I:js::S::E::o::O:d::H::h?")) != -1) {
switch (opt) {
case 'a': /* adapter */
#ifdef USE_LINUXTV
Expand Down Expand Up @@ -452,6 +456,10 @@ int main(int argc, char **argv)
if (scan_method)
fprintf(stderr, "MULTISCAN: %d...\n", scan_method);
break;
case 'n': /* bind to specific interface */
strncpy(network_interface, optarg, sizeof(network_interface));
b_network_interface = true;
break;
case 'S': /* server mode, optional arg 1 for command server, 2 for http stream server, 3 for both */
b_serve = true;
serv_flags = (optarg) ? strtoul(optarg, NULL, 0) : 0;
Expand Down Expand Up @@ -642,7 +650,7 @@ int main(int argc, char **argv)
write_feed iface(context);
hlsfeed(tcpipfeedurl, &iface);
} else {
int ret = context._file_feeder.start_socket(tcpipfeedurl);
int ret = context._file_feeder.start_socket(tcpipfeedurl, (b_network_interface) ? network_interface : NULL);
if (b_serve) goto exit;
if (0 <= ret) {
context._file_feeder.wait_for_streaming_or_timeout(timeout);
Expand Down
106 changes: 101 additions & 5 deletions libdvbtee/feed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_IFADDRS_H
#include <ifaddrs.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include <unistd.h>

#include <fstream>

Expand Down Expand Up @@ -646,7 +659,7 @@ int feed::start_stdin()
return ret;
}

int feed::start_socket(char* source)
int feed::start_socket(char* source, char* net_if)
{
dPrintf("()");
#if 0
Expand Down Expand Up @@ -707,7 +720,9 @@ int feed::start_socket(char* source)
} else
ringbuffer.reset();
#endif
ret = (b_tcp) ? start_tcp_listener(port) : start_udp_listener(port);
ret = (b_tcp) ? start_tcp_listener(port) :
((ip) && (net_if)) ? start_udp_listener(port, ip, net_if) :
start_udp_unbound_listener(port, ip);
#if 0
} else {
perror("socket failed");
Expand Down Expand Up @@ -770,7 +785,7 @@ int feed::start_tcp_listener(uint16_t port_requested)
return listener.start(port_requested);
}

int feed::start_udp_listener(uint16_t port_requested)
int feed::start_udp_unbound_listener(uint16_t port_requested, char *ip)
{
struct sockaddr_in udp_sock;

Expand Down Expand Up @@ -801,7 +816,7 @@ int feed::start_udp_listener(uint16_t port_requested)

udp_sock.sin_family = AF_INET;
udp_sock.sin_port = htons(port_requested);
udp_sock.sin_addr.s_addr = INADDR_ANY;
udp_sock.sin_addr.s_addr = (ip) ? inet_addr(ip) : INADDR_ANY;

if (bind(fd, (struct sockaddr*)&udp_sock, sizeof(udp_sock)) < 0) {
perror("bind to local interface failed");
Expand All @@ -822,6 +837,87 @@ int feed::start_udp_listener(uint16_t port_requested)
return ret;
}

int feed::start_udp_listener(uint16_t port_requested, char *ip, char *net_if)
{
dPrintf("(%d)", port_requested);
snprintf(filename, sizeof(filename), "UDPLISTEN: %s:%d %s", ip, port_requested, net_if);

f_kill_thread = false;

fd = -1;

fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd < 0) {
perror("open socket failed");
return fd;
}

struct sockaddr_in sock;
memset(&sock, 0, sizeof(sock));

struct ip_mreq imreq;

imreq.imr_multiaddr.s_addr = inet_addr(ip);

#ifdef HAVE_IFADDRS_H
char host[NI_MAXHOST] = { 0 };
struct ifaddrs *ifaddr, *ifa;
int s;

if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs failed");
return -1;
}

for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
if((strcmp(ifa->ifa_name, net_if) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
if (s != 0) {
perror("unable to get network interface");
return -1;
}
break;
}
}

freeifaddrs(ifaddr);

imreq.imr_interface.s_addr = inet_addr(host);
#endif

sock.sin_family = AF_INET;
sock.sin_port = htons(port_requested);
sock.sin_addr.s_addr = inet_addr(ip);

#if defined(_WIN32)
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&imreq, sizeof(imreq)) < 0) {
#else
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(imreq)) < 0) {
#endif
perror("setting IPPROTO_IP / IP_ADD_MEMBERSHIP failed");
return -1;
}

if (bind(fd, (struct sockaddr*)&sock, sizeof(sock)) < 0) {
perror("bind to specified interface failed");
return -1;
}
#if 0
socket_set_nbio(fd);
#endif
int ret = pthread_create(&h_thread, NULL, udp_listen_feed_thread, this);

if (0 != ret)
perror("pthread_create() failed");
#if FEED_BUFFER
else
start_feed();
#endif
return ret;
}

bool feed::wait_for_event_or_timeout(unsigned int timeout, unsigned int wait_event) {
time_t start_time = time(NULL);
while ((!f_kill_thread) &&
Expand Down Expand Up @@ -911,7 +1007,7 @@ int feed_server::start_udp_listener(uint16_t port_requested, feed_server_iface *
if (feeders.count(0)) delete feeders[0];
feeders[0] = new feed;

int ret = feeders[0]->start_udp_listener(port_requested);
int ret = feeders[0]->start_udp_unbound_listener(port_requested);
if (ret < 0)
goto fail;

Expand Down
5 changes: 3 additions & 2 deletions libdvbtee/feed.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ class feed : public socket_listen_iface
void stop();
int start();
int start_stdin();
int start_socket(char* source);
int start_socket(char* source, char* net_if = NULL);
int start_tcp_listener(uint16_t);
int start_udp_listener(uint16_t);
int start_udp_unbound_listener(uint16_t, char *ip = NULL);
int start_udp_listener(uint16_t, char* ip, char* net_if);

/* initialize for feed via functional interface */
int setup_feed(int prio);
Expand Down
2 changes: 2 additions & 0 deletions libdvbtee/libdvbtee.pro
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ QMAKE_CXXFLAGS += -DHAVE_LIBCURL
QMAKE_CXXFLAGS += -DHAVE_ARPA_INET_H
QMAKE_CXXFLAGS += -DHAVE_NETDB_H
QMAKE_CXXFLAGS += -DHAVE_STRTOK_R
QMAKE_CXXFLAGS += -DHAVE_SYS_SOCKET_H
QMAKE_CXXFLAGS += -DHAVE_IFADDRS_H

disablehdhr {
} else {
Expand Down