blob: 41d8b169e0698cea03c44409d62fcd063c473bb9 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Craig Tiller0c0b60c2015-01-21 15:49:28 -080034#include <grpc/support/port_platform.h>
35
36#ifdef GPR_POSIX_SOCKET
37
ctiller18b49ab2014-12-09 14:39:16 -080038#include "src/core/iomgr/tcp_client.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080039
40#include <errno.h>
nnoble0c475f02014-12-05 15:37:39 -080041#include <netinet/in.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080042#include <string.h>
43#include <unistd.h>
44
ctiller58393c22015-01-07 14:03:30 -080045#include "src/core/iomgr/alarm.h"
46#include "src/core/iomgr/iomgr_posix.h"
47#include "src/core/iomgr/pollset_posix.h"
ctiller18b49ab2014-12-09 14:39:16 -080048#include "src/core/iomgr/sockaddr_utils.h"
49#include "src/core/iomgr/socket_utils_posix.h"
50#include "src/core/iomgr/tcp_posix.h"
Craig Tillerfa275a92015-06-01 13:55:54 -070051#include "src/core/support/string.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080052#include <grpc/support/alloc.h>
53#include <grpc/support/log.h>
Masood Malekghassemi701af602015-06-03 15:01:17 -070054#include <grpc/support/string_util.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080055#include <grpc/support/time.h>
56
57typedef struct {
58 void (*cb)(void *arg, grpc_endpoint *tcp);
59 void *cb_arg;
ctiller58393c22015-01-07 14:03:30 -080060 gpr_mu mu;
ctiller18b49ab2014-12-09 14:39:16 -080061 grpc_fd *fd;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080062 gpr_timespec deadline;
ctiller58393c22015-01-07 14:03:30 -080063 grpc_alarm alarm;
64 int refs;
Craig Tiller0fcd53c2015-02-18 15:10:53 -080065 grpc_iomgr_closure write_closure;
Craig Tillerb49736822015-06-30 08:15:08 -070066 grpc_pollset_set *interested_parties;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080067} async_connect;
68
Craig Tillerd209ed02015-02-13 23:18:15 -080069static int prepare_socket(const struct sockaddr *addr, int fd) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080070 if (fd < 0) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080071 goto error;
72 }
73
74 if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
Craig Tiller2da02962015-05-06 16:14:25 -070075 (addr->sa_family != AF_UNIX && !grpc_set_socket_low_latency(fd, 1)) ||
76 !grpc_set_socket_no_sigpipe_if_possible(fd)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080077 gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
78 strerror(errno));
79 goto error;
80 }
81
nnoble0c475f02014-12-05 15:37:39 -080082 return 1;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080083
84error:
85 if (fd >= 0) {
86 close(fd);
87 }
nnoble0c475f02014-12-05 15:37:39 -080088 return 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080089}
90
ctiller58393c22015-01-07 14:03:30 -080091static void on_alarm(void *acp, int success) {
92 int done;
93 async_connect *ac = acp;
94 gpr_mu_lock(&ac->mu);
95 if (ac->fd != NULL && success) {
96 grpc_fd_shutdown(ac->fd);
97 }
98 done = (--ac->refs == 0);
99 gpr_mu_unlock(&ac->mu);
100 if (done) {
101 gpr_mu_destroy(&ac->mu);
102 gpr_free(ac);
103 }
104}
105
106static void on_writable(void *acp, int success) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800107 async_connect *ac = acp;
108 int so_error = 0;
109 socklen_t so_error_size;
110 int err;
ctiller58393c22015-01-07 14:03:30 -0800111 int fd = ac->fd->fd;
112 int done;
113 grpc_endpoint *ep = NULL;
114 void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
115 void *cb_arg = ac->cb_arg;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800116
Craig Tiller26205362015-07-21 08:21:57 -0700117 grpc_alarm_cancel(&ac->alarm);
118
Craig Tiller71bf1be2015-07-09 14:51:24 -0700119 gpr_mu_lock(&ac->mu);
ctiller58393c22015-01-07 14:03:30 -0800120 if (success) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800121 do {
122 so_error_size = sizeof(so_error);
123 err = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
124 } while (err < 0 && errno == EINTR);
125 if (err < 0) {
126 gpr_log(GPR_ERROR, "getsockopt(ERROR): %s", strerror(errno));
ctiller58393c22015-01-07 14:03:30 -0800127 goto finish;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800128 } else if (so_error != 0) {
129 if (so_error == ENOBUFS) {
130 /* We will get one of these errors if we have run out of
131 memory in the kernel for the data structures allocated
132 when you connect a socket. If this happens it is very
133 likely that if we wait a little bit then try again the
134 connection will work (since other programs or this
135 program will close their network connections and free up
136 memory). This does _not_ indicate that there is anything
137 wrong with the server we are connecting to, this is a
138 local problem.
139
140 If you are looking at this code, then chances are that
141 your program or another program on the same computer
142 opened too many network connections. The "easy" fix:
143 don't do that! */
144 gpr_log(GPR_ERROR, "kernel out of buffers");
Craig Tiller71bf1be2015-07-09 14:51:24 -0700145 gpr_mu_unlock(&ac->mu);
Craig Tiller0fcd53c2015-02-18 15:10:53 -0800146 grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800147 return;
148 } else {
ctillerccd27fd2014-12-11 09:12:02 -0800149 switch (so_error) {
150 case ECONNREFUSED:
151 gpr_log(GPR_ERROR, "socket error: connection refused");
152 break;
153 default:
154 gpr_log(GPR_ERROR, "socket error: %d", so_error);
155 break;
156 }
ctiller58393c22015-01-07 14:03:30 -0800157 goto finish;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800158 }
159 } else {
Craig Tillerb49736822015-06-30 08:15:08 -0700160 grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
ctiller58393c22015-01-07 14:03:30 -0800161 ep = grpc_tcp_create(ac->fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE);
162 goto finish;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800163 }
164 } else {
ctiller58393c22015-01-07 14:03:30 -0800165 gpr_log(GPR_ERROR, "on_writable failed during connect");
166 goto finish;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800167 }
168
169 abort();
170
ctiller58393c22015-01-07 14:03:30 -0800171finish:
Craig Tiller71bf1be2015-07-09 14:51:24 -0700172 if (ep == NULL) {
Craig Tillerb49736822015-06-30 08:15:08 -0700173 grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
Craig Tiller4b678bd2015-06-02 16:12:24 -0700174 grpc_fd_orphan(ac->fd, NULL, "tcp_client_orphan");
Craig Tiller71bf1be2015-07-09 14:51:24 -0700175 } else {
176 ac->fd = NULL;
ctiller58393c22015-01-07 14:03:30 -0800177 }
178 done = (--ac->refs == 0);
179 gpr_mu_unlock(&ac->mu);
180 if (done) {
181 gpr_mu_destroy(&ac->mu);
182 gpr_free(ac);
183 }
184 cb(cb_arg, ep);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800185}
186
187void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
Craig Tiller8ed24e22015-05-08 09:59:51 -0700188 void *arg, grpc_pollset_set *interested_parties,
189 const struct sockaddr *addr, int addr_len,
190 gpr_timespec deadline) {
nnoble0c475f02014-12-05 15:37:39 -0800191 int fd;
192 grpc_dualstack_mode dsmode;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800193 int err;
194 async_connect *ac;
nnoble0c475f02014-12-05 15:37:39 -0800195 struct sockaddr_in6 addr6_v4mapped;
196 struct sockaddr_in addr4_copy;
Craig Tiller9bcc7512015-05-11 14:59:48 -0700197 grpc_fd *fdobj;
Craig Tillerfa275a92015-06-01 13:55:54 -0700198 char *name;
199 char *addr_str;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800200
nnoble0c475f02014-12-05 15:37:39 -0800201 /* Use dualstack sockets where available. */
202 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
203 addr = (const struct sockaddr *)&addr6_v4mapped;
204 addr_len = sizeof(addr6_v4mapped);
205 }
206
207 fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800208 if (fd < 0) {
nnoble0c475f02014-12-05 15:37:39 -0800209 gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
210 }
211 if (dsmode == GRPC_DSMODE_IPV4) {
212 /* If we got an AF_INET socket, map the address back to IPv4. */
213 GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy));
214 addr = (struct sockaddr *)&addr4_copy;
215 addr_len = sizeof(addr4_copy);
216 }
Craig Tillerae7fe922015-02-13 23:16:32 -0800217 if (!prepare_socket(addr, fd)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800218 cb(arg, NULL);
219 return;
220 }
221
222 do {
nnoble0c475f02014-12-05 15:37:39 -0800223 err = connect(fd, addr, addr_len);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800224 } while (err < 0 && errno == EINTR);
225
Craig Tillerfa275a92015-06-01 13:55:54 -0700226 grpc_sockaddr_to_string(&addr_str, addr, 1);
227 gpr_asprintf(&name, "tcp-client:%s", addr_str);
228
Craig Tiller8e0b08a2015-06-01 17:04:17 -0700229 fdobj = grpc_fd_create(fd, name);
Craig Tiller9bcc7512015-05-11 14:59:48 -0700230
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800231 if (err >= 0) {
Craig Tiller8674cb12015-06-05 07:09:25 -0700232 cb(arg, grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
Craig Tillerfa275a92015-06-01 13:55:54 -0700233 goto done;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800234 }
235
236 if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
Craig Tiller4b678bd2015-06-02 16:12:24 -0700237 gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
238 grpc_fd_orphan(fdobj, NULL, "tcp_client_connect_error");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800239 cb(arg, NULL);
Craig Tillerfa275a92015-06-01 13:55:54 -0700240 goto done;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800241 }
242
Craig Tiller4b678bd2015-06-02 16:12:24 -0700243 grpc_pollset_set_add_fd(interested_parties, fdobj);
244
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800245 ac = gpr_malloc(sizeof(async_connect));
246 ac->cb = cb;
247 ac->cb_arg = arg;
Craig Tiller9bcc7512015-05-11 14:59:48 -0700248 ac->fd = fdobj;
Craig Tillerb49736822015-06-30 08:15:08 -0700249 ac->interested_parties = interested_parties;
ctiller58393c22015-01-07 14:03:30 -0800250 gpr_mu_init(&ac->mu);
251 ac->refs = 2;
Craig Tiller0fcd53c2015-02-18 15:10:53 -0800252 ac->write_closure.cb = on_writable;
253 ac->write_closure.cb_arg = ac;
ctiller58393c22015-01-07 14:03:30 -0800254
Craig Tiller0317b3d2015-06-01 21:57:03 -0700255 gpr_mu_lock(&ac->mu);
Craig Tiller6a7626c2015-07-19 22:21:41 -0700256 grpc_alarm_init(&ac->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
257 on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
Craig Tiller0317b3d2015-06-01 21:57:03 -0700258 grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
259 gpr_mu_unlock(&ac->mu);
Craig Tillerfa275a92015-06-01 13:55:54 -0700260
261done:
262 gpr_free(name);
263 gpr_free(addr_str);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800264}
Craig Tiller0c0b60c2015-01-21 15:49:28 -0800265
Craig Tiller190d3602015-02-18 09:23:38 -0800266#endif