static void filter_io_in(struct io *io, int evt) { struct filter_session *s = io->arg; char *line; size_t len; log_trace(TRACE_FILTERS, "filter-api:%s filter_io_in(%p, %s)", filter_name, s, io_strevent(evt)); switch (evt) { case IO_DATAIN: nextline: line = iobuf_getline(&s->pipe.ibuf, &len); if ((line == NULL && iobuf_len(&s->pipe.ibuf) >= LINE_MAX) || (line && len >= LINE_MAX)) { s->pipe.error = 1; break; } /* No complete line received */ if (line == NULL) { iobuf_normalize(&s->pipe.ibuf); /* flow control */ if (iobuf_queued(&s->pipe.obuf) >= FILTER_HIWAT) io_pause(&s->pipe.iev, IO_PAUSE_IN); return; } s->pipe.idatalen += len + 1; /* XXX warning: do not clear io from this call! */ filter_dispatch_dataline(s->id, line); goto nextline; case IO_DISCONNECTED: if (iobuf_len(&s->pipe.ibuf)) { log_warn("warn: filter-api:%s %016"PRIx64" incomplete input", filter_name, s->id); } log_trace(TRACE_FILTERS, "filter-api:%s %016"PRIx64" input done (%zu bytes)", filter_name, s->id, s->pipe.idatalen); break; default: log_warn("warn: filter-api:%s %016"PRIx64": unexpected io event %d on data pipe", filter_name, s->id, evt); s->pipe.error = 1; } if (s->pipe.error) { io_clear(&s->pipe.oev); iobuf_clear(&s->pipe.obuf); } io_clear(&s->pipe.iev); iobuf_clear(&s->pipe.ibuf); filter_trigger_eom(s); }
static void filter_dispatch(struct mproc *p, struct imsg *imsg) { struct filter_connect q_connect; struct mailaddr maddr; struct msg m; const char *line; uint32_t v; uint64_t id, qid; int status, event, hook; log_debug("debug: %s: imsg %i", filter_name, imsg->hdr.type); switch (imsg->hdr.type) { case IMSG_FILTER_REGISTER: m_msg(&m, imsg); m_get_u32(&m, &v); m_end(&m); if (v != FILTER_API_VERSION) errx(1, "API version mismatch"); m_create(p, IMSG_FILTER_REGISTER, 0, 0, -1); m_add_int(p, fi.hooks); m_add_int(p, fi.flags); m_close(p); break; case IMSG_FILTER_EVENT: m_msg(&m, imsg); m_get_id(&m, &id); m_get_int(&m, &event); m_end(&m); filter_dispatch_event(id, event); break; case IMSG_FILTER_QUERY: m_msg(&m, imsg); m_get_id(&m, &id); m_get_id(&m, &qid); m_get_int(&m, &hook); tree_xset(&queries, qid, NULL); switch(hook) { case HOOK_CONNECT: m_get_sockaddr(&m, (struct sockaddr*)&q_connect.local); m_get_sockaddr(&m, (struct sockaddr*)&q_connect.remote); m_get_string(&m, &q_connect.hostname); m_end(&m); filter_dispatch_connect(id, qid, &q_connect); break; case HOOK_HELO: m_get_string(&m, &line); m_end(&m); filter_dispatch_helo(id, qid, line); break; case HOOK_MAIL: m_get_mailaddr(&m, &maddr); m_end(&m); filter_dispatch_mail(id, qid, &maddr); break; case HOOK_RCPT: m_get_mailaddr(&m, &maddr); m_end(&m); filter_dispatch_rcpt(id, qid, &maddr); break; case HOOK_DATA: m_end(&m); filter_dispatch_data(id, qid); break; case HOOK_EOM: m_end(&m); filter_dispatch_eom(id, qid); break; default: errx(1, "bad query hook: %d", hook); } break; case IMSG_FILTER_NOTIFY: m_msg(&m, imsg); m_get_id(&m, &qid); m_get_int(&m, &status); m_end(&m); filter_dispatch_notify(qid, status); break; case IMSG_FILTER_DATA: m_msg(&m, imsg); m_get_id(&m, &id); m_get_string(&m, &line); m_end(&m); filter_dispatch_dataline(id, line); break; } }