|  | @@ -48,11 +48,12 @@
 | 
		
	
		
			
			| 48 | 48 |  
 | 
		
	
		
			
			| 49 | 49 |  static char *self = NULL;
 | 
		
	
		
			
			| 50 | 50 |  
 | 
		
	
		
			
			| 51 |  | -static int bind_service (const char *service, int family)
 | 
		
	
		
			
			|  | 51 | +static size_t bind_service (const char *service, int family, int* socks, size_t max_socks)
 | 
		
	
		
			
			| 52 | 52 |  {
 | 
		
	
		
			
			| 53 | 53 |    struct addrinfo *addr, *it;
 | 
		
	
		
			
			| 54 | 54 |    struct addrinfo hints;
 | 
		
	
		
			
			| 55 | 55 |    int err, sock, flags;
 | 
		
	
		
			
			|  | 56 | +  size_t count = 0;
 | 
		
	
		
			
			| 56 | 57 |    static const int one = 1;
 | 
		
	
		
			
			| 57 | 58 |  
 | 
		
	
		
			
			| 58 | 59 |    memset (&hints, 0, sizeof(hints));
 | 
		
	
	
		
			
			|  | @@ -62,10 +63,11 @@ static int bind_service (const char *service, int family)
 | 
		
	
		
			
			| 62 | 63 |    err = getaddrinfo(NULL, service, &hints, &addr);
 | 
		
	
		
			
			| 63 | 64 |    if (err != 0) {
 | 
		
	
		
			
			| 64 | 65 |      fprintf(stderr, "%s: bind_service(%s): %s\n", self, service, gai_strerror(err));
 | 
		
	
		
			
			| 65 |  | -    return -1;
 | 
		
	
		
			
			|  | 66 | +    return count;
 | 
		
	
		
			
			| 66 | 67 |    }
 | 
		
	
		
			
			| 67 | 68 |    sock = -1;
 | 
		
	
		
			
			| 68 | 69 |    for (it = addr; it; it = it->ai_next) {
 | 
		
	
		
			
			|  | 70 | +    if (max_socks == 0) break;
 | 
		
	
		
			
			| 69 | 71 |      sock = socket(it->ai_family, it->ai_socktype, it->ai_protocol);
 | 
		
	
		
			
			| 70 | 72 |      if (sock < 0) goto fail;
 | 
		
	
		
			
			| 71 | 73 |      if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) goto fail;
 | 
		
	
	
		
			
			|  | @@ -74,16 +76,18 @@ static int bind_service (const char *service, int family)
 | 
		
	
		
			
			| 74 | 76 |      flags = fcntl (sock, F_GETFL, 0);
 | 
		
	
		
			
			| 75 | 77 |      if (flags < 0) goto fail;
 | 
		
	
		
			
			| 76 | 78 |      if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) goto fail;
 | 
		
	
		
			
			| 77 |  | -    break;
 | 
		
	
		
			
			|  | 79 | +    *socks++ = sock;
 | 
		
	
		
			
			|  | 80 | +    ++count;
 | 
		
	
		
			
			|  | 81 | +    --max_socks;
 | 
		
	
		
			
			|  | 82 | +    continue;
 | 
		
	
		
			
			| 78 | 83 |    fail:
 | 
		
	
		
			
			| 79 | 84 |      err = errno;
 | 
		
	
		
			
			| 80 | 85 |      if (sock >= 0) close (sock);
 | 
		
	
		
			
			| 81 |  | -    sock = -1;
 | 
		
	
		
			
			| 82 | 86 |    }
 | 
		
	
		
			
			| 83 | 87 |    freeaddrinfo (addr);
 | 
		
	
		
			
			| 84 |  | -  if (sock < 0)
 | 
		
	
		
			
			|  | 88 | +  if (count == 0)
 | 
		
	
		
			
			| 85 | 89 |      fprintf (stderr, "%s: bind_service(%s): %s\n", self, service, strerror(err));
 | 
		
	
		
			
			| 86 |  | -  return sock;
 | 
		
	
		
			
			|  | 90 | +  return count;
 | 
		
	
		
			
			| 87 | 91 |  }
 | 
		
	
		
			
			| 88 | 92 |  
 | 
		
	
		
			
			| 89 | 93 |  static int is_hexdigit (char c)
 | 
		
	
	
		
			
			|  | @@ -237,12 +241,11 @@ typedef void(*handle_t)(srs_t*, FILE*, const char*, const char*, const char**);
 | 
		
	
		
			
			| 237 | 241 |  
 | 
		
	
		
			
			| 238 | 242 |  int main (int argc, char **argv)
 | 
		
	
		
			
			| 239 | 243 |  {
 | 
		
	
		
			
			| 240 |  | -  int opt, timeout = 1800, family = AF_INET;
 | 
		
	
		
			
			|  | 244 | +  int opt, timeout = 1800, family = AF_UNSPEC;
 | 
		
	
		
			
			| 241 | 245 |    int daemonize = FALSE;
 | 
		
	
		
			
			| 242 | 246 |    char *forward_service = NULL, *reverse_service = NULL,
 | 
		
	
		
			
			| 243 | 247 |         *user = NULL, *domain = NULL, *chroot_dir = NULL;
 | 
		
	
		
			
			| 244 | 248 |    char separator = '=';
 | 
		
	
		
			
			| 245 |  | -  int forward_sock, reverse_sock;
 | 
		
	
		
			
			| 246 | 249 |    char *secret_file = NULL, *pid_file = NULL;
 | 
		
	
		
			
			| 247 | 250 |    FILE *pf = NULL, *sf = NULL;
 | 
		
	
		
			
			| 248 | 251 |    struct passwd *pwd = NULL;
 | 
		
	
	
		
			
			|  | @@ -250,10 +253,12 @@ int main (int argc, char **argv)
 | 
		
	
		
			
			| 250 | 253 |    char *tmp;
 | 
		
	
		
			
			| 251 | 254 |    time_t now;
 | 
		
	
		
			
			| 252 | 255 |    srs_t *srs;
 | 
		
	
		
			
			| 253 |  | -  struct pollfd fds[3];
 | 
		
	
		
			
			| 254 | 256 |    const char **excludes;
 | 
		
	
		
			
			| 255 | 257 |    size_t s1 = 0, s2 = 1;
 | 
		
	
		
			
			| 256 |  | -  handle_t handler[2] = { handle_forward, handle_reverse };
 | 
		
	
		
			
			|  | 258 | +  struct pollfd fds[4];
 | 
		
	
		
			
			|  | 259 | +  size_t socket_count = 0, sc;
 | 
		
	
		
			
			|  | 260 | +  int sockets[4] = { -1, -1, -1, -1 };
 | 
		
	
		
			
			|  | 261 | +  handle_t handler[4] = { 0, 0, 0, 0 };
 | 
		
	
		
			
			| 257 | 262 |  
 | 
		
	
		
			
			| 258 | 263 |    excludes = (const char**)calloc(1, sizeof(char*));
 | 
		
	
		
			
			| 259 | 264 |    tmp = strrchr(argv[0], '/');
 | 
		
	
	
		
			
			|  | @@ -374,6 +379,8 @@ int main (int argc, char **argv)
 | 
		
	
		
			
			| 374 | 379 |      fprintf (stderr, "%s: SRS separator character must be one of '=+-'\n", self);
 | 
		
	
		
			
			| 375 | 380 |      return EXIT_FAILURE;
 | 
		
	
		
			
			| 376 | 381 |    }
 | 
		
	
		
			
			|  | 382 | +  if (forward_service == NULL) forward_service = strdup("10001");
 | 
		
	
		
			
			|  | 383 | +  if (reverse_service == NULL) reverse_service = strdup("10002");
 | 
		
	
		
			
			| 377 | 384 |  
 | 
		
	
		
			
			| 378 | 385 |    /* The stuff we do first may not be possible from within chroot or without privileges */
 | 
		
	
		
			
			| 379 | 386 |  
 | 
		
	
	
		
			
			|  | @@ -397,21 +404,14 @@ int main (int argc, char **argv)
 | 
		
	
		
			
			| 397 | 404 |      return EXIT_FAILURE;
 | 
		
	
		
			
			| 398 | 405 |    }
 | 
		
	
		
			
			| 399 | 406 |    /* Bind ports. May require privileges if the config specifies ports below 1024 */
 | 
		
	
		
			
			| 400 |  | -  if (forward_service != NULL) {
 | 
		
	
		
			
			| 401 |  | -    forward_sock = bind_service(forward_service, family);
 | 
		
	
		
			
			| 402 |  | -    free (forward_service);
 | 
		
	
		
			
			| 403 |  | -  } else {
 | 
		
	
		
			
			| 404 |  | -    forward_sock = bind_service("10001", family);
 | 
		
	
		
			
			| 405 |  | -  }
 | 
		
	
		
			
			| 406 |  | -  if (forward_sock < 0) return EXIT_FAILURE;
 | 
		
	
		
			
			| 407 |  | -  if (reverse_service != NULL) {
 | 
		
	
		
			
			| 408 |  | -    reverse_sock = bind_service(reverse_service, family);
 | 
		
	
		
			
			| 409 |  | -    free (reverse_service);
 | 
		
	
		
			
			| 410 |  | -  } else {
 | 
		
	
		
			
			| 411 |  | -    reverse_sock = bind_service("10002", family);
 | 
		
	
		
			
			| 412 |  | -  }
 | 
		
	
		
			
			| 413 |  | -  if (reverse_sock < 0) return EXIT_FAILURE;
 | 
		
	
		
			
			| 414 |  | -
 | 
		
	
		
			
			|  | 407 | +  sc = bind_service(forward_service, family, &sockets[socket_count], 4 - socket_count);
 | 
		
	
		
			
			|  | 408 | +  if (sc == 0) return EXIT_FAILURE;
 | 
		
	
		
			
			|  | 409 | +  while (sc-- > 0) handler[socket_count++] = handle_forward;
 | 
		
	
		
			
			|  | 410 | +  free (forward_service);
 | 
		
	
		
			
			|  | 411 | +  sc = bind_service(reverse_service, family, &sockets[socket_count], 4 - socket_count);
 | 
		
	
		
			
			|  | 412 | +  if (sc == 0) return EXIT_FAILURE;
 | 
		
	
		
			
			|  | 413 | +  while (sc-- > 0) handler[socket_count++] = handle_reverse;
 | 
		
	
		
			
			|  | 414 | +  free (reverse_service);
 | 
		
	
		
			
			| 415 | 415 |    /* Open syslog now (NDELAY), because it may no longer be reachable from chroot */
 | 
		
	
		
			
			| 416 | 416 |    openlog (self, LOG_PID | LOG_NDELAY, LOG_MAIL);
 | 
		
	
		
			
			| 417 | 417 |    /* Force loading of timezone info (suggested by patrickdk77) */
 | 
		
	
	
		
			
			|  | @@ -470,18 +470,17 @@ int main (int argc, char **argv)
 | 
		
	
		
			
			| 470 | 470 |  
 | 
		
	
		
			
			| 471 | 471 |    srs_set_separator (srs, separator);
 | 
		
	
		
			
			| 472 | 472 |  
 | 
		
	
		
			
			| 473 |  | -  fds[0].fd = forward_sock;
 | 
		
	
		
			
			| 474 |  | -  fds[0].events = POLLIN;
 | 
		
	
		
			
			| 475 |  | -  fds[1].fd = reverse_sock;
 | 
		
	
		
			
			| 476 |  | -  fds[1].events = POLLIN;
 | 
		
	
		
			
			| 477 |  | -
 | 
		
	
		
			
			|  | 473 | +  for (sc = 0; sc < socket_count; ++sc) {
 | 
		
	
		
			
			|  | 474 | +    fds[sc].fd = sockets[sc];
 | 
		
	
		
			
			|  | 475 | +    fds[sc].events = POLLIN;
 | 
		
	
		
			
			|  | 476 | +  }
 | 
		
	
		
			
			| 478 | 477 |    while(TRUE) {
 | 
		
	
		
			
			| 479 |  | -    int i, conn;
 | 
		
	
		
			
			|  | 478 | +    int conn;
 | 
		
	
		
			
			| 480 | 479 |      FILE *fp;
 | 
		
	
		
			
			| 481 | 480 |      char linebuf[1024], *line;
 | 
		
	
		
			
			| 482 | 481 |      char keybuf[1024], *key;
 | 
		
	
		
			
			| 483 | 482 |  
 | 
		
	
		
			
			| 484 |  | -    if (poll(fds, 2, 1000) < 0) {
 | 
		
	
		
			
			|  | 483 | +    if (poll(fds, socket_count, 1000) < 0) {
 | 
		
	
		
			
			| 485 | 484 |        if (errno == EINTR)
 | 
		
	
		
			
			| 486 | 485 |          continue;
 | 
		
	
		
			
			| 487 | 486 |        if (daemonize)
 | 
		
	
	
		
			
			|  | @@ -490,20 +489,20 @@ int main (int argc, char **argv)
 | 
		
	
		
			
			| 490 | 489 |          fprintf (stderr, "%s: Poll failure: %s\n", self, strerror(errno));
 | 
		
	
		
			
			| 491 | 490 |        return EXIT_FAILURE;
 | 
		
	
		
			
			| 492 | 491 |      }
 | 
		
	
		
			
			| 493 |  | -    for (i = 0; i < 2; ++i) {
 | 
		
	
		
			
			| 494 |  | -      if (fds[i].revents) {
 | 
		
	
		
			
			| 495 |  | -        conn = accept(fds[i].fd, NULL, NULL);
 | 
		
	
		
			
			|  | 492 | +    for (sc = 0; sc < socket_count; ++sc) {
 | 
		
	
		
			
			|  | 493 | +      if (fds[sc].revents) {
 | 
		
	
		
			
			|  | 494 | +        conn = accept(fds[sc].fd, NULL, NULL);
 | 
		
	
		
			
			| 496 | 495 |          if (conn < 0) continue;
 | 
		
	
		
			
			| 497 | 496 |          if (fork() == 0) {
 | 
		
	
		
			
			|  | 497 | +          int i;
 | 
		
	
		
			
			| 498 | 498 |            // close listen sockets so that we don't stop the main daemon process from restarting
 | 
		
	
		
			
			| 499 |  | -          close(forward_sock);
 | 
		
	
		
			
			| 500 |  | -          close(reverse_sock);
 | 
		
	
		
			
			|  | 499 | +          for (i = 0; i < socket_count; ++i) close (sockets[i]);
 | 
		
	
		
			
			| 501 | 500 |  
 | 
		
	
		
			
			| 502 | 501 |            fp = fdopen(conn, "r+");
 | 
		
	
		
			
			| 503 | 502 |            if (fp == NULL) exit(EXIT_FAILURE);
 | 
		
	
		
			
			| 504 |  | -          fds[2].fd = conn;
 | 
		
	
		
			
			| 505 |  | -          fds[2].events = POLLIN;
 | 
		
	
		
			
			| 506 |  | -          if (poll(&fds[2], 1, timeout * 1000) <= 0) return EXIT_FAILURE;
 | 
		
	
		
			
			|  | 503 | +          fds[0].fd = conn;
 | 
		
	
		
			
			|  | 504 | +          fds[0].events = POLLIN;
 | 
		
	
		
			
			|  | 505 | +          if (poll(fds, 1, timeout * 1000) <= 0) return EXIT_FAILURE;
 | 
		
	
		
			
			| 507 | 506 |            line = fgets(linebuf, sizeof(linebuf), fp);
 | 
		
	
		
			
			| 508 | 507 |            while (line) {
 | 
		
	
		
			
			| 509 | 508 |              fseek (fp, 0, SEEK_CUR); /* Workaround for Solaris */
 | 
		
	
	
		
			
			|  | @@ -522,9 +521,9 @@ int main (int argc, char **argv)
 | 
		
	
		
			
			| 522 | 521 |              }
 | 
		
	
		
			
			| 523 | 522 |              key = url_decode(keybuf, sizeof(keybuf), token);
 | 
		
	
		
			
			| 524 | 523 |              if (!key) break;
 | 
		
	
		
			
			| 525 |  | -            handler[i](srs, fp, key, domain, excludes);
 | 
		
	
		
			
			|  | 524 | +            handler[sc](srs, fp, key, domain, excludes);
 | 
		
	
		
			
			| 526 | 525 |              fflush (fp);
 | 
		
	
		
			
			| 527 |  | -            if (poll(&fds[2], 1, timeout * 1000) <= 0) break;
 | 
		
	
		
			
			|  | 526 | +            if (poll(fds, 1, timeout * 1000) <= 0) break;
 | 
		
	
		
			
			| 528 | 527 |              line = fgets(linebuf, sizeof(linebuf), fp);
 | 
		
	
		
			
			| 529 | 528 |            }
 | 
		
	
		
			
			| 530 | 529 |            fclose (fp);
 |