1*bf921b2aSclaudio /* $OpenBSD: mproc.c,v 1.47 2024/11/21 13:42:22 claudio Exp $ */ 265c4fdfbSgilles 365c4fdfbSgilles /* 465c4fdfbSgilles * Copyright (c) 2012 Eric Faurot <eric@faurot.net> 565c4fdfbSgilles * 665c4fdfbSgilles * Permission to use, copy, modify, and distribute this software for any 765c4fdfbSgilles * purpose with or without fee is hereby granted, provided that the above 865c4fdfbSgilles * copyright notice and this permission notice appear in all copies. 965c4fdfbSgilles * 1065c4fdfbSgilles * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1165c4fdfbSgilles * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1265c4fdfbSgilles * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1365c4fdfbSgilles * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1465c4fdfbSgilles * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1565c4fdfbSgilles * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1665c4fdfbSgilles * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1765c4fdfbSgilles */ 1865c4fdfbSgilles 1965c4fdfbSgilles #include <errno.h> 2065c4fdfbSgilles #include <stdlib.h> 2165c4fdfbSgilles #include <string.h> 2265c4fdfbSgilles #include <unistd.h> 2365c4fdfbSgilles 2465c4fdfbSgilles #include "smtpd.h" 2565c4fdfbSgilles #include "log.h" 2665c4fdfbSgilles 2765c4fdfbSgilles static void mproc_dispatch(int, short, void *); 2865c4fdfbSgilles 2965c4fdfbSgilles int 30d6f2ac01Seric mproc_fork(struct mproc *p, const char *path, char *argv[]) 3165c4fdfbSgilles { 3265c4fdfbSgilles int sp[2]; 3365c4fdfbSgilles 34df69c215Sderaadt if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) 3565c4fdfbSgilles return (-1); 3665c4fdfbSgilles 37907c4b99Skrw io_set_nonblocking(sp[0]); 38907c4b99Skrw io_set_nonblocking(sp[1]); 3965c4fdfbSgilles 4065c4fdfbSgilles if ((p->pid = fork()) == -1) 4165c4fdfbSgilles goto err; 4265c4fdfbSgilles 4365c4fdfbSgilles if (p->pid == 0) { 4465c4fdfbSgilles /* child process */ 4565c4fdfbSgilles dup2(sp[0], STDIN_FILENO); 46df69c215Sderaadt if (closefrom(STDERR_FILENO + 1) == -1) 4765c4fdfbSgilles exit(1); 4865c4fdfbSgilles 49d6f2ac01Seric execv(path, argv); 50ff01b044Seric fatal("execv: %s", path); 5165c4fdfbSgilles } 5265c4fdfbSgilles 5365c4fdfbSgilles /* parent process */ 5465c4fdfbSgilles close(sp[0]); 5565c4fdfbSgilles mproc_init(p, sp[1]); 5665c4fdfbSgilles return (0); 5765c4fdfbSgilles 5865c4fdfbSgilles err: 59d6f2ac01Seric log_warn("warn: Failed to start process %s, instance of %s", argv[0], path); 6065c4fdfbSgilles close(sp[0]); 6165c4fdfbSgilles close(sp[1]); 6265c4fdfbSgilles return (-1); 6365c4fdfbSgilles } 6465c4fdfbSgilles 6565c4fdfbSgilles void 6665c4fdfbSgilles mproc_init(struct mproc *p, int fd) 6765c4fdfbSgilles { 68*bf921b2aSclaudio if (imsgbuf_init(&p->imsgbuf, fd) == -1) 69*bf921b2aSclaudio fatal("mproc_init: imsgbuf_init"); 70*bf921b2aSclaudio if (p->proc != PROC_CLIENT) 71*bf921b2aSclaudio imsgbuf_allow_fdpass(&p->imsgbuf); 7265c4fdfbSgilles } 7365c4fdfbSgilles 7465c4fdfbSgilles void 7565c4fdfbSgilles mproc_clear(struct mproc *p) 7665c4fdfbSgilles { 7743962b9cSeric log_debug("debug: clearing p=%s, fd=%d, pid=%d", p->name, p->imsgbuf.fd, p->pid); 7843962b9cSeric 79ef75f1bdSmartijn if (p->events) 8065c4fdfbSgilles event_del(&p->ev); 8165c4fdfbSgilles close(p->imsgbuf.fd); 82dd7efffeSclaudio imsgbuf_clear(&p->imsgbuf); 8365c4fdfbSgilles } 8465c4fdfbSgilles 8565c4fdfbSgilles void 8665c4fdfbSgilles mproc_enable(struct mproc *p) 8765c4fdfbSgilles { 8865c4fdfbSgilles if (p->enable == 0) { 89299c4efeSeric log_trace(TRACE_MPROC, "mproc: %s -> %s: enabled", 90299c4efeSeric proc_name(smtpd_process), 9165c4fdfbSgilles proc_name(p->proc)); 9265c4fdfbSgilles p->enable = 1; 9365c4fdfbSgilles } 9465c4fdfbSgilles mproc_event_add(p); 9565c4fdfbSgilles } 9665c4fdfbSgilles 9765c4fdfbSgilles void 9865c4fdfbSgilles mproc_disable(struct mproc *p) 9965c4fdfbSgilles { 10065c4fdfbSgilles if (p->enable == 1) { 101299c4efeSeric log_trace(TRACE_MPROC, "mproc: %s -> %s: disabled", 102299c4efeSeric proc_name(smtpd_process), 10365c4fdfbSgilles proc_name(p->proc)); 10465c4fdfbSgilles p->enable = 0; 10565c4fdfbSgilles } 10665c4fdfbSgilles mproc_event_add(p); 10765c4fdfbSgilles } 10865c4fdfbSgilles 109c4df3bf2Sreyk void 11065c4fdfbSgilles mproc_event_add(struct mproc *p) 11165c4fdfbSgilles { 11265c4fdfbSgilles short events; 11365c4fdfbSgilles 11465c4fdfbSgilles if (p->enable) 11565c4fdfbSgilles events = EV_READ; 11665c4fdfbSgilles else 11765c4fdfbSgilles events = 0; 11865c4fdfbSgilles 11931be28caSclaudio if (imsgbuf_queuelen(&p->imsgbuf) > 0) 12065c4fdfbSgilles events |= EV_WRITE; 12165c4fdfbSgilles 12265c4fdfbSgilles if (p->events) 12365c4fdfbSgilles event_del(&p->ev); 12465c4fdfbSgilles 12565c4fdfbSgilles p->events = events; 12665c4fdfbSgilles if (events) { 12765c4fdfbSgilles event_set(&p->ev, p->imsgbuf.fd, events, mproc_dispatch, p); 12865c4fdfbSgilles event_add(&p->ev, NULL); 12965c4fdfbSgilles } 13065c4fdfbSgilles } 13165c4fdfbSgilles 13265c4fdfbSgilles static void 13365c4fdfbSgilles mproc_dispatch(int fd, short event, void *arg) 13465c4fdfbSgilles { 13565c4fdfbSgilles struct mproc *p = arg; 13665c4fdfbSgilles struct imsg imsg; 13765c4fdfbSgilles ssize_t n; 13865c4fdfbSgilles 13965c4fdfbSgilles p->events = 0; 14065c4fdfbSgilles 14165c4fdfbSgilles if (event & EV_READ) { 14265c4fdfbSgilles 143dd7efffeSclaudio n = imsgbuf_read(&p->imsgbuf); 144cc03c9a7Sgilles 1451a473d40Smillert switch (n) { 1461a473d40Smillert case -1: 147dd7efffeSclaudio log_warn("warn: %s -> %s: imsgbuf_read", 148299c4efeSeric proc_name(smtpd_process), p->name); 149299c4efeSeric fatal("exiting"); 1501a473d40Smillert /* NOTREACHED */ 1511a473d40Smillert case 0: 15265c4fdfbSgilles /* this pipe is dead, so remove the event handler */ 15343962b9cSeric log_debug("debug: %s -> %s: pipe closed", 154299c4efeSeric proc_name(smtpd_process), p->name); 15565c4fdfbSgilles p->handler(p, NULL); 15665c4fdfbSgilles return; 1571a473d40Smillert default: 1581a473d40Smillert break; 1591a473d40Smillert } 16065c4fdfbSgilles } 16165c4fdfbSgilles 16265c4fdfbSgilles if (event & EV_WRITE) { 163dd7efffeSclaudio if (imsgbuf_write(&p->imsgbuf) == -1) { 1645db1b16bSeric /* this pipe is dead, so remove the event handler */ 16543962b9cSeric log_debug("debug: %s -> %s: pipe closed", 1665db1b16bSeric proc_name(smtpd_process), p->name); 1675db1b16bSeric p->handler(p, NULL); 1685db1b16bSeric return; 16965c4fdfbSgilles } 1702f366c99Seric } 17165c4fdfbSgilles 17265c4fdfbSgilles for (;;) { 1731c6ac251Seric if ((n = imsg_get(&p->imsgbuf, &imsg)) == -1) { 1748e9397b5Sgilles 1758e9397b5Sgilles if (smtpd_process == PROC_CONTROL && 1768e9397b5Sgilles p->proc == PROC_CLIENT) { 1778e9397b5Sgilles log_warnx("warn: client sent invalid imsg " 1788e9397b5Sgilles "over control socket"); 1798e9397b5Sgilles p->handler(p, NULL); 1808e9397b5Sgilles return; 1818e9397b5Sgilles } 1821c6ac251Seric log_warn("fatal: %s: error in imsg_get for %s", 1831c6ac251Seric proc_name(smtpd_process), p->name); 1841c6ac251Seric fatalx(NULL); 1851c6ac251Seric } 18665c4fdfbSgilles if (n == 0) 18765c4fdfbSgilles break; 18865c4fdfbSgilles 18965c4fdfbSgilles p->handler(p, &imsg); 19065c4fdfbSgilles 19165c4fdfbSgilles imsg_free(&imsg); 19265c4fdfbSgilles } 19365c4fdfbSgilles 19465c4fdfbSgilles mproc_event_add(p); 19565c4fdfbSgilles } 19665c4fdfbSgilles 19765c4fdfbSgilles void 19865c4fdfbSgilles m_forward(struct mproc *p, struct imsg *imsg) 19965c4fdfbSgilles { 20065c4fdfbSgilles imsg_compose(&p->imsgbuf, imsg->hdr.type, imsg->hdr.peerid, 201510586acSclaudio imsg->hdr.pid, imsg_get_fd(imsg), imsg->data, 20265c4fdfbSgilles imsg->hdr.len - sizeof(imsg->hdr)); 20365c4fdfbSgilles 204a6d7bf9fSgilles if (imsg->hdr.type != IMSG_STAT_DECREMENT && 205a6d7bf9fSgilles imsg->hdr.type != IMSG_STAT_INCREMENT) 206299c4efeSeric log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s (forward)", 207299c4efeSeric proc_name(smtpd_process), 208299c4efeSeric proc_name(p->proc), 209299c4efeSeric imsg->hdr.len - sizeof(imsg->hdr), 210299c4efeSeric imsg_to_str(imsg->hdr.type)); 211299c4efeSeric 21265c4fdfbSgilles mproc_event_add(p); 21365c4fdfbSgilles } 21465c4fdfbSgilles 21565c4fdfbSgilles void 21665c4fdfbSgilles m_compose(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd, 21765c4fdfbSgilles void *data, size_t len) 21865c4fdfbSgilles { 21965c4fdfbSgilles imsg_compose(&p->imsgbuf, type, peerid, pid, fd, data, len); 22065c4fdfbSgilles 221a6d7bf9fSgilles if (type != IMSG_STAT_DECREMENT && 222a6d7bf9fSgilles type != IMSG_STAT_INCREMENT) 223299c4efeSeric log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s", 224299c4efeSeric proc_name(smtpd_process), 225299c4efeSeric proc_name(p->proc), 226299c4efeSeric len, 227299c4efeSeric imsg_to_str(type)); 228299c4efeSeric 22965c4fdfbSgilles mproc_event_add(p); 23065c4fdfbSgilles } 23165c4fdfbSgilles 23265c4fdfbSgilles void 23365c4fdfbSgilles m_composev(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid, 23465c4fdfbSgilles int fd, const struct iovec *iov, int n) 23565c4fdfbSgilles { 236299c4efeSeric size_t len; 23765c4fdfbSgilles int i; 23865c4fdfbSgilles 23965c4fdfbSgilles imsg_composev(&p->imsgbuf, type, peerid, pid, fd, iov, n); 24065c4fdfbSgilles 241299c4efeSeric len = 0; 24265c4fdfbSgilles for (i = 0; i < n; i++) 243299c4efeSeric len += iov[i].iov_len; 244299c4efeSeric 245a6d7bf9fSgilles if (type != IMSG_STAT_DECREMENT && 246a6d7bf9fSgilles type != IMSG_STAT_INCREMENT) 247299c4efeSeric log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s", 248299c4efeSeric proc_name(smtpd_process), 249299c4efeSeric proc_name(p->proc), 250299c4efeSeric len, 251299c4efeSeric imsg_to_str(type)); 252299c4efeSeric 25365c4fdfbSgilles mproc_event_add(p); 25465c4fdfbSgilles } 25565c4fdfbSgilles 25665c4fdfbSgilles void 257299c4efeSeric m_create(struct mproc *p, uint32_t type, uint32_t peerid, pid_t pid, int fd) 25865c4fdfbSgilles { 259299c4efeSeric p->m_pos = 0; 260299c4efeSeric p->m_type = type; 261299c4efeSeric p->m_peerid = peerid; 262299c4efeSeric p->m_pid = pid; 263299c4efeSeric p->m_fd = fd; 26465c4fdfbSgilles } 26565c4fdfbSgilles 26665c4fdfbSgilles void 26765c4fdfbSgilles m_add(struct mproc *p, const void *data, size_t len) 26865c4fdfbSgilles { 269299c4efeSeric size_t alloc; 270299c4efeSeric void *tmp; 27165c4fdfbSgilles 272299c4efeSeric if (p->m_pos + len + IMSG_HEADER_SIZE > MAX_IMSGSIZE) { 273ca0c3639Sgilles log_warnx("warn: message too large"); 274299c4efeSeric fatal(NULL); 275299c4efeSeric } 276299c4efeSeric 277107c21adSeric alloc = p->m_alloc ? p->m_alloc : 128; 278299c4efeSeric while (p->m_pos + len > alloc) 279299c4efeSeric alloc *= 2; 280299c4efeSeric if (alloc != p->m_alloc) { 281299c4efeSeric log_trace(TRACE_MPROC, "mproc: %s -> %s: realloc %zu -> %zu", 282299c4efeSeric proc_name(smtpd_process), 283299c4efeSeric proc_name(p->proc), 284299c4efeSeric p->m_alloc, 285299c4efeSeric alloc); 286299c4efeSeric 287107c21adSeric tmp = recallocarray(p->m_buf, p->m_alloc, alloc, 1); 288299c4efeSeric if (tmp == NULL) 289299c4efeSeric fatal("realloc"); 290299c4efeSeric p->m_alloc = alloc; 291299c4efeSeric p->m_buf = tmp; 292299c4efeSeric } 293299c4efeSeric 294299c4efeSeric memmove(p->m_buf + p->m_pos, data, len); 295299c4efeSeric p->m_pos += len; 29665c4fdfbSgilles } 29765c4fdfbSgilles 29865c4fdfbSgilles void 29965c4fdfbSgilles m_close(struct mproc *p) 30065c4fdfbSgilles { 301299c4efeSeric if (imsg_compose(&p->imsgbuf, p->m_type, p->m_peerid, p->m_pid, p->m_fd, 302299c4efeSeric p->m_buf, p->m_pos) == -1) 303299c4efeSeric fatal("imsg_compose"); 30465c4fdfbSgilles 305299c4efeSeric log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s", 30665c4fdfbSgilles proc_name(smtpd_process), 30765c4fdfbSgilles proc_name(p->proc), 308299c4efeSeric p->m_pos, 309299c4efeSeric imsg_to_str(p->m_type)); 31065c4fdfbSgilles 31165c4fdfbSgilles mproc_event_add(p); 31265c4fdfbSgilles } 31365c4fdfbSgilles 314c4df3bf2Sreyk void 315c4df3bf2Sreyk m_flush(struct mproc *p) 316c4df3bf2Sreyk { 317c4df3bf2Sreyk if (imsg_compose(&p->imsgbuf, p->m_type, p->m_peerid, p->m_pid, p->m_fd, 318c4df3bf2Sreyk p->m_buf, p->m_pos) == -1) 319c4df3bf2Sreyk fatal("imsg_compose"); 320c4df3bf2Sreyk 321c4df3bf2Sreyk log_trace(TRACE_MPROC, "mproc: %s -> %s : %zu %s (flush)", 322c4df3bf2Sreyk proc_name(smtpd_process), 323c4df3bf2Sreyk proc_name(p->proc), 324c4df3bf2Sreyk p->m_pos, 325c4df3bf2Sreyk imsg_to_str(p->m_type)); 326c4df3bf2Sreyk 327c4df3bf2Sreyk p->m_pos = 0; 328c4df3bf2Sreyk 329dd7efffeSclaudio if (imsgbuf_flush(&p->imsgbuf) == -1) 330dd7efffeSclaudio fatal("imsgbuf_flush"); 331c4df3bf2Sreyk } 332c4df3bf2Sreyk 33365c4fdfbSgilles static struct imsg * current; 33465c4fdfbSgilles 33565c4fdfbSgilles static void 33665c4fdfbSgilles m_error(const char *error) 33765c4fdfbSgilles { 33865c4fdfbSgilles char buf[512]; 33965c4fdfbSgilles 340dd7aa8c7Sgilles (void)snprintf(buf, sizeof buf, "%s: %s: %s", 34165c4fdfbSgilles proc_name(smtpd_process), 34265c4fdfbSgilles imsg_to_str(current->hdr.type), 34365c4fdfbSgilles error); 344d6f2ac01Seric fatalx("%s", buf); 34565c4fdfbSgilles } 34665c4fdfbSgilles 34765c4fdfbSgilles void 34865c4fdfbSgilles m_msg(struct msg *m, struct imsg *imsg) 34965c4fdfbSgilles { 35065c4fdfbSgilles current = imsg; 35165c4fdfbSgilles m->pos = imsg->data; 35265c4fdfbSgilles m->end = m->pos + (imsg->hdr.len - sizeof(imsg->hdr)); 35365c4fdfbSgilles } 35465c4fdfbSgilles 35565c4fdfbSgilles void 35665c4fdfbSgilles m_end(struct msg *m) 35765c4fdfbSgilles { 35865c4fdfbSgilles if (m->pos != m->end) 35965c4fdfbSgilles m_error("not at msg end"); 36065c4fdfbSgilles } 36165c4fdfbSgilles 36265c4fdfbSgilles int 36365c4fdfbSgilles m_is_eom(struct msg *m) 36465c4fdfbSgilles { 36565c4fdfbSgilles return (m->pos == m->end); 36665c4fdfbSgilles } 36765c4fdfbSgilles 36865c4fdfbSgilles static inline void 36965c4fdfbSgilles m_get(struct msg *m, void *dst, size_t sz) 37065c4fdfbSgilles { 37181a33c5dSeric if (sz > MAX_IMSGSIZE || 37281a33c5dSeric m->end - m->pos < (ssize_t)sz) 37381a33c5dSeric fatalx("msg too short"); 37481a33c5dSeric 37565c4fdfbSgilles memmove(dst, m->pos, sz); 37665c4fdfbSgilles m->pos += sz; 37765c4fdfbSgilles } 37865c4fdfbSgilles 37965c4fdfbSgilles void 38065c4fdfbSgilles m_add_int(struct mproc *m, int v) 38165c4fdfbSgilles { 38281a33c5dSeric m_add(m, &v, sizeof(v)); 38365c4fdfbSgilles }; 38465c4fdfbSgilles 38565c4fdfbSgilles void 38665c4fdfbSgilles m_add_u32(struct mproc *m, uint32_t u32) 38765c4fdfbSgilles { 38881a33c5dSeric m_add(m, &u32, sizeof(u32)); 38965c4fdfbSgilles }; 39065c4fdfbSgilles 39165c4fdfbSgilles void 392c4df3bf2Sreyk m_add_size(struct mproc *m, size_t sz) 393c4df3bf2Sreyk { 39481a33c5dSeric m_add(m, &sz, sizeof(sz)); 395c4df3bf2Sreyk }; 396c4df3bf2Sreyk 397c4df3bf2Sreyk void 39865c4fdfbSgilles m_add_time(struct mproc *m, time_t v) 39965c4fdfbSgilles { 40081a33c5dSeric m_add(m, &v, sizeof(v)); 40165c4fdfbSgilles }; 40265c4fdfbSgilles 40365c4fdfbSgilles void 4044e92310aSgilles m_add_timeval(struct mproc *m, struct timeval *tv) 4054e92310aSgilles { 4064e92310aSgilles m_add(m, tv, sizeof(*tv)); 4074e92310aSgilles } 4084e92310aSgilles 4094e92310aSgilles 4104e92310aSgilles void 41165c4fdfbSgilles m_add_string(struct mproc *m, const char *v) 41265c4fdfbSgilles { 413d6a71827Seric if (v) { 414d6a71827Seric m_add(m, "s", 1); 41581a33c5dSeric m_add(m, v, strlen(v) + 1); 416d6a71827Seric } 417d6a71827Seric else 418d6a71827Seric m_add(m, "\0", 1); 41965c4fdfbSgilles }; 42065c4fdfbSgilles 42165c4fdfbSgilles void 42265c4fdfbSgilles m_add_data(struct mproc *m, const void *v, size_t len) 42365c4fdfbSgilles { 42481a33c5dSeric m_add_size(m, len); 42581a33c5dSeric m_add(m, v, len); 42665c4fdfbSgilles }; 42765c4fdfbSgilles 42865c4fdfbSgilles void 42965c4fdfbSgilles m_add_id(struct mproc *m, uint64_t v) 43065c4fdfbSgilles { 43181a33c5dSeric m_add(m, &v, sizeof(v)); 43265c4fdfbSgilles } 43365c4fdfbSgilles 43465c4fdfbSgilles void 43565c4fdfbSgilles m_add_evpid(struct mproc *m, uint64_t v) 43665c4fdfbSgilles { 43781a33c5dSeric m_add(m, &v, sizeof(v)); 43865c4fdfbSgilles } 43965c4fdfbSgilles 44065c4fdfbSgilles void 44165c4fdfbSgilles m_add_msgid(struct mproc *m, uint32_t v) 44265c4fdfbSgilles { 44381a33c5dSeric m_add(m, &v, sizeof(v)); 44465c4fdfbSgilles } 44565c4fdfbSgilles 44665c4fdfbSgilles void 44765c4fdfbSgilles m_add_sockaddr(struct mproc *m, const struct sockaddr *sa) 44865c4fdfbSgilles { 44981a33c5dSeric m_add_size(m, sa->sa_len); 45081a33c5dSeric m_add(m, sa, sa->sa_len); 45165c4fdfbSgilles } 45265c4fdfbSgilles 45365c4fdfbSgilles void 45465c4fdfbSgilles m_add_mailaddr(struct mproc *m, const struct mailaddr *maddr) 45565c4fdfbSgilles { 45681a33c5dSeric m_add(m, maddr, sizeof(*maddr)); 45765c4fdfbSgilles } 45865c4fdfbSgilles 45965c4fdfbSgilles void 46065c4fdfbSgilles m_add_envelope(struct mproc *m, const struct envelope *evp) 46165c4fdfbSgilles { 46265c4fdfbSgilles char buf[sizeof(*evp)]; 46365c4fdfbSgilles 46465c4fdfbSgilles envelope_dump_buffer(evp, buf, sizeof(buf)); 46565c4fdfbSgilles m_add_evpid(m, evp->id); 46681a33c5dSeric m_add_string(m, buf); 46765c4fdfbSgilles } 46865c4fdfbSgilles 46965c4fdfbSgilles void 470d6f2ac01Seric m_add_params(struct mproc *m, struct dict *d) 471d6f2ac01Seric { 472d6f2ac01Seric const char *key; 473d6f2ac01Seric char *value; 474d6f2ac01Seric void *iter; 475d6f2ac01Seric 476d6f2ac01Seric if (d == NULL) { 477d6f2ac01Seric m_add_size(m, 0); 478d6f2ac01Seric return; 479d6f2ac01Seric } 480d6f2ac01Seric m_add_size(m, dict_count(d)); 481d6f2ac01Seric iter = NULL; 482d6f2ac01Seric while (dict_iter(d, &iter, &key, (void **)&value)) { 483d6f2ac01Seric m_add_string(m, key); 484d6f2ac01Seric m_add_string(m, value); 485d6f2ac01Seric } 486d6f2ac01Seric } 487d6f2ac01Seric 488d6f2ac01Seric void 48965c4fdfbSgilles m_get_int(struct msg *m, int *i) 49065c4fdfbSgilles { 49181a33c5dSeric m_get(m, i, sizeof(*i)); 49265c4fdfbSgilles } 49365c4fdfbSgilles 49465c4fdfbSgilles void 49565c4fdfbSgilles m_get_u32(struct msg *m, uint32_t *u32) 49665c4fdfbSgilles { 49781a33c5dSeric m_get(m, u32, sizeof(*u32)); 49865c4fdfbSgilles } 49965c4fdfbSgilles 50065c4fdfbSgilles void 501c4df3bf2Sreyk m_get_size(struct msg *m, size_t *sz) 502c4df3bf2Sreyk { 50381a33c5dSeric m_get(m, sz, sizeof(*sz)); 504c4df3bf2Sreyk } 505c4df3bf2Sreyk 506c4df3bf2Sreyk void 50765c4fdfbSgilles m_get_time(struct msg *m, time_t *t) 50865c4fdfbSgilles { 50981a33c5dSeric m_get(m, t, sizeof(*t)); 51065c4fdfbSgilles } 51165c4fdfbSgilles 51265c4fdfbSgilles void 5134e92310aSgilles m_get_timeval(struct msg *m, struct timeval *tv) 5144e92310aSgilles { 5154e92310aSgilles m_get(m, tv, sizeof(*tv)); 5164e92310aSgilles } 5174e92310aSgilles 5184e92310aSgilles void 51965c4fdfbSgilles m_get_string(struct msg *m, const char **s) 52065c4fdfbSgilles { 52165c4fdfbSgilles uint8_t *end; 522d6a71827Seric char c; 52365c4fdfbSgilles 52481a33c5dSeric if (m->pos >= m->end) 52565c4fdfbSgilles m_error("msg too short"); 52665c4fdfbSgilles 527d6a71827Seric c = *m->pos++; 528d6a71827Seric if (c == '\0') { 529d6a71827Seric *s = NULL; 530d6a71827Seric return; 531d6a71827Seric } 532d6a71827Seric 533d6a71827Seric if (m->pos >= m->end) 534d6a71827Seric m_error("msg too short"); 53581a33c5dSeric end = memchr(m->pos, 0, m->end - m->pos); 53665c4fdfbSgilles if (end == NULL) 53765c4fdfbSgilles m_error("unterminated string"); 53865c4fdfbSgilles 53981a33c5dSeric *s = m->pos; 54065c4fdfbSgilles m->pos = end + 1; 54165c4fdfbSgilles } 54265c4fdfbSgilles 54365c4fdfbSgilles void 54465c4fdfbSgilles m_get_data(struct msg *m, const void **data, size_t *sz) 54565c4fdfbSgilles { 54681a33c5dSeric m_get_size(m, sz); 54781a33c5dSeric 548db2790b6Seric if (*sz == 0) { 549db2790b6Seric *data = NULL; 550db2790b6Seric return; 551db2790b6Seric } 552db2790b6Seric 55381a33c5dSeric if (m->pos + *sz > m->end) 55481a33c5dSeric m_error("msg too short"); 55581a33c5dSeric 55681a33c5dSeric *data = m->pos; 55781a33c5dSeric m->pos += *sz; 55865c4fdfbSgilles } 55965c4fdfbSgilles 56065c4fdfbSgilles void 56165c4fdfbSgilles m_get_evpid(struct msg *m, uint64_t *evpid) 56265c4fdfbSgilles { 56381a33c5dSeric m_get(m, evpid, sizeof(*evpid)); 56465c4fdfbSgilles } 56565c4fdfbSgilles 56665c4fdfbSgilles void 56765c4fdfbSgilles m_get_msgid(struct msg *m, uint32_t *msgid) 56865c4fdfbSgilles { 56981a33c5dSeric m_get(m, msgid, sizeof(*msgid)); 57065c4fdfbSgilles } 57165c4fdfbSgilles 57265c4fdfbSgilles void 57365c4fdfbSgilles m_get_id(struct msg *m, uint64_t *id) 57465c4fdfbSgilles { 57581a33c5dSeric m_get(m, id, sizeof(*id)); 57665c4fdfbSgilles } 57765c4fdfbSgilles 57865c4fdfbSgilles void 57965c4fdfbSgilles m_get_sockaddr(struct msg *m, struct sockaddr *sa) 58065c4fdfbSgilles { 58181a33c5dSeric size_t len; 58265c4fdfbSgilles 58381a33c5dSeric m_get_size(m, &len); 58481a33c5dSeric m_get(m, sa, len); 58565c4fdfbSgilles } 58665c4fdfbSgilles 58765c4fdfbSgilles void 58865c4fdfbSgilles m_get_mailaddr(struct msg *m, struct mailaddr *maddr) 58965c4fdfbSgilles { 59081a33c5dSeric m_get(m, maddr, sizeof(*maddr)); 59165c4fdfbSgilles } 59265c4fdfbSgilles 59365c4fdfbSgilles void 59465c4fdfbSgilles m_get_envelope(struct msg *m, struct envelope *evp) 59565c4fdfbSgilles { 59665c4fdfbSgilles uint64_t evpid; 59781a33c5dSeric const char *buf; 59865c4fdfbSgilles 59965c4fdfbSgilles m_get_evpid(m, &evpid); 60081a33c5dSeric m_get_string(m, &buf); 60191145277Stobhe if (buf == NULL) 60291145277Stobhe fatalx("empty envelope buffer"); 60365c4fdfbSgilles 60481a33c5dSeric if (!envelope_load_buffer(evp, buf, strlen(buf))) 6054e5d6ca2Seric fatalx("failed to retrieve envelope"); 60665c4fdfbSgilles evp->id = evpid; 60765c4fdfbSgilles } 608d6f2ac01Seric 609d6f2ac01Seric void 610d6f2ac01Seric m_get_params(struct msg *m, struct dict *d) 611d6f2ac01Seric { 612d6f2ac01Seric size_t c; 613d6f2ac01Seric const char *key; 614d6f2ac01Seric const char *value; 615d6f2ac01Seric char *tmp; 616d6f2ac01Seric 617d6f2ac01Seric dict_init(d); 618d6f2ac01Seric 619d6f2ac01Seric m_get_size(m, &c); 620d6f2ac01Seric 621d6f2ac01Seric for (; c; c--) { 622d6f2ac01Seric m_get_string(m, &key); 623d6f2ac01Seric m_get_string(m, &value); 624d6f2ac01Seric if ((tmp = strdup(value)) == NULL) 625d6f2ac01Seric fatal("m_get_params"); 626d6f2ac01Seric dict_set(d, key, tmp); 627d6f2ac01Seric } 628d6f2ac01Seric } 629d6f2ac01Seric 630d6f2ac01Seric void 631d6f2ac01Seric m_clear_params(struct dict *d) 632d6f2ac01Seric { 633d6f2ac01Seric char *value; 634d6f2ac01Seric 635d6f2ac01Seric while (dict_poproot(d, (void **)&value)) 636d6f2ac01Seric free(value); 637d6f2ac01Seric } 638