Fix for decrement
[awesomized/libmemcached] / libmemcached / memcached_connect.c
1 #include "common.h"
2 #include <netdb.h>
3 #include <poll.h>
4 #include <sys/time.h>
5
6 static memcached_return set_hostinfo(memcached_server_st *server)
7 {
8 struct addrinfo *ai;
9 struct addrinfo hints;
10 int e;
11 char str_port[NI_MAXSERV];
12
13 sprintf(str_port, "%u", server->port);
14
15 memset(&hints, 0, sizeof(hints));
16
17 // hints.ai_family= AF_INET;
18 if (server->type == MEMCACHED_CONNECTION_UDP)
19 {
20 hints.ai_protocol= IPPROTO_UDP;
21 hints.ai_socktype= SOCK_DGRAM;
22 }
23 else
24 {
25 hints.ai_socktype= SOCK_STREAM;
26 hints.ai_protocol= IPPROTO_TCP;
27 }
28
29 e= getaddrinfo(server->hostname, str_port, &hints, &ai);
30 if (e != 0)
31 {
32 WATCHPOINT_STRING(server->hostname);
33 WATCHPOINT_STRING(gai_strerror(e));
34 return MEMCACHED_HOST_LOOKUP_FAILURE;
35 }
36
37 if (server->address_info)
38 {
39 freeaddrinfo(server->address_info);
40 server->address_info= NULL;
41 }
42 server->address_info= ai;
43
44 return MEMCACHED_SUCCESS;
45 }
46
47 static memcached_return set_socket_options(memcached_server_st *ptr)
48 {
49 WATCHPOINT_ASSERT(ptr->fd != -1);
50
51 if (ptr->type == MEMCACHED_CONNECTION_UDP)
52 return MEMCACHED_SUCCESS;
53
54 #ifndef __sun
55 if (ptr->root->snd_timeout)
56 {
57 int error;
58 struct timeval waittime;
59
60 waittime.tv_sec= 0;
61 waittime.tv_usec= ptr->root->snd_timeout;
62
63 error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO,
64 &waittime, (socklen_t)sizeof(struct timeval));
65 WATCHPOINT_ASSERT(error == 0);
66 }
67
68 if (ptr->root->rcv_timeout)
69 {
70 int error;
71 struct timeval waittime;
72
73 waittime.tv_sec= 0;
74 waittime.tv_usec= ptr->root->rcv_timeout;
75
76 error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO,
77 &waittime, (socklen_t)sizeof(struct timeval));
78 WATCHPOINT_ASSERT(error == 0);
79 }
80 #endif
81
82 {
83 int error;
84 struct linger linger;
85
86 linger.l_onoff= 1;
87 linger.l_linger= MEMCACHED_DEFAULT_TIMEOUT;
88 error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER,
89 &linger, (socklen_t)sizeof(struct linger));
90 WATCHPOINT_ASSERT(error == 0);
91 }
92
93 if (ptr->root->flags & MEM_TCP_NODELAY)
94 {
95 int flag= 1;
96 int error;
97
98 error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY,
99 &flag, (socklen_t)sizeof(int));
100 WATCHPOINT_ASSERT(error == 0);
101 }
102
103 if (ptr->root->send_size)
104 {
105 int error;
106
107 error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
108 &ptr->root->send_size, (socklen_t)sizeof(int));
109 WATCHPOINT_ASSERT(error == 0);
110 }
111
112 if (ptr->root->recv_size)
113 {
114 int error;
115
116 error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
117 &ptr->root->recv_size, (socklen_t)sizeof(int));
118 WATCHPOINT_ASSERT(error == 0);
119 }
120
121 /* For the moment, not getting a nonblocking mode will not be fatal */
122 if (ptr->root->flags & MEM_NO_BLOCK)
123 {
124 int flags;
125
126 flags= fcntl(ptr->fd, F_GETFL, 0);
127 unlikely (flags != -1)
128 {
129 (void)fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
130 }
131 }
132
133 return MEMCACHED_SUCCESS;
134 }
135
136 static memcached_return unix_socket_connect(memcached_server_st *ptr)
137 {
138 struct sockaddr_un servAddr;
139 socklen_t addrlen;
140
141 if (ptr->fd == -1)
142 {
143 if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
144 {
145 ptr->cached_errno= errno;
146 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
147 }
148
149 memset(&servAddr, 0, sizeof (struct sockaddr_un));
150 servAddr.sun_family= AF_UNIX;
151 strcpy(servAddr.sun_path, ptr->hostname); /* Copy filename */
152
153 addrlen= strlen(servAddr.sun_path) + sizeof(servAddr.sun_family);
154
155 test_connect:
156 if (connect(ptr->fd,
157 (struct sockaddr *)&servAddr,
158 sizeof(servAddr)) < 0)
159 {
160 switch (errno) {
161 case EINPROGRESS:
162 case EALREADY:
163 case EINTR:
164 goto test_connect;
165 case EISCONN: /* We were spinning waiting on connect */
166 break;
167 default:
168 WATCHPOINT_ERRNO(errno);
169 ptr->cached_errno= errno;
170 return MEMCACHED_ERRNO;
171 }
172 }
173 }
174
175 WATCHPOINT_ASSERT(ptr->fd != -1);
176 return MEMCACHED_SUCCESS;
177 }
178
179 static memcached_return network_connect(memcached_server_st *ptr)
180 {
181 if (ptr->fd == -1)
182 {
183 struct addrinfo *use;
184
185 if (ptr->root->server_failure_limit != 0)
186 {
187 if (ptr->server_failure_counter >= ptr->root->server_failure_limit)
188 {
189 memcached_server_remove(ptr);
190 return MEMCACHED_FAILURE;
191 }
192 }
193
194 if (ptr->sockaddr_inited == MEMCACHED_NOT_ALLOCATED ||
195 (!(ptr->root->flags & MEM_USE_CACHE_LOOKUPS)))
196 {
197 memcached_return rc;
198
199 rc= set_hostinfo(ptr);
200 if (rc != MEMCACHED_SUCCESS)
201 return rc;
202 ptr->sockaddr_inited= MEMCACHED_ALLOCATED;
203 }
204
205 use= ptr->address_info;
206 /* Create the socket */
207 while (use != NULL)
208 {
209 if ((ptr->fd= socket(use->ai_family,
210 use->ai_socktype,
211 use->ai_protocol)) < 0)
212 {
213 ptr->cached_errno= errno;
214 WATCHPOINT_ERRNO(errno);
215 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
216 }
217
218 (void)set_socket_options(ptr);
219
220 /* connect to server */
221 test_connect:
222 if (connect(ptr->fd,
223 use->ai_addr,
224 use->ai_addrlen) < 0)
225 {
226 switch (errno) {
227 /* We are spinning waiting on connect */
228 case EALREADY:
229 case EINPROGRESS:
230 {
231 struct pollfd fds[1];
232 int error;
233
234 memset(&fds, 0, sizeof(struct pollfd));
235 fds[0].fd= ptr->fd;
236 fds[0].events= POLLOUT | POLLERR;
237 error= poll(fds, 1, ptr->root->connect_timeout);
238
239 if (error == 0)
240 {
241 goto handle_retry;
242 }
243 else if (error != 1 && fds[0].revents & POLLERR)
244 {
245 ptr->cached_errno= errno;
246 WATCHPOINT_ERRNO(ptr->cached_errno);
247 WATCHPOINT_NUMBER(ptr->root->connect_timeout);
248 memcached_quit_server(ptr, 1);
249
250 if (ptr->root->retry_timeout)
251 {
252 struct timeval next_time;
253
254 gettimeofday(&next_time, NULL);
255 ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
256 }
257 ptr->server_failure_counter+= 1;
258
259 return MEMCACHED_ERRNO;
260 }
261
262 break;
263 }
264 /* We are spinning waiting on connect */
265 case EINTR:
266 goto test_connect;
267 case EISCONN: /* We were spinning waiting on connect */
268 break;
269 default:
270 handle_retry:
271 ptr->cached_errno= errno;
272 close(ptr->fd);
273 ptr->fd= -1;
274 if (ptr->root->retry_timeout)
275 {
276 struct timeval next_time;
277
278 gettimeofday(&next_time, NULL);
279 ptr->next_retry= next_time.tv_sec + ptr->root->retry_timeout;
280 }
281 }
282 }
283 else
284 {
285 WATCHPOINT_ASSERT(ptr->cursor_active == 0);
286 ptr->server_failure_counter= 0;
287 return MEMCACHED_SUCCESS;
288 }
289 use = use->ai_next;
290 }
291 }
292
293 if (ptr->fd == -1) {
294 ptr->server_failure_counter+= 1;
295 return MEMCACHED_ERRNO; /* The last error should be from connect() */
296 }
297
298 ptr->server_failure_counter= 0;
299 return MEMCACHED_SUCCESS; /* The last error should be from connect() */
300 }
301
302
303 memcached_return memcached_connect(memcached_server_st *ptr)
304 {
305 memcached_return rc= MEMCACHED_NO_SERVERS;
306 LIBMEMCACHED_MEMCACHED_CONNECT_START();
307
308 if (ptr->root->retry_timeout)
309 {
310 struct timeval next_time;
311
312 gettimeofday(&next_time, NULL);
313 if (next_time.tv_sec < ptr->next_retry)
314 return MEMCACHED_TIMEOUT;
315 }
316 /* We need to clean up the multi startup piece */
317 switch (ptr->type)
318 {
319 case MEMCACHED_CONNECTION_UNKNOWN:
320 WATCHPOINT_ASSERT(0);
321 rc= MEMCACHED_NOT_SUPPORTED;
322 break;
323 case MEMCACHED_CONNECTION_UDP:
324 case MEMCACHED_CONNECTION_TCP:
325 rc= network_connect(ptr);
326 break;
327 case MEMCACHED_CONNECTION_UNIX_SOCKET:
328 rc= unix_socket_connect(ptr);
329 break;
330 default:
331 WATCHPOINT_ASSERT(0);
332 }
333
334 LIBMEMCACHED_MEMCACHED_CONNECT_END();
335
336 return rc;
337 }