Initial support for Windows
authorTrond Norbye <trond.norbye@gmail.com>
Tue, 27 Jul 2010 22:38:51 +0000 (00:38 +0200)
committerTrond Norbye <trond.norbye@gmail.com>
Tue, 27 Jul 2010 22:38:51 +0000 (00:38 +0200)
In order to support Windows without adding a lot of #ifdefs all over
the code I decided to move all the inclusions of platform-specific
network headers into a separate include file. Windows use separate
subsystem for sockets (WinSock), and it is almost compatible with how
it works on Unix except from:

* The socket handle is a SOCKET and not a typical filedescriptor.
* It should be closed with closesocket() and not close().
* It does not set the global errno variable, but one should call
  WSAGetLastError() instead.

35 files changed:
Makefile.am
clients/include.am
clients/memcapable.c
clients/memcat.c
clients/memcp.c
clients/memrm.c
clients/memstat.c
clients/utilities.c
clients/utilities.h
configure.ac
example/interface_v0.c
example/interface_v1.c
example/memcached_light.c
libmemcached/behavior.c
libmemcached/callback.c
libmemcached/common.h
libmemcached/connect.c
libmemcached/include.am
libmemcached/io.c
libmemcached/memcached.h
libmemcached/platform.h [new file with mode: 0644]
libmemcached/protocol/binary_handler.c
libmemcached/protocol/common.h
libmemcached/protocol/pedantic.c
libmemcached/protocol/protocol_handler.c
libmemcached/protocol_handler.h
libmemcached/server.h
poll/include.am [new file with mode: 0644]
poll/poll.c [new file with mode: 0644]
poll/poll.h [new file with mode: 0644]
tests/mem_functions.c
tests/server.c
tests/test.c
win32/include.am [new file with mode: 0644]
win32/wrappers.h [new file with mode: 0644]

index 386494118ee63d15b4eb94db850c2213b48d7644..079f9482c6912d33cdb85f76b4b62cecfbd335ad 100644 (file)
@@ -45,6 +45,8 @@ include unittests/include.am
 include tests/include.am
 include example/include.am
 include support/include.am
+include poll/include.am
+include win32/include.am
 
 TESTS += ${check_PROGRAMS}
 
index 7b7cbc125d0b3276c00f75d0eb6b70f5216d7dd2..a709e38df6c979e6f28a4657e500a8a4b6bfd6b7 100644 (file)
@@ -22,8 +22,10 @@ bin_PROGRAMS+= \
        clients/memstat
 
 if HAVE_LIBEVENT
+if !BUILD_WIN32_WRAPPERS
   bin_PROGRAMS+= clients/memslap
 endif
+endif
 
 noinst_HEADERS+= \
                clients/client_options.h \
@@ -77,8 +79,9 @@ clients_memslap_SOURCES= \
 clients_memslap_LDADD= $(LTLIBEVENT) clients/libgenexec.la $(CLIENTS_LDADDS)
 
 clients_memcapable_SOURCES= clients/memcapable.c
+clients_memcapable_LDADD= $(CLIENTS_LDADDS)
 if BUILD_BYTEORDER
-clients_memcapable_LDADD= libmemcached/libbyteorder.la
+clients_memcapable_LDADD+= libmemcached/libbyteorder.la
 endif
 
 test-start-server:
index 08524c495647de4aa300624b40931445d9ab64b8..051c6457cca165d8e2e2b2c15cced21cf919731e 100644 (file)
 #include "config.h"
 #include <pthread.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
 #include <inttypes.h>
 #include <stdbool.h>
 #include <unistd.h>
-#include <poll.h>
 #include <ctype.h>
 
+#include <libmemcached/memcached.h>
 #include <libmemcached/memcached/protocol_binary.h>
 #include <libmemcached/byteorder.h>
+#include "utilities.h"
 
 #ifdef linux
 /* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
@@ -48,7 +44,7 @@
 /* Should we generate coredumps when we enounter an error (-c) */
 static bool do_core= false;
 /* connection to the server */
-static int sock;
+static SOCKET sock;
 /* Should the output from test failures be verbose or quiet? */
 static bool verbose= false;
 
@@ -112,14 +108,23 @@ static struct addrinfo *lookuphost(const char *hostname, const char *port)
  * Set the socket in nonblocking mode
  * @return -1 if failure, the socket otherwise
  */
-static int set_noblock(void)
+static SOCKET set_noblock(void)
 {
+#ifdef WIN32
+  u_long arg = 1;
+  if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
+  {
+    perror("Failed to set nonblocking io");
+    closesocket(sock);
+    return INVALID_SOCKET;
+  }
+#else
   int flags= fcntl(sock, F_GETFL, 0);
   if (flags == -1)
   {
     perror("Failed to get socket flags");
-    close(sock);
-    return -1;
+    closesocket(sock);
+    return INVALID_SOCKET;
   }
 
   if ((flags & O_NONBLOCK) != O_NONBLOCK)
@@ -127,11 +132,11 @@ static int set_noblock(void)
     if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
     {
       perror("Failed to set socket to nonblocking mode");
-      close(sock);
-      return -1;
+      closesocket(sock);
+      return INVALID_SOCKET;
     }
   }
-
+#endif
   return sock;
 }
 
@@ -141,28 +146,30 @@ static int set_noblock(void)
  * @param port the port number (or service) to connect to
  * @return positive integer if success, -1 otherwise
  */
-static int connect_server(const char *hostname, const char *port)
+static SOCKET connect_server(const char *hostname, const char *port)
 {
   struct addrinfo *ai= lookuphost(hostname, port);
-  sock= -1;
+  sock= INVALID_SOCKET;
   if (ai != NULL)
   {
-    if ((sock=socket(ai->ai_family, ai->ai_socktype,
-                     ai->ai_protocol)) != -1)
+    if ((sock= socket(ai->ai_family, ai->ai_socktype,
+                      ai->ai_protocol)) != INVALID_SOCKET)
     {
-      if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1)
+      if (connect(sock, ai->ai_addr, ai->ai_addrlen) == SOCKET_ERROR)
       {
         fprintf(stderr, "Failed to connect socket: %s\n",
-                strerror(errno));
-        close(sock);
-        sock= -1;
+                strerror(get_socket_errno()));
+        closesocket(sock);
+        sock= INVALID_SOCKET;
       }
       else
       {
         sock= set_noblock();
       }
-    } else
-      fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
+    }
+    else
+      fprintf(stderr, "Failed to create socket: %s\n",
+              strerror(get_socket_errno()));
 
     freeaddrinfo(ai);
   }
@@ -170,28 +177,29 @@ static int connect_server(const char *hostname, const char *port)
   return sock;
 }
 
