Makes a TCP connection to given service at server.
authorThadeu Lima de Souza Cascardo <cascardo@cascardo.info>
Sun, 6 Apr 2008 17:50:59 +0000 (14:50 -0300)
committerThadeu Lima de Souza Cascardo <cascardo@cascardo.info>
Sun, 6 Apr 2008 17:50:59 +0000 (14:50 -0300)
This is a synchronous/blocking implementation of a TCP connection. Given
a domain name and service, uses SRV to get server name and port, orders
it, and tries to get server address for each name, trying IPv6 before
IPv4.

tcp_connect.c [new file with mode: 0644]
tcp_connect.h [new file with mode: 0644]

diff --git a/tcp_connect.c b/tcp_connect.c
new file mode 100644 (file)
index 0000000..54ea3fd
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <udns.h>
+#include "sort_udns.h"
+
+int tcp_connect_a4 (struct in_addr addr, int port)
+{
+  int fd;
+  struct sockaddr_in in4;
+  fd = socket (PF_INET, SOCK_STREAM, 0);
+  if (fd < 0)
+    return -1;
+  in4.sin_family = AF_INET;
+  in4.sin_port = htons (port);
+  in4.sin_addr = addr;
+  if (connect (fd, (struct sockaddr *) &in4, sizeof (in4)) < 0)
+    {
+      close (fd);
+      return -1;
+    }
+  return fd;
+}
+
+int
+tcp_connect_a6 (struct in6_addr addr, int port)
+{
+  int fd;
+  struct sockaddr_in6 in6;
+  fd = socket (PF_INET6, SOCK_STREAM, 0);
+  if (fd < 0)
+    return -1;
+  memset (&in6, sizeof (in6), 0);
+  in6.sin6_family = AF_INET6;
+  in6.sin6_port = htons (port);
+  in6.sin6_addr = addr;
+  if (connect (fd, (struct sockaddr *) &in6, sizeof (in6)) < 0)
+    {
+      close (fd);
+      return -1;
+    }
+  return fd;
+}
+
+int
+tcp_connect4 (struct dns_srv srv)
+{
+  struct dns_rr_a4 *a4;
+  int i;
+  int fd;
+  a4 = dns_resolve_a4 (NULL, srv.name, 0);
+  if (a4 == NULL)
+    return -1;
+  for (i = 0; i < a4->dnsa4_nrr; i++)
+    {
+      fd = tcp_connect_a4 (a4->dnsa4_addr[i], srv.port);
+      if (fd >= 0)
+        {
+         free (a4);
+         return fd;
+       }
+    }
+  free (a4);
+  return -1;
+}
+
+int
+tcp_connect6 (struct dns_srv srv)
+{
+  struct dns_rr_a6 *a6;
+  int i;
+  int fd;
+  a6 = dns_resolve_a6 (NULL, srv.name, 0);
+  if (a6 == NULL)
+    return -1;
+  for (i = 0; i < a6->dnsa6_nrr; i++)
+    {
+      fd = tcp_connect_a6 (a6->dnsa6_addr[i], srv.port);
+      if (fd >= 0)
+        {
+         free (a6);
+          return fd;
+       }
+    }
+  free (a6);
+  return -1;
+}
+
+int
+tcp_connect (char *server, char *service)
+{
+  struct dns_rr_srv *srv;
+  int i;
+  int fd;
+  srv = dns_resolve_srv (NULL, server, service, "tcp", 0);
+  if (srv == NULL)
+    return -1;
+  dns_srv_sort (srv->dnssrv_srv, srv->dnssrv_nrr);
+  for (i = 0; i < srv->dnssrv_nrr; i++)
+    {
+      fd = tcp_connect6 (srv->dnssrv_srv[i]);
+      if (fd < 0)
+        fd = tcp_connect4 (srv->dnssrv_srv[i]);
+      if (fd >= 0)
+        {
+         free (srv);
+          return fd;
+       }
+     }
+  free (srv);
+  return -1;
+}
+
+#ifdef TEST
+int
+main (int argc, char **argv)
+{
+  char *server;
+  char *service;
+  int fd;
+  dns_init (NULL, 1);
+  server = (argc >= 2) ? argv[1] : "holoscopio.com";
+  service = (argc >= 3) ? argv[2] : "xmpp-client";
+  fd = tcp_connect (server, service);
+  if (fd > 0)
+    close (fd);
+  return 0;
+}
+#endif
diff --git a/tcp_connect.h b/tcp_connect.h
new file mode 100644 (file)
index 0000000..1d62037
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2008  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef SORT_UDNS_H
+#define SORT_UDNS_H
+
+int tcp_connect (char *, char*);
+
+#endif