kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

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 }