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