]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
tcp: add helpers to determine default and used IP address for SAT>IP
authorJaroslav Kysela <perex@perex.cz>
Thu, 12 Feb 2015 17:50:40 +0000 (18:50 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 11 Mar 2015 20:41:12 +0000 (21:41 +0100)
src/tcp.c
src/tcp.h

index 3e6e771468ec74e54832a1b9ad1182357a2b315e..e4558bad184d123aba6d2cdee8585e7432562843 100644 (file)
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -381,6 +381,7 @@ static uint32_t tcp_server_launch_id;
 
 typedef struct tcp_server {
   int serverfd;
+  struct sockaddr_storage bound;
   tcp_server_ops_t ops;
   void *opaque;
 } tcp_server_t;
@@ -641,6 +642,7 @@ tcp_server_create
   int fd, x;
   tcp_server_t *ts;
   struct addrinfo hints, *res, *ressave, *use = NULL;
+  struct sockaddr_storage bound;
   char port_buf[6];
   int one = 1;
   int zero = 0;
@@ -683,6 +685,10 @@ tcp_server_create
     setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(int));
 
   setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
+
+  assert(use->ai_addrlen <= sizeof(bound));
+  memset(&bound, 0, sizeof(bound));
+  memcpy(&bound, use->ai_addr, use->ai_addrlen);
   
   x = bind(fd, use->ai_addr, use->ai_addrlen);
   freeaddrinfo(ressave);
@@ -698,6 +704,7 @@ tcp_server_create
 
   ts = malloc(sizeof(tcp_server_t));
   ts->serverfd = fd;
+  ts->bound  = bound;
   ts->ops    = *ops;
   ts->opaque = opaque;
   return ts;
@@ -744,6 +751,94 @@ tcp_server_delete(void *server)
   free(ts);
 }
 
+/**
+ *
+ */
+int
+tcp_default_ip_addr ( struct sockaddr_storage *deflt )
+{
+
+  struct sockaddr_storage ss;
+  socklen_t ss_len;
+  int sock;
+
+  memset(&ss, 0, sizeof(ss));
+  ss.ss_family = tcp_preferred_address_family;
+  if (inet_pton(ss.ss_family,
+                ss.ss_family == AF_INET ?
+                  /* Google name servers */
+                  "8.8.8.8" : "2001:4860:4860::8888",
+                IP_IN_ADDR(ss)) <= 0)
+    return -1;
+
+  if (ss.ss_family == AF_INET)
+    IP_AS_V4(ss, port) = htons(53);
+  else
+    IP_AS_V6(ss, port) = htons(53);
+
+  sock = tvh_socket(ss.ss_family, SOCK_STREAM, 0);
+  if (sock < 0)
+    return -1;
+
+  if (connect(sock, (struct sockaddr *)&ss, IP_IN_ADDRLEN(ss)) < 0) {
+    close(sock);
+    return -1;
+  }
+
+  ss_len = sizeof(ss);
+  if (getsockname(sock, (struct sockaddr *)&ss, &ss_len) < 0) {
+    close(sock);
+    return -1;
+  }
+
+  if (ss.ss_family == AF_INET)
+    IP_AS_V4(ss, port) = 0;
+  else
+    IP_AS_V6(ss, port) = 0;
+
+  memset(deflt, 0, sizeof(*deflt));
+  memcpy(deflt, &ss, ss_len);
+
+  close(sock);
+  return 0;
+}
+
+/**
+ *
+ */
+int
+tcp_server_bound ( void *server, struct sockaddr_storage *bound )
+{
+  tcp_server_t *ts = server;
+  int i, len, port;
+  uint8_t *ptr;
+
+  if (server == NULL) {
+    memset(bound, 0, sizeof(*bound));
+    return 0;
+  }
+
+  len = IP_IN_ADDRLEN(*bound);
+  ptr = (uint8_t *)IP_IN_ADDR(*bound);
+  for (i = 0; i < len; i++)
+    if (ptr[0])
+      break;
+  if (i < len) {
+    *bound = ts->bound;
+    return 0;
+  }
+  port = IP_PORT(ts->bound);
+
+  /* no bind address was set, try to find one */
+  if (tcp_default_ip_addr(bound) < 0)
+    return -1;
+  if (bound->ss_family == AF_INET)
+    IP_AS_V4(*bound, port) = port;
+  else
+    IP_AS_V6(*bound, port) = port;
+  return 0;
+}
+
 /*
  * Connections status
  */
index 43dd7d44d684e2ce3fa8e043a32a68f0b958e991..33b4d86bc691f5b7638a42f836eec62d1f8d0ada 100644 (file)
--- a/src/tcp.h
+++ b/src/tcp.h
@@ -66,6 +66,10 @@ void tcp_server_register(void *server);
 
 void tcp_server_delete(void *server);
 
+int tcp_default_ip_addr(struct sockaddr_storage *deflt);
+
+int tcp_server_bound(void *server, struct sockaddr_storage *bound);
+
 int tcp_read(int fd, void *buf, size_t len);
 
 char *tcp_read_line(int fd, htsbuf_queue_t *spill);