xref: /openbsd-src/usr.sbin/smtpd/scheduler_proc.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: scheduler_proc.c,v 1.5 2014/07/10 14:45:02 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2013 Eric Faurot <eric@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/tree.h>
22 #include <sys/param.h>
23 #include <sys/socket.h>
24 
25 #include <ctype.h>
26 #include <event.h>
27 #include <fcntl.h>
28 #include <imsg.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "smtpd.h"
35 #include "log.h"
36 
37 static struct imsgbuf	 ibuf;
38 static struct imsg	 imsg;
39 static size_t		 rlen;
40 static char		*rdata;
41 
42 static void
43 scheduler_proc_call(void)
44 {
45 	ssize_t	n;
46 
47 	if (imsg_flush(&ibuf) == -1) {
48 		log_warn("warn: scheduler-proc: imsg_flush");
49 		fatalx("scheduler-proc: exiting");
50 	}
51 
52 	while (1) {
53 		if ((n = imsg_get(&ibuf, &imsg)) == -1) {
54 			log_warn("warn: scheduler-proc: imsg_get");
55 			break;
56 		}
57 		if (n) {
58 			rlen = imsg.hdr.len - IMSG_HEADER_SIZE;
59 			rdata = imsg.data;
60 
61 			if (imsg.hdr.type != PROC_SCHEDULER_OK) {
62 				log_warnx("warn: scheduler-proc: bad response");
63 				break;
64 			}
65 			return;
66 		}
67 
68 		if ((n = imsg_read(&ibuf)) == -1) {
69 			log_warn("warn: scheduler-proc: imsg_read");
70 			break;
71 		}
72 
73 		if (n == 0) {
74 			log_warnx("warn: scheduler-proc: pipe closed");
75 			break;
76 		}
77 	}
78 
79 	fatalx("scheduler-proc: exiting");
80 }
81 
82 static void
83 scheduler_proc_read(void *dst, size_t len)
84 {
85 	if (len > rlen) {
86 		log_warnx("warn: scheduler-proc: bad msg len");
87 		fatalx("scheduler-proc: exiting");
88 	}
89 
90 	memmove(dst, rdata, len);
91 	rlen -= len;
92 	rdata += len;
93 }
94 
95 static void
96 scheduler_proc_end(void)
97 {
98 	if (rlen) {
99 		log_warnx("warn: scheduler-proc: bogus data");
100 		fatalx("scheduler-proc: exiting");
101 	}
102 	imsg_free(&imsg);
103 }
104 
105 /*
106  * API
107  */
108 
109 static int
110 scheduler_proc_init(const char *conf)
111 {
112 	int		fd, r;
113 	uint32_t	version;
114 
115 	fd = fork_proc_backend("scheduler", conf, "scheduler-proc");
116 	if (fd == -1)
117 		fatalx("scheduler-proc: exiting");
118 
119 	imsg_init(&ibuf, fd);
120 
121 	version = PROC_SCHEDULER_API_VERSION;
122 	imsg_compose(&ibuf, PROC_SCHEDULER_INIT, 0, 0, -1,
123 	    &version, sizeof(version));
124 	scheduler_proc_call();
125 	scheduler_proc_read(&r, sizeof(r));
126 	scheduler_proc_end();
127 
128 	return (1);
129 }
130 
131 static int
132 scheduler_proc_insert(struct scheduler_info *si)
133 {
134 	int	r;
135 
136 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_INSERT");
137 
138 	imsg_compose(&ibuf, PROC_SCHEDULER_INSERT, 0, 0, -1, si, sizeof(*si));
139 
140 	scheduler_proc_call();
141 	scheduler_proc_read(&r, sizeof(r));
142 	scheduler_proc_end();
143 
144 	return (r);
145 }
146 
147 static size_t
148 scheduler_proc_commit(uint32_t msgid)
149 {
150 	size_t	s;
151 
152 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_COMMIT");
153 
154 	imsg_compose(&ibuf, PROC_SCHEDULER_COMMIT, 0, 0, -1,
155 	    &msgid, sizeof(msgid));
156 
157 	scheduler_proc_call();
158 	scheduler_proc_read(&s, sizeof(s));
159 	scheduler_proc_end();
160 
161 	return (s);
162 }
163 
164 static size_t
165 scheduler_proc_rollback(uint32_t msgid)
166 {
167 	size_t	s;
168 
169 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_ROLLBACK");
170 
171 	imsg_compose(&ibuf, PROC_SCHEDULER_ROLLBACK, 0, 0, -1,
172 	    &msgid, sizeof(msgid));
173 
174 	scheduler_proc_call();
175 	scheduler_proc_read(&s, sizeof(s));
176 	scheduler_proc_end();
177 
178 	return (s);
179 }
180 
181 static int
182 scheduler_proc_update(struct scheduler_info *si)
183 {
184 	int	r;
185 
186 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_UPDATE");
187 
188 	imsg_compose(&ibuf, PROC_SCHEDULER_UPDATE, 0, 0, -1, si, sizeof(*si));
189 
190 	scheduler_proc_call();
191 	scheduler_proc_read(&r, sizeof(r));
192 	if (r == 1)
193 		scheduler_proc_read(si, sizeof(*si));
194 	scheduler_proc_end();
195 
196 	return (r);
197 }
198 
199 static int
200 scheduler_proc_delete(uint64_t evpid)
201 {
202 	int	r;
203 
204 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_DELETE");
205 
206 	imsg_compose(&ibuf, PROC_SCHEDULER_DELETE, 0, 0, -1,
207 	    &evpid, sizeof(evpid));
208 
209 	scheduler_proc_call();
210 	scheduler_proc_read(&r, sizeof(r));
211 	scheduler_proc_end();
212 
213 	return (r);
214 }
215 
216 static int
217 scheduler_proc_hold(uint64_t evpid, uint64_t holdq)
218 {
219 	struct ibuf	*buf;
220 	int		 r;
221 
222 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_HOLD");
223 
224 	buf = imsg_create(&ibuf, PROC_SCHEDULER_HOLD, 0, 0,
225 	    sizeof(evpid) + sizeof(holdq));
226 	if (buf == NULL)
227 		return (-1);
228 	if (imsg_add(buf, &evpid, sizeof(evpid)) == -1)
229 		return (-1);
230 	if (imsg_add(buf, &holdq, sizeof(holdq)) == -1)
231 		return (-1);
232 	imsg_close(&ibuf, buf);
233 
234 	scheduler_proc_call();
235 
236 	scheduler_proc_read(&r, sizeof(r));
237 	scheduler_proc_end();
238 
239 	return (r);
240 }
241 
242 static int
243 scheduler_proc_release(int type, uint64_t holdq, int n)
244 {
245 	struct ibuf	*buf;
246 	int		 r;
247 
248 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_RELEASE");
249 
250 	buf = imsg_create(&ibuf, PROC_SCHEDULER_RELEASE, 0, 0,
251 	    sizeof(holdq) + sizeof(n));
252 	if (buf == NULL)
253 		return (-1);
254 	if (imsg_add(buf, &type, sizeof(type)) == -1)
255 		return (-1);
256 	if (imsg_add(buf, &holdq, sizeof(holdq)) == -1)
257 		return (-1);
258 	if (imsg_add(buf, &n, sizeof(n)) == -1)
259 		return (-1);
260 	imsg_close(&ibuf, buf);
261 
262 	scheduler_proc_call();
263 
264 	scheduler_proc_read(&r, sizeof(r));
265 	scheduler_proc_end();
266 
267 	return (r);
268 }
269 
270 static int
271 scheduler_proc_batch(int typemask, int *delay, size_t *count, uint64_t *evpids, int *types)
272 {
273 	struct ibuf	*buf;
274 	int		 r;
275 
276 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_BATCH");
277 
278 	buf = imsg_create(&ibuf, PROC_SCHEDULER_BATCH, 0, 0,
279 	    sizeof(typemask) + sizeof(*count));
280 	if (buf == NULL)
281 		return (-1);
282 	if (imsg_add(buf, &typemask, sizeof(typemask)) == -1)
283 		return (-1);
284 	if (imsg_add(buf, count, sizeof(*count)) == -1)
285 		return (-1);
286 	imsg_close(&ibuf, buf);
287 
288 	scheduler_proc_call();
289 	scheduler_proc_read(&r, sizeof(r));
290 	scheduler_proc_read(delay, sizeof(*delay));
291 	scheduler_proc_read(count, sizeof(*count));
292 	if (r > 0) {
293 		scheduler_proc_read(evpids, sizeof(*evpids) * (*count));
294 		scheduler_proc_read(types, sizeof(*types) * (*count));
295 	}
296 	scheduler_proc_end();
297 
298 	return (r);
299 }
300 
301 static size_t
302 scheduler_proc_messages(uint32_t from, uint32_t *dst, size_t size)
303 {
304 	struct ibuf	*buf;
305 	size_t		 s;
306 
307 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_MESSAGES");
308 
309 	buf = imsg_create(&ibuf, PROC_SCHEDULER_MESSAGES, 0, 0,
310 	    sizeof(from) + sizeof(size));
311 	if (buf == NULL)
312 		return (-1);
313 	if (imsg_add(buf, &from, sizeof(from)) == -1)
314 		return (-1);
315 	if (imsg_add(buf, &size, sizeof(size)) == -1)
316 		return (-1);
317 	imsg_close(&ibuf, buf);
318 
319 	scheduler_proc_call();
320 
321 	s = rlen / sizeof(*dst);
322 	scheduler_proc_read(dst, s * sizeof(*dst));
323 	scheduler_proc_end();
324 
325 	return (s);
326 }
327 
328 static size_t
329 scheduler_proc_envelopes(uint64_t from, struct evpstate *dst, size_t size)
330 {
331 	struct ibuf	*buf;
332 	size_t		 s;
333 
334 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_ENVELOPES");
335 
336 	buf = imsg_create(&ibuf, PROC_SCHEDULER_ENVELOPES, 0, 0,
337 	    sizeof(from) + sizeof(size));
338 	if (buf == NULL)
339 		return (-1);
340 	if (imsg_add(buf, &from, sizeof(from)) == -1)
341 		return (-1);
342 	if (imsg_add(buf, &size, sizeof(size)) == -1)
343 		return (-1);
344 	imsg_close(&ibuf, buf);
345 
346 	scheduler_proc_call();
347 
348 	s = rlen / sizeof(*dst);
349 	scheduler_proc_read(dst, s * sizeof(*dst));
350 	scheduler_proc_end();
351 
352 	return (s);
353 }
354 
355 static int
356 scheduler_proc_schedule(uint64_t evpid)
357 {
358 	int	r;
359 
360 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_SCHEDULE");
361 
362 	imsg_compose(&ibuf, PROC_SCHEDULER_SCHEDULE, 0, 0, -1,
363 	    &evpid, sizeof(evpid));
364 
365 	scheduler_proc_call();
366 
367 	scheduler_proc_read(&r, sizeof(r));
368 	scheduler_proc_end();
369 
370 	return (r);
371 }
372 
373 static int
374 scheduler_proc_remove(uint64_t evpid)
375 {
376 	int	r;
377 
378 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_REMOVE");
379 
380 	imsg_compose(&ibuf, PROC_SCHEDULER_REMOVE, 0, 0, -1,
381 	    &evpid, sizeof(evpid));
382 
383 	scheduler_proc_call();
384 
385 	scheduler_proc_read(&r, sizeof(r));
386 	scheduler_proc_end();
387 
388 	return (r);
389 }
390 
391 static int
392 scheduler_proc_suspend(uint64_t evpid)
393 {
394 	int	r;
395 
396 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_SUSPEND");
397 
398 	imsg_compose(&ibuf, PROC_SCHEDULER_SUSPEND, 0, 0, -1,
399 	    &evpid, sizeof(evpid));
400 
401 	scheduler_proc_call();
402 
403 	scheduler_proc_read(&r, sizeof(r));
404 	scheduler_proc_end();
405 
406 	return (r);
407 }
408 
409 static int
410 scheduler_proc_resume(uint64_t evpid)
411 {
412 	int	r;
413 
414 	log_debug("debug: scheduler-proc: PROC_SCHEDULER_RESUME");
415 
416 	imsg_compose(&ibuf, PROC_SCHEDULER_RESUME, 0, 0, -1,
417 	    &evpid, sizeof(evpid));
418 
419 	scheduler_proc_call();
420 
421 	scheduler_proc_read(&r, sizeof(r));
422 	scheduler_proc_end();
423 
424 	return (r);
425 }
426 
427 struct scheduler_backend scheduler_backend_proc = {
428 	scheduler_proc_init,
429 	scheduler_proc_insert,
430 	scheduler_proc_commit,
431 	scheduler_proc_rollback,
432 	scheduler_proc_update,
433 	scheduler_proc_delete,
434 	scheduler_proc_hold,
435 	scheduler_proc_release,
436 	scheduler_proc_batch,
437 	scheduler_proc_messages,
438 	scheduler_proc_envelopes,
439 	scheduler_proc_schedule,
440 	scheduler_proc_remove,
441 	scheduler_proc_suspend,
442 	scheduler_proc_resume,
443 };
444