connection.c (9302B)
1 /*
2 * Copyright (c) 2013-2022 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <sys/param.h>
18 #include <sys/socket.h>
19
20 #include <netinet/tcp.h>
21
22 #include <inttypes.h>
23 #include <fcntl.h>
24
25 #include "kore.h"
26 #include "http.h"
27
28 struct kore_pool connection_pool;
29 struct connection_list connections;
30 struct connection_list disconnected;
31
32 void
33 kore_connection_init(void)
34 {
35 u_int32_t elm;
36
37 TAILQ_INIT(&connections);
38 TAILQ_INIT(&disconnected);
39
40 /* Add some overhead so we don't rollover for internal items. */
41 elm = worker_max_connections + 10;
42
43 kore_pool_init(&connection_pool, "connection_pool",
44 sizeof(struct connection), elm);
45 }
46
47 void
48 kore_connection_cleanup(void)
49 {
50 kore_debug("connection_cleanup()");
51
52 /* Drop all connections */
53 kore_connection_prune(KORE_CONNECTION_PRUNE_ALL);
54 kore_pool_cleanup(&connection_pool);
55 }
56
57 struct connection *
58 kore_connection_new(void *owner)
59 {
60 struct connection *c;
61
62 c = kore_pool_get(&connection_pool);
63
64 c->flags = 0;
65 c->rnb = NULL;
66 c->snb = NULL;
67 c->owner = owner;
68 c->handle = NULL;
69
70 c->tls = NULL;
71 c->tls_cert = NULL;
72 c->tls_reneg = 0;
73 c->tls_sni = NULL;
74
75 c->disconnect = NULL;
76 c->hdlr_extra = NULL;
77 c->proto = CONN_PROTO_UNKNOWN;
78 c->idle_timer.start = 0;
79 c->idle_timer.length = KORE_IDLE_TIMER_MAX;
80
81 c->evt.type = KORE_TYPE_CONNECTION;
82 c->evt.handle = kore_connection_event;
83
84 #if !defined(KORE_NO_HTTP)
85 c->ws_connect = NULL;
86 c->ws_message = NULL;
87 c->ws_disconnect = NULL;
88 c->http_start = kore_time_ms();
89 c->http_timeout = http_header_timeout * 1000;
90 TAILQ_INIT(&(c->http_requests));
91 #endif
92
93 TAILQ_INIT(&(c->send_queue));
94
95 return (c);
96 }
97
98 int
99 kore_connection_accept(struct listener *listener, struct connection **out)
100 {
101 struct connection *c;
102 struct sockaddr *s;
103 socklen_t len;
104
105 kore_debug("kore_connection_accept(%p)", listener);
106
107 *out = NULL;
108 c = kore_connection_new(listener);
109
110 c->family = listener->family;
111
112 switch (c->family) {
113 case AF_INET:
114 len = sizeof(struct sockaddr_in);
115 s = (struct sockaddr *)&(c->addr.ipv4);
116 break;
117 case AF_INET6:
118 len = sizeof(struct sockaddr_in6);
119 s = (struct sockaddr *)&(c->addr.ipv6);
120 break;
121 case AF_UNIX:
122 len = sizeof(struct sockaddr_un);
123 s = (struct sockaddr *)&(c->addr.sun);
124 break;
125 default:
126 fatal("unknown family type %d", c->family);
127 }
128
129 if ((c->fd = accept(listener->fd, s, &len)) == -1) {
130 kore_pool_put(&connection_pool, c);
131 kore_debug("accept(): %s", errno_s);
132 return (KORE_RESULT_ERROR);
133 }
134
135 if (!kore_connection_nonblock(c->fd, listener->family != AF_UNIX)) {
136 close(c->fd);
137 kore_pool_put(&connection_pool, c);
138 return (KORE_RESULT_ERROR);
139 }
140
141 if (fcntl(c->fd, F_SETFD, FD_CLOEXEC) == -1) {
142 close(c->fd);
143 kore_pool_put(&connection_pool, c);
144 return (KORE_RESULT_ERROR);
145 }
146
147 c->handle = kore_connection_handle;
148 TAILQ_INSERT_TAIL(&connections, c, list);
149
150 if (listener->server->tls) {
151 c->state = CONN_STATE_TLS_SHAKE;
152 c->write = kore_tls_write;
153 c->read = kore_tls_read;
154 } else {
155 c->state = CONN_STATE_ESTABLISHED;
156 c->write = net_write;
157 c->read = net_read;
158
159 if (listener->connect != NULL) {
160 kore_runtime_connect(listener->connect, c);
161 } else {
162 #if !defined(KORE_NO_HTTP)
163 c->proto = CONN_PROTO_HTTP;
164 if (http_keepalive_time != 0) {
165 c->idle_timer.length =
166 http_keepalive_time * 1000;
167 }
168 net_recv_queue(c, http_header_max,
169 NETBUF_CALL_CB_ALWAYS, http_header_recv);
170 #endif
171 }
172 }
173
174 kore_connection_start_idletimer(c);
175 worker_active_connections++;
176
177 *out = c;
178 return (KORE_RESULT_OK);
179 }
180
181 void
182 kore_connection_check_timeout(u_int64_t now)
183 {
184 struct connection *c, *next;
185
186 for (c = TAILQ_FIRST(&connections); c != NULL; c = next) {
187 next = TAILQ_NEXT(c, list);
188 if (c->proto == CONN_PROTO_MSG)
189 continue;
190 #if !defined(KORE_NO_HTTP)
191 if (c->state == CONN_STATE_ESTABLISHED &&
192 c->proto == CONN_PROTO_HTTP) {
193 if (!http_check_timeout(c, now))
194 continue;
195 if (!TAILQ_EMPTY(&c->http_requests))
196 continue;
197 }
198 #endif
199 if (c->flags & CONN_IDLE_TIMER_ACT)
200 kore_connection_check_idletimer(now, c);
201 }
202 }
203
204 void
205 kore_connection_prune(int all)
206 {
207 struct connection *c, *cnext;
208
209 if (all) {
210 for (c = TAILQ_FIRST(&connections); c != NULL; c = cnext) {
211 cnext = TAILQ_NEXT(c, list);
212 net_send_flush(c);
213 kore_connection_disconnect(c);
214 }
215 }
216
217 for (c = TAILQ_FIRST(&disconnected); c != NULL; c = cnext) {
218 cnext = TAILQ_NEXT(c, list);
219 TAILQ_REMOVE(&disconnected, c, list);
220 kore_connection_remove(c);
221 }
222 }
223
224 void
225 kore_connection_disconnect(struct connection *c)
226 {
227 if (c->state != CONN_STATE_DISCONNECTING) {
228 kore_debug("preparing %p for disconnection", c);
229 c->state = CONN_STATE_DISCONNECTING;
230 if (c->disconnect)
231 c->disconnect(c);
232
233 TAILQ_REMOVE(&connections, c, list);
234 TAILQ_INSERT_TAIL(&disconnected, c, list);
235 }
236 }
237
238 void
239 kore_connection_event(void *arg, int error)
240 {
241 struct connection *c = arg;
242
243 if (error) {
244 kore_connection_disconnect(c);
245 return;
246 }
247
248 if (!c->handle(c))
249 kore_connection_disconnect(c);
250 }
251
252 int
253 kore_connection_handle(struct connection *c)
254 {
255 struct listener *listener;
256
257 kore_debug("kore_connection_handle(%p) -> %d", c, c->state);
258 kore_connection_stop_idletimer(c);
259
260 switch (c->state) {
261 case CONN_STATE_TLS_SHAKE:
262 switch (kore_tls_connection_accept(c)) {
263 case KORE_RESULT_OK:
264 break;
265 case KORE_RESULT_RETRY:
266 return (KORE_RESULT_OK);
267 default:
268 return (KORE_RESULT_ERROR);
269 }
270
271 if (c->owner != NULL) {
272 listener = (struct listener *)c->owner;
273 if (listener->connect != NULL) {
274 kore_runtime_connect(listener->connect, c);
275 kore_connection_start_idletimer(c);
276 return (KORE_RESULT_OK);
277 }
278 }
279
280 #if !defined(KORE_NO_HTTP)
281 c->proto = CONN_PROTO_HTTP;
282 if (http_keepalive_time != 0) {
283 c->idle_timer.length =
284 http_keepalive_time * 1000;
285 }
286
287 net_recv_queue(c, http_header_max,
288 NETBUF_CALL_CB_ALWAYS, http_header_recv);
289 #endif
290
291 c->state = CONN_STATE_ESTABLISHED;
292 /* FALLTHROUGH */
293 case CONN_STATE_ESTABLISHED:
294 if (c->evt.flags & KORE_EVENT_READ) {
295 if (!net_recv_flush(c))
296 return (KORE_RESULT_ERROR);
297 }
298
299 if (c->evt.flags & KORE_EVENT_WRITE) {
300 if (!net_send_flush(c))
301 return (KORE_RESULT_ERROR);
302 }
303 break;
304 case CONN_STATE_DISCONNECTING:
305 break;
306 default:
307 kore_debug("unknown state on %d (%d)", c->fd, c->state);
308 break;
309 }
310
311 kore_connection_start_idletimer(c);
312
313 return (KORE_RESULT_OK);
314 }
315
316 void
317 kore_connection_remove(struct connection *c)
318 {
319 struct netbuf *nb, *next;
320 #if !defined(KORE_NO_HTTP)
321 struct http_request *req, *rnext;
322 #endif
323
324 kore_debug("kore_connection_remove(%p)", c);
325
326 kore_tls_connection_cleanup(c);
327
328 close(c->fd);
329
330 if (c->hdlr_extra != NULL)
331 kore_free(c->hdlr_extra);
332
333 #if !defined(KORE_NO_HTTP)
334 for (req = TAILQ_FIRST(&(c->http_requests));
335 req != NULL; req = rnext) {
336 rnext = TAILQ_NEXT(req, olist);
337 TAILQ_REMOVE(&(c->http_requests), req, olist);
338 req->owner = NULL;
339 req->flags |= HTTP_REQUEST_DELETE;
340 http_request_wakeup(req);
341 }
342
343 kore_free(c->ws_connect);
344 kore_free(c->ws_message);
345 kore_free(c->ws_disconnect);
346 #endif
347
348 for (nb = TAILQ_FIRST(&(c->send_queue)); nb != NULL; nb = next) {
349 next = TAILQ_NEXT(nb, list);
350 nb->flags &= ~NETBUF_MUST_RESEND;
351 net_remove_netbuf(c, nb);
352 }
353
354 if (c->rnb != NULL) {
355 kore_free(c->rnb->buf);
356 kore_pool_put(&nb_pool, c->rnb);
357 }
358
359 kore_pool_put(&connection_pool, c);
360 worker_active_connections--;
361 }
362
363 void
364 kore_connection_check_idletimer(u_int64_t now, struct connection *c)
365 {
366 u_int64_t d;
367
368 if (now > c->idle_timer.start)
369 d = now - c->idle_timer.start;
370 else
371 d = 0;
372
373 if (d >= c->idle_timer.length) {
374 kore_debug("%p idle for %" PRIu64 " ms, expiring", c, d);
375 kore_connection_disconnect(c);
376 }
377 }
378
379 void
380 kore_connection_start_idletimer(struct connection *c)
381 {
382 kore_debug("kore_connection_start_idletimer(%p)", c);
383
384 c->flags |= CONN_IDLE_TIMER_ACT;
385 c->idle_timer.start = kore_time_ms();
386 }
387
388 void
389 kore_connection_stop_idletimer(struct connection *c)
390 {
391 kore_debug("kore_connection_stop_idletimer(%p)", c);
392
393 c->flags &= ~CONN_IDLE_TIMER_ACT;
394 c->idle_timer.start = 0;
395 }
396
397 int
398 kore_connection_nonblock(int fd, int nodelay)
399 {
400 int flags;
401
402 kore_debug("kore_connection_nonblock(%d)", fd);
403
404 if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
405 kore_debug("fcntl(): F_GETFL %s", errno_s);
406 return (KORE_RESULT_ERROR);
407 }
408
409 flags |= O_NONBLOCK;
410 if (fcntl(fd, F_SETFL, flags) == -1) {
411 kore_debug("fcntl(): F_SETFL %s", errno_s);
412 return (KORE_RESULT_ERROR);
413 }
414
415 if (nodelay) {
416 if (!kore_sockopt(fd, IPPROTO_TCP, TCP_NODELAY)) {
417 kore_log(LOG_NOTICE,
418 "failed to set TCP_NODELAY on %d", fd);
419 }
420 }
421
422 return (KORE_RESULT_OK);
423 }