]>
git.saurik.com Git - redis.git/blob - deps/hiredis/net.c
1 /* Extracted from anet.c to work properly with Hiredis error reporting.
3 * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
4 * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of Redis nor the names of its contributors may be used
17 * to endorse or promote products derived from this software without
18 * specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/select.h>
38 #include <netinet/in.h>
39 #include <netinet/tcp.h>
40 #include <arpa/inet.h>
52 /* Forward declaration */
53 void __redisSetError(redisContext
*c
, int type
, sds err
);
55 static int redisCreateSocket(redisContext
*c
, int type
) {
57 if ((s
= socket(type
, SOCK_STREAM
, 0)) == -1) {
58 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
61 if (type
== AF_INET
) {
62 if (setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &on
, sizeof(on
)) == -1) {
63 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
71 static int redisSetBlocking(redisContext
*c
, int fd
, int blocking
) {
74 /* Set the socket nonblocking.
75 * Note that fcntl(2) for F_GETFL and F_SETFL can't be
76 * interrupted by a signal. */
77 if ((flags
= fcntl(fd
, F_GETFL
)) == -1) {
78 __redisSetError(c
,REDIS_ERR_IO
,
79 sdscatprintf(sdsempty(), "fcntl(F_GETFL): %s", strerror(errno
)));
89 if (fcntl(fd
, F_SETFL
, flags
) == -1) {
90 __redisSetError(c
,REDIS_ERR_IO
,
91 sdscatprintf(sdsempty(), "fcntl(F_SETFL): %s", strerror(errno
)));
98 static int redisSetTcpNoDelay(redisContext
*c
, int fd
) {
100 if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
, &yes
, sizeof(yes
)) == -1) {
101 __redisSetError(c
,REDIS_ERR_IO
,
102 sdscatprintf(sdsempty(), "setsockopt(TCP_NODELAY): %s", strerror(errno
)));
109 static int redisContextWaitReady(redisContext
*c
, int fd
, const struct timeval
*timeout
) {
111 struct timeval
*toptr
= NULL
;
116 /* Only use timeout when not NULL. */
117 if (timeout
!= NULL
) {
122 if (errno
== EINPROGRESS
) {
126 if (select(FD_SETSIZE
, NULL
, &wfd
, NULL
, toptr
) == -1) {
127 __redisSetError(c
,REDIS_ERR_IO
,
128 sdscatprintf(sdsempty(), "select(2): %s", strerror(errno
)));
133 if (!FD_ISSET(fd
, &wfd
)) {
135 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
141 errlen
= sizeof(err
);
142 if (getsockopt(fd
, SOL_SOCKET
, SO_ERROR
, &err
, &errlen
) == -1) {
143 __redisSetError(c
,REDIS_ERR_IO
,
144 sdscatprintf(sdsempty(), "getsockopt(SO_ERROR): %s", strerror(errno
)));
151 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
159 __redisSetError(c
,REDIS_ERR_IO
,NULL
);
164 int redisContextSetTimeout(redisContext
*c
, struct timeval tv
) {
165 if (setsockopt(c
->fd
,SOL_SOCKET
,SO_RCVTIMEO
,&tv
,sizeof(tv
)) == -1) {
166 __redisSetError(c
,REDIS_ERR_IO
,
167 sdscatprintf(sdsempty(), "setsockopt(SO_RCVTIMEO): %s", strerror(errno
)));
170 if (setsockopt(c
->fd
,SOL_SOCKET
,SO_SNDTIMEO
,&tv
,sizeof(tv
)) == -1) {
171 __redisSetError(c
,REDIS_ERR_IO
,
172 sdscatprintf(sdsempty(), "setsockopt(SO_SNDTIMEO): %s", strerror(errno
)));
178 int redisContextConnectTcp(redisContext
*c
, const char *addr
, int port
, struct timeval
*timeout
) {
180 int blocking
= (c
->flags
& REDIS_BLOCK
);
181 struct sockaddr_in sa
;
183 if ((s
= redisCreateSocket(c
,AF_INET
)) < 0)
185 if (redisSetBlocking(c
,s
,0) != REDIS_OK
)
188 sa
.sin_family
= AF_INET
;
189 sa
.sin_port
= htons(port
);
190 if (inet_aton(addr
, &sa
.sin_addr
) == 0) {
193 he
= gethostbyname(addr
);
195 __redisSetError(c
,REDIS_ERR_OTHER
,
196 sdscatprintf(sdsempty(),"Can't resolve: %s",addr
));
200 memcpy(&sa
.sin_addr
, he
->h_addr
, sizeof(struct in_addr
));
203 if (connect(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
204 if (errno
== EINPROGRESS
&& !blocking
) {
207 if (redisContextWaitReady(c
,s
,timeout
) != REDIS_OK
)
212 /* Reset socket to be blocking after connect(2). */
213 if (blocking
&& redisSetBlocking(c
,s
,1) != REDIS_OK
)
216 if (redisSetTcpNoDelay(c
,s
) != REDIS_OK
)
220 c
->flags
|= REDIS_CONNECTED
;
224 int redisContextConnectUnix(redisContext
*c
, const char *path
, struct timeval
*timeout
) {
226 int blocking
= (c
->flags
& REDIS_BLOCK
);
227 struct sockaddr_un sa
;
229 if ((s
= redisCreateSocket(c
,AF_LOCAL
)) < 0)
231 if (redisSetBlocking(c
,s
,0) != REDIS_OK
)
234 sa
.sun_family
= AF_LOCAL
;
235 strncpy(sa
.sun_path
,path
,sizeof(sa
.sun_path
)-1);
236 if (connect(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
237 if (errno
== EINPROGRESS
&& !blocking
) {
240 if (redisContextWaitReady(c
,s
,timeout
) != REDIS_OK
)
245 /* Reset socket to be blocking after connect(2). */
246 if (blocking
&& redisSetBlocking(c
,s
,1) != REDIS_OK
)
250 c
->flags
|= REDIS_CONNECTED
;