bsd.c (6669B)
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 u_int32_t
302 kore_platform_random_uint32(void)
303 {
304 return (arc4random());
305 }
306
307 #if defined(KORE_USE_PLATFORM_PLEDGE)
308 void
309 kore_platform_pledge(void)
310 {
311 if (worker->id == KORE_WORKER_KEYMGR || worker->id == KORE_WORKER_ACME)
312 return;
313
314 if (pledge(pledges, NULL) == -1)
315 fatal("failed to pledge process");
316 }
317
318 void
319 kore_platform_add_pledge(const char *pledge)
320 {
321 size_t len;
322
323 len = strlcat(pledges, " ", sizeof(pledges));
324 if (len >= sizeof(pledges))
325 fatal("truncation on pledges");
326
327 len = strlcat(pledges, pledge, sizeof(pledges));
328 if (len >= sizeof(pledges))
329 fatal("truncation on pledges (%s)", pledge);
330 }
331 #endif