-static ssize_t timeout_io_op(int fd, short direction, void *buf, size_t len)
+static ssize_t timeout_io_op(SOCKET fd, short direction, void *buf, size_t len)
 {
   ssize_t ret;
 
   if (direction == POLLOUT)
-    ret= write(fd, buf, len);
+     ret= send(fd, buf, len, 0);
   else
-    ret= read(fd, buf, len);
+     ret= recv(fd, buf, len, 0);
 
-  if (ret == -1 && errno == EWOULDBLOCK) {
+  if (ret == SOCKET_ERROR && get_socket_errno() == EWOULDBLOCK) {
     struct pollfd fds= {
       .events= direction,
       .fd= fd
     };
+
     int err= poll(&fds, 1, timeout * 1000);
 
     if (err == 1)
     {
       if (direction == POLLOUT)
-        ret= write(fd, buf, len);
+         ret= send(fd, buf, len, 0);
       else
-        ret= read(fd, buf, len);
+         ret= recv(fd, buf, len, 0);
     }
     else if (err == 0)
     {
@@ -245,7 +253,7 @@ static enum test_return retry_write(const void* buf, size_t len)
     size_t num_bytes= len - offset;
     ssize_t nw= timeout_io_op(sock, POLLOUT, (void*)(ptr + offset), num_bytes);
     if (nw == -1)
-      verify(errno == EINTR || errno == EAGAIN);
+      verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
     else
       offset+= (size_t)nw;
   } while (offset < len);
@@ -295,7 +303,7 @@ static enum test_return retry_read(void *buf, size_t len)
     ssize_t nr= timeout_io_op(sock, POLLIN, ((char*) buf) + offset, len - offset);
     switch (nr) {
     case -1 :
-      verify(errno == EINTR || errno == EAGAIN);
+      verify(get_socket_errno() == EINTR || get_socket_errno() == EAGAIN);
       break;
     case 0:
       return TEST_FAIL;
@@ -1891,11 +1899,12 @@ int main(int argc, char **argv)
     }
   }
 
+  initialize_sockets();
   sock= connect_server(hostname, port);
-  if (sock == -1)
+  if (sock == INVALID_SOCKET)
   {
     fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
-            hostname, port, strerror(errno));
+            hostname, port, strerror(get_socket_errno()));
     return 1;
   }
 
@@ -1920,18 +1929,18 @@ int main(int argc, char **argv)
     fprintf(stderr, "%s\n", status_msg[ret]);
     if (reconnect)
     {
-      (void) close(sock);
-      if ((sock=connect_server(hostname, port)) == -1)
+      closesocket(sock);
+      if ((sock= connect_server(hostname, port)) == INVALID_SOCKET)
       {
         fprintf(stderr, "Failed to connect to <%s:%s>: %s\n",
-                hostname, port, strerror(errno));
+                hostname, port, strerror(get_socket_errno()));
         fprintf(stderr, "%d of %d tests failed\n", failed, total);
         return 1;
       }
     }
   }
 
-  (void) close(sock);
+  closesocket(sock);
   if (failed == 0)
     fprintf(stdout, "All tests passed\n");
   else
index f50b069dc53844095fe6a4c17a188eaafca8fb62..5c7a512f2763e9b2214c610f8be841e83d5b731c 100644 (file)
@@ -48,6 +48,7 @@ int main(int argc, char *argv[])
   int return_code= 0;
 
   options_parse(argc, argv);
