Permits binding to an IPv6 address, like so: $ rtl_tcp -a ::
Doesn't break binding to an IPv4 address, and doesn't change the default behaviour of binding only to 0.0.0.0. If accepting connections over both IPv4 and IPv6 is desired, then the sysctl 'net.ipv6.bindv6only' will need to be set to '0', and '::' set as the bind address. Further improvements could involve binding to both 0.0.0.0 and [::], with the latter using IPV6_V6ONLY passed to setsockopt(). This would allow dual-stack behaviour on systems that set 'net.ipv6.bindv6only' to '1' by default (such as Debian). Signed-off-by: Jeremy Visser <[email protected]> --- src/rtl_tcp.c | 59 ++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/src/rtl_tcp.c b/src/rtl_tcp.c index 317e0f3..f20cbc2 100644 --- a/src/rtl_tcp.c +++ b/src/rtl_tcp.c @@ -31,6 +31,7 @@ #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> +#include <netdb.h> #include <fcntl.h> #else #include <winsock2.h> @@ -366,9 +367,11 @@ int main(int argc, char **argv) { int r, opt, i; char* addr = "127.0.0.1"; - int port = 1234; + char* port = "1234"; uint32_t frequency = 100000000, samp_rate = 2048000; - struct sockaddr_in local, remote; + struct addrinfo hints; + struct addrinfo *servinfo, *p; + struct sockaddr_storage remote_addr; uint32_t buf_num = 0; int dev_index = 0; int dev_given = 0; @@ -410,7 +413,7 @@ int main(int argc, char **argv) addr = optarg; break; case 'p': - port = atoi(optarg); + port = optarg; break; case 'b': buf_num = atoi(optarg); @@ -502,16 +505,42 @@ int main(int argc, char **argv) pthread_cond_init(&cond, NULL); pthread_cond_init(&exit_cond, NULL); - memset(&local,0,sizeof(local)); - local.sin_family = AF_INET; - local.sin_port = htons(port); - local.sin_addr.s_addr = inet_addr(addr); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; - listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - r = 1; - setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int)); - setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling)); - bind(listensocket,(struct sockaddr *)&local,sizeof(local)); + if ( 0 != (r = getaddrinfo(addr, port, &hints, &servinfo)) ) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(r)); + exit(1); + } + + listensocket = -1; + + for ( p = servinfo; p != NULL; p = p->ai_next ) { + if ( -1 == (listensocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) ) { + perror("server: socket"); + continue; + } + + r = 1; + setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (char *)&r, sizeof(int)); + setsockopt(listensocket, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling)); + + if ( -1 == bind(listensocket,p->ai_addr,p->ai_addrlen) ) { + close(listensocket); + perror("server: bind"); + continue; + } + + break; + } + + freeaddrinfo(servinfo); + + if ( listensocket == -1 ) { + perror("could not bind socket"); + exit(1); + } #ifdef _WIN32 ioctlsocket(listensocket, FIONBIO, &blockmode); @@ -522,7 +551,7 @@ int main(int argc, char **argv) while(1) { printf("listening...\n"); - printf("Use the device argument 'rtl_tcp=%s:%d' in OsmoSDR " + printf("Use the device argument 'rtl_tcp=%s:%s' in OsmoSDR " "(gr-osmosdr) source\n" "to receive samples in GRC and control " "rtl_tcp parameters (frequency, gain, ...).\n", @@ -538,8 +567,8 @@ int main(int argc, char **argv) if(do_exit) { goto out; } else if(r) { - rlen = sizeof(remote); - s = accept(listensocket,(struct sockaddr *)&remote, &rlen); + rlen = sizeof(remote_addr); + s = accept(listensocket,(struct sockaddr *)&remote_addr, &rlen); break; } } -- 1.9.3
