5d180d185e0208004270c707887a51499e26b91b
[awesomized/libmemcached] / libmemcached / connect.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Libmemcached library
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2006-2010 Brian Aker All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38
39 #include <libmemcached/common.h>
40
41 #include <cassert>
42 #include <ctime>
43 #include <sys/time.h>
44
45 #ifndef SOCK_CLOEXEC
46 #define SOCK_CLOEXEC 0
47 #endif
48
49 static memcached_return_t connect_poll(org::libmemcached::Instance* server)
50 {
51 struct pollfd fds[1];
52 fds[0].fd= server->fd;
53 fds[0].events= POLLOUT;
54
55 size_t loop_max= 5;
56
57 if (server->root->poll_timeout == 0)
58 {
59 return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT);
60 }
61
62 while (--loop_max) // Should only loop on cases of ERESTART or EINTR
63 {
64 int number_of;
65 if ((number_of= poll(fds, 1, server->root->connect_timeout)) <= 0)
66 {
67 if (number_of == -1)
68 {
69 int local_errno= get_socket_errno(); // We cache in case closesocket() modifies errno
70 switch (local_errno)
71 {
72 #ifdef TARGET_OS_LINUX
73 case ERESTART:
74 #endif
75 case EINTR:
76 continue;
77
78 case EFAULT:
79 case ENOMEM:
80 return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
81
82 case EINVAL:
83 return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("RLIMIT_NOFILE exceeded, or if OSX the timeout value was invalid"));
84
85 default: // This should not happen
86 if (fds[0].revents & POLLERR)
87 {
88 int err;
89 socklen_t len= sizeof(err);
90 if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0)
91 {
92 if (err == 0)
93 {
94 // This should never happen, if it does? Punt.
95 continue;
96 }
97 local_errno= err;
98 }
99 }
100
101 assert_msg(server->fd != INVALID_SOCKET, "poll() was passed an invalid file descriptor");
102 (void)closesocket(server->fd);
103 server->fd= INVALID_SOCKET;
104 server->state= MEMCACHED_SERVER_STATE_NEW;
105
106 return memcached_set_errno(*server, local_errno, MEMCACHED_AT);
107 }
108 }
109 assert(number_of == 0);
110
111 server->io_wait_count.timeouts++;
112 return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT);
113 }
114
115 if (fds[0].revents & POLLERR or
116 fds[0].revents & POLLHUP or
117 fds[0].revents & POLLNVAL)
118 {
119 int err;
120 socklen_t len= sizeof (err);
121 if (getsockopt(fds[0].fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0)
122 {
123 // We check the value to see what happened wth the socket.
124 if (err == 0)
125 {
126 return MEMCACHED_SUCCESS;
127 }
128 errno= err;
129 }
130
131 return memcached_set_errno(*server, err, MEMCACHED_AT);
132 }
133 assert(fds[0].revents & POLLIN or fds[0].revents & POLLOUT);
134
135 return MEMCACHED_SUCCESS;
136 }
137
138 // This should only be possible from ERESTART or EINTR;
139 return memcached_set_errno(*server, get_socket_errno(), MEMCACHED_AT);
140 }
141
142 static memcached_return_t set_hostinfo(org::libmemcached::Instance* server)
143 {
144 assert(server->type != MEMCACHED_CONNECTION_UNIX_SOCKET);
145 if (server->address_info)
146 {
147 freeaddrinfo(server->address_info);
148 server->address_info= NULL;
149 server->address_info_next= NULL;
150 }
151
152 char str_port[NI_MAXSERV];
153 int length= snprintf(str_port, NI_MAXSERV, "%u", uint32_t(server->port()));
154 if (length >= NI_MAXSERV or length <= 0)
155 {
156 return MEMCACHED_FAILURE;
157 }
158
159 struct addrinfo hints;
160 memset(&hints, 0, sizeof(struct addrinfo));
161
162 #if 0
163 hints.ai_family= AF_INET;
164 #endif
165 if (memcached_is_udp(server->root))
166 {
167 hints.ai_protocol= IPPROTO_UDP;
168 hints.ai_socktype= SOCK_DGRAM;
169 }
170 else
171 {
172 hints.ai_socktype= SOCK_STREAM;
173 hints.ai_protocol= IPPROTO_TCP;
174 }
175
176 assert(server->address_info == NULL);
177 assert(server->address_info_next == NULL);
178 int errcode;
179 switch(errcode= getaddrinfo(server->hostname, str_port, &hints, &server->address_info))
180 {
181 case 0:
182 break;
183
184 case EAI_AGAIN:
185 if (server->address_info)
186 {
187 freeaddrinfo(server->address_info);
188 server->address_info= NULL;
189 server->address_info_next= NULL;
190 }
191 return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_string_make_from_cstr(gai_strerror(errcode)));
192
193 case EAI_SYSTEM:
194 if (server->address_info)
195 {
196 freeaddrinfo(server->address_info);
197 server->address_info= NULL;
198 server->address_info_next= NULL;
199 }
200 return memcached_set_errno(*server, errno, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_SYSTEM)"));
201
202 case EAI_BADFLAGS:
203 if (server->address_info)
204 {
205 freeaddrinfo(server->address_info);
206 server->address_info= NULL;
207 server->address_info_next= NULL;
208 }
209 return memcached_set_error(*server, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_BADFLAGS)"));
210
211 case EAI_MEMORY:
212 if (server->address_info)
213 {
214 freeaddrinfo(server->address_info);
215 server->address_info= NULL;
216 server->address_info_next= NULL;
217 }
218 return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_MEMORY)"));
219
220 default:
221 {
222 if (server->address_info)
223 {
224 freeaddrinfo(server->address_info);
225 server->address_info= NULL;
226 server->address_info_next= NULL;
227 }
228 return memcached_set_error(*server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT, memcached_string_make_from_cstr(gai_strerror(errcode)));
229 }
230 }
231 server->address_info_next= server->address_info;
232 server->state= MEMCACHED_SERVER_STATE_ADDRINFO;
233
234 return MEMCACHED_SUCCESS;
235 }
236
237 static inline void set_socket_nonblocking(org::libmemcached::Instance* server)
238 {
239 #ifdef WIN32
240 u_long arg= 1;
241 if (ioctlsocket(server->fd, FIONBIO, &arg) == SOCKET_ERROR)
242 {
243 memcached_set_errno(*server, get_socket_errno(), NULL);
244 }
245 #else
246 int flags;
247
248 do
249 {
250 flags= fcntl(server->fd, F_GETFL, 0);
251 } while (flags == -1 && (errno == EINTR || errno == EAGAIN));
252
253 if (flags == -1)
254 {
255 memcached_set_errno(*server, errno, NULL);
256 }
257 else if ((flags & O_NONBLOCK) == 0)
258 {
259 int rval;
260
261 do
262 {
263 rval= fcntl(server->fd, F_SETFL, flags | O_NONBLOCK);
264 } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
265
266 if (rval == -1)
267 {
268 memcached_set_errno(*server, errno, NULL);
269 }
270 }
271 #endif
272 }
273
274 static void set_socket_options(org::libmemcached::Instance* server)
275 {
276 assert_msg(server->fd != INVALID_SOCKET, "invalid socket was passed to set_socket_options()");
277
278 if (memcached_is_udp(server->root))
279 {
280 return;
281 }
282
283 #ifdef HAVE_SNDTIMEO
284 if (server->root->snd_timeout > 0)
285 {
286 struct timeval waittime;
287
288 waittime.tv_sec= server->root->snd_timeout / 1000000;
289 waittime.tv_usec= server->root->snd_timeout % 1000000;
290
291 int error= setsockopt(server->fd, SOL_SOCKET, SO_SNDTIMEO,
292 &waittime, (socklen_t)sizeof(struct timeval));
293 (void)error;
294 assert(error == 0);
295 }
296 #endif
297
298 #ifdef HAVE_RCVTIMEO
299 if (server->root->rcv_timeout > 0)
300 {
301 struct timeval waittime;
302
303 waittime.tv_sec= server->root->rcv_timeout / 1000000;
304 waittime.tv_usec= server->root->rcv_timeout % 1000000;
305
306 int error= setsockopt(server->fd, SOL_SOCKET, SO_RCVTIMEO,
307 &waittime, (socklen_t)sizeof(struct timeval));
308 (void)(error);
309 assert(error == 0);
310 }
311 #endif
312
313
314 #if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
315 {
316 int set= 1;
317 int error= setsockopt(server->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
318
319 assert(error == 0);
320
321 // This is not considered a fatal error
322 if (error == -1)
323 {
324 #if 0
325 perror("setsockopt(SO_NOSIGPIPE)");
326 #endif
327 }
328 }
329 #endif
330
331 if (server->root->flags.no_block)
332 {
333 struct linger linger;
334
335 linger.l_onoff= 1;
336 linger.l_linger= 0; /* By default on close() just drop the socket */
337 int error= setsockopt(server->fd, SOL_SOCKET, SO_LINGER,
338 &linger, (socklen_t)sizeof(struct linger));
339 (void)(error);
340 assert(error == 0);
341 }
342
343 if (server->root->flags.tcp_nodelay)
344 {
345 int flag= 1;
346
347 int error= setsockopt(server->fd, IPPROTO_TCP, TCP_NODELAY,
348 &flag, (socklen_t)sizeof(int));
349 (void)(error);
350 assert(error == 0);
351 }
352
353 if (server->root->flags.tcp_keepalive)
354 {
355 int flag= 1;
356
357 int error= setsockopt(server->fd, SOL_SOCKET, SO_KEEPALIVE,
358 &flag, (socklen_t)sizeof(int));
359 (void)(error);
360 assert(error == 0);
361 }
362
363 #ifdef TCP_KEEPIDLE
364 if (server->root->tcp_keepidle > 0)
365 {
366 int error= setsockopt(server->fd, IPPROTO_TCP, TCP_KEEPIDLE,
367 &server->root->tcp_keepidle, (socklen_t)sizeof(int));
368 (void)(error);
369 assert(error == 0);
370 }
371 #endif
372
373 if (server->root->send_size > 0)
374 {
375 int error= setsockopt(server->fd, SOL_SOCKET, SO_SNDBUF,
376 &server->root->send_size, (socklen_t)sizeof(int));
377 (void)(error);
378 assert(error == 0);
379 }
380
381 if (server->root->recv_size > 0)
382 {
383 int error= setsockopt(server->fd, SOL_SOCKET, SO_RCVBUF,
384 &server->root->recv_size, (socklen_t)sizeof(int));
385 (void)(error);
386 assert(error == 0);
387 }
388
389
390 /* libmemcached will always use nonblocking IO to avoid write deadlocks */
391 set_socket_nonblocking(server);
392 }
393
394 static memcached_return_t unix_socket_connect(org::libmemcached::Instance* server)
395 {
396 #ifndef WIN32
397 WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
398
399 if ((server->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
400 {
401 memcached_set_errno(*server, errno, NULL);
402 return MEMCACHED_CONNECTION_FAILURE;
403 }
404
405 struct sockaddr_un servAddr;
406
407 memset(&servAddr, 0, sizeof (struct sockaddr_un));
408 servAddr.sun_family= AF_UNIX;
409 strncpy(servAddr.sun_path, server->hostname, sizeof(servAddr.sun_path)); /* Copy filename */
410
411 do {
412 if (connect(server->fd, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0)
413 {
414 switch (errno)
415 {
416 case EINPROGRESS:
417 case EALREADY:
418 case EINTR:
419 continue;
420
421 case EISCONN: /* We were spinning waiting on connect */
422 {
423 assert(0); // Programmer error
424 break;
425 }
426
427 default:
428 WATCHPOINT_ERRNO(errno);
429 memcached_set_errno(*server, errno, MEMCACHED_AT);
430 return MEMCACHED_CONNECTION_FAILURE;
431 }
432 }
433 } while (0);
434 server->state= MEMCACHED_SERVER_STATE_CONNECTED;
435
436 WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
437
438 return MEMCACHED_SUCCESS;
439 #else
440 (void)server;
441 return MEMCACHED_NOT_SUPPORTED;
442 #endif
443 }
444
445 static memcached_return_t network_connect(org::libmemcached::Instance* server)
446 {
447 bool timeout_error_occured= false;
448
449 WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
450 WATCHPOINT_ASSERT(server->cursor_active_ == 0);
451
452 /*
453 We want to check both of these because if address_info_next has been fully tried, we want to do a new lookup to make sure we have picked up on any new DNS information.
454 */
455 if (server->address_info == NULL or server->address_info_next == NULL)
456 {
457 WATCHPOINT_ASSERT(server->state == MEMCACHED_SERVER_STATE_NEW);
458 server->address_info_next= NULL;
459 memcached_return_t rc= set_hostinfo(server);
460
461 if (memcached_failed(rc))
462 {
463 return rc;
464 }
465 }
466
467 if (server->address_info_next == NULL)
468 {
469 server->address_info_next= server->address_info;
470 server->state= MEMCACHED_SERVER_STATE_ADDRINFO;
471 }
472
473 /* Create the socket */
474 while (server->address_info_next and server->fd == INVALID_SOCKET)
475 {
476 /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
477 if (memcached_is_udp(server->root) and server->address_info_next->ai_family != AF_INET)
478 {
479 server->address_info_next= server->address_info_next->ai_next;
480 continue;
481 }
482
483 int type= server->address_info_next->ai_socktype;
484 if (HAVE_SOCK_CLOEXEC)
485 {
486 type|= SOCK_CLOEXEC;
487 }
488
489 if ((server->fd= socket(server->address_info_next->ai_family,
490 type,
491 server->address_info_next->ai_protocol)) < 0)
492 {
493 return memcached_set_errno(*server, get_socket_errno(), NULL);
494 }
495
496 if (HAVE_SOCK_CLOEXEC == 0)
497 {
498 #ifdef FD_CLOEXEC
499 int rval;
500 do
501 {
502 rval= fcntl (server->fd, F_SETFD, FD_CLOEXEC);
503 } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
504 #endif
505 }
506
507 set_socket_options(server);
508
509 /* connect to server */
510 if ((connect(server->fd, server->address_info_next->ai_addr, server->address_info_next->ai_addrlen) != SOCKET_ERROR))
511 {
512 server->state= MEMCACHED_SERVER_STATE_CONNECTED;
513 return MEMCACHED_SUCCESS;
514 }
515
516 /* An error occurred */
517 switch (get_socket_errno())
518 {
519 case ETIMEDOUT:
520 timeout_error_occured= true;
521 break;
522
523 case EAGAIN:
524 #if EWOULDBLOCK != EAGAIN
525 case EWOULDBLOCK:
526 #endif
527 case EINPROGRESS: // nonblocking mode - first return
528 case EALREADY: // nonblocking mode - subsequent returns
529 {
530 server->state= MEMCACHED_SERVER_STATE_IN_PROGRESS;
531 memcached_return_t rc= connect_poll(server);
532
533 if (memcached_success(rc))
534 {
535 server->state= MEMCACHED_SERVER_STATE_CONNECTED;
536 return MEMCACHED_SUCCESS;
537 }
538
539 // A timeout here is treated as an error, we will not retry
540 if (rc == MEMCACHED_TIMEOUT)
541 {
542 timeout_error_occured= true;
543 }
544 }
545 break;
546
547 case EISCONN: // we are connected :-)
548 WATCHPOINT_ASSERT(0); // This is a programmer's error
549 break;
550
551 case EINTR: // Special case, we retry ai_addr
552 WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
553 (void)closesocket(server->fd);
554 server->fd= INVALID_SOCKET;
555 continue;
556
557 default:
558 break;
559 }
560
561 WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
562 (void)closesocket(server->fd);
563 server->fd= INVALID_SOCKET;
564 server->address_info_next= server->address_info_next->ai_next;
565 }
566
567 WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
568
569 if (timeout_error_occured)
570 {
571 if (server->fd != INVALID_SOCKET)
572 {
573 (void)closesocket(server->fd);
574 server->fd= INVALID_SOCKET;
575 }
576 }
577
578 WATCHPOINT_STRING("Never got a good file descriptor");
579
580 if (memcached_has_current_error(*server))
581 {
582 return memcached_instance_error_return(server);
583 }
584
585 if (timeout_error_occured and server->state < MEMCACHED_SERVER_STATE_IN_PROGRESS)
586 {
587 return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT);
588 }
589
590 return memcached_set_error(*server, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT); /* The last error should be from connect() */
591 }
592
593
594 /*
595 backoff_handling()
596
597 Based on time/failure count fail the connect without trying. This prevents waiting in a state where
598 we get caught spending cycles just waiting.
599 */
600 static memcached_return_t backoff_handling(org::libmemcached::Instance* server, bool& in_timeout)
601 {
602 struct timeval curr_time;
603 bool _gettime_success= (gettimeofday(&curr_time, NULL) == 0);
604
605 /*
606 If we hit server_failure_limit then something is completely wrong about the server.
607
608 1) If autoeject is enabled we do that.
609 2) If not? We go into timeout again, there is much else to do :(
610 */
611 if (server->server_failure_counter >= server->root->server_failure_limit)
612 {
613 /*
614 We just auto_eject if we hit this point
615 */
616 if (_is_auto_eject_host(server->root))
617 {
618 set_last_disconnected_host(server);
619
620 // Retry dead servers if requested
621 if (_gettime_success and server->root->dead_timeout > 0)
622 {
623 server->next_retry= curr_time.tv_sec +server->root->dead_timeout;
624
625 // We only retry dead servers once before assuming failure again
626 server->server_failure_counter= server->root->server_failure_limit -1;
627 }
628
629 memcached_return_t rc;
630 if (memcached_failed(rc= run_distribution((memcached_st *)server->root)))
631 {
632 return memcached_set_error(*server, rc, MEMCACHED_AT, memcached_literal_param("Backoff handling failed during run_distribution"));
633 }
634
635 return memcached_set_error(*server, MEMCACHED_SERVER_MARKED_DEAD, MEMCACHED_AT);
636 }
637
638 server->state= MEMCACHED_SERVER_STATE_IN_TIMEOUT;
639
640 // Sanity check/setting
641 if (server->next_retry == 0)
642 {
643 server->next_retry= 1;
644 }
645 }
646
647 if (server->state == MEMCACHED_SERVER_STATE_IN_TIMEOUT)
648 {
649 /*
650 If next_retry is less then our current time, then we reset and try everything again.
651 */
652 if (_gettime_success and server->next_retry < curr_time.tv_sec)
653 {
654 server->state= MEMCACHED_SERVER_STATE_NEW;
655 }
656 else
657 {
658 return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT);
659 }
660
661 in_timeout= true;
662 }
663
664 return MEMCACHED_SUCCESS;
665 }
666
667 static memcached_return_t _memcached_connect(org::libmemcached::Instance* server, const bool set_last_disconnected)
668 {
669 assert(server);
670 if (server->fd != INVALID_SOCKET)
671 {
672 return MEMCACHED_SUCCESS;
673 }
674
675 LIBMEMCACHED_MEMCACHED_CONNECT_START();
676
677 bool in_timeout= false;
678 memcached_return_t rc;
679 if (memcached_failed(rc= backoff_handling(server, in_timeout)))
680 {
681 set_last_disconnected_host(server);
682 return rc;
683 }
684
685 if (LIBMEMCACHED_WITH_SASL_SUPPORT and server->root->sasl.callbacks and memcached_is_udp(server->root))
686 {
687 return memcached_set_error(*server, MEMCACHED_INVALID_HOST_PROTOCOL, MEMCACHED_AT, memcached_literal_param("SASL is not supported for UDP connections"));
688 }
689
690 if (server->hostname[0] == '/')
691 {
692 server->type= MEMCACHED_CONNECTION_UNIX_SOCKET;
693 }
694
695 /* We need to clean up the multi startup piece */
696 switch (server->type)
697 {
698 case MEMCACHED_CONNECTION_UDP:
699 case MEMCACHED_CONNECTION_TCP:
700 rc= network_connect(server);
701
702 if (LIBMEMCACHED_WITH_SASL_SUPPORT)
703 {
704 if (server->fd != INVALID_SOCKET and server->root->sasl.callbacks)
705 {
706 rc= memcached_sasl_authenticate_connection(server);
707 if (memcached_failed(rc) and server->fd != INVALID_SOCKET)
708 {
709 WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
710 (void)closesocket(server->fd);
711 server->fd= INVALID_SOCKET;
712 }
713 }
714 }
715 break;
716
717 case MEMCACHED_CONNECTION_UNIX_SOCKET:
718 rc= unix_socket_connect(server);
719 break;
720 }
721
722 if (memcached_success(rc))
723 {
724 server->mark_server_as_clean();
725 memcached_version_instance(server);
726 return rc;
727 }
728 else if (set_last_disconnected)
729 {
730 set_last_disconnected_host(server);
731 if (memcached_has_current_error(*server))
732 {
733 memcached_mark_server_for_timeout(server);
734 assert(memcached_failed(memcached_instance_error_return(server)));
735 }
736 else
737 {
738 memcached_set_error(*server, rc, MEMCACHED_AT);
739 memcached_mark_server_for_timeout(server);
740 }
741
742 LIBMEMCACHED_MEMCACHED_CONNECT_END();
743
744 if (in_timeout)
745 {
746 char buffer[1024];
747 int snprintf_length= snprintf(buffer, sizeof(buffer), "%s:%d", server->hostname, int(server->port()));
748 return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT, buffer, snprintf_length);
749 }
750 }
751
752 return rc;
753 }
754
755 memcached_return_t memcached_connect_try(org::libmemcached::Instance* server)
756 {
757 if (server and server->root and server->root->state.is_parsing)
758 {
759 return MEMCACHED_SUCCESS;
760 }
761
762 return _memcached_connect(server, false);
763 }
764
765 memcached_return_t memcached_connect(org::libmemcached::Instance* server)
766 {
767 return _memcached_connect(server, true);
768 }