2010-11-03 16:03:04 +01:00
/* Extracted from anet.c to work properly with Hiredis error reporting.
*
2016-12-21 12:11:56 +01:00
* Copyright ( c ) 2009 - 2011 , Salvatore Sanfilippo < antirez at gmail dot com >
* Copyright ( c ) 2010 - 2014 , Pieter Noordhuis < pcnoordhuis at gmail dot com >
* Copyright ( c ) 2015 , Matt Stancliff < matt at genges dot com > ,
* Jan - Erik Rediger < janerik at fnordig dot com >
2010-11-03 16:03:04 +01:00
*
2010-12-16 23:32:02 +01:00
* All rights reserved .
2011-04-19 23:07:36 +02:00
*
2010-11-03 16:03:04 +01:00
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* * Redistributions of source code must retain the above copyright notice ,
* this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "fmacros.h"
# include <sys/types.h>
# include <sys/socket.h>
2011-04-19 23:07:36 +02:00
# include <sys/select.h>
2010-11-03 16:03:04 +01:00
# include <sys/un.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
# include <unistd.h>
# include <fcntl.h>
# include <string.h>
# include <netdb.h>
# include <errno.h>
# include <stdarg.h>
# include <stdio.h>
2012-08-21 17:27:01 +02:00
# include <poll.h>
# include <limits.h>
2016-12-21 12:11:56 +01:00
# include <stdlib.h>
2010-11-03 16:03:04 +01:00
2010-12-16 23:32:02 +01:00
# include "net.h"
2010-11-03 16:03:04 +01:00
# include "sds.h"
2012-02-19 20:26:36 +01:00
/* Defined in hiredis.c */
void __redisSetError ( redisContext * c , int type , const char * str ) ;
2014-04-24 15:14:54 -04:00
static void redisContextCloseFd ( redisContext * c ) {
if ( c & & c - > fd > = 0 ) {
close ( c - > fd ) ;
c - > fd = - 1 ;
}
}
2012-02-19 20:26:36 +01:00
static void __redisSetErrorFromErrno ( redisContext * c , int type , const char * prefix ) {
2014-04-24 15:14:54 -04:00
char buf [ 128 ] = { 0 } ;
2012-02-19 20:26:36 +01:00
size_t len = 0 ;
if ( prefix ! = NULL )
len = snprintf ( buf , sizeof ( buf ) , " %s: " , prefix ) ;
2016-12-21 12:11:56 +01:00
__redis_strerror_r ( errno , ( char * ) ( buf + len ) , sizeof ( buf ) - len ) ;
2012-02-19 20:26:36 +01:00
__redisSetError ( c , type , buf ) ;
}
2014-04-24 15:14:54 -04:00
static int redisSetReuseAddr ( redisContext * c ) {
2012-02-19 20:26:36 +01:00
int on = 1 ;
2014-04-24 15:14:54 -04:00
if ( setsockopt ( c - > fd , SOL_SOCKET , SO_REUSEADDR , & on , sizeof ( on ) ) = = - 1 ) {
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , NULL ) ;
2014-04-24 15:14:54 -04:00
redisContextCloseFd ( c ) ;
2012-02-19 20:26:36 +01:00
return REDIS_ERR ;
}
return REDIS_OK ;
}
2010-11-03 16:03:04 +01:00
static int redisCreateSocket ( redisContext * c , int type ) {
2012-02-19 20:26:36 +01:00
int s ;
2010-11-03 16:03:04 +01:00
if ( ( s = socket ( type , SOCK_STREAM , 0 ) ) = = - 1 ) {
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , NULL ) ;
2010-11-03 16:03:04 +01:00
return REDIS_ERR ;
}
2014-04-24 15:14:54 -04:00
c - > fd = s ;
2010-11-03 16:03:04 +01:00
if ( type = = AF_INET ) {
2014-04-24 15:14:54 -04:00
if ( redisSetReuseAddr ( c ) = = REDIS_ERR ) {
2010-11-03 16:03:04 +01:00
return REDIS_ERR ;
}
}
2014-04-24 15:14:54 -04:00
return REDIS_OK ;
2010-11-03 16:03:04 +01:00
}
2014-04-24 15:14:54 -04:00
static int redisSetBlocking ( redisContext * c , int blocking ) {
2010-11-03 16:03:04 +01:00
int flags ;
/* Set the socket nonblocking.
* Note that fcntl ( 2 ) for F_GETFL and F_SETFL can ' t be
* interrupted by a signal . */
2014-04-24 15:14:54 -04:00
if ( ( flags = fcntl ( c - > fd , F_GETFL ) ) = = - 1 ) {
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , " fcntl(F_GETFL) " ) ;
2014-04-24 15:14:54 -04:00
redisContextCloseFd ( c ) ;
2010-11-03 16:03:04 +01:00
return REDIS_ERR ;
}
2011-04-19 23:07:36 +02:00
if ( blocking )
flags & = ~ O_NONBLOCK ;
else
flags | = O_NONBLOCK ;
2014-04-24 15:14:54 -04:00
if ( fcntl ( c - > fd , F_SETFL , flags ) = = - 1 ) {
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , " fcntl(F_SETFL) " ) ;
2014-04-24 15:14:54 -04:00
redisContextCloseFd ( c ) ;
return REDIS_ERR ;
}
return REDIS_OK ;
}
int redisKeepAlive ( redisContext * c , int interval ) {
int val = 1 ;
int fd = c - > fd ;
if ( setsockopt ( fd , SOL_SOCKET , SO_KEEPALIVE , & val , sizeof ( val ) ) = = - 1 ) {
__redisSetError ( c , REDIS_ERR_OTHER , strerror ( errno ) ) ;
return REDIS_ERR ;
}
val = interval ;
# ifdef _OSX
if ( setsockopt ( fd , IPPROTO_TCP , TCP_KEEPALIVE , & val , sizeof ( val ) ) < 0 ) {
__redisSetError ( c , REDIS_ERR_OTHER , strerror ( errno ) ) ;
return REDIS_ERR ;
}
# else
2016-12-21 12:11:56 +01:00
# if defined(__GLIBC__) && !defined(__FreeBSD_kernel__)
2014-04-24 15:14:54 -04:00
val = interval ;
if ( setsockopt ( fd , IPPROTO_TCP , TCP_KEEPIDLE , & val , sizeof ( val ) ) < 0 ) {
__redisSetError ( c , REDIS_ERR_OTHER , strerror ( errno ) ) ;
return REDIS_ERR ;
}
val = interval / 3 ;
if ( val = = 0 ) val = 1 ;
if ( setsockopt ( fd , IPPROTO_TCP , TCP_KEEPINTVL , & val , sizeof ( val ) ) < 0 ) {
__redisSetError ( c , REDIS_ERR_OTHER , strerror ( errno ) ) ;
return REDIS_ERR ;
}
val = 3 ;
if ( setsockopt ( fd , IPPROTO_TCP , TCP_KEEPCNT , & val , sizeof ( val ) ) < 0 ) {
__redisSetError ( c , REDIS_ERR_OTHER , strerror ( errno ) ) ;
2010-11-03 16:03:04 +01:00
return REDIS_ERR ;
}
2014-04-24 15:14:54 -04:00
# endif
# endif
2010-11-03 16:03:04 +01:00
return REDIS_OK ;
}
2014-04-24 15:14:54 -04:00
static int redisSetTcpNoDelay ( redisContext * c ) {
2010-11-03 16:03:04 +01:00
int yes = 1 ;
2014-04-24 15:14:54 -04:00
if ( setsockopt ( c - > fd , IPPROTO_TCP , TCP_NODELAY , & yes , sizeof ( yes ) ) = = - 1 ) {
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , " setsockopt(TCP_NODELAY) " ) ;
2014-04-24 15:14:54 -04:00
redisContextCloseFd ( c ) ;
2010-11-03 16:03:04 +01:00
return REDIS_ERR ;
}
return REDIS_OK ;
}
2012-08-21 17:27:01 +02:00
# define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
2016-12-21 12:11:56 +01:00
static int redisContextTimeoutMsec ( redisContext * c , long * result )
{
const struct timeval * timeout = c - > timeout ;
long msec = - 1 ;
2011-04-19 23:07:36 +02:00
/* Only use timeout when not NULL. */
if ( timeout ! = NULL ) {
2012-08-21 17:27:01 +02:00
if ( timeout - > tv_usec > 1000000 | | timeout - > tv_sec > __MAX_MSEC ) {
2016-12-21 12:11:56 +01:00
* result = msec ;
2012-08-21 17:27:01 +02:00
return REDIS_ERR ;
}
msec = ( timeout - > tv_sec * 1000 ) + ( ( timeout - > tv_usec + 999 ) / 1000 ) ;
if ( msec < 0 | | msec > INT_MAX ) {
msec = INT_MAX ;
}
2011-04-19 23:07:36 +02:00
}
2016-12-21 12:11:56 +01:00
* result = msec ;
return REDIS_OK ;
}
static int redisContextWaitReady ( redisContext * c , long msec ) {
struct pollfd wfd [ 1 ] ;
wfd [ 0 ] . fd = c - > fd ;
wfd [ 0 ] . events = POLLOUT ;
2011-04-19 23:07:36 +02:00
if ( errno = = EINPROGRESS ) {
2012-08-21 17:27:01 +02:00
int res ;
2011-04-19 23:07:36 +02:00
2012-08-21 17:27:01 +02:00
if ( ( res = poll ( wfd , 1 , msec ) ) = = - 1 ) {
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , " poll(2) " ) ;
2014-04-24 15:14:54 -04:00
redisContextCloseFd ( c ) ;
2011-04-19 23:07:36 +02:00
return REDIS_ERR ;
2012-08-21 17:27:01 +02:00
} else if ( res = = 0 ) {
2011-04-19 23:07:36 +02:00
errno = ETIMEDOUT ;
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , NULL ) ;
2014-04-24 15:14:54 -04:00
redisContextCloseFd ( c ) ;
2011-04-19 23:07:36 +02:00
return REDIS_ERR ;
}
2014-04-24 15:14:54 -04:00
if ( redisCheckSocketError ( c ) ! = REDIS_OK )
2011-04-19 23:07:36 +02:00
return REDIS_ERR ;
return REDIS_OK ;
}
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , NULL ) ;
2014-04-24 15:14:54 -04:00
redisContextCloseFd ( c ) ;
2011-04-19 23:07:36 +02:00
return REDIS_ERR ;
}
2014-04-24 15:14:54 -04:00
int redisCheckSocketError ( redisContext * c ) {
2012-02-19 20:26:36 +01:00
int err = 0 ;
socklen_t errlen = sizeof ( err ) ;
2014-04-24 15:14:54 -04:00
if ( getsockopt ( c - > fd , SOL_SOCKET , SO_ERROR , & err , & errlen ) = = - 1 ) {
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , " getsockopt(SO_ERROR) " ) ;
return REDIS_ERR ;
}
if ( err ) {
errno = err ;
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , NULL ) ;
return REDIS_ERR ;
}
return REDIS_OK ;
}
2014-04-24 15:14:54 -04:00
int redisContextSetTimeout ( redisContext * c , const struct timeval tv ) {
2011-04-19 23:07:36 +02:00
if ( setsockopt ( c - > fd , SOL_SOCKET , SO_RCVTIMEO , & tv , sizeof ( tv ) ) = = - 1 ) {
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , " setsockopt(SO_RCVTIMEO) " ) ;
2011-04-19 23:07:36 +02:00
return REDIS_ERR ;
}
if ( setsockopt ( c - > fd , SOL_SOCKET , SO_SNDTIMEO , & tv , sizeof ( tv ) ) = = - 1 ) {
2012-02-19 20:26:36 +01:00
__redisSetErrorFromErrno ( c , REDIS_ERR_IO , " setsockopt(SO_SNDTIMEO) " ) ;
2011-04-19 23:07:36 +02:00
return REDIS_ERR ;
}
return REDIS_OK ;
}
2014-04-24 15:14:54 -04:00
static int _redisContextConnectTcp ( redisContext * c , const char * addr , int port ,
const struct timeval * timeout ,
const char * source_addr ) {
2016-12-21 12:11:56 +01:00
int s , rv , n ;
2012-02-19 20:26:36 +01:00
char _port [ 6 ] ; /* strlen("65535"); */
2014-04-24 15:14:54 -04:00
struct addrinfo hints , * servinfo , * bservinfo , * p , * b ;
2010-11-03 16:03:04 +01:00
int blocking = ( c - > flags & REDIS_BLOCK ) ;
2016-12-21 12:11:56 +01:00
int reuseaddr = ( c - > flags & REDIS_REUSEADDR ) ;
int reuses = 0 ;
long timeout_msec = - 1 ;
servinfo = NULL ;
c - > connection_type = REDIS_CONN_TCP ;
c - > tcp . port = port ;
/* We need to take possession of the passed parameters
* to make them reusable for a reconnect .
* We also carefully check we don ' t free data we already own ,
* as in the case of the reconnect method .
*
* This is a bit ugly , but atleast it works and doesn ' t leak memory .
* */
if ( c - > tcp . host ! = addr ) {
if ( c - > tcp . host )
free ( c - > tcp . host ) ;
c - > tcp . host = strdup ( addr ) ;
}
if ( timeout ) {
if ( c - > timeout ! = timeout ) {
if ( c - > timeout = = NULL )
c - > timeout = malloc ( sizeof ( struct timeval ) ) ;
memcpy ( c - > timeout , timeout , sizeof ( struct timeval ) ) ;
}
} else {
if ( c - > timeout )
free ( c - > timeout ) ;
c - > timeout = NULL ;
}
if ( redisContextTimeoutMsec ( c , & timeout_msec ) ! = REDIS_OK ) {
__redisSetError ( c , REDIS_ERR_IO , " Invalid timeout specified " ) ;
goto error ;
}
if ( source_addr = = NULL ) {
free ( c - > tcp . source_addr ) ;
c - > tcp . source_addr = NULL ;
} else if ( c - > tcp . source_addr ! = source_addr ) {
free ( c - > tcp . source_addr ) ;
c - > tcp . source_addr = strdup ( source_addr ) ;
}
2010-11-03 16:03:04 +01:00
2012-02-19 20:26:36 +01:00
snprintf ( _port , 6 , " %d " , port ) ;
memset ( & hints , 0 , sizeof ( hints ) ) ;
hints . ai_family = AF_INET ;
hints . ai_socktype = SOCK_STREAM ;
2010-11-03 16:03:04 +01:00
2013-07-11 13:11:27 +02:00
/* Try with IPv6 if no IPv4 address was found. We do it in this order since
* in a Redis client you can ' t afford to test if you have IPv6 connectivity
* as this would add latency to every connect . Otherwise a more sensible
* route could be : Use IPv6 if both addresses are available and there is IPv6
* connectivity . */
2016-12-21 12:11:56 +01:00
if ( ( rv = getaddrinfo ( c - > tcp . host , _port , & hints , & servinfo ) ) ! = 0 ) {
2013-07-11 13:11:27 +02:00
hints . ai_family = AF_INET6 ;
if ( ( rv = getaddrinfo ( addr , _port , & hints , & servinfo ) ) ! = 0 ) {
__redisSetError ( c , REDIS_ERR_OTHER , gai_strerror ( rv ) ) ;
return REDIS_ERR ;
}
2010-11-03 16:03:04 +01:00
}
2012-02-19 20:26:36 +01:00
for ( p = servinfo ; p ! = NULL ; p = p - > ai_next ) {
2016-12-21 12:11:56 +01:00
addrretry :
2012-02-19 20:26:36 +01:00
if ( ( s = socket ( p - > ai_family , p - > ai_socktype , p - > ai_protocol ) ) = = - 1 )
continue ;
2014-04-24 15:14:54 -04:00
c - > fd = s ;
if ( redisSetBlocking ( c , 0 ) ! = REDIS_OK )
2012-02-19 20:26:36 +01:00
goto error ;
2016-12-21 12:11:56 +01:00
if ( c - > tcp . source_addr ) {
2014-04-24 15:14:54 -04:00
int bound = 0 ;
/* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
2016-12-21 12:11:56 +01:00
if ( ( rv = getaddrinfo ( c - > tcp . source_addr , NULL , & hints , & bservinfo ) ) ! = 0 ) {
2014-04-24 15:14:54 -04:00
char buf [ 128 ] ;
snprintf ( buf , sizeof ( buf ) , " Can't get addr: %s " , gai_strerror ( rv ) ) ;
__redisSetError ( c , REDIS_ERR_OTHER , buf ) ;
goto error ;
}
2016-12-21 12:11:56 +01:00
if ( reuseaddr ) {
n = 1 ;
if ( setsockopt ( s , SOL_SOCKET , SO_REUSEADDR , ( char * ) & n ,
sizeof ( n ) ) < 0 ) {
goto error ;
}
}
2014-04-24 15:14:54 -04:00
for ( b = bservinfo ; b ! = NULL ; b = b - > ai_next ) {
if ( bind ( s , b - > ai_addr , b - > ai_addrlen ) ! = - 1 ) {
bound = 1 ;
break ;
}
}
2014-09-18 14:21:12 -04:00
freeaddrinfo ( bservinfo ) ;
2014-04-24 15:14:54 -04:00
if ( ! bound ) {
char buf [ 128 ] ;
snprintf ( buf , sizeof ( buf ) , " Can't bind socket: %s " , strerror ( errno ) ) ;
__redisSetError ( c , REDIS_ERR_OTHER , buf ) ;
goto error ;
}
}
2012-02-19 20:26:36 +01:00
if ( connect ( s , p - > ai_addr , p - > ai_addrlen ) = = - 1 ) {
if ( errno = = EHOSTUNREACH ) {
2014-04-24 15:14:54 -04:00
redisContextCloseFd ( c ) ;
2012-02-19 20:26:36 +01:00
continue ;
} else if ( errno = = EINPROGRESS & & ! blocking ) {
/* This is ok. */
2016-12-21 12:11:56 +01:00
} else if ( errno = = EADDRNOTAVAIL & & reuseaddr ) {
if ( + + reuses > = REDIS_CONNECT_RETRIES ) {
goto error ;
} else {
redisContextCloseFd ( c ) ;
goto addrretry ;
}
2012-02-19 20:26:36 +01:00
} else {
2016-12-21 12:11:56 +01:00
if ( redisContextWaitReady ( c , timeout_msec ) ! = REDIS_OK )
2012-02-19 20:26:36 +01:00
goto error ;
}
2010-11-03 16:03:04 +01:00
}
2014-04-24 15:14:54 -04:00
if ( blocking & & redisSetBlocking ( c , 1 ) ! = REDIS_OK )
2012-02-19 20:26:36 +01:00
goto error ;
2014-04-24 15:14:54 -04:00
if ( redisSetTcpNoDelay ( c ) ! = REDIS_OK )
2012-02-19 20:26:36 +01:00
goto error ;
c - > flags | = REDIS_CONNECTED ;
rv = REDIS_OK ;
goto end ;
}
if ( p = = NULL ) {
char buf [ 128 ] ;
snprintf ( buf , sizeof ( buf ) , " Can't create socket: %s " , strerror ( errno ) ) ;
__redisSetError ( c , REDIS_ERR_OTHER , buf ) ;
goto error ;
2010-11-03 16:03:04 +01:00
}
2012-02-19 20:26:36 +01:00
error :
rv = REDIS_ERR ;
end :
freeaddrinfo ( servinfo ) ;
return rv ; // Need to return REDIS_OK if alright
2010-11-03 16:03:04 +01:00
}
2014-04-24 15:14:54 -04:00
int redisContextConnectTcp ( redisContext * c , const char * addr , int port ,
const struct timeval * timeout ) {
return _redisContextConnectTcp ( c , addr , port , timeout , NULL ) ;
}
int redisContextConnectBindTcp ( redisContext * c , const char * addr , int port ,
const struct timeval * timeout ,
const char * source_addr ) {
return _redisContextConnectTcp ( c , addr , port , timeout , source_addr ) ;
}
int redisContextConnectUnix ( redisContext * c , const char * path , const struct timeval * timeout ) {
2010-11-03 16:03:04 +01:00
int blocking = ( c - > flags & REDIS_BLOCK ) ;
struct sockaddr_un sa ;
2016-12-21 12:11:56 +01:00
long timeout_msec = - 1 ;
2010-11-03 16:03:04 +01:00
2014-04-24 15:14:54 -04:00
if ( redisCreateSocket ( c , AF_LOCAL ) < 0 )
2010-11-03 16:03:04 +01:00
return REDIS_ERR ;
2014-04-24 15:14:54 -04:00
if ( redisSetBlocking ( c , 0 ) ! = REDIS_OK )
2010-11-03 16:03:04 +01:00
return REDIS_ERR ;
2016-12-21 12:11:56 +01:00
c - > connection_type = REDIS_CONN_UNIX ;
if ( c - > unix_sock . path ! = path )
c - > unix_sock . path = strdup ( path ) ;
if ( timeout ) {
if ( c - > timeout ! = timeout ) {
if ( c - > timeout = = NULL )
c - > timeout = malloc ( sizeof ( struct timeval ) ) ;
memcpy ( c - > timeout , timeout , sizeof ( struct timeval ) ) ;
}
} else {
if ( c - > timeout )
free ( c - > timeout ) ;
c - > timeout = NULL ;
}
if ( redisContextTimeoutMsec ( c , & timeout_msec ) ! = REDIS_OK )
return REDIS_ERR ;
2010-11-03 16:03:04 +01:00
sa . sun_family = AF_LOCAL ;
strncpy ( sa . sun_path , path , sizeof ( sa . sun_path ) - 1 ) ;
2014-04-24 15:14:54 -04:00
if ( connect ( c - > fd , ( struct sockaddr * ) & sa , sizeof ( sa ) ) = = - 1 ) {
2010-11-03 16:03:04 +01:00
if ( errno = = EINPROGRESS & & ! blocking ) {
/* This is ok. */
} else {
2016-12-21 12:11:56 +01:00
if ( redisContextWaitReady ( c , timeout_msec ) ! = REDIS_OK )
2011-04-19 23:07:36 +02:00
return REDIS_ERR ;
2010-11-03 16:03:04 +01:00
}
}
2011-04-19 23:07:36 +02:00
/* Reset socket to be blocking after connect(2). */
2014-04-24 15:14:54 -04:00
if ( blocking & & redisSetBlocking ( c , 1 ) ! = REDIS_OK )
2011-04-19 23:07:36 +02:00
return REDIS_ERR ;
2010-12-16 23:32:02 +01:00
c - > flags | = REDIS_CONNECTED ;
2010-11-03 16:03:04 +01:00
return REDIS_OK ;
}