This cleans up some accidental linking we were getting with curses.
authorBrian Aker <brian@tangent.org>
Sat, 2 Apr 2011 22:27:03 +0000 (15:27 -0700)
committerBrian Aker <brian@tangent.org>
Sat, 2 Apr 2011 22:27:03 +0000 (15:27 -0700)
This also modifies the behavior of DNS caching such that we walk the hosts
and can move to a new host. It also removes any chance of us leaking the DNS
information.

libmemcached/connect.c
libmemcached/memcached.c
libmemcached/memcached.hpp
libmemcached/server.c
libmemcached/server.h
libtest/server.c
m4/pandora_drizzle_build.m4 [deleted file]
m4/pandora_have_libreadline.m4 [deleted file]
tests/mem_functions.c

index 58a6cfd2756f037ff3d130e981c40fcfeb5674fc..5e0c046bd797cdc6ab97d0e67fde5bedcbc1bed9 100644 (file)
@@ -86,10 +86,15 @@ static memcached_return_t connect_poll(memcached_server_st *ptr)
 
 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;
+
+  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)
@@ -97,7 +102,9 @@ static memcached_return_t set_hostinfo(memcached_server_st *server)
 
   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;
@@ -109,9 +116,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)
     {
@@ -137,12 +145,7 @@ static memcached_return_t set_hostinfo(memcached_server_st *server)
     }
   }
 
-  if (server->address_info)
-  {
-    freeaddrinfo(server->address_info);
-    server->address_info= NULL;
-  }
-  server->address_info= ai;
+  server->address_info_next= server->address_info;
 
   return MEMCACHED_SUCCESS;
 }
@@ -370,34 +373,29 @@ static memcached_return_t network_connect(memcached_server_st *ptr)
 {
   bool timeout_error_occured= false;
 
-
   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= get_socket_errno();
       WATCHPOINT_ERRNO(get_socket_errno());
@@ -407,40 +405,43 @@ static memcached_return_t network_connect(memcached_server_st *ptr)
     (void)set_socket_options(ptr);
 
     /* connect to server */
-    if ((connect(ptr->fd, use->ai_addr, use->ai_addrlen) != SOCKET_ERROR))
+    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= get_socket_errno();
-    if (ptr->cached_errno == EWOULDBLOCK ||
-        ptr->cached_errno == EINPROGRESS || /* nonblocking mode - first return, */
-        ptr->cached_errno == EALREADY) /* nonblocking mode - subsequent returns */
+    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 (get_socket_errno() == EISCONN) /* we are connected :-) */
-    {
+        if (rc == MEMCACHED_SUCCESS)
+          break;
+      }
+
+    case EISCONN: // we are connected :-)
       break;
-    }
-    else if (get_socket_errno() == EINTR) // Special case, we retry ai_addr
-    {
+
+    case EINTR: // Special case, we retry ai_addr
       (void)closesocket(ptr->fd);
       ptr->fd= INVALID_SOCKET;
       continue;
-    }
 
