All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
as_socket.h
Go to the documentation of this file.
1 /*
2  * Copyright 2008-2017 Aerospike, Inc.
3  *
4  * Portions may be licensed to Aerospike, Inc. under one or more contributor
5  * license agreements.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8  * use this file except in compliance with the License. You may obtain a copy of
9  * the License at 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, WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14  * License for the specific language governing permissions and limitations under
15  * the License.
16  */
17 #pragma once
18 
19 #include <aerospike/as_error.h>
20 #include <citrusleaf/cf_clock.h>
21 #include <stddef.h>
22 #include <stdint.h>
23 
24 #include <openssl/ssl.h>
25 
26 #include <aerospike/as_config.h>
27 
28 #if defined(__linux__) || defined(__APPLE__)
29 #include <unistd.h>
30 #include <arpa/inet.h>
31 #include <netinet/in.h>
32 #include <sys/socket.h>
33 
34 // Windows send() and recv() parameter types are different.
35 #define as_socket_data_t void
36 #define as_socket_size_t size_t
37 #define as_close(fd) (close(fd))
38 #endif
39 
40 #if defined(__APPLE__)
41 #define SOL_TCP IPPROTO_TCP
42 #define MSG_NOSIGNAL 0
43 #endif
44 
45 #if defined(CF_WINDOWS)
46 #include <WinSock2.h>
47 #include <Ws2tcpip.h>
48 
49 #define as_socket_data_t char
50 #define as_socket_size_t int
51 #define as_close(fd) (closesocket(fd))
52 
53 #define MSG_DONTWAIT 0
54 #define MSG_NOSIGNAL 0
55 
56 #define SHUT_RDWR SD_BOTH
57 #endif // CF_WINDOWS
58 
59 #define AS_IP_ADDRESS_SIZE 64
60 
61 #ifdef __cplusplus
62 extern "C" {
63 #endif
64 
65 /**
66  * This structure holds TLS context which can be shared (read-only)
67  * by all the connections to a specific cluster.
68  */
69 typedef struct as_tls_context_s {
70  SSL_CTX* ssl_ctx;
74 
75 struct as_conn_pool_lock_s;
76 struct as_node_s;
77 
78 /**
79  * Socket fields for both regular and TLS sockets.
80  */
81 typedef struct as_socket_s {
82  int fd;
83  int family;
84  union {
85  struct as_conn_pool_lock_s* pool_lock; // Used when sync socket is active.
86  struct {
87  uint32_t max_socket_idle;
88  uint32_t last_used;
89  } idle_check; // Used when socket in pool.
90  };
92  const char* tls_name;
93  SSL* ssl;
94 } as_socket;
95 
96 /**
97  * @private
98  * Initialize an as_socket structure.
99  */
100 void
102 
103 /**
104  * @private
105  * Create non-blocking socket. Family should be AF_INET or AF_INET6.
106  * If socket create fails, return -errno.
107  */
108 int
109 as_socket_create_fd(int family);
110 
111 /**
112  * @private
113  * Create non-blocking socket.
114  * Family should be AF_INET or AF_INET6.
115  */
116 int
117 as_socket_create(as_socket* sock, int family, as_tls_context* ctx, const char* tls_name);
118 
119 /**
120  * @private
121  * Wrap existing fd in a socket.
122  * Family should be AF_INET or AF_INET6.
123  */
124 bool
125 as_socket_wrap(as_socket* sock, int family, int fd, as_tls_context* ctx, const char* tls_name);
126 
127 /**
128  * @private
129  * Connect to non-blocking socket.
130  */
131 bool
132 as_socket_start_connect(as_socket* sock, struct sockaddr* addr);
133 
134 /**
135  * @private
136  * Create non-blocking socket and connect.
137  */
138 as_status
139 as_socket_create_and_connect(as_socket* sock, as_error* err, struct sockaddr* addr, as_tls_context* ctx, const char* tls_name);
140 
141 /**
142  * @private
143  * Close and release resources associated with a as_socket.
144  */
145 void
147 
148 /**
149  * @private
150  * Create error message for socket error.
151  */
152 as_status
153 as_socket_error(int fd, struct as_node_s* node, as_error* err, as_status status, const char* msg, int code);
154 
155 /**
156  * @private
157  * Append address to error message.
158  */
159 void
160 as_socket_error_append(as_error* err, struct sockaddr* addr);
161 
162 /**
163  * @private
164  * Peek for socket connection status using underlying fd.
165  * Needed to support libuv.
166  *
167  * @return 0 : socket is connected, but no data available.
168  * > 0 : byte size of data available.
169  * < 0 : socket is invalid.
170  */
171 int
172 as_socket_validate_fd(int fd);
173 
174 /**
175  * @private
176  * Peek for socket connection status.
177  *
178  * @return 0 : socket is connected, but no data available.
179  * > 0 : byte size of data available.
180  * < 0 : socket is invalid.
181  */
182 int
184 
185 #if defined(__linux__) || defined(__APPLE__)
186 
187 /**
188  * @private
189  * Calculate future deadline given timeout.
190  */
191 static inline uint64_t
192 as_socket_deadline(uint32_t timeout_ms)
193 {
194  return (timeout_ms && timeout_ms <= INT32_MAX)? cf_getms() + timeout_ms : 0;
195 }
196 
197 /**
198  * @private
199  * Write socket data without timeouts.
200  */
201 as_status
202 as_socket_write_forever(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len);
203 
204 /**
205  * @private
206  * Write socket data with future deadline in milliseconds.
207  * Do not adjust for zero deadline.
208  */
209 as_status
210 as_socket_write_limit(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len, uint64_t deadline);
211 
212 /**
213  * @private
214  * Write socket data with future deadline in milliseconds.
215  * If deadline is zero, do not set deadline.
216  */
217 static inline as_status
218 as_socket_write_deadline(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len, uint64_t deadline)
219 {
220  if (deadline) {
221  return as_socket_write_limit(err, sock, node, buf, buf_len, deadline);
222  }
223  else {
224  return as_socket_write_forever(err, sock, node, buf, buf_len);
225  }
226 }
227 
228 /**
229  * @private
230  * Write socket data with timeout in milliseconds.
231  * If timeout is zero or > MAXINT, do not set timeout.
232  */
233 static inline as_status
234 as_socket_write_timeout(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len, uint32_t timeout_ms)
235 {
236  if (timeout_ms && timeout_ms <= INT32_MAX) {
237  return as_socket_write_limit(err, sock, node, buf, buf_len, cf_getms() + timeout_ms);
238  }
239  else {
240  return as_socket_write_forever(err, sock, node, buf, buf_len);
241  }
242 }
243 
244 /**
245  * @private
246  * Read socket data without timeouts.
247  */
248 as_status
249 as_socket_read_forever(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len);
250 
251 /**
252  * @private
253  * Read socket data with future deadline in milliseconds.
254  * Do not adjust for zero deadline.
255  */
256 as_status
257 as_socket_read_limit(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len, uint64_t deadline);
258 
259 /**
260  * @private
261  * Read socket data with future deadline in milliseconds.
262  * If deadline is zero, do not set deadline.
263  */
264 static inline as_status
265 as_socket_read_deadline(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len, uint64_t deadline)
266 {
267  if (deadline) {
268  return as_socket_read_limit(err, sock, node, buf, buf_len, deadline);
269  }
270  else {
271  return as_socket_read_forever(err, sock, node, buf, buf_len);
272  }
273 }
274 
275 /**
276  * @private
277  * Read socket data with timeout in milliseconds.
278  * If timeout is zero or > MAXINT, do not set timeout.
279  */
280 static inline as_status
281 as_socket_read_timeout(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len, uint32_t timeout_ms)
282 {
283  if (timeout_ms && timeout_ms <= INT32_MAX) {
284  return as_socket_read_limit(err, sock, node, buf, buf_len, cf_getms() + timeout_ms);
285  }
286  else {
287  return as_socket_read_forever(err, sock, node, buf, buf_len);
288  }
289 }
290 
291 #endif
292 
293 #ifdef __cplusplus
294 } // end extern "C"
295 #endif