ntbtls-cli: Use union to access hostent addr.
[ntbtls.git] / src / ntbtls-cli.c
index 46264cf..555961b 100644 (file)
 #include <stdarg.h>
 
 #include <unistd.h>
 #include <stdarg.h>
 
 #include <unistd.h>
+#include <errno.h>
 #include <sys/types.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
+#ifdef HAVE_W32_SYSTEM
+# define WIN32_LEAN_AND_MEAN
+# ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+# endif
+# include <windows.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif
 
 #include "ntbtls.h"
 
 
 #include "ntbtls.h"
 
@@ -37,6 +46,8 @@
 static int verbose;
 static int errorcount;
 static char *opt_hostname;
 static int verbose;
 static int errorcount;
 static char *opt_hostname;
+static int opt_head;
+
 
 \f
 /*
 
 \f
 /*
@@ -111,6 +122,77 @@ info (const char *format, ...)
 
 
 \f
 
 
 \f
+/* Until we support send/recv in estream we need to use es_fopencookie
+ * under Windows.  */
+#ifdef HAVE_W32_SYSTEM
+static gpgrt_ssize_t
+w32_cookie_read (void *cookie, void *buffer, size_t size)
+{
+  int sock = (int)cookie;
+  int nread;
+
+  do
+    {
+      /* Under Windows we need to use recv for a socket.  */
+      nread = recv (sock, buffer, size, 0);
+    }
+  while (nread == -1 && errno == EINTR);
+
+  return (gpgrt_ssize_t)nread;
+}
+
+static gpg_error_t
+w32_write_server (int sock, const char *data, size_t length)
+{
+  int nleft;
+  int nwritten;
+
+  nleft = length;
+  while (nleft > 0)
+    {
+      nwritten = send (sock, data, nleft, 0);
+      if ( nwritten == SOCKET_ERROR )
+        {
+          info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
+          return gpg_error (GPG_ERR_NETWORK);
+        }
+      nleft -= nwritten;
+      data += nwritten;
+    }
+
+  return 0;
+}
+
+/* Write handler for estream.  */
+static gpgrt_ssize_t
+w32_cookie_write (void *cookie, const void *buffer_arg, size_t size)
+{
+  int sock = (int)cookie;
+  const char *buffer = buffer_arg;
+  int nwritten = 0;
+
+  if (w32_write_server (sock, buffer, size))
+    {
+      gpg_err_set_errno (EIO);
+      nwritten = -1;
+    }
+  else
+    nwritten = size;
+
+  return (gpgrt_ssize_t)nwritten;
+}
+
+static es_cookie_io_functions_t w32_cookie_functions =
+  {
+    w32_cookie_read,
+    w32_cookie_write,
+    NULL,
+    NULL
+  };
+#endif /*HAVE_W32_SYSTEM*/
+
+
+\f
 static int
 connect_server (const char *server, unsigned short port)
 {
 static int
 connect_server (const char *server, unsigned short port)
 {
@@ -118,6 +200,10 @@ connect_server (const char *server, unsigned short port)
   int sock = -1;
   struct sockaddr_in addr;
   struct hostent *host;
   int sock = -1;
   struct sockaddr_in addr;
   struct hostent *host;
+  union {
+    char *addr;
+    struct in_addr *in_addr;
+  } addru;
 
   addr.sin_family = AF_INET;
   addr.sin_port = htons (port);
 
   addr.sin_family = AF_INET;
   addr.sin_port = htons (port);
@@ -129,7 +215,8 @@ connect_server (const char *server, unsigned short port)
       return -1;
     }
 
       return -1;
     }
 
-  addr.sin_addr = *(struct in_addr*)host->h_addr;
+  addru.addr = host->h_addr;
+  addr.sin_addr = *addru.in_addr;
 
   sock = socket (AF_INET, SOCK_STREAM, 0);
   if (sock == -1)
 
   sock = socket (AF_INET, SOCK_STREAM, 0);
   if (sock == -1)