+  initialize_sockets();
 
   if (!opt_servers)
   {
index c748c40a6e11668f25e79dc2061fcd0c2633df9b..5b0518e7caa63b4c94d0efb4a79794391f2519db 100644 (file)
@@ -85,6 +85,7 @@ int main(int argc, char *argv[])
   int return_code= 0;
 
   options_parse(argc, argv);
+  initialize_sockets();
 
   memc= memcached_create(NULL);
   process_hash_option(memc, opt_hash);
index c5637608786f0a886182a11d9e26a5c366ed5e42..5ba5cdcd49f862be4e13e2146f2815066184ff7c 100644 (file)
@@ -41,6 +41,7 @@ int main(int argc, char *argv[])
   int return_code= 0;
 
   options_parse(argc, argv);
+  initialize_sockets();
 
   if (!opt_servers)
   {
index 652421bc1dd553bb46e14e6cd17a60aa2a793ee5..0bc365ac8010eabbe6491eb5174cad66e8d5cda3 100644 (file)
@@ -17,7 +17,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <sys/mman.h>
 #include <fcntl.h>
 #include <string.h>
 #include <getopt.h>
@@ -83,6 +82,7 @@ int main(int argc, char *argv[])
   memcached_server_st *servers;
 
   options_parse(argc, argv);
+  initialize_sockets();
 
   if (! opt_servers)
   {
index de2bdf442eba9a866c84485b36b060d12598216a..4d36cd20b135543aaaf854f66d62a3a30f313a1b 100644 (file)
@@ -215,3 +215,16 @@ void shutdown_sasl(void)
     sasl_done();
 #endif
 }
+
+void initialize_sockets(void)
+{
+  /* Define the function for all platforms to avoid #ifdefs in each program */
+#ifdef WIN32
+  WSADATA wsaData;
+  if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0)
+  {
+    fprintf(stderr, "Socket Initialization Error. Program aborted\n");
+    exit(EXIT_FAILURE);
+  }
+#endif
+}
index f74626480028cade60eb37128ac6c8ef3c5715dc..a998773b97f9342e2a3ba2f4dfc757b3082fc0be 100644 (file)
@@ -51,3 +51,4 @@ void help_command(const char *command_name, const char *description,
 void process_hash_option(memcached_st *memc, char *opt_hash);
 bool initialize_sasl(memcached_st *memc, char *user, char *password);
 void shutdown_sasl(void);
+void initialize_sockets(void);
index c192234c3e3f1e0641c38d976a4eecc673d570b9..4be37b7d0cdf0d606a1b465eaf3e3a3ad01d6a3c 100644 (file)
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 # libmemcached
-# Copyright (C) 2008 Brian Aker, Monty Taylor
+# Copyright (C) 2006-2010 Brian Aker, Monty Taylor, Trond Norbye
 # All rights reserved.
 #
 # Use and distribution licensed under the BSD license.  See
@@ -35,6 +35,54 @@ AC_SUBST(MEMCACHED_LIBRARY_VERSION)
 HASHKIT_LIBRARY_VERSION=0:0:0
 AC_SUBST(HASHKIT_LIBRARY_VERSION)
 
+AH_TOP([
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#ifdef _SYS_FEATURE_TESTS_H
+#error "You should include config.h as your first include file"
+#endif
+
+#ifdef WIN32
+#define _WIN32_WINNT 0x0501
+#endif
+])
+
+AH_BOTTOM([
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#else
+#include "poll/poll.h"
+#endif
+
+/* To hide the platform differences between MS Windows and Unix, I am
+ * going to use the Microsoft way and #define the Microsoft-specific
+ * functions to the unix way. Microsoft use a separate subsystem for sockets,
+ * but Unix normally just use a filedescriptor on the same functions. It is
+ * a lot easier to map back to the unix way with macros than going the other
+ * way without side effect ;-)
+ */
+#ifdef WIN32
+#include "win32/wrappers.h"
+#define get_socket_errno() WSAGetLastError()
+#else
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define closesocket(a) close(a)
+#define get_socket_errno() errno
+#endif
+
+#endif
+])
+
 AC_SEARCH_LIBS(getopt_long, gnugetopt)
 AC_SEARCH_LIBS(gethostbyname, nsl)
 
@@ -84,6 +132,30 @@ AS_IF([test "$with_docs" = "yes"],
   ])
 AM_CONDITIONAL(BUILD_DOCS, test "$with_docs" = "yes")
 
+AC_CHECK_HEADERS_ONCE(winsock2.h poll.h sys/wait.h fnmatch.h)
+AM_CONDITIONAL(BUILD_POLL, test "x$ac_cv_header_poll_h" = "xno")
+AM_CONDITIONAL(BUILD_WIN32_WRAPPERS, test "x$ac_cv_header_winsock2_h" = "xyes")
+AS_IF(test "x$ac_cv_header_winsock2_h" = "xyes",
+      AM_LDFLAGS="$AM_LDFLAGS -lws2_32")
+
+#
+# Some platforms define EWOULDBLOCK == EAGAIN, causing our switch for error
+# codes to be illegal (POSIX.1-2001 allows both return codes from recv, so
+# we need to test both if they differ...)
+#
+AC_MSG_CHECKING([if EWOULDBLOCK == EAGAIN])
+AC_RUN_IFELSE(
+  [AC_LANG_PROGRAM([
+#include <errno.h>
+     ], [dnl
+   return EAGAIN == EWOULDBLOCK ? 0 : 1;
+     ])
+  ],[
+   AC_MSG_RESULT([yes])
+  ], [
+   AC_MSG_RESULT([no])
+   AC_DEFINE([USE_EAGAIN], [1], [Define to true if you need to test for eagain])
+  ])
 
 AC_CONFIG_FILES([
   Makefile
index 57459208dc8205f96b13c39aac1e06d46359b73a..3ca4daff1f722253c74b963c43e640ea73759923 100644 (file)
@@ -7,9 +7,6 @@
 #include "config.h"
 #include <assert.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/tcp.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
index 2fcc0790da7a260910c3ddb0036d5cf0ed4479d8..36c0468b28e65b8be047e578217b39295c9c5bde 100644 (file)
@@ -11,9 +11,6 @@
 #include "config.h"
 #include <assert.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/tcp.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
index e2689e03a43ca515ae24346db7d94d0e8c9f964c..96c74d7e6f6904cae5802b61ff74a87141a9f07f 100644 (file)
@@ -26,9 +26,6 @@
 #include "config.h"
 #include <assert.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/tcp.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -45,7 +42,7 @@
 extern memcached_binary_protocol_callback_st interface_v0_impl;
 extern memcached_binary_protocol_callback_st interface_v1_impl;
 
-static int server_sockets[1024];
+static SOCKET server_sockets[1024];
 static int num_server_sockets= 0;
 
 struct connection
@@ -75,7 +72,7 @@ typedef struct options_st options_st;
  * @param which identifying the event that occurred (not used)
  * @param arg the connection structure for the client
  */
-static void drive_client(int fd, short which, void *arg)
+static void drive_client(SOCKET fd, short which, void *arg)
 {
   (void)which;
   struct connection *client= arg;
@@ -86,7 +83,7 @@ static void drive_client(int fd, short which, void *arg)
   if (events & MEMCACHED_PROTOCOL_ERROR_EVENT)
   {
     memcached_protocol_client_destroy(c);
-    (void)close(fd);
+    closesocket(fd);
   } else {
     short flags = 0;
     if (events & MEMCACHED_PROTOCOL_WRITE_EVENT)
@@ -99,14 +96,14 @@ static void drive_client(int fd, short which, void *arg)
       flags|= EV_READ;
     }
 
-    event_set(&client->event, fd, flags, drive_client, client);
+    event_set(&client->event, (intptr_t)fd, flags, drive_client, client);
     event_base_set(event_base, &client->event);
 
     if (event_add(&client->event, 0) == -1)
     {
       (void)fprintf(stderr, "Failed to add event for %d\n", fd);
       memcached_protocol_client_destroy(c);
-      (void)close(fd);
+      closesocket(fd);
     }
   }
 }
@@ -117,47 +114,49 @@ static void drive_client(int fd, short which, void *arg)
  * @param which identifying the event that occurred (not used)
  * @param arg the connection structure for the server
  */
-static void accept_handler(int fd, short which, void *arg)
+static void accept_handler(SOCKET fd, short which, void *arg)
 {
   (void)which;
   struct connection *server= arg;
   /* accept new client */
   struct sockaddr_storage addr;
   socklen_t addrlen= sizeof(addr);
-  int sock= accept(fd, (struct sockaddr *)&addr, &addrlen);
+  SOCKET sock= accept(fd, (struct sockaddr *)&addr, &addrlen);
 
-  if (sock == -1)
+  if (sock == INVALID_SOCKET)
   {
     perror("Failed to accept client");
     return ;
   }
 
+#ifndef WIN32
   if (sock >= maxconns)
   {
     (void)fprintf(stderr, "Client outside socket range (specified with -c)\n");
-    (void)close(sock);
+    closesocket(sock);
     return ;
   }
+#endif
 
   struct memcached_protocol_client_st* c;
   c= memcached_protocol_create_client(server->userdata, sock);
   if (c == NULL)
   {
     (void)fprintf(stderr, "Failed to create client\n");
-    (void)close(sock);
+    closesocket(sock);
   }
   else
   {
     struct connection *client = &socket_userdata_map[sock];
     client->userdata= c;
 
-    event_set(&client->event, sock, EV_READ, drive_client, client);
+    event_set(&client->event, (intptr_t)sock, EV_READ, drive_client, client);
     event_base_set(event_base, &client->event);
     if (event_add(&client->event, 0) == -1)
     {
       (void)fprintf(stderr, "Failed to add event for %d\n", sock);
       memcached_protocol_client_destroy(c);
-      (void)close(sock);
+      closesocket(sock);
     }
   }
 }
@@ -188,18 +187,28 @@ static int server_socket(const char *port)
 
   for (struct addrinfo *next= ai; next; next= next->ai_next)
   {
-    int sock= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-    if (sock == -1)
+    SOCKET sock= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+    if (sock == INVALID_SOCKET)
     {
       perror("Failed to create socket");
       continue;
     }
 
-    int flags= fcntl(sock, F_GETFL, 0);
+    int flags;
+#ifdef WIN32
+    u_long arg = 1;
+    if (ioctlsocket(sock, FIONBIO, &arg) == SOCKET_ERROR)
+    {
+      perror("Failed to set nonblocking io");
+      closesocket(sock);
+      continue;
+    }
+#else
+    flags= fcntl(sock, F_GETFL, 0);
     if (flags == -1)
     {
       perror("Failed to get socket flags");
-      close(sock);
+      closesocket(sock);
       continue;
     }
 
@@ -208,10 +217,11 @@ static int server_socket(const char *port)
       if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
       {
         perror("Failed to set socket to nonblocking mode");
-        close(sock);
+        closesocket(sock);
         continue;
       }
     }
+#endif
 
     flags= 1;
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags)) != 0)
@@ -226,21 +236,21 @@ static int server_socket(const char *port)
     if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)) != 0)
       perror("Failed to set TCP_NODELAY");
 
-    if (bind(sock, next->ai_addr, next->ai_addrlen) == -1)
+    if (bind(sock, next->ai_addr, next->ai_addrlen) == SOCKET_ERROR)
     {
-      if (errno != EADDRINUSE)
+      if (get_socket_errno() != EADDRINUSE)
       {
         perror("bind()");
         freeaddrinfo(ai);
       }
-      close(sock);
+      closesocket(sock);
       continue;
     }
 
-    if (listen(sock, 1024) == -1)
+    if (listen(sock, 1024) == SOCKET_ERROR)
     {
       perror("listen()");
-      close(sock);
+      closesocket(sock);
       continue;
     }
 
@@ -401,7 +411,7 @@ int main(int argc, char **argv)
 
     if (pid_file == NULL)
     {
-      perror(strerror(errno));
+      perror(strerror(get_socket_errno()));
       abort();
     }
 
