diff options
Diffstat (limited to 'mockmta.c')
-rw-r--r-- | mockmta.c | 272 |
1 files changed, 141 insertions, 131 deletions
@@ -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); } |