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

linux.c (5387B)



      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/epoll.h>
     19 #include <sys/sendfile.h>
     20 #include <sys/syscall.h>
     21 
     22 #include <sched.h>
     23 
     24 #include "kore.h"
     25 #include "seccomp.h"
     26 
     27 #if defined(KORE_USE_PGSQL)
     28 #include "pgsql.h"
     29 #endif
     30 
     31 #if defined(KORE_USE_TASKS)
     32 #include "tasks.h"
     33 #endif
     34 
     35 static int			efd = -1;
     36 static u_int32_t		event_count = 0;
     37 static struct epoll_event	*events = NULL;
     38 
     39 void
     40 kore_platform_init(void)
     41 {
     42 	long		n;
     43 
     44 	kore_seccomp_init();
     45 
     46 	if ((n = sysconf(_SC_NPROCESSORS_ONLN)) == -1) {
     47 		cpu_count = 1;
     48 	} else {
     49 		cpu_count = (u_int16_t)n;
     50 	}
     51 }
     52 
     53 void
     54 kore_platform_worker_setcpu(struct kore_worker *kw)
     55 {
     56 	cpu_set_t	cpuset;
     57 
     58 	CPU_ZERO(&cpuset);
     59 	CPU_SET(kw->cpu, &cpuset);
     60 
     61 	if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) == -1)
     62 		kore_log(LOG_WARNING, "kore_worker_setcpu(): %s", errno_s);
     63 }
     64 
     65 void
     66 kore_platform_event_init(void)
     67 {
     68 	if (efd != -1)
     69 		close(efd);
     70 	if (events != NULL)
     71 		kore_free(events);
     72 
     73 	if ((efd = epoll_create(10000)) == -1)
     74 		fatal("epoll_create(): %s", errno_s);
     75 
     76 	event_count = worker_max_connections + nlisteners;
     77 	events = kore_calloc(event_count, sizeof(struct epoll_event));
     78 }
     79 
     80 void
     81 kore_platform_event_cleanup(void)
     82 {
     83 	if (efd != -1) {
     84 		close(efd);
     85 		efd = -1;
     86 	}
     87 
     88 	if (events != NULL) {
     89 		kore_free(events);
     90 		events = NULL;
     91 	}
     92 }
     93 
     94 void
     95 kore_platform_event_wait(u_int64_t timer)
     96 {
     97 	u_int32_t		r;
     98 	struct kore_event	*evt;
     99 	int			n, i, timeo;
    100 
    101 	if (timer == KORE_WAIT_INFINITE)
    102 		timeo = -1;
    103 	else
    104 		timeo = timer;
    105 
    106 	n = epoll_wait(efd, events, event_count, timeo);
    107 	if (n == -1) {
    108 		if (errno == EINTR)
    109 			return;
    110 		fatal("epoll_wait(): %s", errno_s);
    111 	}
    112 
    113 	r = 0;
    114 	for (i = 0; i < n; i++) {
    115 		if (events[i].data.ptr == NULL)
    116 			fatal("events[%d].data.ptr == NULL", i);
    117 
    118 		r = 0;
    119 		evt = (struct kore_event *)events[i].data.ptr;
    120 
    121 		if (events[i].events & EPOLLIN)
    122 			evt->flags |= KORE_EVENT_READ;
    123 
    124 		if (events[i].events & EPOLLOUT)
    125 			evt->flags |= KORE_EVENT_WRITE;
    126 
    127 		if (events[i].events & EPOLLERR ||
    128 		    events[i].events & EPOLLHUP ||
    129 		    events[i].events & EPOLLRDHUP)
    130 			r = 1;
    131 
    132 		evt->handle(events[i].data.ptr, r);
    133 	}
    134 }
    135 
    136 void
    137 kore_platform_event_level_all(int fd, void *c)
    138 {
    139 	kore_platform_event_schedule(fd, EPOLLIN | EPOLLOUT | EPOLLRDHUP, 0, c);
    140 }
    141 
    142 void
    143 kore_platform_event_level_read(int fd, void *c)
    144 {
    145 	kore_platform_event_schedule(fd, EPOLLIN | EPOLLRDHUP, 0, c);
    146 }
    147 
    148 void
    149 kore_platform_event_all(int fd, void *c)
    150 {
    151 	kore_platform_event_schedule(fd,
    152 	    EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET, 0, c);
    153 }
    154 
    155 void
    156 kore_platform_event_schedule(int fd, int type, int flags, void *udata)
    157 {
    158 	struct epoll_event	evt;
    159 
    160 	evt.events = type;
    161 	evt.data.ptr = udata;
    162 	if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &evt) == -1) {
    163 		if (errno == EEXIST) {
    164 			if (epoll_ctl(efd, EPOLL_CTL_MOD, fd, &evt) == -1)
    165 				fatal("epoll_ctl() MOD: %s", errno_s);
    166 		} else {
    167 			fatal("epoll_ctl() ADD: %s", errno_s);
    168 		}
    169 	}
    170 }
    171 
    172 void
    173 kore_platform_schedule_read(int fd, void *data)
    174 {
    175 	kore_platform_event_schedule(fd, EPOLLIN | EPOLLET, 0, data);
    176 }
    177 
    178 void
    179 kore_platform_schedule_write(int fd, void *data)
    180 {
    181 	kore_platform_event_schedule(fd, EPOLLOUT | EPOLLET, 0, data);
    182 }
    183 
    184 void
    185 kore_platform_disable_read(int fd)
    186 {
    187 	if (epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL) == -1)
    188 		fatal("kore_platform_disable_read: %s", errno_s);
    189 }
    190 
    191 void
    192 kore_platform_enable_accept(void)
    193 {
    194 	struct listener		*l;
    195 	struct kore_server	*srv;
    196 
    197 	LIST_FOREACH(srv, &kore_servers, list) {
    198 		LIST_FOREACH(l, &srv->listeners, list)
    199 			kore_platform_event_schedule(l->fd, EPOLLIN, 0, l);
    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 			if (epoll_ctl(efd, EPOLL_CTL_DEL, l->fd, NULL) == -1) {
    212 				fatal("kore_platform_disable_accept: %s",
    213 				    errno_s);
    214 			}
    215 		}
    216 	}
    217 }
    218 
    219 void
    220 kore_platform_proctitle(const char *title)
    221 {
    222 	kore_proctitle(title);
    223 }
    224 
    225 #if defined(KORE_USE_PLATFORM_SENDFILE)
    226 int
    227 kore_platform_sendfile(struct connection *c, struct netbuf *nb)
    228 {
    229 	off_t		smin;
    230 	ssize_t		sent;
    231 	size_t		len, prevoff;
    232 
    233 	prevoff = nb->fd_off;
    234 	smin = nb->fd_len - nb->fd_off;
    235 	len = MIN(SENDFILE_PAYLOAD_MAX, smin);
    236 
    237 resend:
    238 	sent = sendfile(c->fd, nb->file_ref->fd, &nb->fd_off, len);
    239 	if (sent == -1) {
    240 		if (errno == EAGAIN) {
    241 			c->evt.flags &= ~KORE_EVENT_WRITE;
    242 			return (KORE_RESULT_OK);
    243 		}
    244 
    245 		return (KORE_RESULT_ERROR);
    246 	}
    247 
    248 	if (nb->fd_off - prevoff != (size_t)len)
    249 		goto resend;
    250 
    251 	if (sent == 0 || nb->fd_off == nb->fd_len) {
    252 		net_remove_netbuf(c, nb);
    253 		c->snb = NULL;
    254 	}
    255 
    256 	return (KORE_RESULT_OK);
    257 }
    258 #endif
    259 
    260 void
    261 kore_platform_sandbox(void)
    262 {
    263 	kore_seccomp_enable();
    264 }