@@ -446,13 +456,13 @@ int main(int argc, char **argv)
   {
     struct connection *conn= &socket_userdata_map[server_sockets[xx]];
     conn->userdata= protocol_handle;
-    event_set(&conn->event, server_sockets[xx], EV_READ | EV_PERSIST,
+    event_set(&conn->event, (intptr_t)server_sockets[xx], EV_READ | EV_PERSIST,
               accept_handler, conn);
     event_base_set(event_base, &conn->event);
     if (event_add(&conn->event, 0) == -1)
     {
       fprintf(stderr, "Failed to add event for %d\n", server_sockets[xx]);
-      close(server_sockets[xx]);
+      closesocket(server_sockets[xx]);
     }
   }
 
index 2f5311e5a01ddac70d96cc9c36576983d3b66f79..b84e770a5b559cf2f35d6e6e7aa4fdca215b1b3e 100644 (file)
@@ -12,8 +12,6 @@
 #include "common.h"
 #include <time.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/tcp.h>
 
 static bool set_flag(uint64_t data)
 {
index 29fcd1f8429de08ad9c676d5c67769f60b76f384..aba1a383670afd4cf0d297b9f54de423a259dc6f 100644 (file)
@@ -11,8 +11,6 @@
 
 #include "common.h"
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/tcp.h>
 
 /*
   These functions provide data and function callback support
index d07edd6c0b44a1ee6b74f7c55506850d80462f6e..a7d95af71617c0b827f7156cae634d6cf4bbf94e 100644 (file)
 #include <strings.h>
 #include <ctype.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
 #include <unistd.h>
 #include <limits.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <sys/un.h>
-#include <netinet/tcp.h>
 #ifdef TIME_WITH_SYS_TIME
 # include <sys/time.h>
 # include <time.h>
index 84423702cf992655971b5adc86b1109ec17bf0f6..7b38def933762ad29d29c52cf7f5a2952b520bbd 100644 (file)
@@ -10,8 +10,6 @@
  */
 
 #include "common.h"
-#include <netdb.h>
-#include <poll.h>
 #include <sys/time.h>
 #include <time.h>
 
@@ -55,8 +53,8 @@ static memcached_return_t connect_poll(memcached_server_st *ptr)
     case 0:
       return MEMCACHED_TIMEOUT;
     default: // A real error occurred and we need to completely bail
-      WATCHPOINT_ERRNO(errno);
-      switch (errno)
+      WATCHPOINT_ERRNO(get_socket_errno());
+      switch (get_socket_errno())
       {
 #ifdef TARGET_OS_LINUX
       case ERESTART:
@@ -69,15 +67,15 @@ static memcached_return_t connect_poll(memcached_server_st *ptr)
           int err;
           socklen_t len= sizeof (err);
           (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-          ptr->cached_errno= (err == 0) ? errno : err;
+          ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
         }
         else
         {
-          ptr->cached_errno= errno;
+          ptr->cached_errno= get_socket_errno();
         }
 
-        (void)close(ptr->fd);
-        ptr->fd= -1;
+        (void)closesocket(ptr->fd);
+        ptr->fd= INVALID_SOCKET;
 
         return MEMCACHED_ERRNO;
       }
@@ -86,7 +84,7 @@ static memcached_return_t connect_poll(memcached_server_st *ptr)
   }
 
   // This should only be possible from ERESTART or EINTR;
-  ptr->cached_errno= errno;
+  ptr->cached_errno= get_socket_errno();
 
   return MEMCACHED_ERRNO;
 }
@@ -124,13 +122,14 @@ static memcached_return_t set_hostinfo(memcached_server_st *server)
     }
     else if (e == EAI_AGAIN)
     {
+#ifndef WIN32
       struct timespec dream, rem;
 
       dream.tv_nsec= 1000;
       dream.tv_sec= 0;
 
       nanosleep(&dream, &rem);
-
+#endif
       continue;
     }
     else
@@ -151,6 +150,45 @@ static memcached_return_t set_hostinfo(memcached_server_st *server)
   return MEMCACHED_SUCCESS;
 }
 
+static inline memcached_return_t set_socket_nonblocking(memcached_server_st *ptr)
+{
+#ifdef WIN32
+  u_long arg = 1;
+  if (ioctlsocket(ptr->fd, FIONBIO, &arg) == SOCKET_ERROR)
+  {
+    ptr->cached_errno= get_socket_errno();
+    return MEMCACHED_CONNECTION_FAILURE;
+  }
+#else
+  int flags;
+
+  do
+    flags= fcntl(ptr->fd, F_GETFL, 0);
+  while (flags == -1 && (errno == EINTR || errno == EAGAIN));
+
+  unlikely (flags == -1)
+  {
+    ptr->cached_errno= errno;
+    return MEMCACHED_CONNECTION_FAILURE;
+  }
+  else if ((flags & O_NONBLOCK) == 0)
+  {
+    int rval;
+
+    do
+      rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
+    while (rval == -1 && (errno == EINTR || errno == EAGAIN));
+
+    unlikely (rval == -1)
+    {
+      ptr->cached_errno= errno;
+      return MEMCACHED_CONNECTION_FAILURE;
+    }
+  }
+#endif
+  return MEMCACHED_SUCCESS;
+}
+
 static memcached_return_t set_socket_options(memcached_server_st *ptr)
 {
   WATCHPOINT_ASSERT(ptr->fd != -1);
@@ -201,7 +239,7 @@ static memcached_return_t set_socket_options(memcached_server_st *ptr)
     // This is not considered a fatal error
     if (error == -1)
     {
-      WATCHPOINT_ERRNO(errno);
+      WATCHPOINT_ERRNO(get_socket_errno());
       perror("setsockopt(SO_NOSIGPIPE)");
     }
   }
@@ -280,36 +318,14 @@ static memcached_return_t set_socket_options(memcached_server_st *ptr)
       return MEMCACHED_FAILURE;
   }
 
-  /* libmemcached will always use nonblocking IO to avoid write deadlocks */
-  int flags;
-
-  do
-    flags= fcntl(ptr->fd, F_GETFL, 0);
-  while (flags == -1 && (errno == EINTR || errno == EAGAIN));
-
-  unlikely (flags == -1)
-  {
-    return MEMCACHED_CONNECTION_FAILURE;
-  }
-  else if ((flags & O_NONBLOCK) == 0)
-  {
-    int rval;
 
-    do
-      rval= fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
-    while (rval == -1 && (errno == EINTR || errno == EAGAIN));
-
-    unlikely (rval == -1)
-    {
-      return MEMCACHED_CONNECTION_FAILURE;
-    }
-  }
-
-  return MEMCACHED_SUCCESS;
+  /* libmemcached will always use nonblocking IO to avoid write deadlocks */
+  return set_socket_nonblocking(ptr);
 }
 
 static memcached_return_t unix_socket_connect(memcached_server_st *ptr)
 {
+#ifndef WIN32
   struct sockaddr_un servAddr;
 
   WATCHPOINT_ASSERT(ptr->fd == -1);
@@ -347,14 +363,18 @@ test_connect:
   WATCHPOINT_ASSERT(ptr->fd != -1);
 
   return MEMCACHED_SUCCESS;
+#else
+  (void)ptr;
+  return MEMCACHED_NOT_SUPPORTED;
+#endif
 }
 
 static memcached_return_t network_connect(memcached_server_st *ptr)
 {
   bool timeout_error_occured= false;
 
-  
-  WATCHPOINT_ASSERT(ptr->fd == -1);
+
+  WATCHPOINT_ASSERT(ptr->fd == INVALID_SOCKET);
   WATCHPOINT_ASSERT(ptr->cursor_active == 0);
 
   if (! ptr->options.sockaddr_inited || (!(ptr->root->flags.use_cache_lookups)))
@@ -382,23 +402,24 @@ static memcached_return_t network_connect(memcached_server_st *ptr)
                          use->ai_socktype,
                          use->ai_protocol)) < 0)
     {
-      ptr->cached_errno= errno;
-      WATCHPOINT_ERRNO(errno);
+      ptr->cached_errno= get_socket_errno();
+      WATCHPOINT_ERRNO(get_socket_errno());
       return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
     }
 
     (void)set_socket_options(ptr);
 
     /* connect to server */
