gboolean verify_peer;
SSL *ssl;
gchar *hostname;
+ const gchar *log_tag;
struct rspamd_io_ev *ev;
struct ev_loop *event_loop;
rspamd_ssl_handler_t handler;
gpointer handler_data;
};
+#define msg_debug_ssl(...) rspamd_conditional_debug_fast (NULL, NULL, \
+ rspamd_ssl_log_id, "ssl", conn->log_tag, \
+ G_STRFUNC, \
+ __VA_ARGS__)
+
+INIT_LOG_MODULE(ssl)
+
static GQuark
rspamd_ssl_quark (void)
{
if ((ret = SSL_shutdown (conn->ssl)) == 1) {
/* All done */
+ msg_debug_ssl ("ssl shutdown: all done");
rspamd_ssl_connection_dtor (conn);
}
else {
conn->state = ssl_next_shutdown;
if (ret == SSL_ERROR_WANT_READ) {
+ msg_debug_ssl ("ssl shutdown: need read");
what = EV_READ;
}
else if (ret == SSL_ERROR_WANT_WRITE) {
+ msg_debug_ssl ("ssl shutdown: need read");
what = EV_WRITE;
}
else {
/* Cannot do anything else, fatal error */
+ msg_debug_ssl ("ssl shutdown: fatal error");
rspamd_ssl_connection_dtor (conn);
return;
static void
rspamd_ssl_event_handler (gint fd, short what, gpointer ud)
{
- struct rspamd_ssl_connection *c = ud;
+ struct rspamd_ssl_connection *conn = ud;
gint ret;
GError *err = NULL;
if (what == EV_TIMER) {
- if (c->state == ssl_next_shutdown) {
+ if (conn->state == ssl_next_shutdown) {
/* No way to restore, just terminate */
- rspamd_ssl_connection_dtor (c);
+ rspamd_ssl_connection_dtor (conn);
}
else {
- c->shut = ssl_shut_unclean;
- rspamd_ev_watcher_stop (c->event_loop, c->ev);
+ conn->shut = ssl_shut_unclean;
+ rspamd_ev_watcher_stop (conn->event_loop, conn->ev);
g_set_error (&err, rspamd_ssl_quark (), ETIMEDOUT,
"ssl connection timed out");
- c->err_handler (c->handler_data, err);
+ conn->err_handler (conn->handler_data, err);
g_error_free (err);
}
return;
}
- msg_debug ("ssl event; what=%d; c->state=%d", (int)what, (int)c->state);
+ msg_debug_ssl ("ssl event; what=%d; c->state=%d", (int)what,
+ (int)conn->state);
- switch (c->state) {
+ switch (conn->state) {
case ssl_conn_init:
/* Continue connection */
- ret = SSL_connect (c->ssl);
+ ret = SSL_connect (conn->ssl);
if (ret == 1) {
- rspamd_ev_watcher_stop (c->event_loop, c->ev);
+ rspamd_ev_watcher_stop (conn->event_loop, conn->ev);
/* Verify certificate */
- if ((!c->verify_peer) || rspamd_ssl_peer_verify (c)) {
- c->state = ssl_conn_connected;
- c->handler (fd, EV_WRITE, c->handler_data);
+ if ((!conn->verify_peer) || rspamd_ssl_peer_verify (conn)) {
+ msg_debug_ssl ("ssl connect: connected");
+ conn->state = ssl_conn_connected;
+ conn->handler (fd, EV_WRITE, conn->handler_data);
}
else {
return;
}
}
else {
- ret = SSL_get_error (c->ssl, ret);
+ ret = SSL_get_error (conn->ssl, ret);
if (ret == SSL_ERROR_WANT_READ) {
+ msg_debug_ssl ("ssl connect: need read");
what = EV_READ;
}
else if (ret == SSL_ERROR_WANT_WRITE) {
+ msg_debug_ssl ("ssl connect: need write");
what = EV_WRITE;
}
else {
- rspamd_ev_watcher_stop (c->event_loop, c->ev);
+ rspamd_ev_watcher_stop (conn->event_loop, conn->ev);
rspamd_tls_set_error (ret, "connect", &err);
- c->err_handler (c->handler_data, err);
+ conn->err_handler (conn->handler_data, err);
g_error_free (err);
return;
}
- rspamd_ev_watcher_reschedule (c->event_loop, c->ev, what);
+ rspamd_ev_watcher_reschedule (conn->event_loop, conn->ev, what);
}
break;
case ssl_next_read:
- rspamd_ev_watcher_reschedule (c->event_loop, c->ev, EV_READ);
- c->state = ssl_conn_connected;
- c->handler (fd, EV_READ, c->handler_data);
+ rspamd_ev_watcher_reschedule (conn->event_loop, conn->ev, EV_READ);
+ conn->state = ssl_conn_connected;
+ conn->handler (fd, EV_READ, conn->handler_data);
break;
case ssl_next_write:
- rspamd_ev_watcher_reschedule (c->event_loop, c->ev, EV_WRITE);
- c->state = ssl_conn_connected;
- c->handler (fd, EV_WRITE, c->handler_data);
+ rspamd_ev_watcher_reschedule (conn->event_loop, conn->ev, EV_WRITE);
+ conn->state = ssl_conn_connected;
+ conn->handler (fd, EV_WRITE, conn->handler_data);
break;
case ssl_conn_connected:
- rspamd_ev_watcher_reschedule (c->event_loop, c->ev, what);
- c->state = ssl_conn_connected;
- c->handler (fd, what, c->handler_data);
+ rspamd_ev_watcher_reschedule (conn->event_loop, conn->ev, what);
+ conn->state = ssl_conn_connected;
+ conn->handler (fd, what, conn->handler_data);
break;
case ssl_next_shutdown:
- rspamd_ssl_shutdown (c);
+ rspamd_ssl_shutdown (conn);
break;
default:
- rspamd_ev_watcher_stop (c->event_loop, c->ev);
+ rspamd_ev_watcher_stop (conn->event_loop, conn->ev);
g_set_error (&err, rspamd_ssl_quark (), EINVAL,
- "ssl bad state error: %d", c->state);
- c->err_handler (c->handler_data, err);
+ "ssl bad state error: %d", conn->state);
+ conn->err_handler (conn->handler_data, err);
g_error_free (err);
break;
}
struct rspamd_ssl_connection *
rspamd_ssl_connection_new (gpointer ssl_ctx, struct ev_loop *ev_base,
- gboolean verify_peer)
+ gboolean verify_peer, const gchar *log_tag)
{
struct rspamd_ssl_connection *c;
c->ssl = SSL_new (ssl_ctx);
c->event_loop = ev_base;
c->verify_peer = verify_peer;
+ c->log_tag = log_tag;
return c;
}
if (ret == 1) {
conn->state = ssl_conn_connected;
+ msg_debug_ssl ("connected, start write event");
rspamd_ev_watcher_stop (conn->event_loop, ev);
rspamd_ev_watcher_init (ev, fd, EV_WRITE, rspamd_ssl_event_handler, conn);
rspamd_ev_watcher_start (conn->event_loop, ev, timeout);
ret = SSL_get_error (conn->ssl, ret);
if (ret == SSL_ERROR_WANT_READ) {
+ msg_debug_ssl ("not connected, want read");
what = EV_READ;
}
else if (ret == SSL_ERROR_WANT_WRITE) {
+ msg_debug_ssl ("not connected, want write");
what = EV_WRITE;
}
else {
conn->shut = ssl_shut_unclean;
+ msg_debug_ssl ("not connected, fatal error %d", ret);
return FALSE;
}
}
ret = SSL_read (conn->ssl, buf, buflen);
+ msg_debug_ssl ("ssl read: %d", ret);
if (ret > 0) {
conn->state = ssl_conn_connected;
what = 0;
if (ret == SSL_ERROR_WANT_READ) {
+ msg_debug_ssl ("ssl read: need read");
what |= EV_READ;
}
else if (ret == SSL_ERROR_WANT_WRITE) {
+ msg_debug_ssl ("ssl read: need write");
what |= EV_WRITE;
}
else {
}
ret = SSL_write (conn->ssl, buf, buflen);
+ msg_debug_ssl ("ssl write: ret=%d, buflen=%z", ret, buflen);
if (ret > 0) {
conn->state = ssl_conn_connected;
conn->state = ssl_next_write;
if (ret == SSL_ERROR_WANT_READ) {
+ msg_debug_ssl ("ssl write: need read");
what = EV_READ;
}
else if (ret == SSL_ERROR_WANT_WRITE) {
+ msg_debug_ssl ("ssl write: need write");
what = EV_WRITE;
}
else {
rspamd_ssl_writev (struct rspamd_ssl_connection *conn, struct iovec *iov,
gsize iovlen)
{
- guchar ssl_buf[16000];
+ /*
+ * Static is needed to avoid issue:
+ * https://github.com/openssl/openssl/issues/6865
+ */
+ static guchar ssl_buf[16384];
guchar *p;
struct iovec *cur;
- guint i, remain;
+ gsize i, remain;
remain = sizeof (ssl_buf);
p = ssl_buf;
if (conn) {
if (conn->shut == ssl_shut_unclean) {
/* Ignore return result and close socket */
+ msg_debug_ssl ("unclean shutdown");
(void)SSL_shutdown (conn->ssl);
rspamd_ssl_connection_dtor (conn);
}
else {
+ msg_debug_ssl ("normal shutdown");
rspamd_ssl_shutdown (conn);
}
}
}
if (r == -1) {
- lua_tcp_push_error (cbd, FALSE, "IO write error while trying to write %d "
- "bytes: %s", (gint)remain, strerror (errno));
- if (!IS_SYNC (cbd)) {
- /* sync connection methods perform this inside */
- lua_tcp_shift_handler (cbd);
- lua_tcp_plan_handler_event (cbd, TRUE, FALSE);
+ if (!(cbd->ssl_conn)) {
+ lua_tcp_push_error (cbd, FALSE,
+ "IO write error while trying to write %d bytes: %s",
+ (gint) remain, strerror (errno));
+ if (!IS_SYNC (cbd)) {
+ /* sync connection methods perform this inside */
+ lua_tcp_shift_handler (cbd);
+ lua_tcp_plan_handler_event (cbd, TRUE, FALSE);
+ }
}
return;
}
else {
/* Want to write more */
- if (niov > IOV_MAX && r > 0) {
+ if (r > 0) {
/* XXX: special case: we know that we want to write more data
* than it is available in iov function.
*
verify_peer = TRUE;
}
- cbd->ssl_conn =
- rspamd_ssl_connection_new (ssl_ctx, cbd->event_loop, verify_peer);
+ cbd->ssl_conn = rspamd_ssl_connection_new (ssl_ctx,
+ cbd->event_loop,
+ verify_peer,
+ cbd->tag);
if (!rspamd_ssl_connect_fd (cbd->ssl_conn, fd, cbd->hostname, &cbd->ev,
cbd->ev.timeout, lua_tcp_handler, lua_tcp_ssl_on_error, cbd)) {
struct rspamd_dns_resolver *resolver = NULL;
struct rspamd_config *cfg = NULL;
struct ev_loop *ev_base = NULL;
+ struct lua_tcp_cbdata *cbd;
+
int arguments_validated = rspamd_lua_parse_table_arguments (L, 1, &err,
RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
timeout = default_tcp_timeout;
}
+ cbd = g_new0 (struct lua_tcp_cbdata, 1);
+
if (task) {
+ static const gchar hexdigests[16] = "0123456789abcdef";
+
cfg = task->cfg;
ev_base = task->event_loop;
session = task->s;
+ /* Make a readable tag */
+ memcpy (cbd->tag, task->task_pool->tag.uid, sizeof (cbd->tag) - 2);
+ cbd->tag[sizeof (cbd->tag) - 2] = hexdigests[GPOINTER_TO_INT (cbd) & 0xf];
+ cbd->tag[sizeof (cbd->tag) - 1] = 0;
}
+ else {
+ h = rspamd_random_uint64_fast ();
+ rspamd_snprintf (cbd->tag, sizeof (cbd->tag), "%uxL", h);
+ }
+
if (resolver == NULL) {
if (task) {
resolver = task->resolver;
}
}
- struct lua_tcp_cbdata *cbd = g_new0 (struct lua_tcp_cbdata, 1);
-
cbd->task = task;
cbd->cfg = cfg;
cbd->thread = lua_thread_pool_get_running_entry (cfg->lua_thread_pool);
- h = rspamd_random_uint64_fast ();
- rspamd_snprintf (cbd->tag, sizeof (cbd->tag), "%uxL", h);
+
cbd->handlers = g_queue_new ();
cbd->event_loop = ev_base;
verify_peer = TRUE;
}
- cbd->ssl_conn =
- rspamd_ssl_connection_new (ssl_ctx, cbd->event_loop, verify_peer);
+ cbd->ssl_conn = rspamd_ssl_connection_new (ssl_ctx,
+ cbd->event_loop,
+ verify_peer,
+ cbd->tag);
if (!rspamd_ssl_connect_fd (cbd->ssl_conn, cbd->fd, cbd->hostname, &cbd->ev,
cbd->ev.timeout, lua_tcp_handler, lua_tcp_ssl_on_error, cbd)) {