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



      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 		kore_debug("could not get number of cpu's falling back to 1");
     48 		cpu_count = 1;
     49 	} else {
     50 		cpu_count = (u_int16_t)n;
     51 	}
     52 }
     53 
     54 void
     55 kore_platform_worker_setcpu(struct kore_worker *kw)
     56 {
     57 	cpu_set_t	cpuset;
     58 
     59 	CPU_ZERO(&cpuset);
     60 	CPU_SET(kw->cpu, &cpuset);
     61 	if (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) == -1) {
     62 		kore_debug("kore_worker_setcpu(): %s", errno_s);
     63 	} else {
     64 		kore_debug("kore_worker_setcpu(): worker %d on cpu %d",
     65 		    kw->id, kw->cpu);
     66 	}
     67 }
     68 
     69 void
     70 kore_platform_event_init(void)
     71 {
     72 	if (efd != -1)
     73 		close(efd);
     74 	if (events != NULL)
     75 		kore_free(events);
     76 
     77 	if ((efd = epoll_create(10000)) == -1)
     78 		fatal("epoll_create(): %s", errno_s);
     79 
     80 	event_count = worker_max_connections + nlisteners;
     81 	events = kore_calloc(event_count, sizeof(struct epoll_event));
     82 }
     83 
     84 void
     85 kore_platform_event_cleanup(void)
     86 {
     87 	if (efd != -1) {
     88 		close(efd);
     89 		efd = -1;
     90 	}
     91 
     92 	if (events != NULL) {
     93 		kore_free(events);
     94 		events = NULL;
     95 	}
     96 }
     97 
     98 void
     99 kore_platform_event_wait(u_int64_t timer)
    100 {
    101 	u_int32_t		r;
    102 	struct kore_event	*evt;
    103 	int			n, i, timeo;
    104 
    105 	if (timer == KORE_WAIT_INFINITE)
    106 		timeo = -1;
    107 	else
    108 		timeo = timer;
    109 
    110 	n = epoll_wait(efd, events, event_count, timeo);
    111 	if (n == -1) {
    112 		if (errno == EINTR)
    113 			return;
    114 		fatal("epoll_wait(): %s", errno_s);
    115 	}
    116 
    117 	if (n > 0) {
    118 		kore_debug("main(): %d sockets available", n);
    119 	}
    120 
    121 	r = 0;
    122 	for (i = 0; i < n; i++) {
    123 		if (events[i].data.ptr == NULL)
    124 			fatal("events[%d].data.ptr == NULL", i);
    125 
    126 		r = 0;
    127 		evt = (struct kore_event *)events[i].data.ptr;
    128 
    129 		if (events[i].events & EPOLLIN)
    130 			evt->flags |= KORE_EVENT_READ;
    131 
    132 		if (events[i].events & EPOLLOUT)
    133 			evt->flags |= KORE_EVENT_WRITE;
    134 
    135 		if (events[i].events & EPOLLERR ||
    136 		    events[i].events & EPOLLHUP ||
    137 		    events[i].events & EPOLLRDHUP)
    138 			r = 1;
    139 
    140 		evt->handle(events[i].data.ptr, r);
    141 	}
    142 }
    143 
    144 void
    145 kore_platform_event_level_all(int fd, void *c)
    146 {
    147 	kore_platform_event_schedule(fd, EPOLLIN | EPOLLOUT | EPOLLRDHUP, 0, c);
    148 }
    149 
    150 void
    151 kore_platform_event_level_read(int fd, void *c)
    152 {
    153 	kore_platform_event_schedule(fd, EPOLLIN | EPOLLRDHUP, 0, c);
    154 }
    155 
    156 void
    157 kore_platform_event_all(int fd, void *c)
    158 {
    159 	kore_platform_event_schedule(fd,
    160 	    EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET, 0, c);
    161 }
    162 
    163 void
    164 kore_platform_event_schedule(int fd, int type, int flags, void *udata)
    165 {
    166 	struct epoll_event	evt;
    167 
    168 	kore_debug("kore_platform_event_schedule(%d, %d, %d, %p)",
    169 	    fd, type, flags, udata);
    170 
    171 	evt.events = type;
    172 	evt.data.ptr = udata;
    173 	if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &evt) == -1) {
    174 		if (errno == EEXIST) {
    175 			if (epoll_ctl(efd, EPOLL_CTL_MOD, fd, &evt) == -1)
    176 				fatal("epoll_ctl() MOD: %s", errno_s);
    177 		} else {
    178 			fatal("epoll_ctl() ADD: %s", errno_s);
    179 		}
    180 	}
    181 }
    182 
    183 void
    184 kore_platform_schedule_read(int fd, void *data)
    185 {
    186 	kore_platform_event_schedule(fd, EPOLLIN | EPOLLET, 0, data);
    187 }
    188 
    189 void
    190 kore_platform_schedule_write(int fd, void *data)
    191 {
    192 	kore_platform_event_schedule(fd, EPOLLOUT | EPOLLET, 0, data);
    193 }
    194 
    195 void
    196 kore_platform_disable_read(int fd)
    197 {
    198 	if (epoll_ctl(efd, EPOLL_CTL_DEL, fd, NULL) == -1)
    199 		fatal("kore_platform_disable_read: %s", errno_s);
    200 }
    201 
    202 void
    203 kore_platform_enable_accept(void)
    204 {
    205 	struct listener		*l;
    206 	struct kore_server	*srv;
    207 
    208 	kore_debug("kore_platform_enable_accept()");
    209 
    210 	LIST_FOREACH(srv, &kore_servers, list) {
    211 		LIST_FOREACH(l, &srv->listeners, list)
    212 			kore_platform_event_schedule(l->fd, EPOLLIN, 0, l);
    213 	}
    214 }
    215 
    216 void
    217 kore_platform_disable_accept(void)
    218 {
    219 	struct listener		*l;
    220 	struct kore_server	*srv;
    221 
    222 	kore_debug("kore_platform_disable_accept()");
    223 
    224 	LIST_FOREACH(srv, &kore_servers, list) {
    225 		LIST_FOREACH(l, &srv->listeners, list) {
    226 			if (epoll_ctl(efd, EPOLL_CTL_DEL, l->fd, NULL) == -1) {
    227 				fatal("kore_platform_disable_accept: %s",
    228 				    errno_s);
    229 			}
    230 		}
    231 	}
    232 }
    233 
    234 void
    235 kore_platform_proctitle(const char *title)
    236 {
    237 	kore_proctitle(title);
    238 }
    239 
    240 #if defined(KORE_USE_PLATFORM_SENDFILE)
    241 int
    242 kore_platform_sendfile(struct connection *c, struct netbuf *nb)
    243 {
    244 	off_t		smin;
    245 	ssize_t		sent;
    246 	size_t		len, prevoff;
    247 
    248 	prevoff = nb->fd_off;
    249 	smin = nb->fd_len - nb->fd_off;
    250 	len = MIN(SENDFILE_PAYLOAD_MAX, smin);
    251 
    252 resend:
    253 	sent = sendfile(c->fd, nb->file_ref->fd, &nb->fd_off, len);
    254 	if (sent == -1) {
    255 		if (errno == EAGAIN) {
    256 			c->evt.flags &= ~KORE_EVENT_WRITE;
    257 			return (KORE_RESULT_OK);
    258 		}
    259 
    260 		return (KORE_RESULT_ERROR);
    261 	}
    262 
    263 	if (nb->fd_off - prevoff != (size_t)len)
    264 		goto resend;
    265 
    266 	if (sent == 0 || nb->fd_off == nb->fd_len) {
    267 		net_remove_netbuf(c, nb);
    268 		c->snb = NULL;
    269 	}
    270 
    271 	return (KORE_RESULT_OK);
    272 }
    273 #endif
    274 
    275 void
    276 kore_platform_sandbox(void)
    277 {
    278 	kore_seccomp_enable();
    279 }