-    if ((connect(ptr->fd, use->ai_addr, use->ai_addrlen) > -1))
+    if ((connect(ptr->fd, use->ai_addr, use->ai_addrlen) != SOCKET_ERROR))
     {
       break; // Success
     }
 
     /* An error occurred */
-    ptr->cached_errno= errno;
-    if (errno == EINPROGRESS || /* nonblocking mode - first return, */
-        errno == EALREADY) /* nonblocking mode - subsequent returns */
+    ptr->cached_errno= get_socket_errno();
+    if (ptr->cached_errno == EWOULDBLOCK ||
+        ptr->cached_errno == EINPROGRESS || /* nonblocking mode - first return, */
+        ptr->cached_errno == EALREADY) /* nonblocking mode - subsequent returns */
     {
       memcached_return_t rc;
       rc= connect_poll(ptr);
@@ -409,23 +430,23 @@ static memcached_return_t network_connect(memcached_server_st *ptr)
       if (rc == MEMCACHED_SUCCESS)
         break;
     }
-    else if (errno == EISCONN) /* we are connected :-) */
+    else if (get_socket_errno() == EISCONN) /* we are connected :-) */
     {
       break;
     }
-    else if (errno == EINTR) // Special case, we retry ai_addr
+    else if (get_socket_errno() == EINTR) // Special case, we retry ai_addr
     {
-      (void)close(ptr->fd);
-      ptr->fd= -1;
+      (void)closesocket(ptr->fd);
+      ptr->fd= INVALID_SOCKET;
       continue;
     }
 
-    (void)close(ptr->fd);
-    ptr->fd= -1;
+    (void)closesocket(ptr->fd);
+    ptr->fd= INVALID_SOCKET;
     use= use->ai_next;
   }
 
