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 (6596B)



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