Rename struct connection' to
struct client'
It is shorter and makes more sense. Also replaced "conn" with "c" to keep it even more concise, and thus clearer.
This commit is contained in:
parent
cc4ca46cc3
commit
b0cf09fb4c
292
src/kike.c
292
src/kike.c
@ -219,11 +219,10 @@ enum
|
||||
IRC_USER_MODE_RX_SERVER_NOTICES = (1 << 4)
|
||||
};
|
||||
|
||||
// TODO: rename to client?
|
||||
struct connection
|
||||
struct client
|
||||
{
|
||||
struct connection *next; ///< The next link in a chain
|
||||
struct connection *prev; ///< The previous link in a chain
|
||||
struct client *next; ///< The next link in a chain
|
||||
struct client *prev; ///< The previous link in a chain
|
||||
|
||||
struct server_context *ctx; ///< Server context
|
||||
|
||||
@ -249,7 +248,7 @@ struct connection
|
||||
};
|
||||
|
||||
static void
|
||||
connection_init (struct connection *self)
|
||||
client_init (struct client *self)
|
||||
{
|
||||
memset (self, 0, sizeof *self);
|
||||
|
||||
@ -259,7 +258,7 @@ connection_init (struct connection *self)
|
||||
}
|
||||
|
||||
static void
|
||||
connection_free (struct connection *self)
|
||||
client_free (struct client *self)
|
||||
{
|
||||
if (!soft_assert (self->socket_fd == -1))
|
||||
xclose (self->socket_fd);
|
||||
@ -351,11 +350,11 @@ struct server_context
|
||||
struct str_map config; ///< Server configuration
|
||||
|
||||
int listen_fd; ///< Listening socket FD
|
||||
struct connection *clients; ///< Client connections
|
||||
struct client *clients; ///< Clients
|
||||
SSL_CTX *ssl_ctx; ///< SSL context
|
||||
|
||||
char *server_name; ///< Our server name
|
||||
struct str_map users; ///< Maps nicknames to connections
|
||||
struct str_map users; ///< Maps nicknames to clients
|
||||
struct str_map channels; ///< Maps channel names to data
|
||||
struct str_map handlers; ///< Message handlers
|
||||
|
||||
@ -405,11 +404,11 @@ server_context_free (struct server_context *self)
|
||||
SSL_CTX_free (self->ssl_ctx);
|
||||
|
||||
// TODO: terminate the connections properly before this is called
|
||||
struct connection *link, *tmp;
|
||||
struct client *link, *tmp;
|
||||
for (link = self->clients; link; link = tmp)
|
||||
{
|
||||
tmp = link->next;
|
||||
connection_free (link);
|
||||
client_free (link);
|
||||
free (link);
|
||||
}
|
||||
|
||||
@ -436,40 +435,40 @@ enum
|
||||
};
|
||||
|
||||
static void
|
||||
connection_kill (struct connection *conn, const char *reason)
|
||||
client_kill (struct client *c, const char *reason)
|
||||
{
|
||||
// TODO: multicast a QUIT message with `reason' || "Client exited"
|
||||
(void) reason;
|
||||
|
||||
// TODO: do further cleanup if the client has successfully registered etc.
|
||||
|
||||
struct server_context *ctx = conn->ctx;
|
||||
ssize_t i = poller_find_by_fd (&ctx->poller, conn->socket_fd);
|
||||
struct server_context *ctx = c->ctx;
|
||||
ssize_t i = poller_find_by_fd (&ctx->poller, c->socket_fd);
|
||||
if (i != -1)
|
||||
poller_remove_at_index (&ctx->poller, i);
|
||||
|
||||
xclose (conn->socket_fd);
|
||||
conn->socket_fd = -1;
|
||||
connection_free (conn);
|
||||
LIST_UNLINK (ctx->clients, conn);
|
||||
free (conn);
|
||||
xclose (c->socket_fd);
|
||||
c->socket_fd = -1;
|
||||
client_free (c);
|
||||
LIST_UNLINK (ctx->clients, c);
|
||||
free (c);
|
||||
}
|
||||
|
||||
static void
|
||||
irc_send_str (struct connection *conn, const struct str *s)
|
||||
irc_send_str (struct client *c, const struct str *s)
|
||||
{
|
||||
// TODO: kill the connection above some "SendQ" threshold (careful!)
|
||||
|
||||
str_append_data (&conn->write_buffer, s->str,
|
||||
str_append_data (&c->write_buffer, s->str,
|
||||
s->len > IRC_MAX_MESSAGE_LENGTH ? IRC_MAX_MESSAGE_LENGTH : s->len);
|
||||
str_append (&conn->write_buffer, "\r\n");
|
||||
str_append (&c->write_buffer, "\r\n");
|
||||
}
|
||||
|
||||
static void irc_send (struct connection *conn,
|
||||
static void irc_send (struct client *c,
|
||||
const char *format, ...) ATTRIBUTE_PRINTF (2, 3);
|
||||
|
||||
static void
|
||||
irc_send (struct connection *conn, const char *format, ...)
|
||||
irc_send (struct client *c, const char *format, ...)
|
||||
{
|
||||
struct str tmp;
|
||||
str_init (&tmp);
|
||||
@ -479,7 +478,7 @@ irc_send (struct connection *conn, const char *format, ...)
|
||||
str_append_vprintf (&tmp, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
irc_send_str (conn, &tmp);
|
||||
irc_send_str (c, &tmp);
|
||||
str_free (&tmp);
|
||||
}
|
||||
|
||||
@ -541,7 +540,7 @@ static const char *g_default_replies[] =
|
||||
|
||||
// XXX: this way we cannot typecheck the arguments, so we must be careful
|
||||
static void
|
||||
irc_send_reply (struct connection *conn, int id, ...)
|
||||
irc_send_reply (struct client *c, int id, ...)
|
||||
{
|
||||
struct str tmp;
|
||||
str_init (&tmp);
|
||||
@ -549,115 +548,112 @@ irc_send_reply (struct connection *conn, int id, ...)
|
||||
va_list ap;
|
||||
va_start (ap, id);
|
||||
str_append_printf (&tmp, ":%s %03d %s ",
|
||||
conn->ctx->server_name, id, conn->nickname ? conn->nickname : "");
|
||||
c->ctx->server_name, id, c->nickname ? c->nickname : "");
|
||||
str_append_vprintf (&tmp,
|
||||
irc_get_text (conn->ctx, id, g_default_replies[id]), ap);
|
||||
irc_get_text (c->ctx, id, g_default_replies[id]), ap);
|
||||
va_end (ap);
|
||||
|
||||
irc_send_str (conn, &tmp);
|
||||
irc_send_str (c, &tmp);
|
||||
str_free (&tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
irc_send_motd (struct connection *conn)
|
||||
irc_send_motd (struct client *c)
|
||||
{
|
||||
struct server_context *ctx = conn->ctx;
|
||||
struct server_context *ctx = c->ctx;
|
||||
if (!ctx->motd.len)
|
||||
{
|
||||
irc_send_reply (conn, IRC_ERR_NOMOTD);
|
||||
irc_send_reply (c, IRC_ERR_NOMOTD);
|
||||
return;
|
||||
}
|
||||
|
||||
irc_send_reply (conn, IRC_RPL_MOTDSTART, ctx->server_name);
|
||||
irc_send_reply (c, IRC_RPL_MOTDSTART, ctx->server_name);
|
||||
for (size_t i = 0; i < ctx->motd.len; i++)
|
||||
irc_send_reply (conn, IRC_RPL_MOTD, ctx->motd.vector[i]);
|
||||
irc_send_reply (conn, IRC_RPL_ENDOFMOTD);
|
||||
irc_send_reply (c, IRC_RPL_MOTD, ctx->motd.vector[i]);
|
||||
irc_send_reply (c, IRC_RPL_ENDOFMOTD);
|
||||
}
|
||||
|
||||
static void
|
||||
irc_try_finish_registration (struct connection *conn)
|
||||
irc_try_finish_registration (struct client *c)
|
||||
{
|
||||
if (!conn->nickname || !conn->username || !conn->realname)
|
||||
if (!c->nickname || !c->username || !c->realname)
|
||||
return;
|
||||
|
||||
conn->registered = true;
|
||||
irc_send_reply (conn, IRC_RPL_WELCOME,
|
||||
conn->nickname, conn->username, conn->hostname);
|
||||
c->registered = true;
|
||||
irc_send_reply (c, IRC_RPL_WELCOME, c->nickname, c->username, c->hostname);
|
||||
|
||||
irc_send_reply (conn, IRC_RPL_YOURHOST,
|
||||
conn->ctx->server_name, PROGRAM_VERSION);
|
||||
irc_send_reply (c, IRC_RPL_YOURHOST, c->ctx->server_name, PROGRAM_VERSION);
|
||||
// The purpose of this message eludes me
|
||||
irc_send_reply (conn, IRC_RPL_CREATED, __DATE__);
|
||||
irc_send_reply (conn, IRC_RPL_MYINFO,
|
||||
conn->ctx->server_name, PROGRAM_VERSION,
|
||||
irc_send_reply (c, IRC_RPL_CREATED, __DATE__);
|
||||
irc_send_reply (c, IRC_RPL_MYINFO, c->ctx->server_name, PROGRAM_VERSION,
|
||||
IRC_SUPPORTED_USER_MODES, IRC_SUPPORTED_CHAN_MODES);
|
||||
|
||||
// Although not strictly required, bots often need this to work
|
||||
irc_send_motd (conn);
|
||||
irc_send_motd (c);
|
||||
}
|
||||
|
||||
static void
|
||||
irc_handle_pass (const struct irc_message *msg, struct connection *conn)
|
||||
irc_handle_pass (const struct irc_message *msg, struct client *c)
|
||||
{
|
||||
if (conn->registered)
|
||||
irc_send_reply (conn, IRC_ERR_ALREADYREGISTERED);
|
||||
if (c->registered)
|
||||
irc_send_reply (c, IRC_ERR_ALREADYREGISTERED);
|
||||
else if (msg->params.len < 1)
|
||||
irc_send_reply (conn, IRC_ERR_NEEDMOREPARAMS, msg->command);
|
||||
irc_send_reply (c, IRC_ERR_NEEDMOREPARAMS, msg->command);
|
||||
|
||||
// We have SSL client certificates for this purpose; ignoring
|
||||
}
|
||||
|
||||
static void
|
||||
irc_handle_nick (const struct irc_message *msg, struct connection *conn)
|
||||
irc_handle_nick (const struct irc_message *msg, struct client *c)
|
||||
{
|
||||
struct server_context *ctx = conn->ctx;
|
||||
struct server_context *ctx = c->ctx;
|
||||
|
||||
if (conn->registered)
|
||||
if (c->registered)
|
||||
{
|
||||
irc_send_reply (conn, IRC_ERR_ALREADYREGISTERED);
|
||||
irc_send_reply (c, IRC_ERR_ALREADYREGISTERED);
|
||||
return;
|
||||
}
|
||||
if (msg->params.len < 1)
|
||||
{
|
||||
irc_send_reply (conn, IRC_ERR_NONICKNAMEGIVEN);
|
||||
irc_send_reply (c, IRC_ERR_NONICKNAMEGIVEN);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *nickname = msg->params.vector[0];
|
||||
if (irc_validate_nickname (nickname) != VALIDATION_OK)
|
||||
{
|
||||
irc_send_reply (conn, IRC_ERR_ERRONEOUSNICKNAME, nickname);
|
||||
irc_send_reply (c, IRC_ERR_ERRONEOUSNICKNAME, nickname);
|
||||
return;
|
||||
}
|
||||
if (str_map_find (&ctx->users, nickname))
|
||||
{
|
||||
irc_send_reply (conn, IRC_ERR_NICKNAMEINUSE, nickname);
|
||||
irc_send_reply (c, IRC_ERR_NICKNAMEINUSE, nickname);
|
||||
return;
|
||||
}
|
||||
if (conn->nickname)
|
||||
if (c->nickname)
|
||||
{
|
||||
str_map_set (&ctx->users, conn->nickname, NULL);
|
||||
free (conn->nickname);
|
||||
str_map_set (&ctx->users, c->nickname, NULL);
|
||||
free (c->nickname);
|
||||
}
|
||||
|
||||
// Allocate the nickname
|
||||
conn->nickname = xstrdup (nickname);
|
||||
str_map_set (&ctx->users, nickname, conn);
|
||||
c->nickname = xstrdup (nickname);
|
||||
str_map_set (&ctx->users, nickname, c);
|
||||
|
||||
irc_try_finish_registration (conn);
|
||||
irc_try_finish_registration (c);
|
||||
}
|
||||
|
||||
static void
|
||||
irc_handle_user (const struct irc_message *msg, struct connection *conn)
|
||||
irc_handle_user (const struct irc_message *msg, struct client *c)
|
||||
{
|
||||
if (conn->registered)
|
||||
if (c->registered)
|
||||
{
|
||||
irc_send_reply (conn, IRC_ERR_ALREADYREGISTERED);
|
||||
irc_send_reply (c, IRC_ERR_ALREADYREGISTERED);
|
||||
return;
|
||||
}
|
||||
if (msg->params.len < 4)
|
||||
{
|
||||
irc_send_reply (conn, IRC_ERR_NEEDMOREPARAMS, msg->command);
|
||||
irc_send_reply (c, IRC_ERR_NEEDMOREPARAMS, msg->command);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -669,30 +665,30 @@ irc_handle_user (const struct irc_message *msg, struct connection *conn)
|
||||
if (!irc_is_valid_user (username))
|
||||
username = "xxx";
|
||||
|
||||
free (conn->username);
|
||||
conn->username = xstrdup (username);
|
||||
free (conn->realname);
|
||||
conn->realname = xstrdup (realname);
|
||||
free (c->username);
|
||||
c->username = xstrdup (username);
|
||||
free (c->realname);
|
||||
c->realname = xstrdup (realname);
|
||||
|
||||
unsigned long m;
|
||||
if (xstrtoul (&m, mode, 10))
|
||||
{
|
||||
if (m & 4) conn->mode |= IRC_USER_MODE_RX_WALLOPS;
|
||||
if (m & 8) conn->mode |= IRC_USER_MODE_INVISIBLE;
|
||||
if (m & 4) c->mode |= IRC_USER_MODE_RX_WALLOPS;
|
||||
if (m & 8) c->mode |= IRC_USER_MODE_INVISIBLE;
|
||||
}
|
||||
|
||||
irc_try_finish_registration (conn);
|
||||
irc_try_finish_registration (c);
|
||||
}
|
||||
|
||||
static void
|
||||
irc_handle_ping (const struct irc_message *msg, struct connection *conn)
|
||||
irc_handle_ping (const struct irc_message *msg, struct client *c)
|
||||
{
|
||||
// XXX: the RFC is pretty incomprehensible about the exact usage
|
||||
if (msg->params.len < 1)
|
||||
irc_send_reply (conn, IRC_ERR_NOORIGIN);
|
||||
irc_send_reply (c, IRC_ERR_NOORIGIN);
|
||||
else
|
||||
irc_send (conn, ":%s PONG :%s",
|
||||
conn->ctx->server_name, msg->params.vector[0]);
|
||||
irc_send (c, ":%s PONG :%s",
|
||||
c->ctx->server_name, msg->params.vector[0]);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -701,7 +697,7 @@ struct irc_command
|
||||
{
|
||||
const char *name;
|
||||
bool requires_registration;
|
||||
void (*handler) (const struct irc_message *, struct connection *);
|
||||
void (*handler) (const struct irc_message *, struct client *);
|
||||
};
|
||||
|
||||
static void
|
||||
@ -730,44 +726,44 @@ irc_process_message (const struct irc_message *msg,
|
||||
(void) raw;
|
||||
|
||||
// XXX: we may want to discard everything following a QUIT etc.
|
||||
// We can set a flag within the connection object.
|
||||
// We can set a flag within the client object.
|
||||
// TODO: see RFC 2812 :!
|
||||
|
||||
struct connection *conn = user_data;
|
||||
struct irc_command *cmd = str_map_find (&conn->ctx->handlers, msg->command);
|
||||
struct client *c = user_data;
|
||||
struct irc_command *cmd = str_map_find (&c->ctx->handlers, msg->command);
|
||||
if (!cmd)
|
||||
irc_send_reply (conn, IRC_ERR_UNKNOWNCOMMAND,
|
||||
irc_send_reply (c, IRC_ERR_UNKNOWNCOMMAND,
|
||||
"%s: Unknown command", msg->command);
|
||||
else if (cmd->requires_registration && !conn->registered)
|
||||
irc_send_reply (conn, IRC_ERR_NOTREGISTERED);
|
||||
else if (cmd->requires_registration && !c->registered)
|
||||
irc_send_reply (c, IRC_ERR_NOTREGISTERED);
|
||||
else
|
||||
cmd->handler (msg, conn);
|
||||
cmd->handler (msg, c);
|
||||
}
|
||||
|
||||
// --- Network I/O -------------------------------------------------------------
|
||||
|
||||
static bool
|
||||
irc_try_read (struct connection *conn)
|
||||
irc_try_read (struct client *c)
|
||||
{
|
||||
struct str *buf = &conn->read_buffer;
|
||||
struct str *buf = &c->read_buffer;
|
||||
ssize_t n_read;
|
||||
|
||||
while (true)
|
||||
{
|
||||
str_ensure_space (buf, 512);
|
||||
n_read = recv (conn->socket_fd, buf->str + buf->len,
|
||||
n_read = recv (c->socket_fd, buf->str + buf->len,
|
||||
buf->alloc - buf->len - 1 /* null byte */, 0);
|
||||
|
||||
if (n_read > 0)
|
||||
{
|
||||
buf->str[buf->len += n_read] = '\0';
|
||||
// TODO: discard characters above the 512 character limit
|
||||
irc_process_buffer (buf, irc_process_message, conn);
|
||||
irc_process_buffer (buf, irc_process_message, c);
|
||||
continue;
|
||||
}
|
||||
if (n_read == 0)
|
||||
{
|
||||
connection_kill (conn, NULL);
|
||||
client_kill (c, NULL);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -777,60 +773,60 @@ irc_try_read (struct connection *conn)
|
||||
continue;
|
||||
|
||||
print_debug ("%s: %s: %s", __func__, "recv", strerror (errno));
|
||||
connection_kill (conn, strerror (errno));
|
||||
client_kill (c, strerror (errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
irc_try_read_ssl (struct connection *conn)
|
||||
irc_try_read_ssl (struct client *c)
|
||||
{
|
||||
if (conn->ssl_tx_want_rx)
|
||||
if (c->ssl_tx_want_rx)
|
||||
return true;
|
||||
|
||||
struct str *buf = &conn->read_buffer;
|
||||
conn->ssl_rx_want_tx = false;
|
||||
struct str *buf = &c->read_buffer;
|
||||
c->ssl_rx_want_tx = false;
|
||||
while (true)
|
||||
{
|
||||
str_ensure_space (buf, 512);
|
||||
int n_read = SSL_read (conn->ssl, buf->str + buf->len,
|
||||
int n_read = SSL_read (c->ssl, buf->str + buf->len,
|
||||
buf->alloc - buf->len - 1 /* null byte */);
|
||||
|
||||
const char *error_info = NULL;
|
||||
switch (xssl_get_error (conn->ssl, n_read, &error_info))
|
||||
switch (xssl_get_error (c->ssl, n_read, &error_info))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
buf->str[buf->len += n_read] = '\0';
|
||||
// TODO: discard characters above the 512 character limit
|
||||
irc_process_buffer (buf, irc_process_message, conn);
|
||||
irc_process_buffer (buf, irc_process_message, c);
|
||||
continue;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
connection_kill (conn, NULL);
|
||||
client_kill (c, NULL);
|
||||
return false;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
return true;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
conn->ssl_rx_want_tx = true;
|
||||
c->ssl_rx_want_tx = true;
|
||||
return true;
|
||||
case XSSL_ERROR_TRY_AGAIN:
|
||||
continue;
|
||||
default:
|
||||
print_debug ("%s: %s: %s", __func__, "SSL_read", error_info);
|
||||
connection_kill (conn, error_info);
|
||||
client_kill (c, error_info);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
irc_try_write (struct connection *conn)
|
||||
irc_try_write (struct client *c)
|
||||
{
|
||||
struct str *buf = &conn->write_buffer;
|
||||
struct str *buf = &c->write_buffer;
|
||||
ssize_t n_written;
|
||||
|
||||
while (buf->len)
|
||||
{
|
||||
n_written = send (conn->socket_fd, buf->str, buf->len, 0);
|
||||
n_written = send (c->socket_fd, buf->str, buf->len, 0);
|
||||
if (n_written >= 0)
|
||||
{
|
||||
str_remove_slice (buf, 0, n_written);
|
||||
@ -843,43 +839,43 @@ irc_try_write (struct connection *conn)
|
||||
continue;
|
||||
|
||||
print_debug ("%s: %s: %s", __func__, "send", strerror (errno));
|
||||
connection_kill (conn, strerror (errno));
|
||||
client_kill (c, strerror (errno));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
irc_try_write_ssl (struct connection *conn)
|
||||
irc_try_write_ssl (struct client *c)
|
||||
{
|
||||
if (conn->ssl_rx_want_tx)
|
||||
if (c->ssl_rx_want_tx)
|
||||
return true;
|
||||
|
||||
struct str *buf = &conn->write_buffer;
|
||||
conn->ssl_tx_want_rx = false;
|
||||
struct str *buf = &c->write_buffer;
|
||||
c->ssl_tx_want_rx = false;
|
||||
while (buf->len)
|
||||
{
|
||||
int n_written = SSL_write (conn->ssl, buf->str, buf->len);
|
||||
int n_written = SSL_write (c->ssl, buf->str, buf->len);
|
||||
|
||||
const char *error_info = NULL;
|
||||
switch (xssl_get_error (conn->ssl, n_written, &error_info))
|
||||
switch (xssl_get_error (c->ssl, n_written, &error_info))
|
||||
{
|
||||
case SSL_ERROR_NONE:
|
||||
str_remove_slice (buf, 0, n_written);
|
||||
continue;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
connection_kill (conn, NULL);
|
||||
client_kill (c, NULL);
|
||||
return false;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
return true;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
conn->ssl_tx_want_rx = true;
|
||||
c->ssl_tx_want_rx = true;
|
||||
return true;
|
||||
case XSSL_ERROR_TRY_AGAIN:
|
||||
continue;
|
||||
default:
|
||||
print_debug ("%s: %s: %s", __func__, "SSL_write", error_info);
|
||||
connection_kill (conn, error_info);
|
||||
client_kill (c, error_info);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -887,7 +883,7 @@ irc_try_write_ssl (struct connection *conn)
|
||||
}
|
||||
|
||||
static bool
|
||||
irc_autodetect_ssl (struct connection *conn)
|
||||
irc_autodetect_ssl (struct client *c)
|
||||
{
|
||||
// Trivial SSL/TLS autodetection. The first block of data returned by
|
||||
// recv() must be at least three bytes long for this to work reliably,
|
||||
@ -903,7 +899,7 @@ irc_autodetect_ssl (struct connection *conn)
|
||||
|
||||
char buf[3];
|
||||
start:
|
||||
switch (recv (conn->socket_fd, buf, sizeof buf, MSG_PEEK))
|
||||
switch (recv (c->socket_fd, buf, sizeof buf, MSG_PEEK))
|
||||
{
|
||||
case 3:
|
||||
if ((buf[0] & 0x80) && buf[2] == 1)
|
||||
@ -926,81 +922,81 @@ start:
|
||||
}
|
||||
|
||||
static bool
|
||||
connection_initialize_ssl (struct connection *conn)
|
||||
client_initialize_ssl (struct client *c)
|
||||
{
|
||||
// SSL support not enabled
|
||||
if (!conn->ctx->ssl_ctx)
|
||||
if (!c->ctx->ssl_ctx)
|
||||
return false;
|
||||
|
||||
conn->ssl = SSL_new (conn->ctx->ssl_ctx);
|
||||
if (!conn->ssl)
|
||||
c->ssl = SSL_new (c->ctx->ssl_ctx);
|
||||
if (!c->ssl)
|
||||
goto error_ssl_1;
|
||||
|
||||
if (!SSL_set_fd (conn->ssl, conn->socket_fd))
|
||||
if (!SSL_set_fd (c->ssl, c->socket_fd))
|
||||
goto error_ssl_2;
|
||||
SSL_set_accept_state (conn->ssl);
|
||||
SSL_set_accept_state (c->ssl);
|
||||
return true;
|
||||
|
||||
error_ssl_2:
|
||||
SSL_free (conn->ssl);
|
||||
conn->ssl = NULL;
|
||||
SSL_free (c->ssl);
|
||||
c->ssl = NULL;
|
||||
error_ssl_1:
|
||||
// XXX: these error strings are really nasty; also there could be
|
||||
// multiple errors on the OpenSSL stack.
|
||||
print_debug ("%s: %s: %s", "could not initialize SSL",
|
||||
conn->hostname, ERR_error_string (ERR_get_error (), NULL));
|
||||
c->hostname, ERR_error_string (ERR_get_error (), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
on_irc_client_ready (const struct pollfd *pfd, void *user_data)
|
||||
{
|
||||
struct connection *conn = user_data;
|
||||
if (!conn->initialized)
|
||||
struct client *c = user_data;
|
||||
if (!c->initialized)
|
||||
{
|
||||
hard_assert (pfd->events == POLLIN);
|
||||
if (irc_autodetect_ssl (conn) && !connection_initialize_ssl (conn))
|
||||
if (irc_autodetect_ssl (c) && !client_initialize_ssl (c))
|
||||
{
|
||||
connection_kill (conn, NULL);
|
||||
client_kill (c, NULL);
|
||||
return;
|
||||
}
|
||||
conn->initialized = true;
|
||||
c->initialized = true;
|
||||
}
|
||||
|
||||
int new_events = 0;
|
||||
if (conn->ssl)
|
||||
if (c->ssl)
|
||||
{
|
||||
// Reads may want to write, writes may want to read, poll() may
|
||||
// return unexpected things in `revents'... let's try both
|
||||
if (!irc_try_read_ssl (conn) || !irc_try_write_ssl (conn))
|
||||
if (!irc_try_read_ssl (c) || !irc_try_write_ssl (c))
|
||||
return;
|
||||
|
||||
new_events |= POLLIN;
|
||||
if (conn->write_buffer.len || conn->ssl_rx_want_tx)
|
||||
if (c->write_buffer.len || c->ssl_rx_want_tx)
|
||||
new_events |= POLLOUT;
|
||||
|
||||
// While we're waiting for an opposite event, we ignore the original
|
||||
if (conn->ssl_rx_want_tx) new_events &= ~POLLIN;
|
||||
if (conn->ssl_tx_want_rx) new_events &= ~POLLOUT;
|
||||
if (c->ssl_rx_want_tx) new_events &= ~POLLIN;
|
||||
if (c->ssl_tx_want_rx) new_events &= ~POLLOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!irc_try_read (conn) || !irc_try_write (conn))
|
||||
if (!irc_try_read (c) || !irc_try_write (c))
|
||||
return;
|
||||
|
||||
new_events |= POLLIN;
|
||||
if (conn->write_buffer.len)
|
||||
if (c->write_buffer.len)
|
||||
new_events |= POLLOUT;
|
||||
}
|
||||
|
||||
hard_assert (new_events != 0);
|
||||
if (pfd->events != new_events)
|
||||
poller_set (&conn->ctx->poller, conn->socket_fd, new_events,
|
||||
(poller_dispatcher_func) on_irc_client_ready, conn);
|
||||
poller_set (&c->ctx->poller, c->socket_fd, new_events,
|
||||
(poller_dispatcher_func) on_irc_client_ready, c);
|
||||
}
|
||||
|
||||
static void
|
||||
on_irc_connection_available (const struct pollfd *pfd, void *user_data)
|
||||
on_irc_client_available (const struct pollfd *pfd, void *user_data)
|
||||
{
|
||||
(void) pfd;
|
||||
struct server_context *ctx = user_data;
|
||||
@ -1038,16 +1034,16 @@ on_irc_connection_available (const struct pollfd *pfd, void *user_data)
|
||||
print_debug ("%s: %s", "getnameinfo", gai_strerror (err));
|
||||
print_debug ("accepted connection from %s:%s", host, port);
|
||||
|
||||
struct connection *conn = xmalloc (sizeof *conn);
|
||||
connection_init (conn);
|
||||
conn->socket_fd = fd;
|
||||
conn->hostname = xstrdup (host);
|
||||
LIST_PREPEND (ctx->clients, conn);
|
||||
struct client *c = xmalloc (sizeof *c);
|
||||
client_init (c);
|
||||
c->socket_fd = fd;
|
||||
c->hostname = xstrdup (host);
|
||||
LIST_PREPEND (ctx->clients, c);
|
||||
|
||||
// TODO: set a timeout on the socket, something like 3 minutes, then we
|
||||
// should terminate the connection.
|
||||
poller_set (&ctx->poller, conn->socket_fd, POLLIN,
|
||||
(poller_dispatcher_func) on_irc_client_ready, conn);
|
||||
poller_set (&ctx->poller, c->socket_fd, POLLIN,
|
||||
(poller_dispatcher_func) on_irc_client_ready, c);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1279,7 +1275,7 @@ irc_listen (struct server_context *ctx, struct error **e)
|
||||
|
||||
ctx->listen_fd = sockfd;
|
||||
poller_set (&ctx->poller, ctx->listen_fd, POLLIN,
|
||||
(poller_dispatcher_func) on_irc_connection_available, ctx);
|
||||
(poller_dispatcher_func) on_irc_client_available, ctx);
|
||||
|
||||
print_status ("listening at %s:%s", real_host, real_port);
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user