Rework of the server connect so that "hostname" lookup does not occur for
[awesomized/libmemcached] / lib / memcached_connect.c
1 #include "common.h"
2
3 #include <fcntl.h>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <sys/un.h>
7 #include <netinet/tcp.h>
8 #include <netdb.h>
9
10 static memcached_return set_hostinfo(memcached_server_st *server)
11 {
12 struct hostent *h;
13
14 if ((h= gethostbyname(server->hostname)) == NULL)
15 {
16 return MEMCACHED_HOST_LOCKUP_FAILURE;
17 }
18
19 server->servAddr.sin_family= h->h_addrtype;
20 memcpy((char *) &server->servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
21 server->servAddr.sin_port = htons(server->port);
22
23 return MEMCACHED_SUCCESS;
24 }
25
26 static memcached_return unix_socket_connect(memcached_st *ptr, unsigned int server_key)
27 {
28 struct sockaddr_un servAddr;
29 socklen_t addrlen;
30
31 if (ptr->hosts[server_key].fd == -1)
32 {
33 if ((ptr->hosts[server_key].fd= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
34 {
35 ptr->cached_errno= errno;
36 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
37 }
38
39 memset(&servAddr, 0, sizeof (struct sockaddr_un));
40 servAddr.sun_family= AF_UNIX;
41 strcpy(servAddr.sun_path, ptr->hosts[server_key].hostname); /* Copy filename */
42
43 addrlen= strlen(servAddr.sun_path) + sizeof(servAddr.sun_family);
44
45 test_connect:
46 if (connect(ptr->hosts[server_key].fd,
47 (struct sockaddr *)&servAddr,
48 sizeof(servAddr)) < 0)
49 {
50 switch (errno) {
51 /* We are spinning waiting on connect */
52 case EALREADY:
53 case EINPROGRESS:
54 case EINTR:
55 goto test_connect;
56 case EISCONN: /* We were spinning waiting on connect */
57 break;
58 default:
59 ptr->cached_errno= errno;
60 return MEMCACHED_ERRNO;
61 }
62 ptr->connected++;
63 }
64 }
65 return MEMCACHED_SUCCESS;
66 }
67
68 static memcached_return udp_connect(memcached_st *ptr, unsigned int server_key)
69 {
70 if (ptr->hosts[server_key].fd == -1)
71 {
72 /* Old connection junk still is in the structure */
73 WATCHPOINT_ASSERT(ptr->hosts[server_key].stack_responses == 0);
74
75 if (ptr->hosts[server_key].servAddr.sin_family == 0)
76 {
77 memcached_return rc;
78
79 rc= set_hostinfo(&ptr->hosts[server_key]);
80 if (rc != MEMCACHED_SUCCESS)
81 return rc;
82 }
83
84 /* Create the socket */
85 if ((ptr->hosts[server_key].fd= socket(AF_INET, SOCK_DGRAM, 0)) < 0)
86 {
87 ptr->cached_errno= errno;
88 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
89 }
90 }
91
92 return MEMCACHED_SUCCESS;
93 }
94
95 static memcached_return tcp_connect(memcached_st *ptr, unsigned int server_key)
96 {
97 if (ptr->hosts[server_key].fd == -1)
98 {
99 /* Old connection junk still is in the structure */
100 WATCHPOINT_ASSERT(ptr->hosts[server_key].stack_responses == 0);
101
102 if (ptr->hosts[server_key].servAddr.sin_family == 0)
103 {
104 memcached_return rc;
105
106 rc= set_hostinfo(&ptr->hosts[server_key]);
107 if (rc != MEMCACHED_SUCCESS)
108 return rc;
109 }
110
111 /* Create the socket */
112 if ((ptr->hosts[server_key].fd= socket(AF_INET, SOCK_STREAM, 0)) < 0)
113 {
114 ptr->cached_errno= errno;
115 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
116 }
117
118 /* For the moment, not getting a nonblocking mode will note be fatal */
119 if (ptr->flags & MEM_NO_BLOCK)
120 {
121 int flags;
122
123 flags= fcntl(ptr->hosts[server_key].fd, F_GETFL, 0);
124 if (flags != -1)
125 (void)fcntl(ptr->hosts[server_key].fd, F_SETFL, flags | O_NONBLOCK);
126 }
127
128 if (ptr->flags & MEM_TCP_NODELAY)
129 {
130 int flag= 1;
131
132 setsockopt(ptr->hosts[server_key].fd, IPPROTO_TCP, TCP_NODELAY,
133 &flag, (socklen_t)sizeof(int));
134 }
135
136 if (ptr->send_size)
137 {
138 setsockopt(ptr->hosts[server_key].fd, SOL_SOCKET, SO_SNDBUF,
139 &ptr->send_size, (socklen_t)sizeof(int));
140 }
141
142 if (ptr->recv_size)
143 {
144 setsockopt(ptr->hosts[server_key].fd, SOL_SOCKET, SO_SNDBUF,
145 &ptr->recv_size, (socklen_t)sizeof(int));
146 }
147
148 /* connect to server */
149 test_connect:
150 if (connect(ptr->hosts[server_key].fd,
151 (struct sockaddr *)&ptr->hosts[server_key].servAddr,
152 sizeof(struct sockaddr)) < 0)
153 {
154 switch (errno) {
155 /* We are spinning waiting on connect */
156 case EALREADY:
157 case EINPROGRESS:
158 case EINTR:
159 goto test_connect;
160 case EISCONN: /* We were spinning waiting on connect */
161 break;
162 default:
163 ptr->cached_errno= errno;
164 return MEMCACHED_ERRNO;
165 }
166 ptr->connected++;
167 }
168 WATCHPOINT_ASSERT(ptr->hosts[server_key].stack_responses == 0);
169 }
170
171 return MEMCACHED_SUCCESS;
172 }
173
174
175 memcached_return memcached_connect(memcached_st *ptr, unsigned int server_key)
176 {
177 memcached_return rc= MEMCACHED_NO_SERVERS;
178 LIBMEMCACHED_MEMCACHED_CONNECT_START();
179
180 if (ptr->connected == ptr->number_of_hosts && ptr->number_of_hosts)
181 return MEMCACHED_SUCCESS;
182
183 if (ptr->hosts == NULL || ptr->number_of_hosts == 0)
184 return MEMCACHED_NO_SERVERS;
185
186 /* We need to clean up the multi startup piece */
187 if (server_key)
188 {
189 rc= tcp_connect(ptr, server_key);
190 switch (ptr->hosts[server_key].type)
191 {
192 case MEMCACHED_CONNECTION_UNKNOWN:
193 WATCHPOINT_ASSERT(0);
194 rc= MEMCACHED_NOT_SUPPORTED;
195 break;
196 case MEMCACHED_CONNECTION_UDP:
197 rc= udp_connect(ptr, server_key);
198 break;
199 case MEMCACHED_CONNECTION_TCP:
200 rc= tcp_connect(ptr, server_key);
201 break;
202 case MEMCACHED_CONNECTION_UNIX_SOCKET:
203 rc= unix_socket_connect(ptr, server_key);
204 break;
205 }
206 }
207 else
208 {
209 unsigned int x;
210
211 for (x= 0; x < ptr->number_of_hosts; x++)
212 {
213 memcached_return possible_rc;
214
215 possible_rc= MEMCACHED_NOT_SUPPORTED; /* Remove warning */
216
217 switch (ptr->hosts[x].type)
218 {
219 case MEMCACHED_CONNECTION_UNKNOWN:
220 WATCHPOINT_ASSERT(0);
221 possible_rc= MEMCACHED_NOT_SUPPORTED;
222 break;
223 case MEMCACHED_CONNECTION_UDP:
224 possible_rc= udp_connect(ptr, x);
225 break;
226 case MEMCACHED_CONNECTION_TCP:
227 possible_rc= tcp_connect(ptr, x);
228 break;
229 case MEMCACHED_CONNECTION_UNIX_SOCKET:
230 possible_rc= unix_socket_connect(ptr, x);
231 break;
232 }
233 rc= MEMCACHED_SUCCESS;
234
235 if (possible_rc != MEMCACHED_SUCCESS)
236 rc= MEMCACHED_SOME_ERRORS;
237 }
238 }
239 LIBMEMCACHED_MEMCACHED_CONNECT_END();
240
241 return rc;
242 }