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

bsd.c (6716B)



      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/event.h>
     19 #include <sys/sysctl.h>
     20 #include <sys/socket.h>
     21 #include <sys/uio.h>
     22 
     23 #if defined(__FreeBSD_version)
     24 #include <sys/cpuset.h>
     25 #endif
     26 
     27 #include <errno.h>
     28 #include <string.h>
     29 
     30 #include "kore.h"
     31 
     32 #if defined(KORE_USE_PGSQL)
     33 #include "pgsql.h"
     34 #endif
     35 
     36 #if defined(KORE_USE_TASKS)
     37 #include "tasks.h"
     38 #endif
     39 
     40 static int			kfd = -1;
     41 static int			scheduled = 0;
     42 static struct kevent		*events = NULL;
     43 static u_int32_t		event_count = 0;
     44 
     45 #if defined(KORE_USE_PLATFORM_PLEDGE)
     46 static char	pledges[256] = { "stdio rpath inet" };
     47 #endif
     48 
     49 void
     50 kore_platform_init(void)
     51 {
     52 	long	n;
     53 	size_t	len = sizeof(n);
     54 	int	mib[] = { CTL_HW, HW_NCPU };
     55 
     56 	if (sysctl(mib, 2, &n, &len, NULL, 0) == -1) {
     57 		kore_debug("kore_platform_init(): sysctl %s", errno_s);
     58 		cpu_count = 1;
     59 	} else {
     60 		cpu_count = (u_int16_t)n;
     61 	}
     62 }
     63 
     64 void
     65 kore_platform_worker_setcpu(struct kore_worker *kw)
     66 {
     67 #if defined(__FreeBSD_version)
     68 	cpuset_t	cpuset;
     69 
     70 	CPU_ZERO(&cpuset);
     71 	CPU_SET(kw->cpu, &cpuset);
     72 	if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
     73 	    -1, sizeof(cpuset), &cpuset) == -1) {
     74 		fatal("failed: %s", errno_s);
     75 	}
     76 #endif /* __FreeBSD_version */
     77 }
     78 
     79 void
     80 kore_platform_event_init(void)
     81 {
     82 	if (kfd != -1)
     83 		close(kfd);
     84 	if (events != NULL)
     85 		kore_free(events);
     86 
     87 	if ((kfd = kqueue()) == -1)
     88 		fatal("kqueue(): %s", errno_s);
     89 
     90 	event_count = (worker_max_connections * 2) + nlisteners;
     91 	events = kore_calloc(event_count, sizeof(struct kevent));
     92 }
     93 
     94 void
     95 kore_platform_event_cleanup(void)
     96 {
     97 	if (kfd != -1) {
     98 		close(kfd);
     99 		kfd = -1;
    100 	}
    101 
    102 	if (events != NULL) {
    103 		kore_free(events);
    104 		events = NULL;
    105 	}
    106 }
    107 
    108 void
    109 kore_platform_event_wait(u_int64_t timer)
    110 {
    111 	u_int32_t		r;
    112 	struct kore_event	*evt;
    113 	int			n, i;
    114 	struct timespec		timeo, *ts;
    115 
    116 	if (timer == KORE_WAIT_INFINITE) {
    117 		ts = NULL;
    118 	} else {
    119 		timeo.tv_sec = timer / 1000;
    120 		timeo.tv_nsec = (timer % 1000) * 1000000;
    121 		ts = &timeo;
    122 	}
    123 
    124 	n = kevent(kfd, NULL, 0, events, event_count, ts);
    125 	if (n == -1) {
    126 		if (errno == EINTR)
    127 			return;
    128 		fatal("kevent(): %s", errno_s);
    129 	}
    130 
    131 	if (n > 0)
    132 		kore_debug("main(): %d sockets available", n);
    133 
    134 	for (i = 0; i < n; i++) {
    135 		evt = (struct kore_event *)events[i].udata;
    136 
    137 		if (evt == NULL)
    138 			fatal("evt == NULL");
    139 
    140 		r = 0;
    141 
    142 		if (events[i].filter == EVFILT_READ)
    143 			evt->flags |= KORE_EVENT_READ;
    144 
    145 		if (events[i].filter == EVFILT_WRITE)
    146 			evt->flags |= KORE_EVENT_WRITE;
    147 
    148 		if (events[i].flags & EV_EOF || events[i].flags & EV_ERROR)
    149 			r = 1;
    150 
    151 		evt->handle(evt, r);
    152 	}
    153 }
    154 
    155 void
    156 kore_platform_event_all(int fd, void *c)
    157 {
    158 	kore_platform_event_schedule(fd, EVFILT_READ, EV_ADD | EV_CLEAR, c);
    159 	kore_platform_event_schedule(fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, c);
    160 }
    161 
    162 void
    163 kore_platform_event_level_all(int fd, void *c)
    164 {
    165 	kore_platform_event_schedule(fd, EVFILT_READ, EV_ADD, c);
    166 	kore_platform_event_schedule(fd, EVFILT_WRITE, EV_ADD, c);
    167 }
    168 
    169 void
    170 kore_platform_event_level_read(int fd, void *c)
    171 {
    172 	kore_platform_event_schedule(fd, EVFILT_READ, EV_ADD, c);
    173 }
    174 
    175 void
    176 kore_platform_event_schedule(int fd, int type, int flags, void *data)
    177 {
    178 	struct kevent		event[1];
    179 
    180 	EV_SET(&event[0], fd, type, flags, 0, 0, data);
    181 	if (kevent(kfd, event, 1, NULL, 0, NULL) == -1 && errno != ENOENT)
    182 		fatal("kevent: %s", errno_s);
    183 }
    184 
    185 void
    186 kore_platform_enable_accept(void)
    187 {
    188 	struct listener		*l;
    189 	struct kore_server	*srv;
    190 	int			flags;
    191 
    192 	if (scheduled == 0) {
    193 		scheduled = 1;
    194 		flags = EV_ADD | EV_ENABLE;
    195 	} else {
    196 		flags = EV_ENABLE;
    197 	}
    198 
    199 	LIST_FOREACH(srv, &kore_servers, list) {
    200 		LIST_FOREACH(l, &srv->listeners, list) {
    201 			kore_platform_event_schedule(l->fd,
    202 			    EVFILT_READ, flags, l);
    203 		}
    204 	}
    205 }
    206 
    207 void
    208 kore_platform_disable_accept(void)
    209 {
    210 	struct listener		*l;
    211 	struct kore_server	*srv;
    212 
    213 	LIST_FOREACH(srv, &kore_servers, list) {
    214 		LIST_FOREACH(l, &srv->listeners, list) {
    215 			kore_platform_event_schedule(l->fd,
    216 			    EVFILT_READ, EV_DISABLE, l);
    217 		}
    218 	}
    219 }
    220 
    221 void
    222 kore_platform_schedule_read(int fd, void *data)
    223 {
    224 	kore_platform_event_schedule(fd, EVFILT_READ, EV_ADD | EV_CLEAR, data);
    225 }
    226 
    227 void
    228 kore_platform_schedule_write(int fd, void *data)
    229 {
    230 	kore_platform_event_schedule(fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, data);
    231 }
    232 
    233 void
    234 kore_platform_disable_read(int fd)
    235 {
    236 	kore_platform_event_schedule(fd, EVFILT_READ, EV_DELETE, NULL);
    237 }
    238 
    239 void
    240 kore_platform_disable_write(int fd)
    241 {
    242 	kore_platform_event_schedule(fd, EVFILT_WRITE, EV_DELETE, NULL);
    243 }
    244 
    245 void
    246 kore_platform_proctitle(const char *title)
    247 {
    248 #ifdef __MACH__
    249 	kore_proctitle(title);
    250 #else
    251 	setproctitle("%s", title);
    252 #endif
    253 }
    254 
    255 #if defined(KORE_USE_PLATFORM_SENDFILE)
    256 int
    257 kore_platform_sendfile(struct connection *c, struct netbuf *nb)
    258 {
    259 	int		ret;
    260 	off_t		len, smin;
    261 
    262 	smin = nb->fd_len - nb->fd_off;
    263 	len = MIN(SENDFILE_PAYLOAD_MAX, smin);
    264 
    265 #if defined(__MACH__)
    266 	ret = sendfile(nb->file_ref->fd, c->fd, nb->fd_off, &len, NULL, 0);
    267 #else
    268 	ret = sendfile(nb->file_ref->fd, c->fd, nb->fd_off, len, NULL, &len, 0);
    269 #endif
    270 
    271 	if (ret == -1) {
    272 		if (errno == EAGAIN) {
    273 			nb->fd_off += len;
    274 			c->evt.flags &= ~KORE_EVENT_WRITE;
    275 			return (KORE_RESULT_OK);
    276 		}
    277 
    278 		if (errno == EINTR) {
    279 			nb->fd_off += len;
    280 			return (KORE_RESULT_OK);
    281 		}
    282 
    283 		return (KORE_RESULT_ERROR);
    284 	}
    285 
    286 	nb->fd_off += len;
    287 
    288 	if (len == 0 || nb->fd_off == nb->fd_len) {
    289 		net_remove_netbuf(c, nb);
    290 		c->snb = NULL;
    291 	}
    292 
    293 	return (KORE_RESULT_OK);
    294 }
    295 #endif
    296 
    297 void
    298 kore_platform_sandbox(void)
    299 {
    300 #if defined(KORE_USE_PLATFORM_PLEDGE)
    301 	kore_platform_pledge();
    302 #endif
    303 }
    304 
    305 #if defined(KORE_USE_PLATFORM_PLEDGE)
    306 void
    307 kore_platform_pledge(void)
    308 {
    309 	if (worker->id == KORE_WORKER_KEYMGR || worker->id == KORE_WORKER_ACME)
    310 		return;
    311 
    312 	if (pledge(pledges, NULL) == -1)
    313 		fatal("failed to pledge process");
    314 }
    315 
    316 void
    317 kore_platform_add_pledge(const char *pledge)
    318 {
    319 	size_t		len;
    320 
    321 	len = strlcat(pledges, " ", sizeof(pledges));
    322 	if (len >= sizeof(pledges))
    323 		fatal("truncation on pledges");
    324 
    325 	len = strlcat(pledges, pledge, sizeof(pledges));
    326 	if (len >= sizeof(pledges))
    327 		fatal("truncation on pledges (%s)", pledge);
    328 }
    329 #endif