Fix allocation on stat so that it uses malloc() since a user will need to use free...
[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
43 #ifndef SOCK_CLOEXEC
44 # define SOCK_CLOEXEC 0
45 #endif
46
47 #ifndef SOCK_NONBLOCK
48 # define SOCK_NONBLOCK 0
49 #endif
50
51 #ifndef FD_CLOEXEC
52 # define FD_CLOEXEC 0
53 #endif
54
55 #ifndef SO_NOSIGPIPE
56 # define SO_NOSIGPIPE 0
57 #endif
58
59 #ifndef TCP_NODELAY
60 # define TCP_NODELAY 0
61 #endif
62
63 #ifndef TCP_KEEPIDLE
64 # define TCP_KEEPIDLE 0
65 #endif
66
67 static memcached_return_t connect_poll(org::libmemcached::Instance* server)
68 {
69 struct pollfd fds[1];
70 fds[0].fd= server->fd;
71 fds[0].events= server->events();
72 fds[0].revents= 0;
73
74 size_t loop_max= 5;
75
76 if (server->root->poll_timeout == 0)
77 {
78 return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT);
79 }
80
81 while (--loop_max) // Should only loop on cases of ERESTART or EINTR
82 {
83 int number_of;
84 if ((number_of= poll(fds, 1, server->root->connect_timeout)) <= 0)
85 {
86 if (number_of == -1)
87 {
88 int local_errno= get_socket_errno(); // We cache in case closesocket() modifies errno
89 switch (local_errno)
90 {
91 #ifdef TARGET_OS_LINUX
92 case ERESTART:
93 #endif
94 case EINTR:
95 continue;
96
97 case EFAULT:
98 case ENOMEM:
99 return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT);
100
101 case EINVAL:
102 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"));
103
104 default: // This should not happen
105 if (fds[0].revents & POLLERR)
106 {
107 int err;
108 socklen_t len= sizeof(err);
109 if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == 0)
110 {
111 if (err == 0)
112 {
113 // This should never happen, if it does? Punt.
114 continue;
115 }
116 local_errno= err;
117 }
118 }
119
120 assert_msg(server->fd != INVALID_SOCKET, "poll() was passed an invalid file descriptor");
121 (void)closesocket(server->fd);
122 server->fd= INVALID_SOCKET;
123 server->state= MEMCACHED_SERVER_STATE_NEW;
124
125 return memcached_set_errno(*server, local_errno, MEMCACHED_AT);
126 }
127 }
128 assert(number_of == 0);
129
130 server->io_wait_count.timeouts++;
131 return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT);
132 }
133
134 #if 0
135 server->revents(fds[0].revents);
136 #endif
137
138 if (fds[0].revents & POLLERR or
139 fds[0].revents & POLLHUP or
140 fds[0].revents & POLLNVAL)
141 {
142 int err;
143 socklen_t len= sizeof (err);
144 if (getsockopt(fds[0].fd, SOL_SOCKET, SO_ERROR, (char*)&err, &len) == 0)
145 {
146 // We check the value to see what happened wth the socket.
147 if (err == 0)
148 {
149 return MEMCACHED_SUCCESS;
150 }
151 errno= err;
152 }
153
154 return memcached_set_errno(*server, err, MEMCACHED_AT);
155 }
156 assert(fds[0].revents & POLLIN or fds[0].revents & POLLOUT);
157
158 return MEMCACHED_SUCCESS;
159 }
160
161 // This should only be possible from ERESTART or EINTR;
162 return memcached_set_errno(*server, get_socket_errno(), MEMCACHED_AT);
163 }
164
165 static memcached_return_t set_hostinfo(org::libmemcached::Instance* server)
166 {
167 assert(server->type != MEMCACHED_CONNECTION_UNIX_SOCKET);
168 if (server->address_info)
169 {
170 freeaddrinfo(server->address_info);
171 server->address_info= NULL;
172 server->address_info_next= NULL;
173 }
174
175 char str_port[MEMCACHED_NI_MAXSERV];
176 int length= snprintf(str_port, MEMCACHED_NI_MAXSERV, "%u", uint32_t(server->port()));
177 if (length >= MEMCACHED_NI_MAXSERV or length <= 0)
178 {
179 return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT,
180 memcached_literal_param("snprintf(NI_MAXSERV)"));
181 }
182
183 struct addrinfo hints;
184 memset(&hints, 0, sizeof(struct addrinfo));
185
186 #if 0
187 hints.ai_family= AF_INET;
188 #endif
189 if (memcached_is_udp(server->root))
190 {
191 hints.ai_protocol= IPPROTO_UDP;
192 hints.ai_socktype= SOCK_DGRAM;
193 }
194 else
195 {
196 hints.ai_socktype= SOCK_STREAM;
197 hints.ai_protocol= IPPROTO_TCP;
198 }
199
200 assert(server->address_info == NULL);
201 assert(server->address_info_next == NULL);
202 int errcode;
203 switch(errcode= getaddrinfo(server->hostname, str_port, &hints, &server->address_info))
204 {
205 case 0:
206 break;
207
208 case EAI_AGAIN:
209 if (server->address_info)
210 {
211 freeaddrinfo(server->address_info);
212 server->address_info= NULL;
213 server->address_info_next= NULL;
214 }
215 return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT, memcached_string_make_from_cstr(gai_strerror(errcode)));
216
217 case EAI_SYSTEM:
218 if (server->address_info)
219 {
220 freeaddrinfo(server->address_info);
221 server->address_info= NULL;
222 server->address_info_next= NULL;
223 }
224 return memcached_set_errno(*server, errno, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_SYSTEM)"));
225
226 case EAI_BADFLAGS:
227 if (server->address_info)
228 {
229 freeaddrinfo(server->address_info);
230 server->address_info= NULL;
231 server->address_info_next= NULL;
232 }
233 return memcached_set_error(*server, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_BADFLAGS)"));
234
235 case EAI_MEMORY:
236 if (server->address_info)
237 {
238 freeaddrinfo(server->address_info);
239 server->address_info= NULL;
240 server->address_info_next= NULL;
241 }
242 return memcached_set_error(*server, MEMCACHED_MEMORY_ALLOCATION_FAILURE, MEMCACHED_AT, memcached_literal_param("getaddrinfo(EAI_MEMORY)"));
243
244 default:
245 {
246 if (server->address_info)
247 {
248 freeaddrinfo(server->address_info);
249 server->address_info= NULL;
250 server->address_info_next= NULL;
251 }
252 return memcached_set_error(*server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT, memcached_string_make_from_cstr(gai_strerror(errcode)));
253 }
254 }
255 server->address_info_next= server->address_info;
256 server->state= MEMCACHED_SERVER_STATE_ADDRINFO;
257
258 return MEMCACHED_SUCCESS;
259 }
260
261 static inline void set_socket_nonblocking(org::libmemcached::Instance* server)
262 {
263 #ifdef WIN32
264 u_long arg= 1;
265 if (ioctlsocket(server->fd, FIONBIO, &arg) == SOCKET_ERROR)
266 {
267 memcached_set_errno(*server, get_socket_errno(), NULL);
268 }
269 #else
270 int flags;
271
272 if (SOCK_NONBLOCK == 0)
273 {
274 do
275 {
276 flags= fcntl(server->fd, F_GETFL, 0);
277 } while (flags == -1 && (errno == EINTR || errno == EAGAIN));
278
279 if (flags == -1)
280 {
281 memcached_set_errno(*server, errno, NULL);
282 }
283 else if ((flags & O_NONBLOCK) == 0)
284 {
285 int rval;
286
287 do
288 {
289 rval= fcntl(server->fd, F_SETFL, flags | O_NONBLOCK);
290 } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
291
292 if (rval == -1)
293 {
294 memcached_set_errno(*server, errno, NULL);
295 }
296 }
297 }
298 #endif
299 }
300
301 static bool set_socket_options(org::libmemcached::Instance* server)
302 {
303 assert_msg(server->fd != INVALID_SOCKET, "invalid socket was passed to set_socket_options()");
304
305 #ifdef HAVE_FCNTL
306 // If SOCK_CLOEXEC exists then we don't need to call the following
307 if (SOCK_CLOEXEC == 0)
308 {
309 if (FD_CLOEXEC)
310 {
311 int flags;
312 do
313 {
314 flags= fcntl(server->fd, F_GETFD, 0);
315 } while (flags == -1 and (errno == EINTR or errno == EAGAIN));
316
317 if (flags != -1)
318 {
319 int rval;
320 do
321 {
322 rval= fcntl (server->fd, F_SETFD, flags | FD_CLOEXEC);
323 } while (rval == -1 && (errno == EINTR or errno == EAGAIN));
324 // we currently ignore the case where rval is -1
325 }
326 }
327 }
328 #endif
329
330 if (memcached_is_udp(server->root))
331 {
332 return true;
333 }
334
335 #ifdef HAVE_SNDTIMEO
336 if (server->root->snd_timeout > 0)
337 {
338 struct timeval waittime;
339
340 waittime.tv_sec= server->root->snd_timeout / 1000000;
341 waittime.tv_usec= server->root->snd_timeout % 1000000;
342
343 int error= setsockopt(server->fd, SOL_SOCKET, SO_SNDTIMEO,
344 (char*)&waittime, (socklen_t)sizeof(struct timeval));
345 (void)error;
346 assert(error == 0);
347 }
348 #endif
349
350 #ifdef HAVE_RCVTIMEO
351 if (server->root->rcv_timeout > 0)
352 {
353 struct timeval waittime;
354
355 waittime.tv_sec= server->root->rcv_timeout / 1000000;
356 waittime.tv_usec= server->root->rcv_timeout % 1000000;
357
358 int error= setsockopt(server->fd, SOL_SOCKET, SO_RCVTIMEO,
359 (char*)&waittime, (socklen_t)sizeof(struct timeval));
360 (void)(error);
361 assert(error == 0);
362 }
363 #endif
364
365
366 #if defined(SO_NOSIGPIPE)
367 if (SO_NOSIGPIPE)
368 {
369 int set= 1;
370 int error= setsockopt(server->fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
371
372 assert(error == 0);
373
374 // This is not considered a fatal error
375 if (error == -1)
376 {
377 #if 0
378 perror("setsockopt(SO_NOSIGPIPE)");
379 #endif
380 }
381 }
382 #endif
383
384 if (server->root->flags.no_block)
385 {
386 struct linger linger;
387
388 linger.l_onoff= 1;
389 linger.l_linger= 0; /* By default on close() just drop the socket */
390 int error= setsockopt(server->fd, SOL_SOCKET, SO_LINGER,
391 (char*)&linger, (socklen_t)sizeof(struct linger));
392 (void)(error);
393 assert(error == 0);
394 }
395
396 if (TCP_NODELAY)
397 {
398 if (server->root->flags.tcp_nodelay)
399 {
400 int flag= 1;
401
402 int error= setsockopt(server->fd, IPPROTO_TCP, TCP_NODELAY,
403 (char*)&flag, (socklen_t)sizeof(int));
404 (void)(error);
405 assert(error == 0);
406 }
407 }
408
409 if (server->root->flags.tcp_keepalive)
410 {
411 int flag= 1;
412
413 int error= setsockopt(server->fd, SOL_SOCKET, SO_KEEPALIVE,
414 (char*)&flag, (socklen_t)sizeof(int));
415 (void)(error);
416 assert(error == 0);
417 }
418
419 if (TCP_KEEPIDLE)
420 {
421 if (server->root->tcp_keepidle > 0)
422 {
423 int error= setsockopt(server->fd, IPPROTO_TCP, TCP_KEEPIDLE,
424 (char*)&server->root->tcp_keepidle, (socklen_t)sizeof(int));
425 (void)(error);
426 assert(error == 0);
427 }
428 }
429
430 if (server->root->send_size > 0)
431 {
432 int error= setsockopt(server->fd, SOL_SOCKET, SO_SNDBUF,
433 (char*)&server->root->send_size, (socklen_t)sizeof(int));
434 (void)(error);
435 assert(error == 0);
436 }
437
438 if (server->root->recv_size > 0)
439 {
440 int error= setsockopt(server->fd, SOL_SOCKET, SO_RCVBUF,
441 (char*)&server->root->recv_size, (socklen_t)sizeof(int));
442 (void)(error);
443 assert(error == 0);
444 }
445
446 /* libmemcached will always use nonblocking IO to avoid write deadlocks */
447 set_socket_nonblocking(server);
448
449 return true;
450 }
451
452 static memcached_return_t unix_socket_connect(org::libmemcached::Instance* server)
453 {
454 #ifndef WIN32
455 WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
456
457 do {
458 int type= SOCK_STREAM;
459 if (SOCK_CLOEXEC)
460 {
461 type|= SOCK_CLOEXEC;
462 }
463
464 if (SOCK_NONBLOCK)
465 {
466 type|= SOCK_NONBLOCK;
467 }
468
469 if ((server->fd= socket(AF_UNIX, type, 0)) < 0)
470 {
471 return memcached_set_errno(*server, errno, NULL);
472 }
473
474 struct sockaddr_un servAddr;
475
476 memset(&servAddr, 0, sizeof (struct sockaddr_un));
477 servAddr.sun_family= AF_UNIX;
478 strncpy(servAddr.sun_path, server->hostname, sizeof(servAddr.sun_path)); /* Copy filename */
479
480 if (connect(server->fd, (struct sockaddr *)&servAddr, sizeof(servAddr)) < 0)
481 {
482 switch (errno)
483 {
484 case EINPROGRESS:
485 case EALREADY:
486 server->events(POLLOUT);
487 break;
488
489 case EINTR:
490 (void)closesocket(server->fd);
491 server->fd= INVALID_SOCKET;
492 continue;
493
494 case EISCONN: /* We were spinning waiting on connect */
495 {
496 assert(0); // Programmer error
497 (void)closesocket(server->fd);
498 server->fd= INVALID_SOCKET;
499 continue;
500 }
501
502 default:
503 WATCHPOINT_ERRNO(errno);
504 (void)closesocket(server->fd);
505 server->fd= INVALID_SOCKET;
506 return memcached_set_errno(*server, errno, MEMCACHED_AT);
507 }
508 }
509 } while (0);
510 server->state= MEMCACHED_SERVER_STATE_CONNECTED;
511
512 WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
513
514 return MEMCACHED_SUCCESS;
515 #else
516 (void)server;
517 return MEMCACHED_NOT_SUPPORTED;
518 #endif
519 }
520
521 static memcached_return_t network_connect(org::libmemcached::Instance* server)
522 {
523 bool timeout_error_occured= false;
524
525 WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
526 WATCHPOINT_ASSERT(server->cursor_active_ == 0);
527
528 /*
529 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.
530 */
531 if (server->address_info == NULL or server->address_info_next == NULL)
532 {
533 WATCHPOINT_ASSERT(server->state == MEMCACHED_SERVER_STATE_NEW);
534 server->address_info_next= NULL;
535 memcached_return_t rc= set_hostinfo(server);
536
537 if (memcached_failed(rc))
538 {
539 return rc;
540 }
541 }
542
543 if (server->address_info_next == NULL)
544 {
545 server->address_info_next= server->address_info;
546 server->state= MEMCACHED_SERVER_STATE_ADDRINFO;
547 }
548
549 /* Create the socket */
550 while (server->address_info_next and server->fd == INVALID_SOCKET)
551 {
552 /* Memcache server does not support IPV6 in udp mode, so skip if not ipv4 */
553 if (memcached_is_udp(server->root) and server->address_info_next->ai_family != AF_INET)
554 {
555 server->address_info_next= server->address_info_next->ai_next;
556 continue;
557 }
558
559 int type= server->address_info_next->ai_socktype;
560 if (SOCK_CLOEXEC)
561 {
562 type|= SOCK_CLOEXEC;
563 }
564
565 if (SOCK_NONBLOCK)
566 {
567 type|= SOCK_NONBLOCK;
568 }
569
570 server->fd= socket(server->address_info_next->ai_family,
571 type,
572 server->address_info_next->ai_protocol);
573
574 if (int(server->fd) == SOCKET_ERROR)
575 {
576 return memcached_set_errno(*server, get_socket_errno(), NULL);
577 }
578
579 if (set_socket_options(server) == false)
580 {
581 (void)closesocket(server->fd);
582 return MEMCACHED_CONNECTION_FAILURE;
583 }
584
585 /* connect to server */
586 if ((connect(server->fd, server->address_info_next->ai_addr, server->address_info_next->ai_addrlen) != SOCKET_ERROR))
587 {
588 server->state= MEMCACHED_SERVER_STATE_CONNECTED;
589 return MEMCACHED_SUCCESS;
590 }
591
592 /* An error occurred */
593 switch (get_socket_errno())
594 {
595 case ETIMEDOUT:
596 timeout_error_occured= true;
597 break;
598
599 case EAGAIN:
600 #if EWOULDBLOCK != EAGAIN
601 case EWOULDBLOCK:
602 #endif
603 case EINPROGRESS: // nonblocking mode - first return
604 case EALREADY: // nonblocking mode - subsequent returns
605 {
606 server->events(POLLOUT);
607 server->state= MEMCACHED_SERVER_STATE_IN_PROGRESS;
608 memcached_return_t rc= connect_poll(server);
609
610 if (memcached_success(rc))
611 {
612 server->state= MEMCACHED_SERVER_STATE_CONNECTED;
613 return MEMCACHED_SUCCESS;
614 }
615
616 // A timeout here is treated as an error, we will not retry
617 if (rc == MEMCACHED_TIMEOUT)
618 {
619 timeout_error_occured= true;
620 }
621 }
622 break;
623
624 case EISCONN: // we are connected :-)
625 WATCHPOINT_ASSERT(0); // This is a programmer's error
626 break;
627
628 case EINTR: // Special case, we retry ai_addr
629 WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
630 (void)closesocket(server->fd);
631 server->fd= INVALID_SOCKET;
632 continue;
633
634 case ECONNREFUSED:
635 // Probably not running service
636
637 default:
638 break;
639 }
640
641 WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
642 (void)closesocket(server->fd);
643 server->fd= INVALID_SOCKET;
644 server->address_info_next= server->address_info_next->ai_next;
645 }
646
647 WATCHPOINT_ASSERT(server->fd == INVALID_SOCKET);
648
649 if (timeout_error_occured)
650 {
651 if (server->fd != INVALID_SOCKET)
652 {
653 (void)closesocket(server->fd);
654 server->fd= INVALID_SOCKET;
655 }
656 }
657
658 WATCHPOINT_STRING("Never got a good file descriptor");
659
660 if (memcached_has_current_error(*server))
661 {
662 return memcached_instance_error_return(server);
663 }
664
665 if (timeout_error_occured and server->state < MEMCACHED_SERVER_STATE_IN_PROGRESS)
666 {
667 return memcached_set_error(*server, MEMCACHED_TIMEOUT, MEMCACHED_AT);
668 }
669
670 return memcached_set_error(*server, MEMCACHED_CONNECTION_FAILURE, MEMCACHED_AT); /* The last error should be from connect() */
671 }
672
673
674 /*
675 backoff_handling()
676
677 Based on time/failure count fail the connect without trying. This prevents waiting in a state where
678 we get caught spending cycles just waiting.
679 */
680 static memcached_return_t backoff_handling(org::libmemcached::Instance* server, bool& in_timeout)
681 {
682 struct timeval curr_time;
683 bool _gettime_success= (gettimeofday(&curr_time, NULL) == 0);
684
685 /*
686 If we hit server_failure_limit then something is completely wrong about the server.
687
688 1) If autoeject is enabled we do that.
689 2) If not? We go into timeout again, there is much else to do :(
690 */
691 if (server->server_failure_counter >= server->root->server_failure_limit)
692 {
693 /*
694 We just auto_eject if we hit this point
695 */
696 if (_is_auto_eject_host(server->root))
697 {
698 set_last_disconnected_host(server);
699
700 // Retry dead servers if requested
701 if (_gettime_success and server->root->dead_timeout > 0)
702 {
703 server->next_retry= curr_time.tv_sec +server->root->dead_timeout;
704
705 // We only retry dead servers once before assuming failure again
706 server->server_failure_counter= server->root->server_failure_limit -1;
707 }
708
709 memcached_return_t rc;
710 if (memcached_failed(rc= run_distribution((memcached_st *)server->root)))
711 {
712 return memcached_set_error(*server, rc, MEMCACHED_AT, memcached_literal_param("Backoff handling failed during run_distribution"));
713 }
714
715 return memcached_set_error(*server, MEMCACHED_SERVER_MARKED_DEAD, MEMCACHED_AT);
716 }
717
718 server->state= MEMCACHED_SERVER_STATE_IN_TIMEOUT;
719
720 // Sanity check/setting
721 if (server->next_retry == 0)
722 {
723 server->next_retry= 1;
724 }
725 }
726
727 if (server->state == MEMCACHED_SERVER_STATE_IN_TIMEOUT)
728 {
729 /*
730 If next_retry is less then our current time, then we reset and try everything again.
731 */
732 if (_gettime_success and server->next_retry < curr_time.tv_sec)
733 {
734 server->state= MEMCACHED_SERVER_STATE_NEW;
735 }
736 else
737 {
738 return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT);
739 }
740
741 in_timeout= true;
742 }
743
744 return MEMCACHED_SUCCESS;
745 }
746
747 static memcached_return_t _memcached_connect(org::libmemcached::Instance* server, const bool set_last_disconnected)
748 {
749 assert(server);
750 if (server->fd != INVALID_SOCKET)
751 {
752 return MEMCACHED_SUCCESS;
753 }
754
755 LIBMEMCACHED_MEMCACHED_CONNECT_START();
756
757 bool in_timeout= false;
758 memcached_return_t rc;
759 if (memcached_failed(rc= backoff_handling(server, in_timeout)))
760 {
761 set_last_disconnected_host(server);
762 return rc;
763 }
764
765 if (LIBMEMCACHED_WITH_SASL_SUPPORT and server->root->sasl.callbacks and memcached_is_udp(server->root))
766 {
767 return memcached_set_error(*server, MEMCACHED_INVALID_HOST_PROTOCOL, MEMCACHED_AT, memcached_literal_param("SASL is not supported for UDP connections"));
768 }
769
770 if (server->hostname[0] == '/')
771 {
772 server->type= MEMCACHED_CONNECTION_UNIX_SOCKET;
773 }
774
775 /* We need to clean up the multi startup piece */
776 switch (server->type)
777 {
778 case MEMCACHED_CONNECTION_UDP:
779 case MEMCACHED_CONNECTION_TCP:
780 rc= network_connect(server);
781
782 if (LIBMEMCACHED_WITH_SASL_SUPPORT)
783 {
784 if (server->fd != INVALID_SOCKET and server->root->sasl.callbacks)
785 {
786 rc= memcached_sasl_authenticate_connection(server);
787 fprintf(stderr, "%s:%d %s\n", __FILE__, __LINE__, memcached_strerror(NULL, rc));
788 if (memcached_failed(rc) and server->fd != INVALID_SOCKET)
789 {
790 WATCHPOINT_ASSERT(server->fd != INVALID_SOCKET);
791 (void)closesocket(server->fd);
792 server->fd= INVALID_SOCKET;
793 }
794 }
795 }
796 break;
797
798 case MEMCACHED_CONNECTION_UNIX_SOCKET:
799 rc= unix_socket_connect(server);
800 break;
801 }
802
803 if (memcached_success(rc))
804 {
805 server->mark_server_as_clean();
806 memcached_version_instance(server);
807 return rc;
808 }
809 else if (set_last_disconnected)
810 {
811 set_last_disconnected_host(server);
812 if (memcached_has_current_error(*server))
813 {
814 memcached_mark_server_for_timeout(server);
815 assert(memcached_failed(memcached_instance_error_return(server)));
816 }
817 else
818 {
819 memcached_set_error(*server, rc, MEMCACHED_AT);
820 memcached_mark_server_for_timeout(server);
821 }
822
823 LIBMEMCACHED_MEMCACHED_CONNECT_END();
824
825 if (in_timeout)
826 {
827 char buffer[1024];
828 int snprintf_length= snprintf(buffer, sizeof(buffer), "%s:%d", server->hostname, int(server->port()));
829 return memcached_set_error(*server, MEMCACHED_SERVER_TEMPORARILY_DISABLED, MEMCACHED_AT, buffer, snprintf_length);
830 }
831 }
832
833 return rc;
834 }
835
836 memcached_return_t memcached_connect(org::libmemcached::Instance* server)
837 {
838 return _memcached_connect(server, true);
839 }