b4642c7630fb542ece0935e0f9312ebf31b7ab60
[m6w6/libmemcached] / lib / memcached_connect.c
1 #include "common.h"
2
3 static memcached_return set_hostinfo(memcached_server_st *server)
4 {
5 struct addrinfo *ai;
6 struct addrinfo hints;
7 int e;
8 char str_port[NI_MAXSERV];
9
10 sprintf(str_port, "%u", server->port);
11
12 memset(&hints, 0, sizeof(hints));
13
14 hints.ai_family= AF_INET;
15 if (server->type == MEMCACHED_CONNECTION_UDP)
16 {
17 hints.ai_protocol= IPPROTO_UDP;
18 hints.ai_socktype= SOCK_DGRAM;
19 }
20 else
21 {
22 hints.ai_socktype= SOCK_STREAM;
23 hints.ai_protocol= IPPROTO_TCP;
24 }
25
26 e= getaddrinfo(server->hostname, str_port, &hints, &ai);
27 if (e != 0)
28 {
29 WATCHPOINT_STRING(server->hostname);
30 WATCHPOINT_STRING(gai_strerror(e));
31 return MEMCACHED_HOST_LOOKUP_FAILURE;
32 }
33
34 if (server->address_info)
35 freeaddrinfo(server->address_info);
36 server->address_info= ai;
37
38 return MEMCACHED_SUCCESS;
39 }
40
41 static memcached_return set_socket_options(memcached_server_st *ptr)
42 {
43 if (ptr->type == MEMCACHED_CONNECTION_UDP)
44 return MEMCACHED_SUCCESS;
45
46 if (ptr->root->flags & MEM_NO_BLOCK)
47 {
48 int error;
49 struct linger linger;
50 struct timeval waittime;
51
52 waittime.tv_sec= 10;
53 waittime.tv_usec= 0;
54
55 linger.l_onoff= 1;
56 linger.l_linger= MEMCACHED_DEFAULT_TIMEOUT;
57 error= setsockopt(ptr->fd, SOL_SOCKET, SO_LINGER,
58 &linger, (socklen_t)sizeof(struct linger));
59 WATCHPOINT_ASSERT(error == 0);
60
61 error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDTIMEO,
62 &waittime, (socklen_t)sizeof(struct timeval));
63 WATCHPOINT_ASSERT(error == 0);
64
65 error= setsockopt(ptr->fd, SOL_SOCKET, SO_RCVTIMEO,
66 &waittime, (socklen_t)sizeof(struct timeval));
67 WATCHPOINT_ASSERT(error == 0);
68 }
69
70 if (ptr->root->flags & MEM_TCP_NODELAY)
71 {
72 int flag= 1;
73 int error;
74
75 error= setsockopt(ptr->fd, IPPROTO_TCP, TCP_NODELAY,
76 &flag, (socklen_t)sizeof(int));
77 WATCHPOINT_ASSERT(error == 0);
78 }
79
80 if (ptr->root->send_size)
81 {
82 int error;
83
84 error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
85 &ptr->root->send_size, (socklen_t)sizeof(int));
86 WATCHPOINT_ASSERT(error == 0);
87 }
88
89 if (ptr->root->recv_size)
90 {
91 int error;
92
93 error= setsockopt(ptr->fd, SOL_SOCKET, SO_SNDBUF,
94 &ptr->root->recv_size, (socklen_t)sizeof(int));
95 WATCHPOINT_ASSERT(error == 0);
96 }
97
98 /* For the moment, not getting a nonblocking mode will not be fatal */
99 if (ptr->root->flags & MEM_NO_BLOCK)
100 {
101 int flags;
102
103 flags= fcntl(ptr->fd, F_GETFL, 0);
104 if (flags != -1)
105 {
106 (void)fcntl(ptr->fd, F_SETFL, flags | O_NONBLOCK);
107 }
108 }
109
110 return MEMCACHED_SUCCESS;
111 }
112
113 static memcached_return unix_socket_connect(memcached_server_st *ptr)
114 {
115 struct sockaddr_un servAddr;
116 socklen_t addrlen;
117
118 if (ptr->fd == -1)
119 {
120 if ((ptr->fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
121 {
122 ptr->cached_errno= errno;
123 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
124 }
125
126 memset(&servAddr, 0, sizeof (struct sockaddr_un));
127 servAddr.sun_family= AF_UNIX;
128 strcpy(servAddr.sun_path, ptr->hostname); /* Copy filename */
129
130 addrlen= strlen(servAddr.sun_path) + sizeof(servAddr.sun_family);
131
132 test_connect:
133 if (connect(ptr->fd,
134 (struct sockaddr *)&servAddr,
135 sizeof(servAddr)) < 0)
136 {
137 switch (errno) {
138 /* We are spinning waiting on connect */
139 case EALREADY:
140 case EINPROGRESS:
141 case EINTR:
142 goto test_connect;
143 case EISCONN: /* We were spinning waiting on connect */
144 break;
145 default:
146 WATCHPOINT_ERRNO(errno);
147 ptr->cached_errno= errno;
148 return MEMCACHED_ERRNO;
149 }
150 }
151 }
152 return MEMCACHED_SUCCESS;
153 }
154
155 static memcached_return network_connect(memcached_server_st *ptr)
156 {
157 if (ptr->fd == -1)
158 {
159 struct addrinfo *use;
160
161 /* Old connection junk still is in the structure */
162 WATCHPOINT_ASSERT(ptr->cursor_active == 0);
163
164 if (ptr->sockaddr_inited == MEMCACHED_NOT_ALLOCATED ||
165 (!(ptr->root->flags & MEM_USE_CACHE_LOOKUPS)))
166 {
167 memcached_return rc;
168
169 rc= set_hostinfo(ptr);
170 if (rc != MEMCACHED_SUCCESS)
171 return rc;
172 ptr->sockaddr_inited= MEMCACHED_ALLOCATED;
173 }
174
175 use= ptr->address_info;
176 /* Create the socket */
177 while (use != NULL)
178 {
179 if ((ptr->fd= socket(use->ai_family,
180 use->ai_socktype,
181 use->ai_protocol)) < 0)
182 {
183 ptr->cached_errno= errno;
184 WATCHPOINT_ERRNO(errno);
185 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
186 }
187
188 (void)set_socket_options(ptr);
189
190 /* connect to server */
191 test_connect:
192 if (connect(ptr->fd,
193 use->ai_addr,
194 use->ai_addrlen) < 0)
195 {
196 switch (errno) {
197 /* We are spinning waiting on connect */
198 case EALREADY:
199 case EINPROGRESS:
200 case EINTR:
201 goto test_connect;
202 case EISCONN: /* We were spinning waiting on connect */
203 break;
204 default:
205 ptr->cached_errno= errno;
206 WATCHPOINT_ERRNO(ptr->cached_errno);
207 close(ptr->fd);
208 ptr->fd= -1;
209 }
210 }
211 else
212 {
213 WATCHPOINT_ASSERT(ptr->cursor_active == 0);
214 return MEMCACHED_SUCCESS;
215 }
216 use = use->ai_next;
217 }
218 }
219
220 if (ptr->fd == -1)
221 return MEMCACHED_ERRNO; /* The last error should be from connect() */
222
223 return MEMCACHED_SUCCESS; /* The last error should be from connect() */
224 }
225
226
227 memcached_return memcached_connect(memcached_server_st *ptr)
228 {
229 memcached_return rc= MEMCACHED_NO_SERVERS;
230 LIBMEMCACHED_MEMCACHED_CONNECT_START();
231
232 /* We need to clean up the multi startup piece */
233 switch (ptr->type)
234 {
235 case MEMCACHED_CONNECTION_UNKNOWN:
236 WATCHPOINT_ASSERT(0);
237 rc= MEMCACHED_NOT_SUPPORTED;
238 break;
239 case MEMCACHED_CONNECTION_UDP:
240 case MEMCACHED_CONNECTION_TCP:
241 rc= network_connect(ptr);
242 break;
243 case MEMCACHED_CONNECTION_UNIX_SOCKET:
244 rc= unix_socket_connect(ptr);
245 break;
246 default:
247 WATCHPOINT_ASSERT(0);
248 }
249
250 if (rc != MEMCACHED_SUCCESS)
251 WATCHPOINT_ERROR(rc);
252
253 LIBMEMCACHED_MEMCACHED_CONNECT_END();
254
255 return rc;
256 }