X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=libmemcached%2Fconnect.c;h=9f17f0c3f26d971c49e15d95bbe26cb0349577d9;hb=c4dbc7e56b01545e25bc95ba122c79d4a2631a99;hp=84423702cf992655971b5adc86b1109ec17bf0f6;hpb=49a02c953ab03f71b819e7a5f68ef7a0e5857544;p=awesomized%2Flibmemcached diff --git a/libmemcached/connect.c b/libmemcached/connect.c index 84423702..9f17f0c3 100644 --- a/libmemcached/connect.c +++ b/libmemcached/connect.c @@ -9,9 +9,8 @@ * */ -#include "common.h" -#include -#include +#include +#include #include #include @@ -21,16 +20,12 @@ static memcached_return_t connect_poll(memcached_server_st *ptr) fds[0].fd = ptr->fd; fds[0].events = POLLOUT; - int timeout= ptr->root->connect_timeout; - if (ptr->root->flags.no_block == true) - timeout= -1; - int error; size_t loop_max= 5; while (--loop_max) // Should only loop on cases of ERESTART or EINTR { - error= poll(fds, 1, timeout); + error= poll(fds, 1, ptr->root->connect_timeout); switch (error) { @@ -55,8 +50,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,40 +64,49 @@ 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; } } - WATCHPOINT_ASSERT(0); // Programming error } // This should only be possible from ERESTART or EINTR; - ptr->cached_errno= errno; + ptr->cached_errno= get_socket_errno(); return MEMCACHED_ERRNO; } static memcached_return_t set_hostinfo(memcached_server_st *server) { - struct addrinfo *ai; struct addrinfo hints; char str_port[NI_MAXSERV]; - uint32_t counter= 5; - snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port); + assert(! server->address_info); // We cover the case where a programming mistake has been made. + if (server->address_info) + { + freeaddrinfo(server->address_info); + server->address_info= NULL; + server->address_info_next= NULL; + } + + int length= snprintf(str_port, NI_MAXSERV, "%u", (uint32_t)server->port); + if (length >= NI_MAXSERV || length < 0) + return MEMCACHED_FAILURE; memset(&hints, 0, sizeof(hints)); - // hints.ai_family= AF_INET; +#if 0 + hints.ai_family= AF_INET; +#endif if (server->type == MEMCACHED_CONNECTION_UDP) { hints.ai_protocol= IPPROTO_UDP; @@ -114,9 +118,10 @@ static memcached_return_t set_hostinfo(memcached_server_st *server) hints.ai_protocol= IPPROTO_TCP; } + uint32_t counter= 5; while (--counter) { - int e= getaddrinfo(server->hostname, str_port, &hints, &ai); + int e= getaddrinfo(server->hostname, str_port, &hints, &server->address_info); if (e == 0) { @@ -124,13 +129,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 @@ -141,13 +147,47 @@ static memcached_return_t set_hostinfo(memcached_server_st *server) } } - if (server->address_info) + server->address_info_next= server->address_info; + + 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) { - freeaddrinfo(server->address_info); - server->address_info= NULL; + ptr->cached_errno= get_socket_errno(); + return MEMCACHED_CONNECTION_FAILURE; } - server->address_info= ai; +#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; } @@ -201,7 +241,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 +320,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); @@ -322,7 +340,7 @@ static memcached_return_t unix_socket_connect(memcached_server_st *ptr) memset(&servAddr, 0, sizeof (struct sockaddr_un)); servAddr.sun_family= AF_UNIX; - strcpy(servAddr.sun_path, ptr->hostname); /* Copy filename */ + strncpy(servAddr.sun_path, ptr->hostname, sizeof(servAddr.sun_path)); /* Copy filename */ test_connect: if (connect(ptr->fd, @@ -347,85 +365,88 @@ 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))) + if (! ptr->address_info) { - memcached_return_t rc; - - rc= set_hostinfo(ptr); + memcached_return_t rc= set_hostinfo(ptr); if (rc != MEMCACHED_SUCCESS) return rc; - ptr->options.sockaddr_inited= true; } - struct addrinfo *use= ptr->address_info; /* Create the socket */ - while (use != NULL) + while (ptr->address_info_next && ptr->fd == INVALID_SOCKET) { /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */ - if (ptr->type == MEMCACHED_CONNECTION_UDP && use->ai_family != AF_INET) + if (ptr->type == MEMCACHED_CONNECTION_UDP && ptr->address_info_next->ai_family != AF_INET) { - use= use->ai_next; + ptr->address_info_next= ptr->address_info_next->ai_next; continue; } - if ((ptr->fd= socket(use->ai_family, - use->ai_socktype, - use->ai_protocol)) < 0) + if ((ptr->fd= socket(ptr->address_info_next->ai_family, + ptr->address_info_next->ai_socktype, + ptr->address_info_next->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, ptr->address_info_next->ai_addr, ptr->address_info_next->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(); + switch (ptr->cached_errno) { - memcached_return_t rc; - rc= connect_poll(ptr); + case EWOULDBLOCK: + case EINPROGRESS: // nonblocking mode - first return + case EALREADY: // nonblocking mode - subsequent returns + { + memcached_return_t rc; + rc= connect_poll(ptr); - if (rc == MEMCACHED_TIMEOUT) - timeout_error_occured= true; + if (rc == MEMCACHED_TIMEOUT) + timeout_error_occured= true; - if (rc == MEMCACHED_SUCCESS) - break; - } - else if (errno == EISCONN) /* we are connected :-) */ - { + if (rc == MEMCACHED_SUCCESS) + break; + } + + case EISCONN: // we are connected :-) break; - } - else if (errno == EINTR) // Special case, we retry ai_addr - { - (void)close(ptr->fd); - ptr->fd= -1; + + case EINTR: // Special case, we retry ai_addr + (void)closesocket(ptr->fd); + ptr->fd= INVALID_SOCKET; continue; - } - (void)close(ptr->fd); - ptr->fd= -1; - use= use->ai_next; + default: + (void)closesocket(ptr->fd); + ptr->fd= INVALID_SOCKET; + ptr->address_info_next= ptr->address_info_next->ai_next; + break; + } } - 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.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