-    (void)closesocket(ptr->fd);
-    ptr->fd= INVALID_SOCKET;
-    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 == INVALID_SOCKET)
index 149437af2d0b21af5ffef2ac992220bea1704242..3d2539eb4c25668358ded45085efe86f6130a8ec 100644 (file)
@@ -55,7 +55,6 @@ static const memcached_st global_copy= {
     .reuse_memory= false,
     .support_cas= false,
     .tcp_nodelay= false,
-    .use_cache_lookups= false,
     .use_sort_hosts= false,
     .use_udp= false,
     .verify_key= false,
index f9d5756cbac67150bc5335f5788c378e25f3df67..55f96c7ea7a18952142d21ae3d0963b5e827e295 100644 (file)
@@ -12,6 +12,7 @@
  * @brief Libmemcached C++ interface
  */
 
+#pragma once
 #ifndef LIBMEMCACHEDPP_H
 #define LIBMEMCACHEDPP_H
 
index 97b0b27c865ccdd2faf1f5728507c75a8b5dfd98..7b9b2eefbbad5b9c287c1b9a08de47cf257647ac 100644 (file)
 /*
   This is a partial implementation for fetching/creating memcached_server_st objects.
 */
-#include "common.h"
+#include <libmemcached/common.h>
 
 static inline void _server_init(memcached_server_st *self, const memcached_st *root,
                                 const char *hostname, in_port_t port,
                                 uint32_t weight, memcached_connection_t type)
 {
-  self->options.sockaddr_inited= false;
   self->options.is_shutting_down= false;
   self->number_of_hosts= 0;
   self->cursor_active= 0;
@@ -42,6 +41,7 @@ static inline void _server_init(memcached_server_st *self, const memcached_st *r
   self->read_data_length= 0;
   self->write_buffer_offset= 0;
   self->address_info= NULL;
+  self->address_info_next= NULL;
 
   if (root)
   {
index aadd690fe0714e1b72e77b1081c4827ed074ca46..b08720148f79476f1447a20bc5ca37939b00b34e 100644 (file)
@@ -17,7 +17,6 @@ struct memcached_server_st {
   struct {
     bool is_allocated:1;
     bool is_initialized:1;
-    bool sockaddr_inited:1;
     bool is_shutting_down:1;
   } options;
   uint32_t number_of_hosts;
@@ -46,6 +45,7 @@ struct memcached_server_st {
   size_t read_data_length;
   size_t write_buffer_offset;
   struct addrinfo *address_info;
+  struct addrinfo *address_info_next;
   time_t next_retry;
   const memcached_st *root;
   uint64_t limit_maxbytes;
index c96ffb5153d546cab133f2cf7e1f230d55cc1719..31238fe64e4c0808ba614e559e3355664a4eb1f5 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/time.h>
 #include <time.h>
 #include <unistd.h>
+#include <errno.h>
 
 #include <libmemcached/memcached.h>
 #include <libmemcached/util.h>
@@ -45,6 +46,27 @@ static void global_sleep(void)
 #endif
 }
 
+static bool wait_for_file(const char *filename)
+{
+  uint32_t timeout= 6;
+  uint32_t waited;
+  uint32_t this_wait;
+  uint32_t retry;
+
+  for (waited= 0, retry= 1; ; retry++, waited+= this_wait)
+  {
+    if ((! access(filename, R_OK)) || (waited >= timeout))
+    {
+      return true;
+    }
+
+    this_wait= retry * retry / 3 + 1;
+    sleep(this_wait);
+  }
+
+  return false;
+}
+
 static void kill_file(const char *file_buffer)
 {
   FILE *fp;
@@ -179,7 +201,21 @@ void server_startup(server_startup_st *construct)
             }
             fclose(file);
           }
-          global_sleep();
+          switch (errno)
+          {
+          default:
+            fprintf(stderr, "%s\n", strerror(errno));
+            abort();
+          case ENOENT:
+          case EINTR:
+          case EACCES:
+            break;
+          }
+
+          if (! wait_for_file(buffer))
+          {
+            abort();
+          }
         }
 
         bool was_started= false;
diff --git a/m4/pandora_drizzle_build.m4 b/m4/pandora_drizzle_build.m4
deleted file mode 100644 (file)
index 54f946f..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-dnl  Copyright (C) 2009 Sun Microsystems, Inc.
-dnl This file is free software; Sun Microsystems, Inc.
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-dnl Check for all of the headers and libs that Drizzle needs. We check all
-dnl of these for plugins too, to ensure that all of the appropriate defines
-dnl are set.
-
-AC_DEFUN([PANDORA_DRIZZLE_BUILD],[
-
-  AC_STRUCT_TM
-
-  AC_FUNC_ALLOCA
-  AC_FUNC_UTIME_NULL
-  AC_FUNC_VPRINTF
-
-  PANDORA_WORKING_FDATASYNC
-
-  AC_CHECK_FUNCS(\
-    gethrtime \
-    setupterm \
-    backtrace \
-    backtrace_symbols \
-    backtrace_symbols_fd)
-
-  AC_HEADER_STAT
-  AC_HEADER_DIRENT
-  AC_HEADER_STDC
-  AC_HEADER_SYS_WAIT
-  AC_HEADER_STDBOOL
-
-  AC_CHECK_HEADERS(sys/types.h sys/fpu.h fpu_control.h ieeefp.h)
-  AC_CHECK_HEADERS(select.h sys/select.h)
-  AC_CHECK_HEADERS(utime.h sys/utime.h )
-  AC_CHECK_HEADERS(synch.h sys/mman.h)
-  AC_CHECK_HEADERS(sched.h)
-  AC_CHECK_HEADERS(sys/prctl.h)
-  AC_CHECK_HEADERS(execinfo.h)
-  AC_CHECK_HEADERS(locale.h)
-  AC_CHECK_HEADERS(termcap.h termio.h termios.h asm/termbits.h)
-  AC_CHECK_HEADERS(paths.h)
-
-  
-  #--------------------------------------------------------------------
-  # Check for system libraries. Adds the library to $LIBS
-  # and defines HAVE_LIBM etc
-  #--------------------------------------------------------------------
-  
-    # For the sched_yield() function on Solaris
-  AC_CHECK_FUNC(sched_yield, [],
-    [AC_CHECK_LIB(posix4, [sched_yield],
-      [AC_DEFINE(HAVE_SCHED_YIELD, 1, [Have sched_yield function]) LIBS="$LIBS -lposix4"])])
-  
-  AS_IF([test "$ac_cv_header_termio_h" = "no" -a "$ac_cv_header_termios_h" = "no"],[
-    AC_CHECK_FUNC(gtty, [], [AC_CHECK_LIB(compat, gtty)])
-  ])
-  
-  AC_CHECK_HEADERS([curses.h term.h],[],[],[[
-    #ifdef HAVE_CURSES_H
-    # include <curses.h>
-    #endif
-  ]])
-  AC_CHECK_TYPES([uint, ulong])
-
-  PANDORA_REQUIRE_BISON
-
-  PANDORA_CXX_DEMANGLE
-  PANDORA_REQUIRE_BOOST([1.38])
-  PANDORA_REQUIRE_BOOST_PROGRAM_OPTIONS
-  PANDORA_REQUIRE_BOOST_THREAD
-  PANDORA_REQUIRE_BOOST_REGEX
-  PANDORA_REQUIRE_BOOST_DATE_TIME
-  PANDORA_REQUIRE_BOOST_FILESYSTEM
-  PANDORA_REQUIRE_BOOST_IOSTREAMS
-
-])
diff --git a/m4/pandora_have_libreadline.m4 b/m4/pandora_have_libreadline.m4
deleted file mode 100644 (file)
index b49e97d..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-#
-# SYNOPSIS
-#
-#   PANDORA_HAVE_LIBREADLINE
-#
-# DESCRIPTION
-#
-#   Searches for a readline compatible library. If found, defines
-#   `HAVE_LIBREADLINE'. If the found library has the `add_history'
-#   function, sets also `HAVE_READLINE_HISTORY'. Also checks for the
-#   locations of the necessary include files and sets `HAVE_READLINE_H'
-#   or `HAVE_READLINE_READLINE_H' and `HAVE_READLINE_HISTORY_H' or
-#   'HAVE_HISTORY_H' if the corresponding include files exists.
-#
-#   The libraries that may be readline compatible are `libedit',
-#   `libeditline' and `libreadline'. Sometimes we need to link a
-#   termcap library for readline to work, this macro tests these cases
-#   too by trying to link with `libtermcap', `libcurses' or
-#   `libncurses' before giving up.
-#
-#   Here is an example of how to use the information provided by this
-#   macro to perform the necessary includes or declarations in a C
-#   file:
-#
-#     #ifdef HAVE_LIBREADLINE
-#     #  if defined(HAVE_READLINE_READLINE_H)
-#     #    include <readline/readline.h>
-#     #  elif defined(HAVE_READLINE_H)
-#     #    include <readline.h>
-#     #  else /* !defined(HAVE_READLINE_H) */
-#     extern char *readline ();
-#     #  endif /* !defined(HAVE_READLINE_H) */
-#     char *cmdline = NULL;
-#     #else /* !defined(HAVE_READLINE_READLINE_H) */
-#       /* no readline */
-#     #endif /* HAVE_LIBREADLINE */
-#
-#     #ifdef HAVE_READLINE_HISTORY
-#     #  if defined(HAVE_READLINE_HISTORY_H)
-#     #    include <readline/history.h>
-#     #  elif defined(HAVE_HISTORY_H)
-#     #    include <history.h>
-#     #  else /* !defined(HAVE_HISTORY_H) */
-#     extern void add_history ();
-#     extern int write_history ();
-#     extern int read_history ();
-#     #  endif /* defined(HAVE_READLINE_HISTORY_H) */
-#       /* no history */
-#     #endif /* HAVE_READLINE_HISTORY */
-#
-# LAST MODIFICATION
-#
-#   2009-11-17
-#
-# Based on VL_LIB_READLINE from  Ville Laurikari
-#
-# COPYLEFT
-#
-#   Copyright (C) 2009 Monty Taylor
-#   Copyright (C) 2002 Ville Laurikari <vl@iki.fi>
-#
-#   Copying and distribution of this file, with or without
-#   modification, are permitted in any medium without royalty provided
-#   the copyright notice and this notice are preserved.
-
-AC_DEFUN([PANDORA_CHECK_TIOCGWINSZ],[
-  AC_CACHE_CHECK([for TIOCGWINSZ in sys/ioctl.h],
-    [pandora_cv_tiocgwinsz_in_ioctl],[
-    AC_COMPILE_IFELSE([
-      AC_LANG_PROGRAM([[
-#include <sys/types.h>
-#include <sys/ioctl.h>
-      ]],[[
-int x= TIOCGWINSZ;
-      ]])
-    ],[
-      pandora_cv_tiocgwinsz_in_ioctl=yes
-    ],[
-      pandora_cv_tiocgwinsz_in_ioctl=no
-    ])
-  ])
-  AS_IF([test "$pandora_cv_tiocgwinsz_in_ioctl" = "yes"],[   
-    AC_DEFINE([GWINSZ_IN_SYS_IOCTL], [1],
-              [READLINE: your system defines TIOCGWINSZ in sys/ioctl.h.])
-  ])
-])
-
-AC_DEFUN([PANDORA_CHECK_RL_COMPENTRY], [
-  AC_CACHE_CHECK([defined rl_compentry_func_t], [pandora_cv_rl_compentry],[
-    AC_COMPILE_IFELSE([
-      AC_LANG_PROGRAM([[
-#include "stdio.h"
-#include "readline/readline.h"
-      ]],[[
-rl_compentry_func_t *func2= (rl_compentry_func_t*)0;
-      ]])
-    ],[
-      pandora_cv_rl_compentry=yes
-    ],[
-      pandora_cv_rl_compentry=no
-    ])
-  ])
-  AS_IF([test "$pandora_cv_rl_compentry" = "yes"],[
-    AC_DEFINE([HAVE_RL_COMPENTRY], [1],
-              [Does system provide rl_compentry_func_t])
-  ])
-
-  save_CXXFLAGS="${CXXFLAGS}"
-  CXXFLAGS="${AM_CXXFLAGS} ${CXXFLAGS}"
-  AC_LANG_PUSH(C++)
-  AC_CACHE_CHECK([rl_compentry_func_t works], [pandora_cv_rl_compentry_works],[
-    AC_COMPILE_IFELSE([
-      AC_LANG_PROGRAM([[
-#include "stdio.h"
-#include "readline/readline.h"
-      ]],[[
-rl_completion_entry_function= (rl_compentry_func_t*)NULL;
-      ]])
-    ],[
-      pandora_cv_rl_compentry_works=yes
-    ],[
-      pandora_cv_rl_compentry_works=no
-    ])
-  ])
-  AS_IF([test "$pandora_cv_rl_compentry_works" = "yes"],[
-    AC_DEFINE([HAVE_WORKING_RL_COMPENTRY], [1],
-              [Does system provide an rl_compentry_func_t that is usable])
-  ])
-  CXXFLAGS="${save_CXXFLAGS}"
-  AC_LANG_POP()
-])
-
-
-AC_DEFUN([PANDORA_CHECK_RL_COMPLETION_FUNC], [
-  AC_CACHE_CHECK([defined rl_completion_func_t], [pandora_cv_rl_completion],[
-    AC_COMPILE_IFELSE([
-      AC_LANG_PROGRAM([[
-#include "stdio.h"
-#include "readline/readline.h"
-      ]],[[
-rl_completion_func_t *func1= (rl_completion_func_t*)0;
-      ]])
-    ],[
-      pandora_cv_rl_completion=yes
-    ],[
-      pandora_cv_rl_completion=no
-    ])
-  ])
-  AS_IF([test "$pandora_cv_rl_completion" = "yes"],[
-    AC_DEFINE([HAVE_RL_COMPLETION], [1],
-              [Does system provide rl_completion_func_t])
-  ])
-])
-
-AC_DEFUN([_PANDORA_SEARCH_LIBREADLINE], [
-
-  save_LIBS="${LIBS}"
-  LIBS=""
-
-  AC_CACHE_CHECK([for a readline compatible library],
-                 ac_cv_libreadline, [
-    ORIG_LIBS="$LIBS"
-    for readline_lib in readline edit editline; do
-      for termcap_lib in "" termcap curses ncurses; do
-        if test -z "$termcap_lib"; then
-          TRY_LIB="-l$readline_lib"
-        else
-          TRY_LIB="-l$readline_lib -l$termcap_lib"
-        fi
-        LIBS="$ORIG_LIBS $TRY_LIB"
-        AC_TRY_LINK_FUNC(readline, ac_cv_libreadline="$TRY_LIB")
-        if test -n "$ac_cv_libreadline"; then
-          break
-        fi
-      done
-      if test -n "$ac_cv_libreadline"; then
-        break
-      fi
-    done
-    if test -z "$ac_cv_libreadline"; then
-      ac_cv_libreadline="no"
-      LIBS="$ORIG_LIBS"
-    fi
-  ])
-
-  if test "$ac_cv_libreadline" != "no"; then
-    AC_DEFINE(HAVE_LIBREADLINE, 1,
-              [Define if you have a readline compatible library])
-    AC_CHECK_HEADERS(readline.h readline/readline.h)
-    AC_CACHE_CHECK([whether readline supports history],
-                   ac_cv_libreadline_history, [
-      ac_cv_libreadline_history="no"
-      AC_TRY_LINK_FUNC(add_history, ac_cv_libreadline_history="yes")
-    ])
-    if test "$ac_cv_libreadline_history" = "yes"; then
-      AC_DEFINE(HAVE_READLINE_HISTORY, 1,
-                [Define if your readline library has \`add_history'])
-      AC_CHECK_HEADERS(history.h readline/history.h)
-    fi
-  fi
-  PANDORA_CHECK_RL_COMPENTRY  
-  PANDORA_CHECK_RL_COMPLETION_FUNC
-  PANDORA_CHECK_TIOCGWINSZ
-
-
-  READLINE_LIBS="${LIBS}"
-  LIBS="${save_LIBS}"
-  AC_SUBST(READLINE_LIBS)
-
-  AM_CONDITIONAL(HAVE_LIBREADLINE, [test "x${ac_cv_libreadline}" = "xyes"])
-])
-
-AC_DEFUN([_PANDORA_HAVE_LIBREADLINE],[
-
-  AC_ARG_ENABLE([libreadline],
-    [AS_HELP_STRING([--disable-libreadline],
-      [Build with libreadline support @<:@default=on@:>@])],
-    [ac_enable_libreadline="$enableval"],
-    [ac_enable_libreadline="yes"])
-
-  _PANDORA_SEARCH_LIBREADLINE
-])
-
-
-AC_DEFUN([PANDORA_HAVE_LIBREADLINE],[
-  AC_REQUIRE([_PANDORA_HAVE_LIBREADLINE])
-])
-
-AC_DEFUN([_PANDORA_REQUIRE_LIBREADLINE],[
-  ac_enable_libreadline="yes"
-  _PANDORA_SEARCH_LIBREADLINE
-
-  AS_IF([test "x$ac_cv_libreadline" = "xno"],
-    AC_MSG_ERROR([libreadline is required for ${PACKAGE}. On Debian this can be found in libreadline5-dev. On RedHat this can be found in readline-devel.]))
-
-])
-
-AC_DEFUN([PANDORA_REQUIRE_LIBREADLINE],[
-  AC_REQUIRE([_PANDORA_REQUIRE_LIBREADLINE])
-])
-
-
index e3f6426a9ecd692352a97d809451e703b6b3ea96..bd01908e2ddc5923e83cf85c098080c84f479cf9 100644 (file)
@@ -5752,7 +5752,7 @@ static test_return_t regression_bug_583031(memcached_st *unused)
 
     (void)memcached_get(memc, "dsf", 3, &length, &flags, &rc);
 
-    test_true_got(rc == MEMCACHED_TIMEOUT || rc == MEMCACHED_ERRNO, memcached_strerror(memc, rc));
+    test_true_got(rc == MEMCACHED_TIMEOUT || rc == MEMCACHED_ERRNO || rc == MEMCACHED_FAILURE, memcached_strerror(memc, rc));
 
     memcached_free(memc);