blob: e20cc3d1b2ed7e829def445d79db1b4e02b5171f [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"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080051#include <grpc/support/alloc.h>
52#include <grpc/support/log.h>
53#include <grpc/support/time.h>
54
55typedef struct {
56 void (*cb)(void *arg, grpc_endpoint *tcp);
57 void *cb_arg;
ctiller58393c22015-01-07 14:03:30 -080058 gpr_mu mu;
ctiller18b49ab2014-12-09 14:39:16 -080059 grpc_fd *fd;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080060 gpr_timespec deadline;
ctiller58393c22015-01-07 14:03:30 -080061 grpc_alarm alarm;
62 int refs;
Craig Tiller0fcd53c2015-02-18 15:10:53 -080063 grpc_iomgr_closure write_closure;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080064} async_connect;
65
Craig Tillerd209ed02015-02-13 23:18:15 -080066static int prepare_socket(const struct sockaddr *addr, int fd) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080067 if (fd < 0) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080068 goto error;
69 }
70
71 if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) ||
Craig Tillerae7fe922015-02-13 23:16:32 -080072 (addr->sa_family != AF_UNIX && !grpc_set_socket_low_latency(fd, 1))) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080073 gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd,
74 strerror(errno));
75 goto error;
76 }
77
nnoble0c475f02014-12-05 15:37:39 -080078 return 1;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080079
80error:
81 if (fd >= 0) {
82 close(fd);
83 }
nnoble0c475f02014-12-05 15:37:39 -080084 return 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080085}
86
ctiller58393c22015-01-07 14:03:30 -080087static void on_alarm(void *acp, int success) {
88 int done;
89 async_connect *ac = acp;
90 gpr_mu_lock(&ac->mu);
91 if (ac->fd != NULL && success) {
92 grpc_fd_shutdown(ac->fd);
93 }
94 done = (--ac->refs == 0);
95 gpr_mu_unlock(&ac->mu);
96 if (done) {
97 gpr_mu_destroy(&ac->mu);
98 gpr_free(ac);
99 }
100}
101
102static void on_writable(void *acp, int success) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800103 async_connect *ac = acp;
104 int so_error = 0;
105 socklen_t so_error_size;
106 int err;
ctiller58393c22015-01-07 14:03:30 -0800107 int fd = ac->fd->fd;
108 int done;
109 grpc_endpoint *ep = NULL;
110 void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
111 void *cb_arg = ac->cb_arg;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800112
ctiller58393c22015-01-07 14:03:30 -0800113 grpc_alarm_cancel(&ac->alarm);
114
115 if (success) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800116 do {
117 so_error_size = sizeof(so_error);
118 err = getsockopt(fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_size);
119 } while (err < 0 && errno == EINTR);
120 if (err < 0) {
121 gpr_log(GPR_ERROR, "getsockopt(ERROR): %s", strerror(errno));
ctiller58393c22015-01-07 14:03:30 -0800122 goto finish;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800123 } else if (so_error != 0) {
124 if (so_error == ENOBUFS) {
125 /* We will get one of these errors if we have run out of
126 memory in the kernel for the data structures allocated
127 when you connect a socket. If this happens it is very
128 likely that if we wait a little bit then try again the
129 connection will work (since other programs or this
130 program will close their network connections and free up
131 memory). This does _not_ indicate that there is anything
132 wrong with the server we are connecting to, this is a
133 local problem.
134
135 If you are looking at this code, then chances are that
136 your program or another program on the same computer
137 opened too many network connections. The "easy" fix:
138 don't do that! */
139 gpr_log(GPR_ERROR, "kernel out of buffers");
Craig Tiller0fcd53c2015-02-18 15:10:53 -0800140 grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800141 return;
142 } else {
ctillerccd27fd2014-12-11 09:12:02 -0800143 switch (so_error) {
144 case ECONNREFUSED:
145 gpr_log(GPR_ERROR, "socket error: connection refused");
146 break;
147 default:
148 gpr_log(GPR_ERROR, "socket error: %d", so_error);
149 break;
150 }
ctiller58393c22015-01-07 14:03:30 -0800151 goto finish;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800152 }
153 } else {
ctiller58393c22015-01-07 14:03:30 -0800154 ep = grpc_tcp_create(ac->fd, GRPC_TCP_DEFAULT_READ_SLICE_SIZE);
155 goto finish;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800156 }
157 } else {
ctiller58393c22015-01-07 14:03:30 -0800158 gpr_log(GPR_ERROR, "on_writable failed during connect");
159 goto finish;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800160 }
161
162 abort();
163
ctiller58393c22015-01-07 14:03:30 -0800164finish:
165 gpr_mu_lock(&ac->mu);
166 if (!ep) {
167 grpc_fd_orphan(ac->fd, NULL, NULL);
168 }
169 done = (--ac->refs == 0);
170 gpr_mu_unlock(&ac->mu);
171 if (done) {
172 gpr_mu_destroy(&ac->mu);
173 gpr_free(ac);
174 }
175 cb(cb_arg, ep);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800176}
177
178void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
ctiller18b49ab2014-12-09 14:39:16 -0800179 void *arg, const struct sockaddr *addr,
180 int addr_len, gpr_timespec deadline) {
nnoble0c475f02014-12-05 15:37:39 -0800181 int fd;
182 grpc_dualstack_mode dsmode;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800183 int err;
184 async_connect *ac;
nnoble0c475f02014-12-05 15:37:39 -0800185 struct sockaddr_in6 addr6_v4mapped;
186 struct sockaddr_in addr4_copy;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800187
nnoble0c475f02014-12-05 15:37:39 -0800188 /* Use dualstack sockets where available. */
189 if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
190 addr = (const struct sockaddr *)&addr6_v4mapped;
191 addr_len = sizeof(addr6_v4mapped);
192 }
193
194 fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800195 if (fd < 0) {
nnoble0c475f02014-12-05 15:37:39 -0800196 gpr_log(GPR_ERROR, "Unable to create socket: %s", strerror(errno));
197 }
198 if (dsmode == GRPC_DSMODE_IPV4) {
199 /* If we got an AF_INET socket, map the address back to IPv4. */
200 GPR_ASSERT(grpc_sockaddr_is_v4mapped(addr, &addr4_copy));
201 addr = (struct sockaddr *)&addr4_copy;
202 addr_len = sizeof(addr4_copy);
203 }
Craig Tillerae7fe922015-02-13 23:16:32 -0800204 if (!prepare_socket(addr, fd)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800205 cb(arg, NULL);
206 return;
207 }
208
209 do {
nnoble0c475f02014-12-05 15:37:39 -0800210 err = connect(fd, addr, addr_len);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800211 } while (err < 0 && errno == EINTR);
212
213 if (err >= 0) {
ctiller58393c22015-01-07 14:03:30 -0800214 gpr_log(GPR_DEBUG, "instant connect");
ctiller18b49ab2014-12-09 14:39:16 -0800215 cb(arg,
216 grpc_tcp_create(grpc_fd_create(fd), GRPC_TCP_DEFAULT_READ_SLICE_SIZE));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800217 return;
218 }
219
220 if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
221 gpr_log(GPR_ERROR, "connect error: %s", strerror(errno));
222 close(fd);
223 cb(arg, NULL);
224 return;
225 }
226
227 ac = gpr_malloc(sizeof(async_connect));
228 ac->cb = cb;
229 ac->cb_arg = arg;
ctiller18b49ab2014-12-09 14:39:16 -0800230 ac->fd = grpc_fd_create(fd);
ctiller58393c22015-01-07 14:03:30 -0800231 gpr_mu_init(&ac->mu);
232 ac->refs = 2;
Craig Tiller0fcd53c2015-02-18 15:10:53 -0800233 ac->write_closure.cb = on_writable;
234 ac->write_closure.cb_arg = ac;
ctiller58393c22015-01-07 14:03:30 -0800235
236 grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
Craig Tiller0fcd53c2015-02-18 15:10:53 -0800237 grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800238}
Craig Tiller0c0b60c2015-01-21 15:49:28 -0800239
Craig Tiller190d3602015-02-18 09:23:38 -0800240#endif