1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2014-2020 Couchbase, Inc.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 
18 #ifndef _WIN32
19 #include <cerrno>
20 #endif
21 
22 #include "connect.h"
23 #include "ioutils.h"
24 #include "hostlist.h"
25 #include "iotable.h"
26 #include "ssl.h"
27 
lcbio_mkcserr(int syserr)28 lcbio_CSERR lcbio_mkcserr(int syserr)
29 {
30     switch (syserr) {
31         case 0:
32             return LCBIO_CSERR_CONNECTED;
33 
34         case EINTR:
35             return LCBIO_CSERR_INTR;
36 
37         case EWOULDBLOCK:
38 #ifdef USE_EAGAIN
39         case EAGAIN:
40 #endif
41         case EINPROGRESS:
42         case EALREADY:
43             return LCBIO_CSERR_BUSY;
44 
45         case EISCONN:
46             return LCBIO_CSERR_CONNECTED;
47 
48 #ifdef _WIN32
49         case EINVAL:
50             return LCBIO_CSERR_EINVAL;
51 #endif
52         default:
53             return LCBIO_CSERR_EFAIL;
54     }
55 }
56 
lcbio_mksyserr(lcbio_OSERR in, lcbio_OSERR *out)57 void lcbio_mksyserr(lcbio_OSERR in, lcbio_OSERR *out)
58 {
59     switch (in) {
60         case EINTR:
61         case EWOULDBLOCK:
62 #ifdef USE_EAGAIN
63         case EAGAIN:
64 #endif
65         case EINVAL:
66         case EINPROGRESS:
67         case EISCONN:
68         case EALREADY:
69             return;
70         default:
71             *out = in;
72             break;
73     }
74 }
75 
ioerr2lcberr(lcbio_OSERR in, const lcb_settings *settings)76 static lcb_STATUS ioerr2lcberr(lcbio_OSERR in, const lcb_settings *settings)
77 {
78     switch (in) {
79         case 0:
80             return LCB_ERR_SOCKET_SHUTDOWN;
81         case ECONNREFUSED:
82             return LCB_ERR_CONNECTION_REFUSED;
83         case ENETUNREACH:
84         case EHOSTUNREACH:
85         case EHOSTDOWN:
86             return LCB_ERR_NODE_UNREACHABLE;
87         case EMFILE:
88         case ENFILE:
89             return LCB_ERR_FD_LIMIT_REACHED;
90         case EADDRINUSE:
91         case EADDRNOTAVAIL:
92             return LCB_ERR_CANNOT_GET_PORT;
93         case ECONNRESET:
94         case ECONNABORTED:
95             return LCB_ERR_CONNECTION_RESET;
96         default:
97             lcb_log(settings, "lcbio", LCB_LOG_WARN, __FILE__, __LINE__,
98                     "OS errno %d (%s) does not have a direct client error code equivalent. Using NETWORK_ERROR", in,
99                     strerror(in));
100             return LCB_ERR_NETWORK;
101     }
102 }
103 
lcbio_mklcberr(lcbio_OSERR in, const lcb_settings *settings)104 lcb_STATUS lcbio_mklcberr(lcbio_OSERR in, const lcb_settings *settings)
105 {
106     if (settings->detailed_neterr == 0) {
107         lcb_log(settings, "lcbio", LCB_LOG_WARN, __FILE__, __LINE__, "Translating errno=%d (%s), %s to LCB_ERR_NETWORK",
108                 in, strerror(in), lcb_strerror_short(ioerr2lcberr(in, settings)));
109         return LCB_ERR_NETWORK;
110     }
111 
112     return ioerr2lcberr(in, settings);
113 }
114 
lcbio_E_ai2sock(lcbio_TABLE *io, struct addrinfo **ai, int *connerr)115 lcb_socket_t lcbio_E_ai2sock(lcbio_TABLE *io, struct addrinfo **ai, int *connerr)
116 {
117     lcb_socket_t ret = INVALID_SOCKET;
118     *connerr = 0;
119 
120     for (; *ai; *ai = (*ai)->ai_next) {
121         ret = io->E_socket(*ai);
122 
123         if (ret != INVALID_SOCKET) {
124             return ret;
125         } else {
126             *connerr = io->get_errno();
127         }
128     }
129 
130     return ret;
131 }
132 
lcbio_C_ai2sock(lcbio_TABLE *io, struct addrinfo **ai, int *connerr)133 lcb_sockdata_t *lcbio_C_ai2sock(lcbio_TABLE *io, struct addrinfo **ai, int *connerr)
134 {
135     lcb_sockdata_t *ret = nullptr;
136     for (; *ai; *ai = (*ai)->ai_next) {
137         ret = io->C_socket(*ai);
138         if (ret) {
139             return ret;
140         } else {
141             *connerr = IOT_ERRNO(io);
142         }
143     }
144     return ret;
145 }
saddr_to_host_and_port(struct sockaddr *saddr, int len, char *host, lcb_size_t nhost, char *port, lcb_size_t nport)146 static int saddr_to_host_and_port(struct sockaddr *saddr, int len, char *host, lcb_size_t nhost, char *port,
147                                   lcb_size_t nport)
148 {
149     return getnameinfo(saddr, len, host, nhost, port, nport, NI_NUMERICHOST | NI_NUMERICSERV);
150 }
151 
saddr_to_string(struct sockaddr *saddr, int len, char *buf, lcb_size_t nbuf)152 static int saddr_to_string(struct sockaddr *saddr, int len, char *buf, lcb_size_t nbuf)
153 {
154     char h[NI_MAXHOST + 1];
155     char p[NI_MAXSERV + 1];
156     int rv;
157 
158     rv = saddr_to_host_and_port(saddr, len, h, sizeof(h), p, sizeof(p));
159     if (rv < 0) {
160         return 0;
161     }
162 
163     if (snprintf(buf, nbuf, "%s;%s", h, p) < 0) {
164         return 0;
165     }
166 
167     return 1;
168 }
169 
lcbio_cache_local_name(lcbio_CONNINFO *sock)170 static void lcbio_cache_local_name(lcbio_CONNINFO *sock)
171 {
172     char addr_str[NI_MAXHOST + 1];
173     switch (sock->sa_local.ss_family) {
174         case AF_INET: {
175             auto *addr = (struct sockaddr_in *)&sock->sa_local;
176             inet_ntop(AF_INET, &(addr->sin_addr), addr_str, sizeof(addr_str));
177             strncpy(sock->ep_local.host, addr_str, sizeof(sock->ep_local.host));
178             snprintf(sock->ep_local.port, sizeof(sock->ep_local.port), "%d", (int)ntohs(addr->sin_port));
179         } break;
180 
181         case AF_INET6: {
182             auto *addr = (struct sockaddr_in6 *)&sock->sa_local;
183             inet_ntop(AF_INET6, &(addr->sin6_addr), addr_str, sizeof(addr_str));
184             strncpy(sock->ep_local.host, addr_str, sizeof(sock->ep_local.host));
185             snprintf(sock->ep_local.port, sizeof(sock->ep_local.port), "%d", (int)ntohs(addr->sin6_port));
186         } break;
187     }
188     snprintf(sock->ep_local_host_and_port, sizeof(sock->ep_local_host_and_port), "%s:%s", sock->ep_local.host,
189              sock->ep_local.port);
190 }
191 
lcbio__load_socknames(lcbio_SOCKET *sock)192 void lcbio__load_socknames(lcbio_SOCKET *sock)
193 {
194     int n_salocal, n_saremote, rv;
195     struct lcb_nameinfo_st ni {
196     };
197     lcbio_CONNINFO *info = sock->info;
198 
199     n_salocal = sizeof(info->sa_local);
200     n_saremote = sizeof(info->sa_remote);
201     ni.local.name = (struct sockaddr *)&info->sa_local;
202     ni.local.len = &n_salocal;
203     ni.remote.name = (struct sockaddr *)&info->sa_remote;
204     ni.remote.len = &n_saremote;
205 
206     if (!IOT_IS_EVENT(sock->io)) {
207         if (!sock->u.sd) {
208             return;
209         }
210 
211         rv = IOT_V1(sock->io).nameinfo(IOT_ARG(sock->io), sock->u.sd, &ni);
212 
213         if (ni.local.len == nullptr || ni.remote.len == nullptr || rv < 0) {
214             return;
215         }
216 
217     } else {
218         socklen_t sl_tmp = sizeof(info->sa_local);
219         if (sock->u.fd == INVALID_SOCKET) {
220             return;
221         }
222 
223         rv = getsockname(sock->u.fd, ni.local.name, &sl_tmp);
224         n_salocal = sl_tmp;
225         if (rv < 0) {
226             return;
227         }
228         rv = getpeername(sock->u.fd, ni.remote.name, &sl_tmp);
229         n_saremote = sl_tmp;
230         if (rv < 0) {
231             return;
232         }
233     }
234     info->naddr = n_salocal;
235     lcbio_cache_local_name(info);
236 }
237 
lcbio_get_nameinfo(lcbio_SOCKET *sock, struct lcbio_NAMEINFO *nistrs)238 int lcbio_get_nameinfo(lcbio_SOCKET *sock, struct lcbio_NAMEINFO *nistrs)
239 {
240     lcbio_CONNINFO *info = sock->info;
241     if (!info) {
242         return 0;
243     }
244     if (!info->naddr) {
245         return 0;
246     }
247 
248     if (!saddr_to_string((struct sockaddr *)&info->sa_remote, info->naddr, nistrs->remote, sizeof(nistrs->remote))) {
249         return 0;
250     }
251 
252     if (!saddr_to_string((struct sockaddr *)&info->sa_local, info->naddr, nistrs->local, sizeof(nistrs->local))) {
253         return 0;
254     }
255 
256     return 1;
257 }
258 
lcbio_is_netclosed(lcbio_SOCKET *sock, int flags)259 int lcbio_is_netclosed(lcbio_SOCKET *sock, int flags)
260 {
261     lcbio_pTABLE iot = sock->io;
262 
263     if (iot->is_E()) {
264         return iot->E_check_closed(sock->u.fd, flags);
265     } else {
266         return iot->C_check_closed(sock->u.sd, flags);
267     }
268 }
269 
lcbio_enable_sockopt(lcbio_SOCKET *s, int cntl)270 lcb_STATUS lcbio_enable_sockopt(lcbio_SOCKET *s, int cntl)
271 {
272     lcbio_pTABLE iot = s->io;
273     int rv;
274     int value = 1;
275 
276     if (!iot->has_cntl()) {
277         return LCB_ERR_UNSUPPORTED_OPERATION;
278     }
279     if (iot->is_E()) {
280         rv = iot->E_cntl(s->u.fd, LCB_IO_CNTL_SET, cntl, &value);
281     } else {
282         rv = iot->C_cntl(s->u.sd, LCB_IO_CNTL_SET, cntl, &value);
283     }
284     if (rv != 0) {
285         return lcbio_mklcberr(IOT_ERRNO(iot), s->settings);
286     } else {
287         return LCB_SUCCESS;
288     }
289 }
290 
lcbio_strsockopt(int cntl)291 const char *lcbio_strsockopt(int cntl)
292 {
293     switch (cntl) {
294         case LCB_IO_CNTL_TCP_KEEPALIVE:
295             return "TCP_KEEPALIVE";
296         case LCB_IO_CNTL_TCP_NODELAY:
297             return "TCP_NODELAY";
298         default:
299             return "FIXME: Unknown option";
300     }
301 }
302 
lcbio_ssl_supported(void)303 int lcbio_ssl_supported(void)
304 {
305 #ifdef LCB_NO_SSL
306     return 0;
307 #else
308     return 1;
309 #endif
310 }
311 
lcbio_ssl_new__fallback(const char *, const char *, const char *, int, lcb_STATUS *errp, lcb_settings *)312 lcbio_pSSLCTX lcbio_ssl_new__fallback(const char *, const char *, const char *, int, lcb_STATUS *errp, lcb_settings *)
313 {
314     if (errp) {
315         *errp = LCB_ERR_SDK_FEATURE_UNAVAILABLE;
316     }
317     return nullptr;
318 }
319 
320 #ifdef LCB_NO_SSL
lcbio_ssl_free(lcbio_pSSLCTX)321 void lcbio_ssl_free(lcbio_pSSLCTX) {}
lcbio_ssl_apply(lcbio_SOCKET *, lcbio_pSSLCTX)322 lcb_STATUS lcbio_ssl_apply(lcbio_SOCKET *, lcbio_pSSLCTX)
323 {
324     return LCB_ERR_SDK_FEATURE_UNAVAILABLE;
325 }
lcbio_ssl_check(lcbio_SOCKET *)326 int lcbio_ssl_check(lcbio_SOCKET *)
327 {
328     return 0;
329 }
lcbio_ssl_get_error(lcbio_SOCKET *)330 lcb_STATUS lcbio_ssl_get_error(lcbio_SOCKET *)
331 {
332     return LCB_SUCCESS;
333 }
lcbio_ssl_global_init(void)334 void lcbio_ssl_global_init(void) {}
lcbio_sslify_if_needed(lcbio_SOCKET *, lcb_settings *)335 lcb_STATUS lcbio_sslify_if_needed(lcbio_SOCKET *, lcb_settings *)
336 {
337     return LCB_SUCCESS;
338 }
339 #endif
340