-  if (ptr->fd == -1)
+  if (ptr->fd == INVALID_SOCKET)
   {
     WATCHPOINT_STRING("Never got a good file descriptor");
 
@@ -466,7 +487,7 @@ memcached_return_t memcached_connect(memcached_server_write_instance_st ptr)
 {
   memcached_return_t rc= MEMCACHED_NO_SERVERS;
 
-  if (ptr->fd > -1)
+  if (ptr->fd != INVALID_SOCKET)
     return MEMCACHED_SUCCESS;
 
   LIBMEMCACHED_MEMCACHED_CONNECT_START();
@@ -516,13 +537,13 @@ memcached_return_t memcached_connect(memcached_server_write_instance_st ptr)
   case MEMCACHED_CONNECTION_TCP:
     rc= network_connect(ptr);
 #ifdef LIBMEMCACHED_WITH_SASL_SUPPORT
-    if (ptr->fd != -1 && ptr->root->sasl && ptr->root->sasl->callbacks)
+    if (ptr->fd != INVALID_SOCKET && ptr->root->sasl && ptr->root->sasl->callbacks)
     {
       rc= memcached_sasl_authenticate_connection(ptr);
       if (rc != MEMCACHED_SUCCESS)
       {
-        (void)close(ptr->fd);
-        ptr->fd= -1;
+        (void)closesocket(ptr->fd);
+        ptr->fd= INVALID_SOCKET;
       }
     }
 #endif
index 280d2c7e20e4f8dc8dbe0bac868c22fe9c518b95..4d705fd070bd523037b66094fdd491638cb729ba 100644 (file)
@@ -39,6 +39,7 @@ nobase_include_HEADERS+= \
                         libmemcached/memcached.hpp \
                         libmemcached/memcached/protocol_binary.h \
                         libmemcached/parse.h \
+                         libmemcached/platform.h \
                         libmemcached/protocol/cache.h \
                         libmemcached/protocol/callback.h \
                         libmemcached/protocol_handler.h \
@@ -65,7 +66,7 @@ libmemcached_libmemcachedprotocol_la_SOURCES =  \
                                                libmemcached/protocol/pedantic.c \
                                                libmemcached/protocol/protocol_handler.c
 
-libmemcached_libmemcachedprotocol_la_LDFLAGS= ${AM_LDFLAGS} -version-info ${MEMCACHED_PROTOCAL_LIBRARY_VERSION}
+libmemcached_libmemcachedprotocol_la_LDFLAGS= ${AM_LDFLAGS} ${PTHREAD} -version-info ${MEMCACHED_PROTOCAL_LIBRARY_VERSION}
 
 noinst_LTLIBRARIES+= \
                     libmemcached/libmemcachedcallbacks.la
@@ -133,7 +134,7 @@ libmemcached_libmemcachedutil_la_SOURCES= \
                                          libmemcached/util/pool.c \
                                          libmemcached/util/version.c
 libmemcached_libmemcachedutil_la_LIBADD= libmemcached/libmemcached.la
-libmemcached_libmemcachedutil_la_LDFLAGS= ${AM_LDFLAGS} -version-info ${MEMCACHED_UTIL_LIBRARY_VERSION}
+libmemcached_libmemcachedutil_la_LDFLAGS= ${AM_LDFLAGS} ${LIBPTHREAD} -version-info ${MEMCACHED_UTIL_LIBRARY_VERSION}
 libmemcached_libmemcachedutil_la_DEPENDENCIES= libmemcached/libmemcached.la
 
 if BUILD_BYTEORDER
index 30a2a1a4921396a967b71bd92bda79ec57ce3bb6..9a20609b1ce4b2343509472428fe30b96e1521f9 100644 (file)
@@ -11,8 +11,6 @@
 
 
 #include "common.h"
-#include <sys/select.h>
-#include <poll.h>
 
 typedef enum {
   MEM_READ,
@@ -76,8 +74,8 @@ static memcached_return_t io_wait(memcached_server_write_instance_st ptr,
     case 0: // Timeout occured, we let the while() loop do its thing.
       return MEMCACHED_TIMEOUT;
     default:
-      WATCHPOINT_ERRNO(errno);
-      switch (errno)
+      WATCHPOINT_ERRNO(get_socket_errno());
+      switch (get_socket_errno())
       {
 #ifdef TARGET_OS_LINUX
       case ERESTART:
@@ -90,11 +88,11 @@ static memcached_return_t io_wait(memcached_server_write_instance_st ptr,
           int err;
           socklen_t len= sizeof (err);
           (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-          ptr->cached_errno= (err == 0) ? errno : err;
+          ptr->cached_errno= (err == 0) ? get_socket_errno() : err;
         }
         else
         {
-          ptr->cached_errno= errno;
+          ptr->cached_errno= get_socket_errno();
         }
         memcached_quit_server(ptr, true);
 
@@ -105,7 +103,7 @@ static memcached_return_t io_wait(memcached_server_write_instance_st ptr,
 
   /* Imposssible for anything other then -1 */
   WATCHPOINT_ASSERT(error == -1);
-  ptr->cached_errno= errno;
+  ptr->cached_errno= get_socket_errno();
   memcached_quit_server(ptr, true);
 
   return MEMCACHED_FAILURE;
@@ -133,9 +131,10 @@ static bool repack_input_buffer(memcached_server_write_instance_st ptr)
   if (ptr->read_buffer_length != MEMCACHED_MAX_BUFFER)
   {
     /* Just try a single read to grab what's available */
-    ssize_t nr= read(ptr->fd,
+    ssize_t nr= recv(ptr->fd,
                      ptr->read_ptr + ptr->read_data_length,
-                     MEMCACHED_MAX_BUFFER - ptr->read_data_length);
+                     MEMCACHED_MAX_BUFFER - ptr->read_data_length,
+                     0);
 
     if (nr > 0)
     {
@@ -247,10 +246,10 @@ void memcached_io_preread(memcached_st *ptr)
     {
       size_t data_read;
 
-      data_read= read(ptr->hosts[x].fd,
+      data_read= recv(ptr->hosts[x].fd,
                       ptr->hosts[x].read_ptr + ptr->hosts[x].read_data_length,
-                      MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length);
-      if (data_read == -1)
+                      MEMCACHED_MAX_BUFFER - ptr->hosts[x].read_data_length, 0);
+      if (data_read == SOCKET_ERROR)
         continue;
 
       ptr->hosts[x].read_buffer_length+= data_read;
@@ -275,18 +274,21 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr,
 
       while (1)
       {
-        data_read= read(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER);
+        data_read= recv(ptr->fd, ptr->read_buffer, MEMCACHED_MAX_BUFFER, 0);
         if (data_read > 0)
         {
           break;
         }
-        else if (data_read == -1)
+        else if (data_read == SOCKET_ERROR)
         {
-          ptr->cached_errno= errno;
+          ptr->cached_errno= get_socket_errno();
           memcached_return_t rc= MEMCACHED_ERRNO;
-          switch (errno)
+          switch (get_socket_errno())
           {
+          case EWOULDBLOCK:
+#ifdef USE_EAGAIN
           case EAGAIN:
+#endif
           case EINTR:
 #ifdef TARGET_OS_LINUX
           case ERESTART:
@@ -314,7 +316,7 @@ memcached_return_t memcached_io_read(memcached_server_write_instance_st ptr,
             for blocking I/O we do not return 0 and for non-blocking case
             it will return EGAIN if data is not immediatly available.
           */
-          WATCHPOINT_STRING("We had a zero length read()");
+          WATCHPOINT_STRING("We had a zero length recv()");
           memcached_quit_server(ptr, true);
           *nread= -1;
           return MEMCACHED_UNKNOWN_READ_FAILURE;
@@ -360,7 +362,7 @@ static ssize_t _io_write(memcached_server_write_instance_st ptr,
   size_t original_length;
   const char* buffer_ptr;
 
-  WATCHPOINT_ASSERT(ptr->fd != -1);
+  WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
 
   original_length= length;
   buffer_ptr= buffer;
@@ -403,7 +405,7 @@ static ssize_t _io_write(memcached_server_write_instance_st ptr,
       memcached_return_t rc;
       ssize_t sent_length;
 
-      WATCHPOINT_ASSERT(ptr->fd != -1);
+      WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
       sent_length= io_flush(ptr, &rc);
       if (sent_length == -1)
         return -1;
@@ -419,7 +421,7 @@ static ssize_t _io_write(memcached_server_write_instance_st ptr,
   if (with_flush)
   {
     memcached_return_t rc;
-    WATCHPOINT_ASSERT(ptr->fd != -1);
+    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
     if (io_flush(ptr, &rc) == -1)
     {
       return -1;
@@ -468,22 +470,22 @@ ssize_t memcached_io_writev(memcached_server_write_instance_st ptr,
 
 memcached_return_t memcached_io_close(memcached_server_write_instance_st ptr)
 {
-  if (ptr->fd == -1)
+  if (ptr->fd == INVALID_SOCKET)
   {
     return MEMCACHED_SUCCESS;
   }
 
   /* in case of death shutdown to avoid blocking at close() */
-  if (shutdown(ptr->fd, SHUT_RDWR) == -1 && errno != ENOTCONN)
+  if (shutdown(ptr->fd, SHUT_RDWR) == SOCKET_ERROR && get_socket_errno() != ENOTCONN)
   {
     WATCHPOINT_NUMBER(ptr->fd);
-    WATCHPOINT_ERRNO(errno);
-    WATCHPOINT_ASSERT(errno);
+    WATCHPOINT_ERRNO(get_socket_errno());
+    WATCHPOINT_ASSERT(get_socket_errno());
   }
 
-  if (close(ptr->fd) == -1)
+  if (closesocket(ptr->fd) == SOCKET_ERROR)
   {
-    WATCHPOINT_ERRNO(errno);
+    WATCHPOINT_ERRNO(get_socket_errno());
   }
 
   return MEMCACHED_SUCCESS;
@@ -534,7 +536,7 @@ memcached_server_write_instance_st memcached_io_get_readable_server(memcached_st
   int err= poll(fds, host_index, memc->poll_timeout);
   switch (err) {
   case -1:
-    memc->cached_errno = errno;
+    memc->cached_errno = get_socket_errno();
     /* FALLTHROUGH */
   case 0:
     break;
@@ -568,7 +570,7 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr,
  */
   {
     memcached_return_t rc;
-    WATCHPOINT_ASSERT(ptr->fd != -1);
+    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
     rc= memcached_purge(ptr);
 
     if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED)
@@ -581,7 +583,7 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr,
 
   *error= MEMCACHED_SUCCESS;
 
-  WATCHPOINT_ASSERT(ptr->fd != -1);
+  WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
 
   // UDP Sanity check, make sure that we are not sending somthing too big
   if (ptr->type == MEMCACHED_CONNECTION_UDP && write_length > MAX_UDP_DATAGRAM_LENGTH)
@@ -601,23 +603,26 @@ static ssize_t io_flush(memcached_server_write_instance_st ptr,
   return_length= 0;
   while (write_length)
   {
-    WATCHPOINT_ASSERT(ptr->fd != -1);
+    WATCHPOINT_ASSERT(ptr->fd != INVALID_SOCKET);
     WATCHPOINT_ASSERT(write_length > 0);
     sent_length= 0;
     if (ptr->type == MEMCACHED_CONNECTION_UDP)
       increment_udp_message_id(ptr);
-    sent_length= write(ptr->fd, local_write_ptr, write_length);
 
-    if (sent_length == -1)
+    sent_length= send(ptr->fd, local_write_ptr, write_length, 0);
+    if (sent_length == SOCKET_ERROR)
     {
-      ptr->cached_errno= errno;
-      WATCHPOINT_ERRNO(errno);
-      WATCHPOINT_NUMBER(errno);
-      switch (errno)
+      ptr->cached_errno= get_socket_errno();
+      WATCHPOINT_ERRNO(get_socket_errno());
+      WATCHPOINT_NUMBER(get_socket_errno());
+      switch (get_socket_errno())
       {
       case ENOBUFS:
         continue;
+      case EWOULDBLOCK:
+#ifdef USE_EAGAIN
       case EAGAIN:
+#endif
         {
           /*
            * We may be blocked on write because the input buffer
index a7cdc97722e289e079b79582e4e129cf93965fdf..58f9f673165aa666b794dbb869fc9a267176b74e 100644 (file)
@@ -14,8 +14,6 @@
 #define __LIBMEMCACHED_MEMCACHED_H__
 
 #include <inttypes.h>
-#include <netdb.h>
-#include <netinet/in.h>
 #include <stdlib.h>
 #include <sys/types.h>
 
@@ -26,6 +24,7 @@
 
 #include <libmemcached/visibility.h>
 #include <libmemcached/configure.h>
+#include <libmemcached/platform.h>
 #include <libmemcached/constants.h>
 #include <libmemcached/types.h>
 #include <libmemcached/string.h>
diff --git a/libmemcached/platform.h b/libmemcached/platform.h
new file mode 100644 (file)
index 0000000..8b30f77
--- /dev/null
@@ -0,0 +1,31 @@
+/* LibMemcached
+ * Copyright (C) 2006-2010 Brian Aker, Trond Norbye
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Try to hide platform-specific stuff
+ *
+ */
+#ifndef LIBMEMCACHED_PLATFORM_H
+#define LIBMEMCACHED_PLATFORM_H 1
+
+#ifdef WIN32
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+typedef short in_port_t;
+#else
+typedef int SOCKET;
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/un.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+
+#endif /* WIN32 */
+
+
+#endif /* LIBMEMCACHED_PLATFORM_H */
index 2bafdeb1a445df0378bb4e366a955f1fca2bee3c..81c09c99f88f01154857cf4e35e7323f105c873c 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <stdlib.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <string.h>
@@ -59,11 +58,11 @@ raw_response_handler(const void *cookie,
                                      num_bytes);
       if (nw == -1)
       {
-        if (errno == EWOULDBLOCK)
+        if (get_socket_errno() == EWOULDBLOCK)
         {
           break;
         }
-        else if (errno != EINTR)
+        else if (get_socket_errno() != EINTR)
         {
           client->error= errno;
           return PROTOCOL_BINARY_RESPONSE_EIO;
index 1d29798c98d5c5b87a7b1861f3e094d2ab6ce43d..0a64df66e9c3ad014c8bb5df94de64cf0cde9bf6 100644 (file)
@@ -7,7 +7,6 @@
 # include <stdbool.h>
 #endif
 #include <assert.h>
-#include <netinet/in.h>
 
 /* Define this here, which will turn on the visibilty controls while we're
  * building libmemcached.
@@ -99,7 +98,7 @@ enum ascii_cmd {
 
 struct memcached_protocol_client_st {
   memcached_protocol_st *root;
-  int sock;
+  SOCKET sock;
   int error;
 
   /* Linked list of data to send */
index 5d750c0a8792c3888095057875025fcc0c338410..ac16099ea10a4755425d40c5f49d303a0284276b 100644 (file)
@@ -2,7 +2,6 @@
 #include "libmemcached/protocol/common.h"
 
 #include <sys/types.h>
-#include <netinet/in.h>
 #include <inttypes.h>
 
 #define ensure(a) if (!(a)) { return false; }
index fb90001db940548c385c635c71c671050d4b8c1c..77d6814d447a42253dd4c93d8cc8352342303ed3 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <stdlib.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <string.h>
@@ -29,7 +28,7 @@
  * @return the number of bytes transferred of -1 upon error
  */
 static ssize_t default_recv(const void *cookie,
-                            int sock,
+                            SOCKET sock,
                             void *buf,
                             size_t nbytes)
 {
@@ -49,7 +48,7 @@ static ssize_t default_recv(const void *cookie,
  * @return the number of bytes transferred of -1 upon error
  */
 static ssize_t default_send(const void *cookie,
-                            int fd,
+                            SOCKET fd,
                             const void *buf,
                             size_t nbytes)
 {
@@ -79,13 +78,13 @@ static bool drain_output(struct memcached_protocol_client_st *client)
 
     if (len == -1)
     {
-      if (errno == EWOULDBLOCK)
+      if (get_socket_errno() == EWOULDBLOCK)
       {
         return true;
       }
-      else if (errno != EINTR)
+      else if (get_socket_errno() != EINTR)
       {
-        client->error= errno;
+        client->error= get_socket_errno();
         return false;
       }
     }
@@ -270,7 +269,7 @@ void memcached_protocol_destroy_instance(struct memcached_protocol_st *instance)
   free(instance);
 }
 
-struct memcached_protocol_client_st *memcached_protocol_create_client(struct memcached_protocol_st *instance, int sock)
+struct memcached_protocol_client_st *memcached_protocol_create_client(struct memcached_protocol_st *instance, SOCKET sock)
 {
   struct memcached_protocol_client_st *ret= calloc(1, sizeof(*ret));
   if (ret != NULL)
@@ -343,9 +342,9 @@ memcached_protocol_event_t memcached_protocol_client_work(struct memcached_proto
     }
     else
     {
-      if (errno != EWOULDBLOCK)
+      if (get_socket_errno() != EWOULDBLOCK)
       {
-        client->error= errno;
+        client->error= get_socket_errno();
         /* mark this client as terminated! */
         return MEMCACHED_PROTOCOL_ERROR_EVENT;
       }
index 78eda07745a4d86a55b214d8d49c905bfe1b3b56..0e65ea9cfd70d3fe9f559d361056d0ba56aa63b9 100644 (file)
@@ -19,6 +19,7 @@
 # include <stdbool.h>
 #endif
 
+#include <libmemcached/platform.h>
 #include <libmemcached/memcached/protocol_binary.h>
 #include <libmemcached/visibility.h>
 #include <libmemcached/protocol/callback.h>
@@ -48,7 +49,7 @@ extern "C" {
  *         or -1 upon error (errno should contain more information)
  */
 typedef ssize_t (*memcached_protocol_recv_func)(const void *cookie,
-                                                int fd,
+                                                SOCKET fd,
                                                 void *buf,
                                                 size_t nbuf);
 
@@ -64,7 +65,7 @@ typedef ssize_t (*memcached_protocol_recv_func)(const void *cookie,
  *         or -1 upon error (errno should contain more information)
  */
 typedef ssize_t (*memcached_protocol_send_func)(const void *cookie,
-                                                int fd,
+                                                SOCKET fd,
                                                 const void *buf,
                                                 size_t nbuf);
 
@@ -139,7 +140,7 @@ void memached_protocol_set_io_functions(memcached_protocol_st *instance,
  * @return NULL if allocation fails, otherwise an instance
  */
 LIBMEMCACHED_API
-memcached_protocol_client_st *memcached_protocol_create_client(memcached_protocol_st *instance, int sock);
+memcached_protocol_client_st *memcached_protocol_create_client(memcached_protocol_st *instance, SOCKET sock);
 
 /**
  * Destroy a client handle.
@@ -191,7 +192,7 @@ memcached_protocol_event_t memcached_protocol_client_work(memcached_protocol_cli
  * @return the socket handle
  */
 LIBMEMCACHED_API
-int memcached_protocol_client_get_socket(memcached_protocol_client_st *client);
+SOCKET memcached_protocol_client_get_socket(memcached_protocol_client_st *client);
 
 /**
  * Get the error id socket attached to a client handle
index eabf7f0ff95725cf506f892810c68f09a6697711..4de191efcaf6a659dc96834340e8b49f90993bbc 100644 (file)
@@ -24,7 +24,7 @@ struct memcached_server_st {
   uint32_t cursor_active;
   in_port_t port;
   int cached_errno;
-  int fd;
+  SOCKET fd;
   uint32_t io_bytes_sent; /* # bytes sent since last read */
   uint32_t server_failure_counter;
   uint32_t weight;
diff --git a/poll/include.am b/poll/include.am
new file mode 100644 (file)
index 0000000..0010520
--- /dev/null
@@ -0,0 +1,8 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+noinst_HEADERS+= poll/poll.h
+
+if BUILD_POLL
+libmemcached_libmemcached_la_SOURCES += poll/poll.c
+endif
diff --git a/poll/poll.c b/poll/poll.c
new file mode 100644 (file)
index 0000000..7f47b75
--- /dev/null
@@ -0,0 +1,77 @@
+/* LibMemcached
+ * Copyright (C) 2010 Brian Aker, Trond Norbye
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Implementation of poll by using select
+ *
+ */
+#include "config.h"
+#include <sys/time.h>
+#include <strings.h>
+
+int poll(struct pollfd fds[], nfds_t nfds, int tmo)
+{
+  fd_set readfds, writefds, errorfds;
+  FD_ZERO(&readfds);
+  FD_ZERO(&writefds);
+  FD_ZERO(&errorfds);
+
+  int maxfd = 0;
+
+  for (int x = 0; x < nfds; ++x)
+  {
+    if (fds[x].events & (POLLIN | POLLOUT))
+    {
+#ifndef WIN32
+      if (fds[x].fd > maxfd)
+      {
+        maxfd = fds[x].fd;
+      }
+#endif
+      if (fds[x].events & POLLIN)
+      {
+        FD_SET(fds[x].fd, &readfds);
+      }
+      if (fds[x].events & POLLOUT)
+      {
+        FD_SET(fds[x].fd, &writefds);
+      }
+    }
+  }
+
+  struct timeval timeout = { .tv_sec = tmo / 1000,
+                             .tv_usec= (tmo % 1000) * 1000 };
+  struct timeval *tp = &timeout;
+  if (tmo == -1)
+  {
+    tp = NULL;
+  }
+  int ret = select(maxfd + 1, &readfds, &writefds, &errorfds, tp);
+  if (ret <= 0)
+  {
+    return ret;
+  }
+
+  /* Iterate through all of them because I need to clear the revent map */
+  for (int x = 0; x < nfds; ++x)
+  {
+    fds[x].revents = 0;
+    if (FD_ISSET(fds[x].fd, &readfds))
+    {
+      fds[x].revents |= POLLIN;
+    }
+    if (FD_ISSET(fds[x].fd, &writefds))
+    {
+      fds[x].revents |= POLLOUT;
+    }
+    if (FD_ISSET(fds[x].fd, &errorfds))
+    {
+      fds[x].revents |= POLLERR;
+    }
+  }
+
+   return ret;
+}
diff --git a/poll/poll.h b/poll/poll.h
new file mode 100644 (file)
index 0000000..82940ca
--- /dev/null
@@ -0,0 +1,45 @@
+/* LibMemcached
+ * Copyright (C) 2010 Brian Aker, Trond Norbye
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: Implementation of poll by using select
+ *
+ */
+#ifndef POLL_POLL_H
+#define POLL_POLL_H 1
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pollfd
+{
+#ifdef WIN32
+  SOCKET fd;
+#else
+  int fd;
+#endif
+  short events;
+  short revents;
+} pollfd_t;
+
+typedef int nfds_t;
+
+#define POLLIN 0x0001
+#define POLLOUT 0x0004
+#define POLLERR 0x0008
+
+int poll(struct pollfd fds[], nfds_t nfds, int tmo);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index a970a11eabc57eca006bedb30e31c2a90afc6b00..ad81f9d91dae9c23b0ca0e2f02fd88090679475a 100644 (file)
@@ -2945,6 +2945,11 @@ static void fail(int unused __attribute__((unused)))
 
 static test_return_t _user_supplied_bug21(memcached_st* memc, size_t key_count)
 {
+#ifdef WIN32
+  (void)memc;
+  (void)key_count;
+  return TEST_SKIPPED;
+#else
   memcached_return_t rc;
   unsigned int x;
   char **keys;
@@ -2993,6 +2998,7 @@ static test_return_t _user_supplied_bug21(memcached_st* memc, size_t key_count)
   memcached_free(memc_clone);
 
   return TEST_SUCCESS;
+#endif
 }
 
 static test_return_t user_supplied_bug21(memcached_st *memc)
index c0521e5bb26d5dabc1d615d82048b2c8fb8bd1ec..f2717795af0af04c2d5f46960a8f0f6a861e0278 100644 (file)
@@ -26,7 +26,7 @@
 #include <libmemcached/memcached.h>
 #include <libmemcached/util.h>
 #include <unistd.h>
-#include <time.h>
+#include <sys/time.h>
 
 #include "server.h"
 
@@ -110,9 +110,10 @@ void server_startup(server_startup_st *construct)
           file= fopen(buffer, "r");
           if (file == NULL)
           {
+#ifndef WIN32
             struct timespec req= { .tv_sec= 0, .tv_nsec= 5000 };
             nanosleep(&req, NULL);
-
+#endif
             continue;
           }
           char *found= fgets(buffer, sizeof(buffer), file);
index 58355f417ecdc36e23035eac48de703b43730b0c..348df72bd9beb00464c444884de10e56306b2dfd 100644 (file)
 
 #include "config.h"
 
+#include <unistd.h>
+
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 #include <unistd.h>
 #include <time.h>
-#include <fnmatch.h>
 #include <stdint.h>
 
 #include "libmemcached/memcached.h"
diff --git a/win32/include.am b/win32/include.am
new file mode 100644 (file)
index 0000000..751a371
--- /dev/null
@@ -0,0 +1,4 @@
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+noinst_HEADERS+= win32/wrappers.h
diff --git a/win32/wrappers.h b/win32/wrappers.h
new file mode 100644 (file)
index 0000000..20218fd
--- /dev/null
@@ -0,0 +1,49 @@
+/* LibMemcached
+ * Copyright (C) 2010 Brian Aker, Trond Norbye
+ * All rights reserved.
+ *
+ * Use and distribution licensed under the BSD license.  See
+ * the COPYING file in the parent directory for full text.
+ *
+ * Summary: "Implementation" of the function we don't have on windows
+ *          to avoid a bunch of ifdefs in the rest of the code
+ *
+ */
+#ifndef WIN32_WRAPPERS_H
+#define WIN32_WRAPPERS_H 1
+
+/*
+ * One of the Windows headers define interface as a macro, but that
+ * is causing problems with the member named "interface" in some of the
+ * structs.
+ */
+#undef interface
+
+/*
+ * WinSock use a separate range for error codes. Let's just map to the
+ * WinSock ones.
+ */
+#define EADDRINUSE WSAEADDRINUSE
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINPROGRESS WSAEINPROGRESS
+#define EALREADY WSAEALREADY
+#define EISCONN WSAEISCONN
+#define ENOTCONN WSAENOTCONN
+#define ENOBUFS WSAENOBUFS
+#define SHUT_RDWR SD_BOTH
+
+/* EAI_SYSTEM isn't defined anywhere... just set it to... 11? */
+#define EAI_SYSTEM 11
+
+/* Best effort mapping of functions to alternative functions */
+#define index(a,b) strchr(a,b)
+#define rindex(a,b) strrchr(a,b)
+#define random() rand()
+#define srandom(a) while (false) {}
+#define kill(a, b) while (false) {}
+#define fork() (-1)
+#define waitpid(a,b,c) (-1)
+#define fnmatch(a,b,c) (-1)
+#define sleep(a) Sleep(a*1000)
+
+#endif /* WIN32_WRAPPERS_H */