6 static memcached_return_t
set_hostinfo(memcached_server_st
*server
)
11 char str_port
[NI_MAXSERV
];
13 snprintf(str_port
, NI_MAXSERV
, "%u", (uint32_t)server
->port
);
15 memset(&hints
, 0, sizeof(hints
));
17 // hints.ai_family= AF_INET;
18 if (server
->type
== MEMCACHED_CONNECTION_UDP
)
20 hints
.ai_protocol
= IPPROTO_UDP
;
21 hints
.ai_socktype
= SOCK_DGRAM
;
25 hints
.ai_socktype
= SOCK_STREAM
;
26 hints
.ai_protocol
= IPPROTO_TCP
;
29 e
= getaddrinfo(server
->hostname
, str_port
, &hints
, &ai
);
32 WATCHPOINT_STRING(server
->hostname
);
33 WATCHPOINT_STRING(gai_strerror(e
));
34 return MEMCACHED_HOST_LOOKUP_FAILURE
;
37 if (server
->address_info
)
39 freeaddrinfo(server
->address_info
);
40 server
->address_info
= NULL
;
42 server
->address_info
= ai
;
44 return MEMCACHED_SUCCESS
;
47 static memcached_return_t
set_socket_options(memcached_server_st
*ptr
)
49 WATCHPOINT_ASSERT(ptr
->fd
!= -1);
51 if (ptr
->type
== MEMCACHED_CONNECTION_UDP
)
52 return MEMCACHED_SUCCESS
;
55 if (ptr
->root
->snd_timeout
)
58 struct timeval waittime
;
61 waittime
.tv_usec
= ptr
->root
->snd_timeout
;
63 error
= setsockopt(ptr
->fd
, SOL_SOCKET
, SO_SNDTIMEO
,
64 &waittime
, (socklen_t
)sizeof(struct timeval
));
65 WATCHPOINT_ASSERT(error
== 0);
67 return MEMCACHED_FAILURE
;
72 if (ptr
->root
->rcv_timeout
)
75 struct timeval waittime
;
78 waittime
.tv_usec
= ptr
->root
->rcv_timeout
;
80 error
= setsockopt(ptr
->fd
, SOL_SOCKET
, SO_RCVTIMEO
,
81 &waittime
, (socklen_t
)sizeof(struct timeval
));
82 WATCHPOINT_ASSERT(error
== 0);
84 return MEMCACHED_FAILURE
;
88 if (ptr
->root
->flags
.no_block
)
94 linger
.l_linger
= 0; /* By default on close() just drop the socket */
95 error
= setsockopt(ptr
->fd
, SOL_SOCKET
, SO_LINGER
,
96 &linger
, (socklen_t
)sizeof(struct linger
));
97 WATCHPOINT_ASSERT(error
== 0);
99 return MEMCACHED_FAILURE
;
102 if (ptr
->root
->flags
.tcp_nodelay
)
107 error
= setsockopt(ptr
->fd
, IPPROTO_TCP
, TCP_NODELAY
,
108 &flag
, (socklen_t
)sizeof(int));
109 WATCHPOINT_ASSERT(error
== 0);
111 return MEMCACHED_FAILURE
;
114 if (ptr
->root
->flags
.tcp_keepalive
)
119 error
= setsockopt(ptr
->fd
, SOL_SOCKET
, SO_KEEPALIVE
,
120 &flag
, (socklen_t
)sizeof(int));
121 WATCHPOINT_ASSERT(error
== 0);
123 return MEMCACHED_FAILURE
;
126 if (ptr
->root
->send_size
> 0)
130 error
= setsockopt(ptr
->fd
, SOL_SOCKET
, SO_SNDBUF
,
131 &ptr
->root
->send_size
, (socklen_t
)sizeof(int));
132 WATCHPOINT_ASSERT(error
== 0);
134 return MEMCACHED_FAILURE
;
137 if (ptr
->root
->recv_size
> 0)
141 error
= setsockopt(ptr
->fd
, SOL_SOCKET
, SO_RCVBUF
,
142 &ptr
->root
->recv_size
, (socklen_t
)sizeof(int));
143 WATCHPOINT_ASSERT(error
== 0);
145 return MEMCACHED_FAILURE
;
148 /* libmemcached will always use nonblocking IO to avoid write deadlocks */
152 flags
= fcntl(ptr
->fd
, F_GETFL
, 0);
153 while (flags
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
155 unlikely (flags
== -1)
157 return MEMCACHED_CONNECTION_FAILURE
;
159 else if ((flags
& O_NONBLOCK
) == 0)
164 rval
= fcntl(ptr
->fd
, F_SETFL
, flags
| O_NONBLOCK
);
165 while (rval
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
167 unlikely (rval
== -1)
169 return MEMCACHED_CONNECTION_FAILURE
;
173 return MEMCACHED_SUCCESS
;
176 static memcached_return_t
unix_socket_connect(memcached_server_st
*ptr
)
178 struct sockaddr_un servAddr
;
182 if ((ptr
->fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0)
184 ptr
->cached_errno
= errno
;
185 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE
;
188 memset(&servAddr
, 0, sizeof (struct sockaddr_un
));
189 servAddr
.sun_family
= AF_UNIX
;
190 strcpy(servAddr
.sun_path
, ptr
->hostname
); /* Copy filename */
194 (struct sockaddr
*)&servAddr
,
195 sizeof(servAddr
)) < 0)
203 case EISCONN
: /* We were spinning waiting on connect */
206 WATCHPOINT_ERRNO(errno
);
207 ptr
->cached_errno
= errno
;
208 return MEMCACHED_ERRNO
;
213 WATCHPOINT_ASSERT(ptr
->fd
!= -1);
214 return MEMCACHED_SUCCESS
;
217 static memcached_return_t
network_connect(memcached_server_st
*ptr
)
221 struct addrinfo
*use
;
223 WATCHPOINT_ASSERT(ptr
->cursor_active
== 0);
225 if (! ptr
->options
.sockaddr_inited
||
226 (!(ptr
->root
->flags
.use_cache_lookups
)))
228 memcached_return_t rc
;
230 rc
= set_hostinfo(ptr
);
231 if (rc
!= MEMCACHED_SUCCESS
)
233 ptr
->options
.sockaddr_inited
= true;
236 use
= ptr
->address_info
;
237 /* Create the socket */
240 /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
241 if (ptr
->type
== MEMCACHED_CONNECTION_UDP
&& use
->ai_family
!= AF_INET
)
247 if ((ptr
->fd
= socket(use
->ai_family
,
249 use
->ai_protocol
)) < 0)
251 ptr
->cached_errno
= errno
;
252 WATCHPOINT_ERRNO(errno
);
253 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE
;
256 (void)set_socket_options(ptr
);
258 /* connect to server */
259 while (ptr
->fd
!= -1 &&
260 connect(ptr
->fd
, use
->ai_addr
, use
->ai_addrlen
) < 0)
262 ptr
->cached_errno
= errno
;
263 if (errno
== EINPROGRESS
|| /* nonblocking mode - first return, */
264 errno
== EALREADY
) /* nonblocking mode - subsequent returns */
266 struct pollfd fds
[1];
268 fds
[0].events
= POLLOUT
;
269 int error
= poll(fds
, 1, ptr
->root
->connect_timeout
);
271 if (error
!= 1 || fds
[0].revents
& POLLERR
)
273 if (fds
[0].revents
& POLLERR
)
276 socklen_t len
= sizeof (err
);
277 (void)getsockopt(ptr
->fd
, SOL_SOCKET
, SO_ERROR
, &err
, &len
);
278 ptr
->cached_errno
= (err
== 0) ? errno
: err
;
281 (void)close(ptr
->fd
);
285 else if (errno
== EISCONN
) /* we are connected :-) */
289 else if (errno
!= EINTR
)
291 (void)close(ptr
->fd
);
299 ptr
->server_failure_counter
= 0;
300 return MEMCACHED_SUCCESS
;
308 /* Failed to connect. schedule next retry */
309 if (ptr
->root
->retry_timeout
)
311 struct timeval next_time
;
313 if (gettimeofday(&next_time
, NULL
) == 0)
314 ptr
->next_retry
= next_time
.tv_sec
+ ptr
->root
->retry_timeout
;
316 ptr
->server_failure_counter
++;
317 if (ptr
->cached_errno
== 0)
318 return MEMCACHED_TIMEOUT
;
320 return MEMCACHED_ERRNO
; /* The last error should be from connect() */
323 ptr
->server_failure_counter
= 0;
324 return MEMCACHED_SUCCESS
; /* The last error should be from connect() */
328 memcached_return_t
memcached_connect(memcached_server_write_instance_st ptr
)
330 memcached_return_t rc
= MEMCACHED_NO_SERVERS
;
331 LIBMEMCACHED_MEMCACHED_CONNECT_START();
333 /* both retry_timeout and server_failure_limit must be set in order to delay retrying a server on error. */
334 WATCHPOINT_ASSERT(ptr
->root
);
335 if (ptr
->root
->retry_timeout
&& ptr
->root
->server_failure_limit
)
337 struct timeval curr_time
;
339 gettimeofday(&curr_time
, NULL
);
341 /* if we've had too many consecutive errors on this server, mark it dead. */
342 if (ptr
->server_failure_counter
>= ptr
->root
->server_failure_limit
)
344 ptr
->next_retry
= curr_time
.tv_sec
+ ptr
->root
->retry_timeout
;
345 ptr
->server_failure_counter
= 0;
348 if (curr_time
.tv_sec
< ptr
->next_retry
)
350 memcached_st
*root
= (memcached_st
*)ptr
->root
;
351 // @todo fix this by fixing behavior to no longer make use of
353 if (memcached_behavior_get(root
, MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS
))
355 run_distribution(root
);
358 root
->last_disconnected_server
= ptr
;
360 return MEMCACHED_SERVER_MARKED_DEAD
;
364 /* We need to clean up the multi startup piece */
367 case MEMCACHED_CONNECTION_UNKNOWN
:
368 WATCHPOINT_ASSERT(0);
369 rc
= MEMCACHED_NOT_SUPPORTED
;
371 case MEMCACHED_CONNECTION_UDP
:
372 case MEMCACHED_CONNECTION_TCP
:
373 rc
= network_connect(ptr
);
375 case MEMCACHED_CONNECTION_UNIX_SOCKET
:
376 rc
= unix_socket_connect(ptr
);
378 case MEMCACHED_CONNECTION_MAX
:
380 WATCHPOINT_ASSERT(0);
383 unlikely ( rc
!= MEMCACHED_SUCCESS
)
385 //@todo create interface around last_discontected_server
386 memcached_st
*root
= (memcached_st
*)ptr
->root
;
387 root
->last_disconnected_server
= ptr
;
390 LIBMEMCACHED_MEMCACHED_CONNECT_END();