0c256b71e07c6b9853798135fa6f4688ecb42fcf
[m6w6/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].sockaddr_inited == MEMCACHED_NOT_ALLOCATED)
76 {
77 memcached_return rc;
78
79 rc= set_hostinfo(&ptr->hosts[server_key]);
80 if (rc != MEMCACHED_SUCCESS)
81 return rc;
82
83 ptr->hosts[server_key].sockaddr_inited= MEMCACHED_ALLOCATED;
84 }
85
86 /* Create the socket */
87 if ((ptr->hosts[server_key].fd= socket(AF_INET, SOCK_DGRAM, 0)) < 0)
88 {
89 ptr->cached_errno= errno;
90 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
91 }
92 }
93
94 return MEMCACHED_SUCCESS;
95 }
96
97 static memcached_return tcp_connect(memcached_st *ptr, unsigned int server_key)
98 {
99 if (ptr->hosts[server_key].fd == -1)
100 {
101 /* Old connection junk still is in the structure */
102 WATCHPOINT_ASSERT(ptr->hosts[server_key].stack_responses == 0);
103
104 if (ptr->hosts[server_key].servAddr.sin_family == 0)
105 {
106 memcached_return rc;
107
108 rc= set_hostinfo(&ptr->hosts[server_key]);
109 if (rc != MEMCACHED_SUCCESS)
110 return rc;
111 }
112
113 /* Create the socket */
114 if ((ptr->hosts[server_key].fd= socket(AF_INET, SOCK_STREAM, 0)) < 0)
115 {
116 ptr->cached_errno= errno;
117 return MEMCACHED_CONNECTION_SOCKET_CREATE_FAILURE;
118 }
119
120 /* For the moment, not getting a nonblocking mode will note be fatal */
121 if (ptr->flags & MEM_NO_BLOCK)
122 {
123 int flags;
124
125 flags= fcntl(ptr->hosts[server_key].fd, F_GETFL, 0);
126 if (flags != -1)
127 (void)fcntl(ptr->hosts[server_key].fd, F_SETFL, flags | O_NONBLOCK);
128 }
129
130 if (ptr->flags & MEM_TCP_NODELAY)
131 {
132 int flag= 1;
133
134 setsockopt(ptr->hosts[server_key].fd, IPPROTO_TCP, TCP_NODELAY,
135 &flag, (socklen_t)sizeof(int));
136 }
137
138 if (ptr->send_size)
139 {
140 setsockopt(ptr->hosts[server_key].fd, SOL_SOCKET, SO_SNDBUF,
141 &ptr->send_size, (socklen_t)sizeof(int));
142 }
143
144 if (ptr->recv_size)
145 {
146 setsockopt(ptr->hosts[server_key].fd, SOL_SOCKET, SO_SNDBUF,
147 &ptr->recv_size, (socklen_t)sizeof(int));
148 }
149
150 /* connect to server */
151 test_connect:
152 if (connect(ptr->hosts[server_key].fd,
153 (struct sockaddr *)&ptr->hosts[server_key].servAddr,
154 sizeof(struct sockaddr)) < 0)
155 {
156 switch (errno) {
157 /* We are spinning waiting on connect */
158 case EALREADY:
159 case EINPROGRESS:
160 case EINTR:
161 goto test_connect;
162 case EISCONN: /* We were spinning waiting on connect */
163 break;
164 default:
165 ptr->cached_errno= errno;
166 return MEMCACHED_ERRNO;
167 }
168 ptr->connected++;
169 }
170 WATCHPOINT_ASSERT(ptr->hosts[server_key].stack_responses == 0);
171 }
172
173 return MEMCACHED_SUCCESS;
174 }
175
176
177 memcached_return memcached_connect(memcached_st *ptr, unsigned int server_key)
178 {
179 memcached_return rc= MEMCACHED_NO_SERVERS;
180 LIBMEMCACHED_MEMCACHED_CONNECT_START();
181
182 if (ptr->connected == ptr->number_of_hosts && ptr->number_of_hosts)
183 return MEMCACHED_SUCCESS;
184
185 if (ptr->hosts == NULL || ptr->number_of_hosts == 0)
186 return MEMCACHED_NO_SERVERS;
187
188 /* We need to clean up the multi startup piece */
189 if (server_key)
190 {
191 rc= tcp_connect(ptr, server_key);
192 switch (ptr->hosts[server_key].type)
193 {
194 case MEMCACHED_CONNECTION_UNKNOWN:
195 WATCHPOINT_ASSERT(0);
196 rc= MEMCACHED_NOT_SUPPORTED;
197 break;
198 case MEMCACHED_CONNECTION_UDP:
199 rc= udp_connect(ptr, server_key);
200 break;
201 case MEMCACHED_CONNECTION_TCP:
202 rc= tcp_connect(ptr, server_key);
203 break;
204 case MEMCACHED_CONNECTION_UNIX_SOCKET:
205 rc= unix_socket_connect(ptr, server_key);
206 break;
207 }
208 }
209 else
210 {
211 unsigned int x;
212
213 for (x= 0; x < ptr->number_of_hosts; x++)
214 {
215 memcached_return possible_rc;
216
217 possible_rc= MEMCACHED_NOT_SUPPORTED; /* Remove warning */
218
219 switch (ptr->hosts[x].type)
220 {
221 case MEMCACHED_CONNECTION_UNKNOWN:
222 WATCHPOINT_ASSERT(0);
223 possible_rc= MEMCACHED_NOT_SUPPORTED;
224 break;
225 case MEMCACHED_CONNECTION_UDP:
226 possible_rc= udp_connect(ptr, x);
227 break;
228 case MEMCACHED_CONNECTION_TCP:
229 possible_rc= tcp_connect(ptr, x);
230 break;
231 case MEMCACHED_CONNECTION_UNIX_SOCKET:
232 possible_rc= unix_socket_connect(ptr, x);
233 break;
234 }
235 rc= MEMCACHED_SUCCESS;
236
237 if (possible_rc != MEMCACHED_SUCCESS)
238 rc= MEMCACHED_SOME_ERRORS;
239 }
240 }
241 LIBMEMCACHED_MEMCACHED_CONNECT_END();
242
243 return rc;
244 }