include tests/include.am
include example/include.am
include support/include.am
+include poll/include.am
+include win32/include.am
TESTS += ${check_PROGRAMS}
clients/memstat
if HAVE_LIBEVENT
+if !BUILD_WIN32_WRAPPERS
bin_PROGRAMS+= clients/memslap
endif
+endif
noinst_HEADERS+= \
clients/client_options.h \
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:
#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
/* 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;
* 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)
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;
}
* @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);
}
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)
{
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);
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;
}
}
+ 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;
}
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
int return_code= 0;
options_parse(argc, argv);
+ initialize_sockets();
if (!opt_servers)
{
int return_code= 0;
options_parse(argc, argv);
+ initialize_sockets();
memc= memcached_create(NULL);
process_hash_option(memc, opt_hash);
int return_code= 0;
options_parse(argc, argv);
+ initialize_sockets();
if (!opt_servers)
{
#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>
memcached_server_st *servers;
options_parse(argc, argv);
+ initialize_sockets();
if (! opt_servers)
{
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
+}
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);
#!/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
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)
])
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
#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>
#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>
#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>
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
* @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;
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)
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);
}
}
}
* @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);
}
}
}
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;
}
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)
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;
}
if (pid_file == NULL)
{
- perror(strerror(errno));
+ perror(strerror(get_socket_errno()));
abort();
}
{
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]);
}
}
#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)
{
#include "common.h"
#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/tcp.h>
/*
These functions provide data and function callback support
#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>
*/
#include "common.h"
-#include <netdb.h>
-#include <poll.h>
#include <sys/time.h>
#include <time.h>
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:
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;
}
}
// This should only be possible from ERESTART or EINTR;
- ptr->cached_errno= errno;
+ ptr->cached_errno= get_socket_errno();
return MEMCACHED_ERRNO;
}
}
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
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);
// This is not considered a fatal error
if (error == -1)
{
- WATCHPOINT_ERRNO(errno);
+ WATCHPOINT_ERRNO(get_socket_errno());
perror("setsockopt(SO_NOSIGPIPE)");
}
}
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);
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)))
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);
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");
{
memcached_return_t rc= MEMCACHED_NO_SERVERS;
- if (ptr->fd > -1)
+ if (ptr->fd != INVALID_SOCKET)
return MEMCACHED_SUCCESS;
LIBMEMCACHED_MEMCACHED_CONNECT_START();
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
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 \
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
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
#include "common.h"
-#include <sys/select.h>
-#include <poll.h>
typedef enum {
MEM_READ,
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:
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);
/* 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;
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)
{
{
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;
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:
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;
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;
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;
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;
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;
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;
*/
{
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)
*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)
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
#define __LIBMEMCACHED_MEMCACHED_H__
#include <inttypes.h>
-#include <netdb.h>
-#include <netinet/in.h>
#include <stdlib.h>
#include <sys/types.h>
#include <libmemcached/visibility.h>
#include <libmemcached/configure.h>
+#include <libmemcached/platform.h>
#include <libmemcached/constants.h>
#include <libmemcached/types.h>
#include <libmemcached/string.h>
--- /dev/null
+/* 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 */
#include <stdlib.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
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;
# 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.
struct memcached_protocol_client_st {
memcached_protocol_st *root;
- int sock;
+ SOCKET sock;
int error;
/* Linked list of data to send */
#include "libmemcached/protocol/common.h"
#include <sys/types.h>
-#include <netinet/in.h>
#include <inttypes.h>
#define ensure(a) if (!(a)) { return false; }
#include <stdlib.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
* @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)
{
* @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)
{
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;
}
}
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)
}
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;
}
# include <stdbool.h>
#endif
+#include <libmemcached/platform.h>
#include <libmemcached/memcached/protocol_binary.h>
#include <libmemcached/visibility.h>
#include <libmemcached/protocol/callback.h>
* 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);
* 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);
* @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.
* @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
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;
--- /dev/null
+# 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
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;
memcached_free(memc_clone);
return TEST_SUCCESS;
+#endif
}
static test_return_t user_supplied_bug21(memcached_st *memc)
#include <libmemcached/memcached.h>
#include <libmemcached/util.h>
#include <unistd.h>
-#include <time.h>
+#include <sys/time.h>
#include "server.h"
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);
#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"
--- /dev/null
+# vim:ft=automake
+# included from Top Level Makefile.am
+# All paths should be given relative to the root
+noinst_HEADERS+= win32/wrappers.h
--- /dev/null
+/* 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 */