master
h 158 lines 4.3 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_ND_SOCK_H
4 #define NETDATA_ND_SOCK_H
5
6 #include "socket-peers.h"
7
8 typedef enum __attribute__((packed)) {
9 ND_SOCK_ERR_NONE = 0,
10 ND_SOCK_ERR_CONNECTION_REFUSED,
11 ND_SOCK_ERR_CANNOT_RESOLVE_HOSTNAME,
12 ND_SOCK_ERR_FAILED_TO_CREATE_SOCKET,
13 ND_SOCK_ERR_NO_HOST_IN_DEFINITION,
14 ND_SOCK_ERR_POLL_ERROR,
15 ND_SOCK_ERR_TIMEOUT,
16 ND_SOCK_ERR_SSL_CANT_ESTABLISH_SSL_CONNECTION,
17 ND_SOCK_ERR_SSL_INVALID_CERTIFICATE,
18 ND_SOCK_ERR_SSL_FAILED_TO_OPEN,
19 ND_SOCK_ERR_THREAD_CANCELLED,
20 ND_SOCK_ERR_NO_DESTINATION_AVAILABLE,
21 ND_SOCK_ERR_UNKNOWN_ERROR,
22
23 // terminator
24 ND_SOCK_ERR_MAX,
25 } ND_SOCK_ERROR;
26
27 ENUM_STR_DEFINE_FUNCTIONS_EXTERN(ND_SOCK_ERROR);
28
29 typedef struct nd_sock {
30 bool verify_certificate;
31 ND_SOCK_ERROR error;
32 int fd;
33 NETDATA_SSL ssl;
34 SSL_CTX *ctx;
35 char *sni_hostname; // hostname for SNI in SSL/TLS connections
36 } ND_SOCK;
37
38 #define ND_SOCK_INIT(ssl_ctx, ssl_verify) (ND_SOCK){ \
39 .verify_certificate = ssl_verify, \
40 .error = ND_SOCK_ERR_NONE, \
41 .fd = -1, \
42 .ssl = NETDATA_SSL_UNSET_CONNECTION, \
43 .ctx = ssl_ctx, \
44 .sni_hostname = NULL, \
45 }
46
47 static inline void nd_sock_init(ND_SOCK *s, SSL_CTX *ctx, bool verify_certificate) {
48 s->verify_certificate = verify_certificate;
49 s->error = ND_SOCK_ERR_NONE;
50 s->fd = -1;
51 s->ssl = NETDATA_SSL_UNSET_CONNECTION;
52 s->ctx = ctx;
53 s->sni_hostname = NULL;
54 }
55
56 ALWAYS_INLINE
57 static bool nd_sock_is_ssl(ND_SOCK *s) {
58 return SSL_connection(&s->ssl);
59 }
60
61 ALWAYS_INLINE
62 static SOCKET_PEERS nd_sock_socket_peers(ND_SOCK *s) {
63 return socket_peers(s->fd);
64 }
65
66 ALWAYS_INLINE
67 static void nd_sock_close(ND_SOCK *s) {
68 netdata_ssl_close(&s->ssl);
69
70 if(s->fd != -1) {
71 close(s->fd);
72 s->fd = -1;
73 }
74
75 freez(s->sni_hostname);
76 s->sni_hostname = NULL;
77 s->error = ND_SOCK_ERR_NONE;
78 }
79
80 ALWAYS_INLINE
81 static ssize_t nd_sock_read(ND_SOCK *s, void *buf, size_t num, size_t retries) {
82 ssize_t rc;
83 do {
84 if (nd_sock_is_ssl(s))
85 rc = netdata_ssl_read(&s->ssl, buf, num);
86 else
87 rc = read(s->fd, buf, num);
88 }
89 while(rc <= 0 && (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) && retries--);
90
91 return rc;
92 }
93
94 ALWAYS_INLINE
95 static ssize_t nd_sock_write(ND_SOCK *s, const void *buf, size_t num, size_t retries) {
96 ssize_t rc;
97
98 do {
99 if (nd_sock_is_ssl(s))
100 rc = netdata_ssl_write(&s->ssl, buf, num);
101 else
102 rc = write(s->fd, buf, num);
103 }
104 while(rc <= 0 && (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) && retries--);
105
106 return rc;
107 }
108
109 ALWAYS_INLINE
110 static ssize_t nd_sock_write_persist(ND_SOCK *s, const void *buf, const size_t num, size_t retries) {
111 const uint8_t *src = (const uint8_t *)buf;
112 ssize_t bytes = 0;
113
114 do {
115 ssize_t sent = nd_sock_write(s, &src[bytes], (ssize_t)num - bytes, retries);
116 if(sent <= 0) return sent;
117 bytes += sent;
118 }
119 while(bytes < (ssize_t)num && retries--);
120
121 return bytes;
122 }
123
124 ALWAYS_INLINE
125 static ssize_t nd_sock_revc_nowait(ND_SOCK *s, void *buf, size_t num) {
126 if (nd_sock_is_ssl(s))
127 return netdata_ssl_read(&s->ssl, buf, num);
128 else
129 return recv(s->fd, buf, num, MSG_DONTWAIT);
130 }
131
132 ALWAYS_INLINE
133 static ssize_t nd_sock_peek_nowait(ND_SOCK *s, void *buf, size_t num) {
134 if (nd_sock_is_ssl(s))
135 return netdata_ssl_peek(&s->ssl, buf, num);
136 else
137 return recv(s->fd, buf, num, MSG_PEEK | MSG_DONTWAIT);
138 }
139
140 ALWAYS_INLINE
141 static ssize_t nd_sock_send_nowait(ND_SOCK *s, void *buf, size_t num) {
142 if (nd_sock_is_ssl(s))
143 return netdata_ssl_write(&s->ssl, buf, num);
144 else
145 return send(s->fd, buf, num, MSG_DONTWAIT);
146 }
147
148 ssize_t nd_sock_send_timeout(ND_SOCK *s, void *buf, size_t len, int flags, time_t timeout);
149 ssize_t nd_sock_recv_timeout(ND_SOCK *s, void *buf, size_t len, int flags, time_t timeout);
150
151 bool nd_sock_connect_to_this(ND_SOCK *s, const char *definition, int default_port, time_t timeout, bool ssl);
152
153 static inline void cleanup_nd_sock_p(ND_SOCK *s) {
154 if(s) nd_sock_close(s);
155 }
156 #define CLEAN_ND_SOCK _cleanup_(cleanup_nd_sock_p) ND_SOCK
157
158 #endif //NETDATA_ND_SOCK_H