From: Trond Norbye Date: Tue, 27 Jul 2010 22:38:51 +0000 (+0200) Subject: Initial support for Windows X-Git-Tag: 0.44~12^2~4 X-Git-Url: https://git.m6w6.name/?p=awesomized%2Flibmemcached;a=commitdiff_plain;h=2230ba7b89bbaa989de311f9d7ea6d6e2cd5a9b8 Initial support for Windows 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. --- diff --git a/Makefile.am b/Makefile.am index 38649411..079f9482 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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} diff --git a/clients/include.am b/clients/include.am index 7b7cbc12..a709e38d 100644 --- a/clients/include.am +++ b/clients/include.am @@ -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: diff --git a/clients/memcapable.c b/clients/memcapable.c index 08524c49..051c6457 100644 --- a/clients/memcapable.c +++ b/clients/memcapable.c @@ -14,11 +14,6 @@ #include "config.h" #include #include -#include -#include -#include -#include -#include #include #include #include @@ -29,11 +24,12 @@ #include #include #include -#include #include +#include #include #include +#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 diff --git a/clients/memcat.c b/clients/memcat.c index f50b069d..5c7a512f 100644 --- a/clients/memcat.c +++ b/clients/memcat.c @@ -48,6 +48,7 @@ int main(int argc, char *argv[]) int return_code= 0; options_parse(argc, argv); + initialize_sockets(); if (!opt_servers) { diff --git a/clients/memcp.c b/clients/memcp.c index c748c40a..5b0518e7 100644 --- a/clients/memcp.c +++ b/clients/memcp.c @@ -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); diff --git a/clients/memrm.c b/clients/memrm.c index c5637608..5ba5cdcd 100644 --- a/clients/memrm.c +++ b/clients/memrm.c @@ -41,6 +41,7 @@ int main(int argc, char *argv[]) int return_code= 0; options_parse(argc, argv); + initialize_sockets(); if (!opt_servers) { diff --git a/clients/memstat.c b/clients/memstat.c index 652421bc..0bc365ac 100644 --- a/clients/memstat.c +++ b/clients/memstat.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -83,6 +82,7 @@ int main(int argc, char *argv[]) memcached_server_st *servers; options_parse(argc, argv); + initialize_sockets(); if (! opt_servers) { diff --git a/clients/utilities.c b/clients/utilities.c index de2bdf44..4d36cd20 100644 --- a/clients/utilities.c +++ b/clients/utilities.c @@ -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 +} diff --git a/clients/utilities.h b/clients/utilities.h index f7462648..a998773b 100644 --- a/clients/utilities.h +++ b/clients/utilities.h @@ -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); diff --git a/configure.ac b/configure.ac index c192234c..4be37b7d 100644 --- a/configure.ac +++ b/configure.ac @@ -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 +#endif + +#ifdef HAVE_FNMATCH_H +#include +#endif + +#ifdef HAVE_POLL_H +#include +#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 + ], [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 diff --git a/example/interface_v0.c b/example/interface_v0.c index 57459208..3ca4daff 100644 --- a/example/interface_v0.c +++ b/example/interface_v0.c @@ -7,9 +7,6 @@ #include "config.h" #include #include -#include -#include -#include #include #include #include diff --git a/example/interface_v1.c b/example/interface_v1.c index 2fcc0790..36c0468b 100644 --- a/example/interface_v1.c +++ b/example/interface_v1.c @@ -11,9 +11,6 @@ #include "config.h" #include #include -#include -#include -#include #include #include #include diff --git a/example/memcached_light.c b/example/memcached_light.c index e2689e03..96c74d7e 100644 --- a/example/memcached_light.c +++ b/example/memcached_light.c @@ -26,9 +26,6 @@ #include "config.h" #include #include -#include -#include -#include #include #include #include @@ -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]); } } diff --git a/libmemcached/behavior.c b/libmemcached/behavior.c index 2f5311e5..b84e770a 100644 --- a/libmemcached/behavior.c +++ b/libmemcached/behavior.c @@ -12,8 +12,6 @@ #include "common.h" #include #include -#include -#include static bool set_flag(uint64_t data) { diff --git a/libmemcached/callback.c b/libmemcached/callback.c index 29fcd1f8..aba1a383 100644 --- a/libmemcached/callback.c +++ b/libmemcached/callback.c @@ -11,8 +11,6 @@ #include "common.h" #include -#include -#include /* These functions provide data and function callback support diff --git a/libmemcached/common.h b/libmemcached/common.h index d07edd6c..a7d95af7 100644 --- a/libmemcached/common.h +++ b/libmemcached/common.h @@ -24,16 +24,10 @@ #include #include #include -#include -#include -#include -#include #include #include #include #include -#include -#include #ifdef TIME_WITH_SYS_TIME # include # include diff --git a/libmemcached/connect.c b/libmemcached/connect.c index 84423702..7b38def9 100644 --- a/libmemcached/connect.c +++ b/libmemcached/connect.c @@ -10,8 +10,6 @@ */ #include "common.h" -#include -#include #include #include @@ -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 diff --git a/libmemcached/include.am b/libmemcached/include.am index 280d2c7e..4d705fd0 100644 --- a/libmemcached/include.am +++ b/libmemcached/include.am @@ -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 diff --git a/libmemcached/io.c b/libmemcached/io.c index 30a2a1a4..9a20609b 100644 --- a/libmemcached/io.c +++ b/libmemcached/io.c @@ -11,8 +11,6 @@ #include "common.h" -#include -#include 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 diff --git a/libmemcached/memcached.h b/libmemcached/memcached.h index a7cdc977..58f9f673 100644 --- a/libmemcached/memcached.h +++ b/libmemcached/memcached.h @@ -14,8 +14,6 @@ #define __LIBMEMCACHED_MEMCACHED_H__ #include -#include -#include #include #include @@ -26,6 +24,7 @@ #include #include +#include #include #include #include diff --git a/libmemcached/platform.h b/libmemcached/platform.h new file mode 100644 index 00000000..8b30f773 --- /dev/null +++ b/libmemcached/platform.h @@ -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 +#include +typedef short in_port_t; +#else +typedef int SOCKET; +#include +#include +#include +#include +#include +#include + +#endif /* WIN32 */ + + +#endif /* LIBMEMCACHED_PLATFORM_H */ diff --git a/libmemcached/protocol/binary_handler.c b/libmemcached/protocol/binary_handler.c index 2bafdeb1..81c09c99 100644 --- a/libmemcached/protocol/binary_handler.c +++ b/libmemcached/protocol/binary_handler.c @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -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; diff --git a/libmemcached/protocol/common.h b/libmemcached/protocol/common.h index 1d29798c..0a64df66 100644 --- a/libmemcached/protocol/common.h +++ b/libmemcached/protocol/common.h @@ -7,7 +7,6 @@ # include #endif #include -#include /* 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 */ diff --git a/libmemcached/protocol/pedantic.c b/libmemcached/protocol/pedantic.c index 5d750c0a..ac16099e 100644 --- a/libmemcached/protocol/pedantic.c +++ b/libmemcached/protocol/pedantic.c @@ -2,7 +2,6 @@ #include "libmemcached/protocol/common.h" #include -#include #include #define ensure(a) if (!(a)) { return false; } diff --git a/libmemcached/protocol/protocol_handler.c b/libmemcached/protocol/protocol_handler.c index fb90001d..77d6814d 100644 --- a/libmemcached/protocol/protocol_handler.c +++ b/libmemcached/protocol/protocol_handler.c @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -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; } diff --git a/libmemcached/protocol_handler.h b/libmemcached/protocol_handler.h index 78eda077..0e65ea9c 100644 --- a/libmemcached/protocol_handler.h +++ b/libmemcached/protocol_handler.h @@ -19,6 +19,7 @@ # include #endif +#include #include #include #include @@ -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 diff --git a/libmemcached/server.h b/libmemcached/server.h index eabf7f0f..4de191ef 100644 --- a/libmemcached/server.h +++ b/libmemcached/server.h @@ -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 index 00000000..00105208 --- /dev/null +++ b/poll/include.am @@ -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 index 00000000..7f47b758 --- /dev/null +++ b/poll/poll.c @@ -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 +#include + +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 index 00000000..82940ca5 --- /dev/null +++ b/poll/poll.h @@ -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 +#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 diff --git a/tests/mem_functions.c b/tests/mem_functions.c index a970a11e..ad81f9d9 100644 --- a/tests/mem_functions.c +++ b/tests/mem_functions.c @@ -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) diff --git a/tests/server.c b/tests/server.c index c0521e5b..f2717795 100644 --- a/tests/server.c +++ b/tests/server.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #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); diff --git a/tests/test.c b/tests/test.c index 58355f41..348df72b 100644 --- a/tests/test.c +++ b/tests/test.c @@ -12,16 +12,16 @@ #include "config.h" +#include + #include #include #include #include #include #include -#include #include #include -#include #include #include "libmemcached/memcached.h" diff --git a/win32/include.am b/win32/include.am new file mode 100644 index 00000000..751a3719 --- /dev/null +++ b/win32/include.am @@ -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 index 00000000..20218fd5 --- /dev/null +++ b/win32/wrappers.h @@ -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 */