libwebsockets/lib/smtp.c
Andy Green be9fb919d1 context deprecation
1) This makes lwsws run a parent process with the original permissions.
But this process is only able to respond to SIGHUP, it doesn't do anything
else.

2) You can send this parent process a SIGHUP now to cause it to

 - close listening sockets in existing lwsws processes

 - mark those processes as to exit when the number of active connections
   on the falls to zero

 - spawn a fresh child process from scratch, using latest configuration
   file content, latest plugins, etc.  It can now reopen listening sockets
   if it chooses to, or open different listen ports or whatever.

Notes:

1) lws_context_destroy() has been split into two pieces... the reason for
the split is the first part closes the per-vhost protocols, but since
they may have created libuv objects in the per-vhost protocol storage,
these cannot be freed until after the loop has been run.

That's the purpose of the second part of the context destruction,
lws_context_destroy2().

For compatibility, if you are not using libuv, the first part calls the
second part.  However if you are using libuv, you must now call the
second part from your own main.c after the first part.
2016-12-20 14:37:07 +08:00

241 lines
5.5 KiB
C

/*
* SMTP support for libwebsockets
*
* Copyright (C) 2016 Andy Green <andy@warmcat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
static unsigned int
lwsgs_now_secs(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec;
}
static void
ccb(uv_handle_t* handle)
{
}
static void
alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
struct lws_email *email = (struct lws_email *)handle->data;
*buf = uv_buf_init(email->email_buf, sizeof(email->email_buf) - 1);
}
static void
on_write_end(uv_write_t *req, int status) {
lwsl_notice("%s\n", __func__);
if (status == -1) {
fprintf(stderr, "error on_write_end");
return;
}
}
static void
lwsgs_email_read(struct uv_stream_s *s, ssize_t nread, const uv_buf_t *buf)
{
struct lws_email *email = (struct lws_email *)s->data;
static const short retcodes[] = {
0, /* idle */
0, /* connecting */
220, /* connected */
250, /* helo */
250, /* from */
250, /* to */
354, /* data */
250, /* body */
221, /* quit */
};
uv_write_t write_req;
uv_buf_t wbuf;
int n;
if (nread >= 0)
email->email_buf[nread] = '\0';
lwsl_notice("%s: %s\n", __func__, buf->base);
if (nread == -1) {
lwsl_err("%s: failed\n", __func__);
return;
}
n = atoi(buf->base);
if (n != retcodes[email->estate]) {
lwsl_err("%s: bad response from server\n", __func__);
goto close_conn;
}
switch (email->estate) {
case LGSSMTP_CONNECTED:
n = sprintf(email->content, "HELO %s\n", email->email_helo);
email->estate = LGSSMTP_SENT_HELO;
break;
case LGSSMTP_SENT_HELO:
n = sprintf(email->content, "MAIL FROM: <%s>\n", email->email_from);
email->estate = LGSSMTP_SENT_FROM;
break;
case LGSSMTP_SENT_FROM:
n = sprintf(email->content, "RCPT TO: <%s>\n", email->email_to);
email->estate = LGSSMTP_SENT_TO;
break;
case LGSSMTP_SENT_TO:
n = sprintf(email->content, "DATA\n");
email->estate = LGSSMTP_SENT_DATA;
break;
case LGSSMTP_SENT_DATA:
if (email->on_get_body(email, email->content, email->max_content_size))
return;
n = strlen(email->content);
email->estate = LGSSMTP_SENT_BODY;
break;
case LGSSMTP_SENT_BODY:
n = sprintf(email->content, "quit\n");
email->estate = LGSSMTP_SENT_QUIT;
break;
case LGSSMTP_SENT_QUIT:
lwsl_notice("%s: done\n", __func__);
email->on_sent(email);
email->estate = LGSSMTP_IDLE;
goto close_conn;
default:
return;
}
puts(email->content);
wbuf = uv_buf_init(email->content, n);
uv_write(&write_req, s, &wbuf, 1, on_write_end);
return;
close_conn:
uv_close((uv_handle_t *)s, ccb);
}
static void
lwsgs_email_on_connect(uv_connect_t *req, int status)
{
struct lws_email *email = (struct lws_email *)req->data;
lwsl_notice("%s\n", __func__);
if (status == -1) {
lwsl_err("%s: failed\n", __func__);
return;
}
uv_read_start(req->handle, alloc_buffer, lwsgs_email_read);
email->estate = LGSSMTP_CONNECTED;
}
static void
uv_timeout_cb_email(uv_timer_t *w
#if UV_VERSION_MAJOR == 0
, int status
#endif
)
{
struct lws_email *email = lws_container_of(w, struct lws_email,
timeout_email);
time_t now = lwsgs_now_secs();
struct sockaddr_in req_addr;
switch (email->estate) {
case LGSSMTP_IDLE:
if (email->on_next(email))
break;
email->estate = LGSSMTP_CONNECTING;
uv_tcp_init(email->loop, &email->email_client);
if (uv_ip4_addr(email->email_smtp_ip, 25, &req_addr)) {
lwsl_err("Unable to convert mailserver ads\n");
return;
}
lwsl_notice("LGSSMTP_IDLE: connecting\n");
email->email_connect_started = now;
email->email_connect_req.data = email;
email->email_client.data = email;
uv_tcp_connect(&email->email_connect_req, &email->email_client,
(struct sockaddr *)&req_addr,
lwsgs_email_on_connect);
uv_timer_start(&email->timeout_email,
uv_timeout_cb_email, 5000, 0);
break;
case LGSSMTP_CONNECTING:
if (email->email_connect_started - now > 5) {
lwsl_err("mail session timed out\n");
/* !!! kill the connection */
uv_close((uv_handle_t *) &email->email_connect_req, ccb);
email->estate = LGSSMTP_IDLE;
}
break;
default:
break;
}
}
LWS_VISIBLE LWS_EXTERN int
lws_email_init(struct lws_email *email, uv_loop_t *loop, int max_content)
{
email->content = lws_malloc(max_content);
if (!email->content)
return 1;
email->max_content_size = max_content;
uv_timer_init(loop, &email->timeout_email);
email->loop = loop;
/* trigger him one time in a bit */
uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 2000, 0);
return 0;
}
LWS_VISIBLE LWS_EXTERN void
lws_email_check(struct lws_email *email)
{
uv_timer_start(&email->timeout_email, uv_timeout_cb_email, 1000, 0);
}
LWS_VISIBLE LWS_EXTERN void
lws_email_destroy(struct lws_email *email)
{
if (email->content)
lws_free_set_NULL(email->content);
uv_timer_stop(&email->timeout_email);
uv_close((uv_handle_t *)&email->timeout_email, NULL);
}