aboutsummaryrefslogtreecommitdiff
path: root/mockmta.c
diff options
context:
space:
mode:
Diffstat (limited to 'mockmta.c')
-rw-r--r--mockmta.c272
1 files changed, 141 insertions, 131 deletions
diff --git a/mockmta.c b/mockmta.c
index 3a68053..2b47176 100644
--- a/mockmta.c
+++ b/mockmta.c
@@ -383,7 +383,6 @@ iobase_readln (struct iobase *bp, char *buf, size_t size)
int cr_seen = 0;
size--;
- smtp_timer_enqueue (pthread_self (), SMTP_IN);
while (len < size)
{
int c = iobase_data_getc (bp);
@@ -415,7 +414,6 @@ iobase_readln (struct iobase *bp, char *buf, size_t size)
if (c == '\n')
break;
}
- smtp_timer_dequeue (pthread_self ());
if (len == 0 && bp->iob_errno)
return -1;
buf[len] = 0;
@@ -453,7 +451,6 @@ iobase_writeln (struct iobase *bp, char *buf, size_t size)
{
size_t len = 0;
- smtp_timer_enqueue (pthread_self (), SMTP_OUT);
while (size)
{
char *p = memchr (buf, '\n', size);
@@ -467,7 +464,6 @@ iobase_writeln (struct iobase *bp, char *buf, size_t size)
len += rc;
size -= rc;
}
- smtp_timer_dequeue (pthread_self ());
if (len == 0 && bp->iob_errno)
return -1;
return len;
@@ -875,9 +871,63 @@ struct smtp
size_t data_len;
size_t data_size;
};
+
+enum
+ {
+ CAPA_PIPELINING,
+ CAPA_STARTTLS,
+ CAPA_HELP,
+ MAX_CAPA
+ };
+
+static char const *capa_str[] = {
+ "PIPELINING",
+ "STARTTLS",
+ "HELP"
+};
+
+#define CAPA_MASK(n) (1<<(n))
+
+
+struct smtp *
+smtp_create (int ifd, int ofd)
+{
+ struct iobase *iob = io2_create (iofile_create (ifd), iofile_create (ofd));
+ struct smtp *smtp = calloc(1, sizeof (*smtp));
+ if (!smtp)
+ nomemory ();
+ smtp->state = STATE_INIT;
+ smtp->iob = iob;
+ smtp->capa_mask = 0;
+ if (!enable_tls ())
+ smtp->capa_mask |= CAPA_MASK (CAPA_STARTTLS);
+ smtp->helo = NULL;
+ smtp->sender = NULL;
+ smtp->nrcpt = 0;
+ smtp->data_buf = NULL;
+ smtp->data_len = 0;
+ smtp->data_size = 0;
+
+ pthread_mutex_lock (&msgid_mutex);
+ smtp->sid = msgid++;
+ pthread_mutex_unlock (&msgid_mutex);
+
+ return smtp;
+}
+
+static ssize_t
+smtp_io_readln (struct smtp *smtp)
+{
+ ssize_t n;
+ smtp_timer_enqueue (pthread_self (), SMTP_IN);
+ n = iobase_readln (smtp->iob, smtp->buf, sizeof (smtp->buf));
+ smtp_timer_dequeue (pthread_self ());
+ return n;
+}
+
static void
-smtp_io_send (struct iobase *iob, int code, char *fmt, ...)
+smtp_io_send (struct smtp *smtp, int code, char *fmt, ...)
{
va_list ap;
char buf[IOBUFSIZE];
@@ -890,15 +940,17 @@ smtp_io_send (struct iobase *iob, int code, char *fmt, ...)
n += 4;
buf[n++] = '\r';
buf[n++] = '\n';
- if (iobase_writeln (iob, buf, n) < 0)
+ smtp_timer_enqueue (pthread_self (), SMTP_OUT);
+ if (iobase_writeln (smtp->iob, buf, n) < 0)
{
- terror ("iobase_writeln: %s", iobase_strerror (iob));
- exit (EX_FAILURE);
+ terror ("iobase_writeln: %s", iobase_strerror (smtp->iob));
+ exit (EX_FAILURE);//FIXME
}
+ smtp_timer_dequeue (pthread_self ());
}
static void
-smtp_io_mlsend (struct iobase *iob, int code, char const **av)
+smtp_io_mlsend (struct smtp *smtp, int code, char const **av)
{
char buf[IOBUFSIZE];
size_t n;
@@ -909,11 +961,13 @@ smtp_io_mlsend (struct iobase *iob, int code, char const **av)
{
n = snprintf (buf, sizeof(buf), "%3d%c%s\r\n",
code, av[i+1] ? '-' : ' ', av[i]);
- if (iobase_writeln (iob, buf, n) < 0)
+ smtp_timer_enqueue (pthread_self (), SMTP_OUT);
+ if (iobase_writeln (smtp->iob, buf, n) < 0)
{
- terror ("iobase_writeln: %s", iobase_strerror (iob));
+ terror ("iobase_writeln: %s", iobase_strerror (smtp->iob));
exit (EX_FAILURE);
}
+ smtp_timer_dequeue (pthread_self ());
}
}
@@ -949,10 +1003,15 @@ smtp_reset (struct smtp *smtp, int state)
void
smtp_end (struct smtp *smtp)
{
- smtp_io_send (smtp->iob, 221, "Bye");
- iobase_close (smtp->iob);
+ smtp_io_send (smtp, 221, "Bye");
smtp_reset (smtp, STATE_INIT);
- smtp->iob = NULL;
+}
+
+void
+smtp_free (struct smtp *smtp)
+{
+ iobase_close (smtp->iob);
+ free (smtp);
}
enum smtp_keyword
@@ -994,7 +1053,7 @@ smtp_keyword_find (char const *kw)
static int
smtp_help (struct smtp *smtp)
{
- smtp_io_send (smtp->iob, 214, "http://www.ietf.org/rfc/rfc2821.txt");
+ smtp_io_send (smtp, 214, "http://www.ietf.org/rfc/rfc2821.txt");
return 0;
}
@@ -1003,32 +1062,16 @@ smtp_rset (struct smtp *smtp)
{
if (smtp->arg)
{
- smtp_io_send (smtp->iob, 501, "rset does not take arguments");
+ smtp_io_send (smtp, 501, "rset does not take arguments");
return -1;
}
- smtp_io_send (smtp->iob, 250, "Reset state");
+ smtp_io_send (smtp, 250, "Reset state");
smtp_reset (smtp, STATE_INIT);
return 0;
}
-enum
- {
- CAPA_PIPELINING,
- CAPA_STARTTLS,
- CAPA_HELP,
- MAX_CAPA
- };
-
-static char const *capa_str[] = {
- "PIPELINING",
- "STARTTLS",
- "HELP"
-};
-
-#define CAPA_MASK(n) (1<<(n))
-
static int
smtp_ehlo (struct smtp *smtp)
{
@@ -1037,7 +1080,7 @@ smtp_ehlo (struct smtp *smtp)
if (!smtp->arg)
{
- smtp_io_send (smtp->iob, 501, "ehlo requires domain address");
+ smtp_io_send (smtp, 501, "ehlo requires domain address");
return -1;
}
@@ -1046,7 +1089,7 @@ smtp_ehlo (struct smtp *smtp)
if (!(smtp->capa_mask & CAPA_MASK (i)))
capa[j++] = capa_str[i];
capa[j] = NULL;
- smtp_io_mlsend (smtp->iob, 250, capa);
+ smtp_io_mlsend (smtp, 250, capa);
smtp_reset (smtp, STATE_INIT);
if ((smtp->helo = strdup (smtp->arg)) == NULL)
@@ -1064,11 +1107,11 @@ smtp_starttls (struct smtp *smtp)
if (smtp->arg)
{
- smtp_io_send (smtp->iob, 501, "Syntax error (no parameters allowed)");
+ smtp_io_send (smtp, 501, "Syntax error (no parameters allowed)");
return -1;
}
- smtp_io_send (smtp->iob, 220, "Ready to start TLS");
+ smtp_io_send (smtp, 220, "Ready to start TLS");
iob = iotls_create (inb->fd, outb->fd);
@@ -1100,10 +1143,10 @@ smtp_helo (struct smtp *smtp)
{
if (!smtp->arg)
{
- smtp_io_send (smtp->iob, 501, "helo requires domain address");
+ smtp_io_send (smtp, 501, "helo requires domain address");
return -1;
}
- smtp_io_send (smtp->iob, 250, "localhost Mock MTA pleased to meet you");
+ smtp_io_send (smtp, 250, "localhost Mock MTA pleased to meet you");
smtp_reset (smtp, STATE_INIT);
if ((smtp->helo = strdup (smtp->arg)) == NULL)
@@ -1120,12 +1163,12 @@ smtp_mail (struct smtp *smtp)
if (!smtp->arg)
{
- smtp_io_send (smtp->iob, 501, "mail requires email address");
+ smtp_io_send (smtp, 501, "mail requires email address");
return -1;
}
if (strncasecmp (smtp->arg, from_str, from_len))
{
- smtp_io_send (smtp->iob, 501, "syntax error");
+ smtp_io_send (smtp, 501, "syntax error");
return -1;
}
p = smtp->arg + from_len;
@@ -1133,13 +1176,13 @@ smtp_mail (struct smtp *smtp)
p++;
if (!*p)
{
- smtp_io_send (smtp->iob, 501, "mail requires email address");
+ smtp_io_send (smtp, 501, "mail requires email address");
return -1;
}
smtp_reset (smtp, STATE_MAIL);
if ((smtp->sender = strdup (p)) == NULL)
nomemory ();
- smtp_io_send (smtp->iob, 250, "Sender ok");
+ smtp_io_send (smtp, 250, "Sender ok");
return 0;
}
@@ -1147,17 +1190,17 @@ static int
smtp_rcpt (struct smtp *smtp)
{
static char to_str[] = "TO:";
- static size_t to_len = sizeof(to_str) - 1;
+ static size_t to_len = sizeof (to_str) - 1;
char *p;
if (!smtp->arg)
{
- smtp_io_send (smtp->iob, 501, "rcpt requires email address");
+ smtp_io_send (smtp, 501, "rcpt requires email address");
return -1;
}
if (strncasecmp (smtp->arg, to_str, to_len))
{
- smtp_io_send (smtp->iob, 501, "syntax error");
+ smtp_io_send (smtp, 501, "syntax error");
return -1;
}
p = smtp->arg + to_len;
@@ -1165,18 +1208,18 @@ smtp_rcpt (struct smtp *smtp)
p++;
if (!*p)
{
- smtp_io_send (smtp->iob, 501, "to requires email address");
+ smtp_io_send (smtp, 501, "to requires email address");
return -1;
}
if (smtp->nrcpt == MAX_RCPT)
{
- smtp_io_send (smtp->iob, 501, "too many recipients");
+ smtp_io_send (smtp, 501, "too many recipients");
return -1;
}
if ((smtp->rcpt[smtp->nrcpt] = strdup (p)) == NULL)
nomemory ();
smtp->nrcpt++;
- smtp_io_send (smtp->iob, 250, "Recipient ok");
+ smtp_io_send (smtp, 250, "Recipient ok");
return 0;
}
@@ -1220,7 +1263,6 @@ static int
smtp_data (struct smtp *smtp)
{
ssize_t n;
- int i;
int fd;
FILE *fp;
struct flock lk;
@@ -1234,7 +1276,7 @@ smtp_data (struct smtp *smtp)
if (fd == -1)
{
terror ("can't open %s: %s", mailbox_name, strerror (errno));
- smtp_io_send (smtp->iob, 451, "Local filesystem error");
+ smtp_io_send (smtp, 451, "Local filesystem error");
return -1;
}
lk.l_type = F_WRLCK;
@@ -1244,7 +1286,7 @@ smtp_data (struct smtp *smtp)
if (fcntl (fd, F_SETLKW, &lk)) /* FIXME: ttl */
{
terror ("can't lock %s: %s", mailbox_name, strerror (errno));
- smtp_io_send (smtp->iob, 451, "Local filesystem error");
+ smtp_io_send (smtp, 451, "Local filesystem error");
close (fd);
return -1;
}
@@ -1255,12 +1297,12 @@ smtp_data (struct smtp *smtp)
if (!fp)
{
terror ("fdopen: %s", strerror (errno));
- smtp_io_send (smtp->iob, 451, "Local filesystem error");
+ smtp_io_send (smtp, 451, "Local filesystem error");
close (fd);
return -1;
}
- smtp_io_send (smtp->iob, 354,
+ smtp_io_send (smtp, 354,
"Enter mail, end with \".\" on a line by itself");
t = time (NULL);
@@ -1269,7 +1311,9 @@ smtp_data (struct smtp *smtp)
while (1)
{
char *p;
- n = iobase_readln (smtp->iob, smtp->buf, sizeof (smtp->buf));
+
+ n = smtp_io_readln (smtp);
+
if (n <= 0)
{
smtp->state = STATE_QUIT;
@@ -1333,7 +1377,7 @@ smtp_data (struct smtp *smtp)
terror ("can't unlock %s: %s", mailbox_name, strerror (errno));
fclose (fp);
- smtp_io_send (smtp->iob, 250, "%x Message accepted for delivery", smtp->sid);
+ smtp_io_send (smtp, 250, "%x Message accepted for delivery", smtp->sid);
return res;
}
@@ -1390,74 +1434,55 @@ disable_starttls (void)
}
static void
-do_smtp (int ifd, int ofd)
+do_smtp (struct smtp *smtp)
{
- struct iobase *iob = io2_create (iofile_create (ifd), iofile_create (ofd));
- struct smtp smtp;
struct smtp_transition *trans;
-
- smtp.state = STATE_INIT;
- smtp.iob = iob;
- smtp.capa_mask = 0;
- if (!enable_tls ())
- smtp.capa_mask |= CAPA_MASK (CAPA_STARTTLS);
- smtp.helo = NULL;
- smtp.sender = NULL;
- smtp.nrcpt = 0;
- smtp.data_buf = NULL;
- smtp.data_len = 0;
- smtp.data_size = 0;
- pthread_mutex_lock (&msgid_mutex);
- smtp.sid = msgid++;
- pthread_mutex_unlock (&msgid_mutex);
-
- smtp_io_send (smtp.iob, 220, "Ready");
- while (smtp.state != STATE_QUIT)
+ smtp_io_send (smtp, 220, "Ready");
+ while (smtp->state != STATE_QUIT)
{
size_t i;
int kw;
int new_state;
- ssize_t n = iobase_readln (smtp.iob, smtp.buf, sizeof (smtp.buf));
+ ssize_t n = smtp_io_readln (smtp);
if (n <= 0)
break;
- smtp.buf[--n] = 0;
- i = strcspn (smtp.buf, " \t");
- if (smtp.buf[i])
+ smtp->buf[--n] = 0;
+ i = strcspn (smtp->buf, " \t");
+ if (smtp->buf[i])
{
- smtp.buf[i++] = 0;
- while (i < n && (smtp.buf[i] == ' ' || smtp.buf[i] == '\t'))
+ smtp->buf[i++] = 0;
+ while (i < n && (smtp->buf[i] == ' ' || smtp->buf[i] == '\t'))
i++;
- if (smtp.buf[i])
- smtp.arg = &smtp.buf[i];
+ if (smtp->buf[i])
+ smtp->arg = &smtp->buf[i];
else
- smtp.arg = NULL;
+ smtp->arg = NULL;
}
else
- smtp.arg = NULL;
+ smtp->arg = NULL;
- kw = smtp_keyword_find (smtp.buf);
+ kw = smtp_keyword_find (smtp->buf);
if (kw == -1)
{
- smtp_io_send(smtp.iob, 500, "Command unrecognized");
+ smtp_io_send (smtp, 500, "Command unrecognized");
continue;
}
- trans = &smtp_transition_table[smtp.state][kw];
+ trans = &smtp_transition_table[smtp->state][kw];
new_state = trans->new_state;
if (new_state == STATE_ERR)
{
- smtp_io_send(smtp.iob, 500, "Command not valid");
+ smtp_io_send (smtp, 500, "Command not valid");
continue;
}
- if (trans->handler (&smtp))
+ if (trans->handler (smtp))
continue;
- smtp.state = new_state;
+ smtp->state = new_state;
}
-
- smtp_end (&smtp);
+ smtp_end (smtp);
}
struct smtp_timer
@@ -1489,7 +1514,7 @@ timespec_cmp (struct timespec const *a, struct timespec const *b)
void
smtp_timer_enqueue (pthread_t tid, int state)
{
- struct smtp_timer *timer, *p;
+ struct smtp_timer *timer;
timer = malloc (sizeof (timer[0]));
if (!timer)
@@ -1500,36 +1525,15 @@ smtp_timer_enqueue (pthread_t tid, int state)
timer->wakeup_time.tv_sec += smtp_timeout;
pthread_mutex_lock (&smtp_timer_mutex);
- for (p = smtp_timer_head; p; p = p->next)
- {
- if (timespec_cmp (&timer->wakeup_time, &p->wakeup_time) < 0)
- break;
- }
- if (p)
- {
- timer->prev = p->prev;
- if (p == smtp_timer_head)
- smtp_timer_head = timer;
- else
- p->prev->next = timer;
-
- p->prev = timer;
- timer->next = p;
- }
+ timer->next = NULL;
+ timer->prev = smtp_timer_tail;
+ if (smtp_timer_tail)
+ smtp_timer_tail->next = timer;
else
- {
- timer->next = NULL;
- timer->prev = smtp_timer_tail;
- if (smtp_timer_tail)
- smtp_timer_tail->next = timer;
- else
- smtp_timer_head = timer;
- smtp_timer_tail = timer;
- }
-
+ smtp_timer_head = timer;
+ smtp_timer_tail = timer;
if (timer == smtp_timer_head)
- pthread_cond_broadcast (&smtp_timer_cond);
-
+ pthread_cond_broadcast (&smtp_timer_cond);
pthread_mutex_unlock (&smtp_timer_mutex);
}
@@ -1645,16 +1649,15 @@ mta_open (int port)
static void
smtp_cleanup (void *ptr)
{
- int fd = *(int*) ptr;
- close (fd);
+ struct smtp *smtp = ptr;
+ smtp_free (smtp);
}
void *
thr_smtp (void *ptr)
{
- int fd = *(int*) ptr;
pthread_cleanup_push (smtp_cleanup, ptr);
- do_smtp (fd, fd);
+ do_smtp (ptr);
pthread_cleanup_pop (1);
return NULL;
}
@@ -1674,14 +1677,16 @@ thr_mta_listener (void *ptr)
struct sockaddr_in remote_addr;
socklen_t len = sizeof (remote_addr);
pthread_t tid;
+ struct smtp *smtp;
if ((sfd = accept (fd, (struct sockaddr *) &remote_addr, &len)) < 0)
{
terror ("accept: %m");
exit (EX_FAILURE);
}
-
- pthread_create (&tid, &attr, thr_smtp, &sfd);
+
+ smtp = smtp_create (sfd, sfd);
+ pthread_create (&tid, &attr, thr_smtp, smtp);
}
return NULL;
}
@@ -1831,6 +1836,11 @@ main (int argc, char **argv)
sigwait (&sigs, &i);
}
else
- do_smtp (0, 1);
+ {
+ struct smtp *smtp = smtp_create (0, 1);
+ do_smtp (smtp);
+ smtp_free (smtp);
+ }
+
exit (EX_OK);
}

Return to:

Send suggestions and report system problems to the System administrator.