@@ -165,14 +252,25 @@ connect_estreams (const char *server, int port,
   sock = connect_server (server, port);
   if (sock == -1)
     return gpg_error (GPG_ERR_GENERAL);
   sock = connect_server (server, port);
   if (sock == -1)
     return gpg_error (GPG_ERR_GENERAL);
-  *r_in = es_fdopen_nc (sock, "rb");
+
+#ifdef HAVE_W32_SYSTEM
+  *r_in = es_fopencookie ((void*)(unsigned int)sock, "rb",
+                          w32_cookie_functions);
+#else
+  *r_in = es_fdopen (sock, "rb");
+#endif
   if (!*r_in)
     {
       err = gpg_error_from_syserror ();
       close (sock);
       return err;
     }
   if (!*r_in)
     {
       err = gpg_error_from_syserror ();
       close (sock);
       return err;
     }
+#ifdef HAVE_W32_SYSTEM
+  *r_out = es_fopencookie ((void*)(unsigned int)sock, "wb",
+                           w32_cookie_functions);
+#else
   *r_out = es_fdopen (sock, "wb");
   *r_out = es_fdopen (sock, "wb");
+#endif
   if (!*r_out)
     {
       err = gpg_error_from_syserror ();
   if (!*r_out)
     {
       err = gpg_error_from_syserror ();
@@ -239,7 +337,7 @@ simple_client (const char *server, int port)
 
   do
     {
 
   do
     {
-      es_fputs ("GET / HTTP/1.0\r\n", writefp);
+      es_fprintf (writefp, "%s / HTTP/1.0\r\n", opt_head? "HEAD":"GET");
       if (opt_hostname)
         es_fprintf (writefp, "Host: %s\r\n", opt_hostname);
       es_fprintf (writefp, "X-ntbtls: %s\r\n",
       if (opt_hostname)
         es_fprintf (writefp, "Host: %s\r\n", opt_hostname);
       es_fprintf (writefp, "X-ntbtls: %s\r\n",
@@ -264,6 +362,7 @@ main (int argc, char **argv)
   int last_argc = -1;
   int debug_level = 0;
   int port = 443;
   int last_argc = -1;
   int debug_level = 0;
   int port = 443;
+  char *host;
 
   if (argc)
     { argc--; argv++; }
 
   if (argc)
     { argc--; argv++; }
@@ -284,7 +383,8 @@ main (int argc, char **argv)
                  "  --verbose       show more diagnostics\n"
                  "  --debug LEVEL   enable debugging at LEVEL\n"
                  "  --port N        connect to port N (default is 443)\n"
                  "  --verbose       show more diagnostics\n"
                  "  --debug LEVEL   enable debugging at LEVEL\n"
                  "  --port N        connect to port N (default is 443)\n"
-                 "  --hostname NAME use NAME for SNI\n"
+                 "  --hostname NAME use NAME instead of HOST for SNI\n"
+                 "  --head          send a HEAD and not a GET request\n"
                  "\n", stdout);
           return 0;
         }
                  "\n", stdout);
           return 0;
         }
@@ -331,10 +431,28 @@ main (int argc, char **argv)
           opt_hostname = *argv;
           argc--; argv++;
         }
           opt_hostname = *argv;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--head"))
+        {
+          opt_head = 1;
+          argc--; argv++;
+        }
       else if (!strncmp (*argv, "--", 2) && (*argv)[2])
         die ("Invalid option '%s'\n", *argv);
     }
 
       else if (!strncmp (*argv, "--", 2) && (*argv)[2])
         die ("Invalid option '%s'\n", *argv);
     }
 
+  host = argc? *argv : "localhost";
+  if (!opt_hostname)
+    opt_hostname = host;
+  if (!*opt_hostname)
+    opt_hostname = NULL;
+
+#ifdef HAVE_W32_SYSTEM
+  {
+    WSADATA wsadat;
+    WSAStartup (0x202, &wsadat);
+  }
+#endif
+
   if (!ntbtls_check_version (PACKAGE_VERSION))
     die ("NTBTLS library too old (need %s, have %s)\n",
          PACKAGE_VERSION, ntbtls_check_version (NULL));
   if (!ntbtls_check_version (PACKAGE_VERSION))
     die ("NTBTLS library too old (need %s, have %s)\n",
          PACKAGE_VERSION, ntbtls_check_version (NULL));
@@ -342,6 +460,6 @@ main (int argc, char **argv)
   if (debug_level)
     ntbtls_set_debug (debug_level, NULL, NULL);
 
   if (debug_level)
     ntbtls_set_debug (debug_level, NULL, NULL);
 
-  simple_client (argc? *argv : "localhost", port);
+  simple_client (host, port);
   return 0;
 }
   return 0;
 }