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