degesch: add server::state, rename stuff
This is in preparation of asynchronous connects.
This commit is contained in:
parent
6414a73d62
commit
9a02c90e3e
96
degesch.c
96
degesch.c
@ -974,14 +974,22 @@ buffer_destroy (struct buffer *self)
|
|||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
|
enum server_state
|
||||||
|
{
|
||||||
|
IRC_DISCONNECTED, ///< Not connected
|
||||||
|
IRC_CONNECTED, ///< Trying to register
|
||||||
|
IRC_REGISTERED ///< We can chat now
|
||||||
|
};
|
||||||
|
|
||||||
struct server
|
struct server
|
||||||
{
|
{
|
||||||
struct app_context *ctx; ///< Application context
|
struct app_context *ctx; ///< Application context
|
||||||
|
|
||||||
int irc_fd; ///< Socket FD of the server
|
enum server_state state; ///< Connection state
|
||||||
|
|
||||||
|
int socket; ///< Socket FD of the server
|
||||||
struct str read_buffer; ///< Input yet to be processed
|
struct str read_buffer; ///< Input yet to be processed
|
||||||
struct poller_fd irc_event; ///< IRC FD event
|
struct poller_fd read_event; ///< We can read from the socket
|
||||||
bool irc_ready; ///< Whether we may send messages now
|
|
||||||
|
|
||||||
SSL_CTX *ssl_ctx; ///< SSL context
|
SSL_CTX *ssl_ctx; ///< SSL context
|
||||||
SSL *ssl; ///< SSL connection
|
SSL *ssl; ///< SSL connection
|
||||||
@ -1020,9 +1028,9 @@ static void on_irc_reconnect_timeout (void *user_data);
|
|||||||
static void
|
static void
|
||||||
server_init (struct server *self, struct poller *poller)
|
server_init (struct server *self, struct poller *poller)
|
||||||
{
|
{
|
||||||
self->irc_fd = -1;
|
self->socket = -1;
|
||||||
str_init (&self->read_buffer);
|
str_init (&self->read_buffer);
|
||||||
self->irc_ready = false;
|
self->state = IRC_DISCONNECTED;
|
||||||
|
|
||||||
str_map_init (&self->irc_users);
|
str_map_init (&self->irc_users);
|
||||||
self->irc_users.key_xfrm = irc_strxfrm;
|
self->irc_users.key_xfrm = irc_strxfrm;
|
||||||
@ -1047,10 +1055,10 @@ server_init (struct server *self, struct poller *poller)
|
|||||||
static void
|
static void
|
||||||
server_free (struct server *self)
|
server_free (struct server *self)
|
||||||
{
|
{
|
||||||
if (self->irc_fd != -1)
|
if (self->socket != -1)
|
||||||
{
|
{
|
||||||
xclose (self->irc_fd);
|
xclose (self->socket);
|
||||||
poller_fd_reset (&self->irc_event);
|
poller_fd_reset (&self->read_event);
|
||||||
}
|
}
|
||||||
str_free (&self->read_buffer);
|
str_free (&self->read_buffer);
|
||||||
|
|
||||||
@ -2547,6 +2555,12 @@ irc_is_channel (struct server *s, const char *ident)
|
|||||||
return *ident && !!strchr ("#&+!", *ident);
|
return *ident && !!strchr ("#&+!", *ident);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
irc_is_connected (struct server *s)
|
||||||
|
{
|
||||||
|
return s->state != IRC_DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
irc_shutdown (struct server *s)
|
irc_shutdown (struct server *s)
|
||||||
{
|
{
|
||||||
@ -2555,14 +2569,14 @@ irc_shutdown (struct server *s)
|
|||||||
if (s->ssl)
|
if (s->ssl)
|
||||||
soft_assert (SSL_shutdown (s->ssl) != -1);
|
soft_assert (SSL_shutdown (s->ssl) != -1);
|
||||||
else
|
else
|
||||||
soft_assert (shutdown (s->irc_fd, SHUT_WR) == 0);
|
soft_assert (shutdown (s->socket, SHUT_WR) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
try_finish_quit (struct app_context *ctx)
|
try_finish_quit (struct app_context *ctx)
|
||||||
{
|
{
|
||||||
// TODO: multiserver
|
// TODO: multiserver
|
||||||
if (ctx->quitting && ctx->server.irc_fd == -1)
|
if (ctx->quitting && !irc_is_connected (&ctx->server))
|
||||||
ctx->polling = false;
|
ctx->polling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2577,7 +2591,7 @@ initiate_quit (struct app_context *ctx)
|
|||||||
// Initiate a connection close
|
// Initiate a connection close
|
||||||
// TODO: multiserver
|
// TODO: multiserver
|
||||||
struct server *s = &ctx->server;
|
struct server *s = &ctx->server;
|
||||||
if (s->irc_fd != -1)
|
if (irc_is_connected (s))
|
||||||
// XXX: when we go async, we'll have to flush output buffers first
|
// XXX: when we go async, we'll have to flush output buffers first
|
||||||
irc_shutdown (s);
|
irc_shutdown (s);
|
||||||
|
|
||||||
@ -2614,7 +2628,7 @@ static bool irc_send (struct server *s,
|
|||||||
static bool
|
static bool
|
||||||
irc_send (struct server *s, const char *format, ...)
|
irc_send (struct server *s, const char *format, ...)
|
||||||
{
|
{
|
||||||
if (!soft_assert (s->irc_fd != -1))
|
if (!soft_assert (irc_is_connected (s)))
|
||||||
{
|
{
|
||||||
print_debug ("tried sending a message to a dead server connection");
|
print_debug ("tried sending a message to a dead server connection");
|
||||||
return false;
|
return false;
|
||||||
@ -2650,7 +2664,7 @@ irc_send (struct server *s, const char *format, ...)
|
|||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (write (s->irc_fd, str.str, str.len) != (ssize_t) str.len)
|
else if (write (s->socket, str.str, str.len) != (ssize_t) str.len)
|
||||||
{
|
{
|
||||||
LOG_LIBC_FAILURE ("write");
|
LOG_LIBC_FAILURE ("write");
|
||||||
result = false;
|
result = false;
|
||||||
@ -2737,7 +2751,7 @@ irc_initialize_ssl (struct server *s, struct error **e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SSL_set_connect_state (s->ssl);
|
SSL_set_connect_state (s->ssl);
|
||||||
if (!SSL_set_fd (s->ssl, s->irc_fd))
|
if (!SSL_set_fd (s->ssl, s->socket))
|
||||||
goto error_ssl_3;
|
goto error_ssl_3;
|
||||||
// Avoid SSL_write() returning SSL_ERROR_WANT_READ
|
// Avoid SSL_write() returning SSL_ERROR_WANT_READ
|
||||||
SSL_set_mode (s->ssl, SSL_MODE_AUTO_RETRY);
|
SSL_set_mode (s->ssl, SSL_MODE_AUTO_RETRY);
|
||||||
@ -2826,7 +2840,7 @@ irc_establish_connection (struct server *s,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->irc_fd = sockfd;
|
s->socket = sockfd;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2880,7 +2894,7 @@ make_prompt (struct app_context *ctx, struct str *output)
|
|||||||
{
|
{
|
||||||
struct server *s = buffer->server;
|
struct server *s = buffer->server;
|
||||||
str_append_c (output, ' ');
|
str_append_c (output, ' ');
|
||||||
if (s->irc_fd == -1)
|
if (!irc_is_connected (s))
|
||||||
str_append (output, "(disconnected)");
|
str_append (output, "(disconnected)");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -3599,13 +3613,13 @@ irc_process_message (const struct irc_message *msg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// XXX: or is the 001 numeric enough? For what?
|
// XXX: or is the 001 numeric enough? For what?
|
||||||
if (!s->irc_ready && (!strcasecmp (msg->command, "MODE")
|
if (s->state == IRC_CONNECTED && (!strcasecmp (msg->command, "MODE")
|
||||||
|| !strcasecmp (msg->command, "376") // RPL_ENDOFMOTD
|
|| !strcasecmp (msg->command, "376") // RPL_ENDOFMOTD
|
||||||
|| !strcasecmp (msg->command, "422"))) // ERR_NOMOTD
|
|| !strcasecmp (msg->command, "422"))) // ERR_NOMOTD
|
||||||
{
|
{
|
||||||
// XXX: should we really print this?
|
// XXX: should we really print this?
|
||||||
buffer_send_status (s->ctx, s->buffer, "Successfully connected");
|
buffer_send_status (s->ctx, s->buffer, "Successfully connected");
|
||||||
s->irc_ready = true;
|
s->state = IRC_REGISTERED;
|
||||||
refresh_prompt (s->ctx);
|
refresh_prompt (s->ctx);
|
||||||
|
|
||||||
// TODO: parse any response and store the result for us in app_context;
|
// TODO: parse any response and store the result for us in app_context;
|
||||||
@ -4024,7 +4038,7 @@ server_command_check (struct app_context *ctx, const char *action)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct server *s = ctx->current_buffer->server;
|
struct server *s = ctx->current_buffer->server;
|
||||||
if (s->irc_fd == -1)
|
if (!irc_is_connected (s))
|
||||||
buffer_send_error (ctx, s->buffer, "Not connected");
|
buffer_send_error (ctx, s->buffer, "Not connected");
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
@ -4399,7 +4413,7 @@ handle_command_quit (struct app_context *ctx, char *arguments)
|
|||||||
{
|
{
|
||||||
// TODO: multiserver
|
// TODO: multiserver
|
||||||
struct server *s = &ctx->server;
|
struct server *s = &ctx->server;
|
||||||
if (s->irc_fd != -1)
|
if (irc_is_connected (s))
|
||||||
{
|
{
|
||||||
if (*arguments)
|
if (*arguments)
|
||||||
irc_send (s, "QUIT :%s", arguments);
|
irc_send (s, "QUIT :%s", arguments);
|
||||||
@ -4471,7 +4485,7 @@ handle_command_connect (struct app_context *ctx, char *arguments)
|
|||||||
{
|
{
|
||||||
// TODO: multiserver
|
// TODO: multiserver
|
||||||
struct server *s = &ctx->server;
|
struct server *s = &ctx->server;
|
||||||
if (s->irc_fd != -1)
|
if (irc_is_connected (s))
|
||||||
{
|
{
|
||||||
buffer_send_error (ctx, s->buffer, "Already connected");
|
buffer_send_error (ctx, s->buffer, "Already connected");
|
||||||
return true;
|
return true;
|
||||||
@ -4719,7 +4733,7 @@ static void
|
|||||||
send_message_to_target (struct server *s,
|
send_message_to_target (struct server *s,
|
||||||
const char *target, char *message, struct buffer *buffer)
|
const char *target, char *message, struct buffer *buffer)
|
||||||
{
|
{
|
||||||
if (s->irc_fd == -1)
|
if (!irc_is_connected (s))
|
||||||
{
|
{
|
||||||
buffer_send_error (s->ctx, buffer, "Not connected");
|
buffer_send_error (s->ctx, buffer, "Not connected");
|
||||||
return;
|
return;
|
||||||
@ -4801,7 +4815,7 @@ start:
|
|||||||
{
|
{
|
||||||
// Let it finish the handshake as we don't poll for writability;
|
// Let it finish the handshake as we don't poll for writability;
|
||||||
// any errors are to be collected by SSL_read() in the next iteration
|
// any errors are to be collected by SSL_read() in the next iteration
|
||||||
struct pollfd pfd = { .fd = s->irc_fd, .events = POLLOUT };
|
struct pollfd pfd = { .fd = s->socket, .events = POLLOUT };
|
||||||
soft_assert (poll (&pfd, 1, 0) > 0);
|
soft_assert (poll (&pfd, 1, 0) > 0);
|
||||||
goto start;
|
goto start;
|
||||||
}
|
}
|
||||||
@ -4818,7 +4832,7 @@ irc_fill_read_buffer (struct server *s, struct str *buf)
|
|||||||
{
|
{
|
||||||
ssize_t n_read;
|
ssize_t n_read;
|
||||||
start:
|
start:
|
||||||
n_read = recv (s->irc_fd, buf->str + buf->len,
|
n_read = recv (s->socket, buf->str + buf->len,
|
||||||
buf->alloc - buf->len - 1 /* null byte */, 0);
|
buf->alloc - buf->len - 1 /* null byte */, 0);
|
||||||
|
|
||||||
if (n_read > 0)
|
if (n_read > 0)
|
||||||
@ -4850,7 +4864,7 @@ static void
|
|||||||
irc_queue_reconnect (struct server *s)
|
irc_queue_reconnect (struct server *s)
|
||||||
{
|
{
|
||||||
// TODO: exponentional backoff
|
// TODO: exponentional backoff
|
||||||
hard_assert (s->irc_fd == -1);
|
hard_assert (s->socket == -1);
|
||||||
buffer_send_status (s->ctx, s->buffer,
|
buffer_send_status (s->ctx, s->buffer,
|
||||||
"Trying to reconnect in %ld seconds...", s->ctx->reconnect_delay);
|
"Trying to reconnect in %ld seconds...", s->ctx->reconnect_delay);
|
||||||
poller_timer_set (&s->reconnect_tmr, s->ctx->reconnect_delay * 1000);
|
poller_timer_set (&s->reconnect_tmr, s->ctx->reconnect_delay * 1000);
|
||||||
@ -4885,9 +4899,9 @@ on_irc_disconnected (struct server *s)
|
|||||||
s->ssl_ctx = NULL;
|
s->ssl_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
xclose (s->irc_fd);
|
xclose (s->socket);
|
||||||
s->irc_fd = -1;
|
s->socket = -1;
|
||||||
s->irc_ready = false;
|
s->state = IRC_DISCONNECTED;
|
||||||
|
|
||||||
user_unref (s->irc_user);
|
user_unref (s->irc_user);
|
||||||
s->irc_user = NULL;
|
s->irc_user = NULL;
|
||||||
@ -4897,8 +4911,8 @@ on_irc_disconnected (struct server *s)
|
|||||||
free (s->irc_user_host);
|
free (s->irc_user_host);
|
||||||
s->irc_user_host = NULL;
|
s->irc_user_host = NULL;
|
||||||
|
|
||||||
s->irc_event.closed = true;
|
s->read_event.closed = true;
|
||||||
poller_fd_reset (&s->irc_event);
|
poller_fd_reset (&s->read_event);
|
||||||
|
|
||||||
// All of our timers have lost their meaning now
|
// All of our timers have lost their meaning now
|
||||||
irc_cancel_timers (s);
|
irc_cancel_timers (s);
|
||||||
@ -4943,7 +4957,7 @@ on_irc_readable (const struct pollfd *fd, struct server *s)
|
|||||||
if (fd->revents & ~(POLLIN | POLLHUP | POLLERR))
|
if (fd->revents & ~(POLLIN | POLLHUP | POLLERR))
|
||||||
print_debug ("fd %d: unexpected revents: %d", fd->fd, fd->revents);
|
print_debug ("fd %d: unexpected revents: %d", fd->fd, fd->revents);
|
||||||
|
|
||||||
(void) set_blocking (s->irc_fd, false);
|
(void) set_blocking (s->socket, false);
|
||||||
|
|
||||||
struct str *buf = &s->read_buffer;
|
struct str *buf = &s->read_buffer;
|
||||||
enum irc_read_result (*fill_buffer)(struct server *, struct str *)
|
enum irc_read_result (*fill_buffer)(struct server *, struct str *)
|
||||||
@ -4981,7 +4995,7 @@ on_irc_readable (const struct pollfd *fd, struct server *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
(void) set_blocking (s->irc_fd, true);
|
(void) set_blocking (s->socket, true);
|
||||||
irc_process_buffer (buf, irc_process_message, s);
|
irc_process_buffer (buf, irc_process_message, s);
|
||||||
|
|
||||||
if (disconnected)
|
if (disconnected)
|
||||||
@ -5045,24 +5059,26 @@ irc_connect (struct server *s, bool *should_retry, struct error **e)
|
|||||||
error_free (error);
|
error_free (error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
s->irc_fd = fd;
|
s->socket = fd;
|
||||||
}
|
}
|
||||||
else if (!irc_establish_connection (s, irc_host, irc_port, e))
|
else if (!irc_establish_connection (s, irc_host, irc_port, e))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (use_ssl && !irc_initialize_ssl (s, e))
|
if (use_ssl && !irc_initialize_ssl (s, e))
|
||||||
{
|
{
|
||||||
xclose (s->irc_fd);
|
xclose (s->socket);
|
||||||
s->irc_fd = -1;
|
s->socket = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s->state = IRC_CONNECTED;
|
||||||
buffer_send_status (ctx, s->buffer, "Connection established");
|
buffer_send_status (ctx, s->buffer, "Connection established");
|
||||||
|
|
||||||
poller_fd_init (&s->irc_event, &ctx->poller, s->irc_fd);
|
poller_fd_init (&s->read_event, &ctx->poller, s->socket);
|
||||||
s->irc_event.dispatcher = (poller_fd_fn) on_irc_readable;
|
s->read_event.dispatcher = (poller_fd_fn) on_irc_readable;
|
||||||
s->irc_event.user_data = s;
|
s->read_event.user_data = s;
|
||||||
|
|
||||||
poller_fd_set (&s->irc_event, POLLIN);
|
poller_fd_set (&s->read_event, POLLIN);
|
||||||
irc_reset_connection_timeouts (s);
|
irc_reset_connection_timeouts (s);
|
||||||
|
|
||||||
irc_send (s, "NICK %s", nickname);
|
irc_send (s, "NICK %s", nickname);
|
||||||
@ -5797,7 +5813,7 @@ on_signal_pipe_readable (const struct pollfd *fd, struct app_context *ctx)
|
|||||||
irc_reset_connection_timeouts (s);
|
irc_reset_connection_timeouts (s);
|
||||||
|
|
||||||
// FIXME: use a normal quit message
|
// FIXME: use a normal quit message
|
||||||
if (s->irc_fd != -1)
|
if (irc_is_connected (s))
|
||||||
irc_send (s, "QUIT :Terminated by signal");
|
irc_send (s, "QUIT :Terminated by signal");
|
||||||
initiate_quit (ctx);
|
initiate_quit (ctx);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user