summaryrefslogtreecommitdiff
path: root/usr.sbin/smtpd/smtpd.c
diff options
context:
space:
mode:
authorEric Faurot <eric@cvs.openbsd.org>2011-05-04 20:45:31 +0000
committerEric Faurot <eric@cvs.openbsd.org>2011-05-04 20:45:31 +0000
commit7e6438dc0acdfa02b269d906ec421b6458252a60 (patch)
treec11d401fdb11974e172f912aa6d01c45450c4565 /usr.sbin/smtpd/smtpd.c
parentb839f913a16554f130408ae674cc27e903cb1f05 (diff)
When enqueueing offline mail, use a wait list to keep the number of
forked processes below a reasonnable limit. This prevents smtpd from fork-bombing on startup when there are lots of mails in the offline queue. ok todd@ gilles@
Diffstat (limited to 'usr.sbin/smtpd/smtpd.c')
-rw-r--r--usr.sbin/smtpd/smtpd.c55
1 files changed, 53 insertions, 2 deletions
diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c
index df12e11c697..c33acb4e183 100644
--- a/usr.sbin/smtpd/smtpd.c
+++ b/usr.sbin/smtpd/smtpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.c,v 1.122 2011/05/01 12:57:11 eric Exp $ */
+/* $OpenBSD: smtpd.c,v 1.123 2011/05/04 20:45:30 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -61,6 +61,18 @@ static struct child *child_lookup(pid_t);
static struct child *child_add(pid_t, int, int);
static void child_del(pid_t);
+static int queueing_add(char *);
+static void queueing_done(void);
+
+struct queueing {
+ TAILQ_ENTRY(queueing) entry;
+ char *path;
+};
+
+#define QUEUEING_MAX 5
+static size_t queueing_running = 0;
+TAILQ_HEAD(, queueing) queueing_q;
+
extern char **environ;
void (*imsg_callback)(struct imsgev *, struct imsg *);
@@ -114,7 +126,7 @@ parent_imsg(struct imsgev *iev, struct imsg *imsg)
if (iev->proc == PROC_QUEUE) {
switch (imsg->hdr.type) {
case IMSG_PARENT_ENQUEUE_OFFLINE:
- if (! parent_enqueue_offline(imsg->data))
+ if (! queueing_add(imsg->data))
imsg_compose_event(iev,
IMSG_PARENT_ENQUEUE_OFFLINE, 0, 0, -1,
NULL, 0);
@@ -392,6 +404,7 @@ parent_sig_handler(int sig, short event, void *p)
imsg_compose_event(env->sc_ievs[PROC_QUEUE],
IMSG_PARENT_ENQUEUE_OFFLINE, 0, 0, -1,
NULL, 0);
+ queueing_done();
break;
default:
@@ -441,6 +454,8 @@ main(int argc, char *argv[])
log_init(1);
+ TAILQ_INIT(&queueing_q);
+
while ((c = getopt(argc, argv, "dD:nf:v")) != -1) {
switch (c) {
case 'd':
@@ -972,12 +987,48 @@ parent_enqueue_offline(char *runner_path)
_exit(1);
}
+ queueing_running++;
child_add(pid, CHILD_ENQUEUE_OFFLINE, -1);
return (1);
}
static int
+queueing_add(char *path)
+{
+ struct queueing *q;
+
+ if (queueing_running < QUEUEING_MAX)
+ /* skip queue */
+ return parent_enqueue_offline(path);
+
+ q = malloc(sizeof(*q) + strlen(path) + 1);
+ if (q == NULL)
+ return (-1);
+ q->path = (char *)q + sizeof(*q);
+ memmove(q->path, path, strlen(path) + 1);
+ TAILQ_INSERT_TAIL(&queueing_q, q, entry);
+
+ return (1);
+}
+
+static void
+queueing_done(void)
+{
+ struct queueing *q;
+
+ queueing_running--;
+
+ while(queueing_running < QUEUEING_MAX) {
+ if ((q = TAILQ_FIRST(&queueing_q)) == NULL)
+ break; /* all done */
+ TAILQ_REMOVE(&queueing_q, q, entry);
+ parent_enqueue_offline(q->path);
+ free(q);
+ }
+}
+
+static int
parent_forward_open(char *username)
{
struct passwd *pw;