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;
72  uint64_t max_socket_idle;
75 
76 struct as_queue_lock_s;
77 struct as_node_s;
78 
79 /**
80  * Socket fields for both regular and TLS sockets.
81  */
82 typedef struct as_socket_s {
83  int fd;
84  int family;
85  union {
86  struct as_queue_lock_s* queue; // Used when sync socket is active.
87  uint64_t last_used; // Used when socket in pool.
88  };
90  const char* tls_name;
91  SSL* ssl;
92 } as_socket;
93 
94 /**
95  * @private
96  * Initialize an as_socket structure.
97  */
98 void
100 
101 /**
102  * @private
103  * Create non-blocking socket. Family should be AF_INET or AF_INET6.
104  * If socket create fails, return -errno.
105  */
106 int
107 as_socket_create_fd(int family);
108 
109 /**
110  * @private
111  * Create non-blocking socket.
112  * Family should be AF_INET or AF_INET6.
113  */
114 int
115 as_socket_create(as_socket* sock, int family, as_tls_context* ctx, const char* tls_name);
116 
117 /**
118  * @private
119  * Wrap existing fd in a socket.
120  * Family should be AF_INET or AF_INET6.
121  */
122 bool
123 as_socket_wrap(as_socket* sock, int family, int fd, as_tls_context* ctx, const char* tls_name);
124 
125 /**
126  * @private
127  * Connect to non-blocking socket.
128  */
129 bool
130 as_socket_start_connect(as_socket* sock, struct sockaddr* addr);
131 
132 /**
133  * @private
134  * Create non-blocking socket and connect.
135  */
136 as_status
137 as_socket_create_and_connect(as_socket* sock, as_error* err, struct sockaddr* addr, as_tls_context* ctx, const char* tls_name);
138 
139 /**
140  * @private
141  * Close and release resources associated with a as_socket.
142  */
143 void
145 
146 /**
147  * @private
148  * Create error message for socket error.
149  */
150 as_status
151 as_socket_error(int fd, struct as_node_s* node, as_error* err, as_status status, const char* msg, int code);
152 
153 /**
154  * @private
155  * Append address to error message.
156  */
157 void
158 as_socket_error_append(as_error* err, struct sockaddr* addr);
159 
160 /**
161  * @private
162  * Peek for socket connection status using underlying fd.
163  * Needed to support libuv.
164  *
165  * @return 0 : socket is connected, but no data available.
166  * > 0 : byte size of data available.
167  * < 0 : socket is invalid.
168  */
169 int
170 as_socket_validate_fd(int fd);
171 
172 /**
173  * @private
174  * Peek for socket connection status.
175  *
176  * @return 0 : socket is connected, but no data available.
177  * > 0 : byte size of data available.
178  * < 0 : socket is invalid.
179  */
180 int
182 
183 #if defined(__linux__) || defined(__APPLE__)
184 
185 /**
186  * @private
187  * Calculate future deadline given timeout.
188  */
189 static inline uint64_t
190 as_socket_deadline(uint32_t timeout_ms)
191 {
192  return (timeout_ms && timeout_ms <= INT32_MAX)? cf_getms() + timeout_ms : 0;
193 }
194 
195 /**
196  * @private
197  * Write socket data without timeouts.
198  */
199 as_status
200 as_socket_write_forever(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len);
201 
202 /**
203  * @private
204  * Write socket data with future deadline in milliseconds.
205  * Do not adjust for zero deadline.
206  */
207 as_status
208 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);
209 
210 /**
211  * @private
212  * Write socket data with future deadline in milliseconds.
213  * If deadline is zero, do not set deadline.
214  */
215 static inline as_status
216 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)
217 {
218  if (deadline) {
219  return as_socket_write_limit(err, sock, node, buf, buf_len, deadline);
220  }
221  else {
222  return as_socket_write_forever(err, sock, node, buf, buf_len);
223  }
224 }
225 
226 /**
227  * @private
228  * Write socket data with timeout in milliseconds.
229  * If timeout is zero or > MAXINT, do not set timeout.
230  */
231 static inline as_status
232 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)
233 {
234  if (timeout_ms && timeout_ms <= INT32_MAX) {
235  return as_socket_write_limit(err, sock, node, buf, buf_len, cf_getms() + timeout_ms);
236  }
237  else {
238  return as_socket_write_forever(err, sock, node, buf, buf_len);
239  }
240 }
241 
242 /**
243  * @private
244  * Read socket data without timeouts.
245  */
246 as_status
247 as_socket_read_forever(as_error* err, as_socket* sock, struct as_node_s* node, uint8_t *buf, size_t buf_len);
248 
249 /**
250  * @private
251  * Read socket data with future deadline in milliseconds.
252  * Do not adjust for zero deadline.
253  */
254 as_status
255 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);
256 
257 /**
258  * @private
259  * Read socket data with future deadline in milliseconds.
260  * If deadline is zero, do not set deadline.
261  */
262 static inline as_status
263 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)
264 {
265  if (deadline) {
266  return as_socket_read_limit(err, sock, node, buf, buf_len, deadline);
267  }
268  else {
269  return as_socket_read_forever(err, sock, node, buf, buf_len);
270  }
271 }
272 
273 /**
274  * @private
275  * Read socket data with timeout in milliseconds.
276  * If timeout is zero or > MAXINT, do not set timeout.
277  */
278 static inline as_status
279 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)
280 {
281  if (timeout_ms && timeout_ms <= INT32_MAX) {
282  return as_socket_read_limit(err, sock, node, buf, buf_len, cf_getms() + timeout_ms);
283  }
284  else {
285  return as_socket_read_forever(err, sock, node, buf, buf_len);
286  }
287 }
288 
289 #endif
290 
291 #ifdef __cplusplus
292 } // end extern "C"
293 #endif