Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
hiredis
Commits
2fc0d875
Commit
2fc0d875
authored
Feb 04, 2011
by
Pieter Noordhuis
Browse files
Use select(2) for enforce a timeout on blocking connect(2)
parent
663d6d12
Changes
5
Show whitespace changes
Inline
Side-by-side
example.c
View file @
2fc0d875
...
...
@@ -9,7 +9,8 @@ int main(void) {
redisContext
*
c
;
redisReply
*
reply
;
c
=
redisConnect
((
char
*
)
"127.0.0.1"
,
6379
);
struct
timeval
timeout
=
{
1
,
500000
};
// 1.5 seconds
c
=
redisConnectWithTimeout
((
char
*
)
"127.0.0.2"
,
6379
,
timeout
);
if
(
c
->
err
)
{
printf
(
"Connection error: %s
\n
"
,
c
->
errstr
);
exit
(
1
);
...
...
hiredis.c
View file @
2fc0d875
...
...
@@ -821,28 +821,42 @@ void redisFree(redisContext *c) {
redisContext
*
redisConnect
(
const
char
*
ip
,
int
port
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
|=
REDIS_BLOCK
;
redisContextConnectTcp
(
c
,
ip
,
port
);
redisContextConnectTcp
(
c
,
ip
,
port
,
NULL
);
return
c
;
}
redisContext
*
redisConnectWithTimeout
(
const
char
*
ip
,
int
port
,
struct
timeval
tv
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
|=
REDIS_BLOCK
;
redisContextConnectTcp
(
c
,
ip
,
port
,
&
tv
);
return
c
;
}
redisContext
*
redisConnectNonBlock
(
const
char
*
ip
,
int
port
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
&=
~
REDIS_BLOCK
;
redisContextConnectTcp
(
c
,
ip
,
port
);
redisContextConnectTcp
(
c
,
ip
,
port
,
NULL
);
return
c
;
}
redisContext
*
redisConnectUnix
(
const
char
*
path
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
|=
REDIS_BLOCK
;
redisContextConnectUnix
(
c
,
path
);
redisContextConnectUnix
(
c
,
path
,
NULL
);
return
c
;
}
redisContext
*
redisConnectUnixWithTimeout
(
const
char
*
path
,
struct
timeval
tv
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
|=
REDIS_BLOCK
;
redisContextConnectUnix
(
c
,
path
,
&
tv
);
return
c
;
}
redisContext
*
redisConnectUnixNonBlock
(
const
char
*
path
)
{
redisContext
*
c
=
redisContextInit
();
c
->
flags
&=
~
REDIS_BLOCK
;
redisContextConnectUnix
(
c
,
path
);
redisContextConnectUnix
(
c
,
path
,
NULL
);
return
c
;
}
...
...
hiredis.h
View file @
2fc0d875
...
...
@@ -144,8 +144,10 @@ int redisFormatCommand(char **target, const char *format, ...);
int
redisFormatCommandArgv
(
char
**
target
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
);
redisContext
*
redisConnect
(
const
char
*
ip
,
int
port
);
redisContext
*
redisConnectWithTimeout
(
const
char
*
ip
,
int
port
,
struct
timeval
tv
);
redisContext
*
redisConnectNonBlock
(
const
char
*
ip
,
int
port
);
redisContext
*
redisConnectUnix
(
const
char
*
path
);
redisContext
*
redisConnectUnixWithTimeout
(
const
char
*
path
,
struct
timeval
tv
);
redisContext
*
redisConnectUnixNonBlock
(
const
char
*
path
);
int
redisSetTimeout
(
redisContext
*
c
,
struct
timeval
tv
);
int
redisSetReplyObjectFunctions
(
redisContext
*
c
,
redisReplyObjectFunctions
*
fn
);
...
...
net.c
View file @
2fc0d875
...
...
@@ -33,6 +33,7 @@
#include "fmacros.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
...
...
@@ -67,7 +68,7 @@ static int redisCreateSocket(redisContext *c, int type) {
return
s
;
}
static
int
redisSet
Non
Block
(
redisContext
*
c
,
int
fd
)
{
static
int
redisSetBlock
ing
(
redisContext
*
c
,
int
fd
,
int
blocking
)
{
int
flags
;
/* Set the socket nonblocking.
...
...
@@ -79,9 +80,15 @@ static int redisSetNonBlock(redisContext *c, int fd) {
close
(
fd
);
return
REDIS_ERR
;
}
if
(
fcntl
(
fd
,
F_SETFL
,
flags
|
O_NONBLOCK
)
==
-
1
)
{
if
(
blocking
)
flags
&=
~
O_NONBLOCK
;
else
flags
|=
O_NONBLOCK
;
if
(
fcntl
(
fd
,
F_SETFL
,
flags
)
==
-
1
)
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
sdscatprintf
(
sdsempty
(),
"fcntl(F_SETFL
,O_NONBLOCK
): %s"
,
strerror
(
errno
)));
sdscatprintf
(
sdsempty
(),
"fcntl(F_SETFL): %s"
,
strerror
(
errno
)));
close
(
fd
);
return
REDIS_ERR
;
}
...
...
@@ -93,9 +100,65 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) {
if
(
setsockopt
(
fd
,
IPPROTO_TCP
,
TCP_NODELAY
,
&
yes
,
sizeof
(
yes
))
==
-
1
)
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
sdscatprintf
(
sdsempty
(),
"setsockopt(TCP_NODELAY): %s"
,
strerror
(
errno
)));
close
(
fd
);
return
REDIS_ERR
;
}
return
REDIS_OK
;
}
static
int
redisContextWaitReady
(
redisContext
*
c
,
int
fd
,
const
struct
timeval
*
timeout
)
{
struct
timeval
to
;
struct
timeval
*
toptr
=
NULL
;
fd_set
wfd
;
int
err
;
socklen_t
errlen
;
/* Only use timeout when not NULL. */
if
(
timeout
!=
NULL
)
{
memcpy
(
&
to
,
timeout
,
sizeof
(
timeout
));
toptr
=
&
to
;
}
if
(
errno
==
EINPROGRESS
)
{
FD_ZERO
(
&
wfd
);
FD_SET
(
fd
,
&
wfd
);
if
(
select
(
FD_SETSIZE
,
NULL
,
&
wfd
,
NULL
,
toptr
)
==
-
1
)
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
sdscatprintf
(
sdsempty
(),
"select(2): %s"
,
strerror
(
errno
)));
close
(
fd
);
return
REDIS_ERR
;
}
if
(
!
FD_ISSET
(
fd
,
&
wfd
))
{
errno
=
ETIMEDOUT
;
__redisSetError
(
c
,
REDIS_ERR_IO
,
NULL
);
close
(
fd
);
return
REDIS_ERR
;
}
err
=
0
;
errlen
=
sizeof
(
err
);
if
(
getsockopt
(
fd
,
SOL_SOCKET
,
SO_ERROR
,
&
err
,
&
errlen
)
==
-
1
)
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
sdscatprintf
(
sdsempty
(),
"getsockopt(SO_ERROR): %s"
,
strerror
(
errno
)));
close
(
fd
);
return
REDIS_ERR
;
}
if
(
err
)
{
errno
=
err
;
__redisSetError
(
c
,
REDIS_ERR_IO
,
NULL
);
close
(
fd
);
return
REDIS_ERR
;
}
return
REDIS_OK
;
}
__redisSetError
(
c
,
REDIS_ERR_IO
,
NULL
);
close
(
fd
);
return
REDIS_ERR
;
}
int
redisContextSetTimeout
(
redisContext
*
c
,
struct
timeval
tv
)
{
...
...
@@ -112,14 +175,14 @@ int redisContextSetTimeout(redisContext *c, struct timeval tv) {
return
REDIS_OK
;
}
int
redisContextConnectTcp
(
redisContext
*
c
,
const
char
*
addr
,
int
port
)
{
int
redisContextConnectTcp
(
redisContext
*
c
,
const
char
*
addr
,
int
port
,
struct
timeval
*
timeout
)
{
int
s
;
int
blocking
=
(
c
->
flags
&
REDIS_BLOCK
);
struct
sockaddr_in
sa
;
if
((
s
=
redisCreateSocket
(
c
,
AF_INET
))
==
REDIS_ERR
)
if
((
s
=
redisCreateSocket
(
c
,
AF_INET
))
<
0
)
return
REDIS_ERR
;
if
(
!
blocking
&&
redisSet
Non
Block
(
c
,
s
)
=
=
REDIS_
ERR
)
if
(
redisSetBlock
ing
(
c
,
s
,
0
)
!
=
REDIS_
OK
)
return
REDIS_ERR
;
sa
.
sin_family
=
AF_INET
;
...
...
@@ -141,30 +204,31 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port) {
if
(
errno
==
EINPROGRESS
&&
!
blocking
)
{
/* This is ok. */
}
else
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
NULL
);
close
(
s
);
if
(
redisContextWaitReady
(
c
,
s
,
timeout
)
!=
REDIS_OK
)
return
REDIS_ERR
;
}
}
if
(
redisSetTcpNoDelay
(
c
,
s
)
!=
REDIS_OK
)
{
close
(
s
);
/* Reset socket to be blocking after connect(2). */
if
(
blocking
&&
redisSetBlocking
(
c
,
s
,
1
)
!=
REDIS_OK
)
return
REDIS_ERR
;
if
(
redisSetTcpNoDelay
(
c
,
s
)
!=
REDIS_OK
)
return
REDIS_ERR
;
}
c
->
fd
=
s
;
c
->
flags
|=
REDIS_CONNECTED
;
return
REDIS_OK
;
}
int
redisContextConnectUnix
(
redisContext
*
c
,
const
char
*
path
)
{
int
redisContextConnectUnix
(
redisContext
*
c
,
const
char
*
path
,
struct
timeval
*
timeout
)
{
int
s
;
int
blocking
=
(
c
->
flags
&
REDIS_BLOCK
);
struct
sockaddr_un
sa
;
if
((
s
=
redisCreateSocket
(
c
,
AF_LOCAL
))
==
REDIS_ERR
)
if
((
s
=
redisCreateSocket
(
c
,
AF_LOCAL
))
<
0
)
return
REDIS_ERR
;
if
(
!
blocking
&&
redisSet
Non
Block
(
c
,
s
)
!=
REDIS_OK
)
if
(
redisSetBlock
ing
(
c
,
s
,
0
)
!=
REDIS_OK
)
return
REDIS_ERR
;
sa
.
sun_family
=
AF_LOCAL
;
...
...
@@ -173,12 +237,15 @@ int redisContextConnectUnix(redisContext *c, const char *path) {
if
(
errno
==
EINPROGRESS
&&
!
blocking
)
{
/* This is ok. */
}
else
{
__redisSetError
(
c
,
REDIS_ERR_IO
,
NULL
);
close
(
s
);
if
(
redisContextWaitReady
(
c
,
s
,
timeout
)
!=
REDIS_OK
)
return
REDIS_ERR
;
}
}
/* Reset socket to be blocking after connect(2). */
if
(
blocking
&&
redisSetBlocking
(
c
,
s
,
1
)
!=
REDIS_OK
)
return
REDIS_ERR
;
c
->
fd
=
s
;
c
->
flags
|=
REDIS_CONNECTED
;
return
REDIS_OK
;
...
...
net.h
View file @
2fc0d875
...
...
@@ -40,7 +40,7 @@
#endif
int
redisContextSetTimeout
(
redisContext
*
c
,
struct
timeval
tv
);
int
redisContextConnectTcp
(
redisContext
*
c
,
const
char
*
addr
,
int
port
);
int
redisContextConnectUnix
(
redisContext
*
c
,
const
char
*
path
);
int
redisContextConnectTcp
(
redisContext
*
c
,
const
char
*
addr
,
int
port
,
struct
timeval
*
timeout
);
int
redisContextConnectUnix
(
redisContext
*
c
,
const
char
*
path
,
struct
timeval
*
timeout
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment