Skip to content

Commit

Permalink
rtsp: cleaner bind handling
Browse files Browse the repository at this point in the history
- nicer debug messages
- arbitrary number of addresses, for multihomed hosts
- get rid of AI_ADDRCONFIG
  • Loading branch information
abrasive committed May 13, 2013
1 parent 38969f2 commit d5b17e2
Showing 1 changed file with 51 additions and 28 deletions.
79 changes: 51 additions & 28 deletions rtsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/select.h>
#include <signal.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Expand All @@ -45,10 +46,10 @@
#include "rtp.h"
#include "mdns.h"

// some BSDs (OpenBSD, NetBSD) do not support AI_ADDRCONFIG
// it's not critical anyway, define it to 0 (a no-op)
#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG 0
#ifdef AF_INET6
#define INETx_ADDRSTRLEN INET6_ADDRSTRLEN
#else
#define INETx_ADDRSTRLEN INET_ADDRSTRLEN
#endif

// only one thread is allowed to use the player at once.
Expand Down Expand Up @@ -695,49 +696,71 @@ static void *rtsp_conversation_thread_func(void *vfd) {
return NULL;
}

// this function is not thread safe.
static const char* format_address(struct sockaddr *fsa) {
static char string[INETx_ADDRSTRLEN];
void *addr;
#ifdef AF_INET6
if (fsa->sa_family == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)(fsa);
addr = &(sa6->sin6_addr);
} else
#endif
{
struct sockaddr_in *sa = (struct sockaddr_in*)(fsa);
addr = &(sa->sin_addr);
}
return inet_ntop(fsa->sa_family, addr, string, sizeof(string));
}

void rtsp_listen_loop(void) {
struct addrinfo hints, *info, *p;
char portstr[6];
int sockfd[2];
int *sockfd = NULL;
int nsock = 0;
int ret;
memset(sockfd, 0, sizeof(sockfd));
int i, ret;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
hints.ai_flags = AI_PASSIVE;

snprintf(portstr, 6, "%d", config.port);

ret = getaddrinfo(NULL, portstr, &hints, &info);
if (ret) {
die("getaddrinfo failed: %s\n", gai_strerror(ret));
}

for (p=info; p; p=p->ai_next) {
int fd = socket(p->ai_family, p->ai_socktype, IPPROTO_TCP);
int yes = 1;

ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));

#ifdef AF_INET6
#ifdef IPV6_V6ONLY
// some systems don't support v4 access on v6 sockets, but some do.
// since we need to account for two sockets we might as well always.
// since we need to account for two sockets we might as well
// always.
if (p->ai_family == AF_INET6)
ret |= setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes));
#endif

if (!ret)
ret = bind(fd, p->ai_addr, p->ai_addrlen);

// one of the address families will fail on some systems that
// report its availability. do not complain.
if (ret) {
perror("could not bind a listen socket");
debug(1, "Failed to bind to address %s\n", format_address(p->ai_addr));
continue;
}
debug(1, "Bound to address %s\n", format_address(p->ai_addr));

listen(fd, 5);
sockfd[nsock++] = fd;
nsock++;
sockfd = realloc(sockfd, nsock*sizeof(int));
sockfd[nsock-1] = fd;
}

freeaddrinfo(info);
Expand All @@ -746,15 +769,14 @@ void rtsp_listen_loop(void) {
die("could not bind any listen sockets!\n");


int maxfd = sockfd[0];
if (sockfd[1]>maxfd)
maxfd = sockfd[1];

int maxfd = -1;
fd_set fds;
FD_ZERO(&fds);
FD_SET(sockfd[0], &fds);
if (sockfd[1])
FD_SET(sockfd[1], &fds);
for (i=0; i<nsock; i++) {
FD_SET(sockfd[i], &fds);
if (sockfd[i] > maxfd)
maxfd = sockfd[i];
}

mdns_register();

Expand All @@ -770,20 +792,21 @@ void rtsp_listen_loop(void) {

int acceptfd;
while (select(maxfd+1, &fds, 0, 0, 0) >= 0) {
if (FD_ISSET(sockfd[0], &fds))
acceptfd = sockfd[0];
if (FD_ISSET(sockfd[1], &fds) && sockfd[1])
acceptfd = sockfd[1];
for (i=0; i<nsock; i++) {
if (FD_ISSET(sockfd[i], &fds)) {
acceptfd = sockfd[i];
break;
}
}

// for now, we do not track these and let them die of natural causes.
// XXX: this leaks threads; they need to be culled with pthread_tryjoin_np.
// XXX: acceptfd could change before the thread is up. which should never happen, but still.
pthread_t rtsp_conversation_thread;
pthread_create(&rtsp_conversation_thread, NULL, rtsp_conversation_thread_func, &acceptfd);

FD_SET(sockfd[0], &fds);
if (sockfd[1])
FD_SET(sockfd[1], &fds);
for (i=0; i<nsock; i++)
FD_SET(sockfd[i], &fds);
}
perror("select");
die("fell out of the RTSP select loop\n");
Expand Down

0 comments on commit d5b17e2

Please sign in to comment.