# define FD_CLOEXEC 0
#endif
+#ifndef SO_NOSIGPIPE
+# define SO_NOSIGPIPE 0
+#endif
+
+#ifndef TCP_NODELAY
+# define TCP_NODELAY 0
+#endif
+
+#ifndef TCP_KEEPIDLE
+# define TCP_KEEPIDLE 0
+#endif
+
static memcached_return_t connect_poll(org::libmemcached::Instance* server)
{
struct pollfd fds[1];
fds[0].fd= server->fd;
- fds[0].events= POLLOUT;
+ fds[0].events= server->events();
+ fds[0].revents= 0;
size_t loop_max= 5;
return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT);
}
+#if 0
+ server->revents(fds[0].revents);
+#endif
+
if (fds[0].revents & POLLERR or
fds[0].revents & POLLHUP or
fds[0].revents & POLLNVAL)
server->address_info_next= NULL;
}
- char str_port[NI_MAXSERV];
- int length= snprintf(str_port, NI_MAXSERV, "%u", uint32_t(server->port()));
- if (length >= NI_MAXSERV or length <= 0)
+ char str_port[MEMCACHED_NI_MAXSERV];
+ int length= snprintf(str_port, MEMCACHED_NI_MAXSERV, "%u", uint32_t(server->port()));
+ if (length >= MEMCACHED_NI_MAXSERV or length <= 0)
{
- return MEMCACHED_FAILURE;
+ return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
+ memcached_literal_param("snprintf(NI_MAXSERV)"));
}
struct addrinfo hints;
#endif
}
-static void set_socket_options(org::libmemcached::Instance* server)
+static bool set_socket_options(org::libmemcached::Instance* server)
{
assert_msg(server->fd != INVALID_SOCKET, "invalid socket was passed to set_socket_options()");
+#ifdef HAVE_FCNTL
+ // If SOCK_CLOEXEC exists then we don't need to call the following
+ if (SOCK_CLOEXEC == 0)
+ {
+ if (FD_CLOEXEC)
+ {
+ int flags;
+ do
+ {
+ flags= fcntl(server->fd, F_GETFD, 0);
+ } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
+
+ if (flags != -1)
+ {
+ int rval;
+ do
+ {
+ rval= fcntl (server->fd, F_SETFD, flags | FD_CLOEXEC);
+ } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
+ // we currently ignore the case where rval is -1
+ }
+ }
+ }
+#endif
+
if (memcached_is_udp(server->root))
{
- return;
+ return true;
}
#ifdef HAVE_SNDTIMEO
#endif
-#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+#if defined(SO_NOSIGPIPE)
+ if (SO_NOSIGPIPE)
{
int set= 1;
int error= setsockopt(server->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
assert(error == 0);
}
- if (server->root->flags.tcp_nodelay)
+ if (TCP_NODELAY)
{
- int flag= 1;
+ if (server->root->flags.tcp_nodelay)
+ {
+ int flag= 1;
- int error= setsockopt(server->fd, IPPROTO_TCP, TCP_NODELAY,
- (char*)&flag, (socklen_t)sizeof(int));
- (void)(error);
- assert(error == 0);
+ int error= setsockopt(server->fd, IPPROTO_TCP, TCP_NODELAY,
+ (char*)&flag, (socklen_t)sizeof(int));
+ (void)(error);
+ assert(error == 0);
+ }
}
if (server->root->flags.tcp_keepalive)
assert(error == 0);
}
-#ifdef TCP_KEEPIDLE
- if (server->root->tcp_keepidle > 0)
+ if (TCP_KEEPIDLE)
{
- int error= setsockopt(server->fd, IPPROTO_TCP, TCP_KEEPIDLE,
- (char*)&server->root->tcp_keepidle, (socklen_t)sizeof(int));
- (void)(error);
- assert(error == 0);
+ if (server->root->tcp_keepidle > 0)
+ {
+ int error= setsockopt(server->fd, IPPROTO_TCP, TCP_KEEPIDLE,
+ (char*)&server->root->tcp_keepidle, (socklen_t)sizeof(int));
+ (void)(error);
+ assert(error == 0);
+ }
}
-#endif
if (server->root->send_size > 0)
{
/* libmemcached will always use nonblocking IO to avoid write deadlocks */
set_socket_nonblocking(server);
+
+ return true;
}
static memcached_return_t unix_socket_connect(org::libmemcached::Instance* server)
#ifndef WIN32
WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
- int type= SOCK_STREAM;
- if (SOCK_CLOEXEC)
- {
- type|= SOCK_CLOEXEC;
- }
+ do {
+ int type= SOCK_STREAM;
+ if (SOCK_CLOEXEC)
+ {
+ type|= SOCK_CLOEXEC;
+ }
- if (SOCK_NONBLOCK)
- {
- type|= SOCK_NONBLOCK;
- }
+ if (SOCK_NONBLOCK)
+ {
+ type|= SOCK_NONBLOCK;
+ }
- if ((server->fd= socket(AF_UNIX, type, 0)) < 0)
- {
- memcached_set_errno(*server, errno, NULL);
- return MEMCACHED_CONNECTION_FAILURE;
- }
+ if ((server->fd= socket(AF_UNIX, type, 0)) < 0)
+ {
+ return memcached_set_errno(*server, errno, NULL);
+ }
- struct sockaddr_un servAddr;
+ struct sockaddr_un servAddr;
- memset(&servAddr, 0, sizeof (struct sockaddr_un));
- servAddr.sun_family= AF_UNIX;
- strncpy(servAddr.sun_path, server->hostname, sizeof(servAddr.sun_path)); /* Copy filename */
+ memset(&servAddr, 0, sizeof (struct sockaddr_un));
+ servAddr.sun_family= AF_UNIX;
+ strncpy(servAddr.sun_path, server->hostname, sizeof(servAddr.sun_path)); /* Copy filename */
- do {
if (connect(server->fd, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0)
{
switch (errno)
{
case EINPROGRESS:
case EALREADY:
+ server->events(POLLOUT);
+ break;
+
case EINTR:
+ (void)closesocket(server->fd);
+ server->fd= INVALID_SOCKET;
continue;
case EISCONN: /* We were spinning waiting on connect */
{
assert(0); // Programmer error
- break;
+ (void)closesocket(server->fd);
+ server->fd= INVALID_SOCKET;
+ continue;
}
default:
WATCHPOINT_ERRNO(errno);
- memcached_set_errno(*server, errno, MEMCACHED_AT);
- return MEMCACHED_CONNECTION_FAILURE;
+ (void)closesocket(server->fd);
+ server->fd= INVALID_SOCKET;
+ return memcached_set_errno(*server, errno, MEMCACHED_AT);
}
}
} while (0);
return memcached_set_errno(*server, get_socket_errno(), NULL);
}
-#ifdef HAVE_FCNTL
- // If SOCK_CLOEXEC exists then we don't need to call the following
- if (SOCK_CLOEXEC == 0)
+ if (set_socket_options(server) == false)
{
- if (FD_CLOEXEC)
- {
- int rval;
- do
- {
- rval= fcntl (server->fd, F_SETFD, FD_CLOEXEC);
- } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
- }
+ (void)closesocket(server->fd);
+ return MEMCACHED_CONNECTION_FAILURE;
}
-#endif
-
- set_socket_options(server);
/* connect to server */
if ((connect(server->fd, server->address_info_next->ai_addr, server->address_info_next->ai_addrlen) != SOCKET_ERROR))
case EINPROGRESS: // nonblocking mode - first return
case EALREADY: // nonblocking mode - subsequent returns
{
+ server->events(POLLOUT);
server->state= MEMCACHED_SERVER_STATE_IN_PROGRESS;
memcached_return_t rc= connect_poll(server);
server->fd= INVALID_SOCKET;
continue;
+ case ECONNREFUSED:
+ // Probably not running service
+
default:
break;
}
return rc;
}
-memcached_return_t memcached_connect_try(org::libmemcached::Instance* server)
-{
- if (server and server->root and server->root->state.is_parsing)
- {
- return MEMCACHED_SUCCESS;
- }
-
- return _memcached_connect(server, false);
-}
-
memcached_return_t memcached_connect(org::libmemcached::Instance* server)
{
return _memcached_connect(server, true);