1/*	$OpenBSD: scheduler_proc.c,v 1.10 2024/05/07 12:10:06 op 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 <errno.h>
20#include <string.h>
21
22#include "smtpd.h"
23#include "log.h"
24
25static struct imsgbuf	 ibuf;
26static struct imsg	 imsg;
27static size_t		 rlen;
28static char		*rdata;
29
30static void
31scheduler_proc_call(void)
32{
33	ssize_t	n;
34
35	if (imsg_flush(&ibuf) == -1) {
36		log_warn("warn: scheduler-proc: imsg_flush");
37		fatalx("scheduler-proc: exiting");
38	}
39
40	while (1) {
41		if ((n = imsg_get(&ibuf, &imsg)) == -1) {
42			log_warn("warn: scheduler-proc: imsg_get");
43			break;
44		}
45		if (n) {
46			rlen = imsg.hdr.len - IMSG_HEADER_SIZE;
47			rdata = imsg.data;
48
49			if (imsg.hdr.type != PROC_SCHEDULER_OK) {
50				log_warnx("warn: scheduler-proc: bad response");
51				break;
52			}
53			return;
54		}
55
56		if ((n = imsg_read(&ibuf)) == -1 && errno != EAGAIN) {
57			log_warn("warn: scheduler-proc: imsg_read");
58			break;
59		}
60
61		if (n == 0) {
62			log_warnx("warn: scheduler-proc: pipe closed");
63			break;
64		}
65	}
66
67	fatalx("scheduler-proc: exiting");
68}
69
70static void
71scheduler_proc_read(void *dst, size_t len)
72{
73	if (len > rlen) {
74		log_warnx("warn: scheduler-proc: bad msg len");
75		fatalx("scheduler-proc: exiting");
76	}
77
78	memmove(dst, rdata, len);
79	rlen -= len;
80	rdata += len;
81}
82
83static void
84scheduler_proc_end(void)
85{
86	if (rlen) {
87		log_warnx("warn: scheduler-proc: bogus data");
88		fatalx("scheduler-proc: exiting");
89	}
90	imsg_free(&imsg);
91}
92
93/*
94 * API
95 */
96
97static int
98scheduler_proc_init(const char *conf)
99{
100	int		fd, r;
101	uint32_t	version;
102
103	fd = fork_proc_backend("scheduler", conf, "scheduler-proc", 0);
104	if (fd == -1)
105		fatalx("scheduler-proc: exiting");
106
107	imsg_init(&ibuf, fd);
108
109	version = PROC_SCHEDULER_API_VERSION;
110	imsg_compose(&ibuf, PROC_SCHEDULER_INIT, 0, 0, -1,
111	    &version, sizeof(version));
112	scheduler_proc_call();
113	scheduler_proc_read(&r, sizeof(r));
114	scheduler_proc_end();
115
116	return (1);
117}
118
119static int
120scheduler_proc_insert(struct scheduler_info *si)
121{
122	int	r;
123
124	log_debug("debug: scheduler-proc: PROC_SCHEDULER_INSERT");
125
126	imsg_compose(&ibuf, PROC_SCHEDULER_INSERT, 0, 0, -1, si, sizeof(*si));
127
128	scheduler_proc_call();
129	scheduler_proc_read(&r, sizeof(r));
130	scheduler_proc_end();
131
132	return (r);
133}
134
135static size_t
136scheduler_proc_commit(uint32_t msgid)
137{
138	size_t	s;
139
140	log_debug("debug: scheduler-proc: PROC_SCHEDULER_COMMIT");
141
142	imsg_compose(&ibuf, PROC_SCHEDULER_COMMIT, 0, 0, -1,
143	    &msgid, sizeof(msgid));
144
145	scheduler_proc_call();
146	scheduler_proc_read(&s, sizeof(s));
147	scheduler_proc_end();
148
149	return (s);
150}
151
152static size_t
153scheduler_proc_rollback(uint32_t msgid)
154{
155	size_t	s;
156
157	log_debug("debug: scheduler-proc: PROC_SCHEDULER_ROLLBACK");
158
159	imsg_compose(&ibuf, PROC_SCHEDULER_ROLLBACK, 0, 0, -1,
160	    &msgid, sizeof(msgid));
161
162	scheduler_proc_call();
163	scheduler_proc_read(&s, sizeof(s));
164	scheduler_proc_end();
165
166	return (s);
167}
168
169static int
170scheduler_proc_update(struct scheduler_info *si)
171{
172	int	r;
173
174	log_debug("debug: scheduler-proc: PROC_SCHEDULER_UPDATE");
175
176	imsg_compose(&ibuf, PROC_SCHEDULER_UPDATE, 0, 0, -1, si, sizeof(*si));
177
178	scheduler_proc_call();
179	scheduler_proc_read(&r, sizeof(r));
180	if (r == 1)
181		scheduler_proc_read(si, sizeof(*si));
182	scheduler_proc_end();
183
184	return (r);
185}
186
187static int
188scheduler_proc_delete(uint64_t evpid)
189{
190	int	r;
191
192	log_debug("debug: scheduler-proc: PROC_SCHEDULER_DELETE");
193
194	imsg_compose(&ibuf, PROC_SCHEDULER_DELETE, 0, 0, -1,
195	    &evpid, sizeof(evpid));
196
197	scheduler_proc_call();
198	scheduler_proc_read(&r, sizeof(r));
199	scheduler_proc_end();
200
201	return (r);
202}
203
204static int
205scheduler_proc_hold(uint64_t evpid, uint64_t holdq)
206{
207	struct ibuf	*buf;
208	int		 r;
209
210	log_debug("debug: scheduler-proc: PROC_SCHEDULER_HOLD");
211
212	buf = imsg_create(&ibuf, PROC_SCHEDULER_HOLD, 0, 0,
213	    sizeof(evpid) + sizeof(holdq));
214	if (buf == NULL)
215		return (-1);
216	if (imsg_add(buf, &evpid, sizeof(evpid)) == -1)
217		return (-1);
218	if (imsg_add(buf, &holdq, sizeof(holdq)) == -1)
219		return (-1);
220	imsg_close(&ibuf, buf);
221
222	scheduler_proc_call();
223
224	scheduler_proc_read(&r, sizeof(r));
225	scheduler_proc_end();
226
227	return (r);
228}
229
230static int
231scheduler_proc_release(int type, uint64_t holdq, int n)
232{
233	struct ibuf	*buf;
234	int		 r;
235
236	log_debug("debug: scheduler-proc: PROC_SCHEDULER_RELEASE");
237
238	buf = imsg_create(&ibuf, PROC_SCHEDULER_RELEASE, 0, 0,
239	    sizeof(holdq) + sizeof(n));
240	if (buf == NULL)
241		return (-1);
242	if (imsg_add(buf, &type, sizeof(type)) == -1)
243		return (-1);
244	if (imsg_add(buf, &holdq, sizeof(holdq)) == -1)
245		return (-1);
246	if (imsg_add(buf, &n, sizeof(n)) == -1)
247		return (-1);
248	imsg_close(&ibuf, buf);
249
250	scheduler_proc_call();
251
252	scheduler_proc_read(&r, sizeof(r));
253	scheduler_proc_end();
254
255	return (r);
256}
257
258static int
259scheduler_proc_batch(int typemask, int *delay, size_t *count, uint64_t *evpids, int *types)
260{
261	struct ibuf	*buf;
262	int		 r;
263
264	log_debug("debug: scheduler-proc: PROC_SCHEDULER_BATCH");
265
266	buf = imsg_create(&ibuf, PROC_SCHEDULER_BATCH, 0, 0,
267	    sizeof(typemask) + sizeof(*count));
268	if (buf == NULL)
269		return (-1);
270	if (imsg_add(buf, &typemask, sizeof(typemask)) == -1)
271		return (-1);
272	if (imsg_add(buf, count, sizeof(*count)) == -1)
273		return (-1);
274	imsg_close(&ibuf, buf);
275
276	scheduler_proc_call();
277	scheduler_proc_read(&r, sizeof(r));
278	scheduler_proc_read(delay, sizeof(*delay));
279	scheduler_proc_read(count, sizeof(*count));
280	if (r > 0) {
281		scheduler_proc_read(evpids, sizeof(*evpids) * (*count));
282		scheduler_proc_read(types, sizeof(*types) * (*count));
283	}
284	scheduler_proc_end();
285
286	return (r);
287}
288
289static size_t
290scheduler_proc_messages(uint32_t from, uint32_t *dst, size_t size)
291{
292	struct ibuf	*buf;
293	size_t		 s;
294
295	log_debug("debug: scheduler-proc: PROC_SCHEDULER_MESSAGES");
296
297	buf = imsg_create(&ibuf, PROC_SCHEDULER_MESSAGES, 0, 0,
298	    sizeof(from) + sizeof(size));
299	if (buf == NULL)
300		return (-1);
301	if (imsg_add(buf, &from, sizeof(from)) == -1)
302		return (-1);
303	if (imsg_add(buf, &size, sizeof(size)) == -1)
304		return (-1);
305	imsg_close(&ibuf, buf);
306
307	scheduler_proc_call();
308
309	s = rlen / sizeof(*dst);
310	scheduler_proc_read(dst, s * sizeof(*dst));
311	scheduler_proc_end();
312
313	return (s);
314}
315
316static size_t
317scheduler_proc_envelopes(uint64_t from, struct evpstate *dst, size_t size)
318{
319	struct ibuf	*buf;
320	size_t		 s;
321
322	log_debug("debug: scheduler-proc: PROC_SCHEDULER_ENVELOPES");
323
324	buf = imsg_create(&ibuf, PROC_SCHEDULER_ENVELOPES, 0, 0,
325	    sizeof(from) + sizeof(size));
326	if (buf == NULL)
327		return (-1);
328	if (imsg_add(buf, &from, sizeof(from)) == -1)
329		return (-1);
330	if (imsg_add(buf, &size, sizeof(size)) == -1)
331		return (-1);
332	imsg_close(&ibuf, buf);
333
334	scheduler_proc_call();
335
336	s = rlen / sizeof(*dst);
337	scheduler_proc_read(dst, s * sizeof(*dst));
338	scheduler_proc_end();
339
340	return (s);
341}
342
343static int
344scheduler_proc_schedule(uint64_t evpid)
345{
346	int	r;
347
348	log_debug("debug: scheduler-proc: PROC_SCHEDULER_SCHEDULE");
349
350	imsg_compose(&ibuf, PROC_SCHEDULER_SCHEDULE, 0, 0, -1,
351	    &evpid, sizeof(evpid));
352
353	scheduler_proc_call();
354
355	scheduler_proc_read(&r, sizeof(r));
356	scheduler_proc_end();
357
358	return (r);
359}
360
361static int
362scheduler_proc_remove(uint64_t evpid)
363{
364	int	r;
365
366	log_debug("debug: scheduler-proc: PROC_SCHEDULER_REMOVE");
367
368	imsg_compose(&ibuf, PROC_SCHEDULER_REMOVE, 0, 0, -1,
369	    &evpid, sizeof(evpid));
370
371	scheduler_proc_call();
372
373	scheduler_proc_read(&r, sizeof(r));
374	scheduler_proc_end();
375
376	return (r);
377}
378
379static int
380scheduler_proc_suspend(uint64_t evpid)
381{
382	int	r;
383
384	log_debug("debug: scheduler-proc: PROC_SCHEDULER_SUSPEND");
385
386	imsg_compose(&ibuf, PROC_SCHEDULER_SUSPEND, 0, 0, -1,
387	    &evpid, sizeof(evpid));
388
389	scheduler_proc_call();
390
391	scheduler_proc_read(&r, sizeof(r));
392	scheduler_proc_end();
393
394	return (r);
395}
396
397static int
398scheduler_proc_resume(uint64_t evpid)
399{
400	int	r;
401
402	log_debug("debug: scheduler-proc: PROC_SCHEDULER_RESUME");
403
404	imsg_compose(&ibuf, PROC_SCHEDULER_RESUME, 0, 0, -1,
405	    &evpid, sizeof(evpid));
406
407	scheduler_proc_call();
408
409	scheduler_proc_read(&r, sizeof(r));
410	scheduler_proc_end();
411
412	return (r);
413}
414
415struct scheduler_backend scheduler_backend_proc = {
416	scheduler_proc_init,
417	scheduler_proc_insert,
418	scheduler_proc_commit,
419	scheduler_proc_rollback,
420	scheduler_proc_update,
421	scheduler_proc_delete,
422	scheduler_proc_hold,
423	scheduler_proc_release,
424	scheduler_proc_batch,
425	scheduler_proc_messages,
426	scheduler_proc_envelopes,
427	scheduler_proc_schedule,
428	scheduler_proc_remove,
429	scheduler_proc_suspend,
430	scheduler_proc_resume,
431};
432