diff --git a/degesch.c b/degesch.c index 4e67558..e066edf 100644 --- a/degesch.c +++ b/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 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 poller_fd irc_event; ///< IRC FD event - bool irc_ready; ///< Whether we may send messages now + struct poller_fd read_event; ///< We can read from the socket SSL_CTX *ssl_ctx; ///< SSL context SSL *ssl; ///< SSL connection @@ -1020,9 +1028,9 @@ static void on_irc_reconnect_timeout (void *user_data); static void server_init (struct server *self, struct poller *poller) { - self->irc_fd = -1; + self->socket = -1; str_init (&self->read_buffer); - self->irc_ready = false; + self->state = IRC_DISCONNECTED; str_map_init (&self->irc_users); self->irc_users.key_xfrm = irc_strxfrm; @@ -1047,10 +1055,10 @@ server_init (struct server *self, struct poller *poller) static void server_free (struct server *self) { - if (self->irc_fd != -1) + if (self->socket != -1) { - xclose (self->irc_fd); - poller_fd_reset (&self->irc_event); + xclose (self->socket); + poller_fd_reset (&self->read_event); } str_free (&self->read_buffer); @@ -2547,6 +2555,12 @@ irc_is_channel (struct server *s, const char *ident) return *ident && !!strchr ("#&+!", *ident); } +static bool +irc_is_connected (struct server *s) +{ + return s->state != IRC_DISCONNECTED; +} + static void irc_shutdown (struct server *s) { @@ -2555,14 +2569,14 @@ irc_shutdown (struct server *s) if (s->ssl) soft_assert (SSL_shutdown (s->ssl) != -1); else - soft_assert (shutdown (s->irc_fd, SHUT_WR) == 0); + soft_assert (shutdown (s->socket, SHUT_WR) == 0); } static void try_finish_quit (struct app_context *ctx) { // TODO: multiserver - if (ctx->quitting && ctx->server.irc_fd == -1) + if (ctx->quitting && !irc_is_connected (&ctx->server)) ctx->polling = false; } @@ -2577,7 +2591,7 @@ initiate_quit (struct app_context *ctx) // Initiate a connection close // TODO: multiserver 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 irc_shutdown (s); @@ -2614,7 +2628,7 @@ static bool irc_send (struct server *s, static bool 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"); return false; @@ -2650,7 +2664,7 @@ irc_send (struct server *s, const char *format, ...) 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"); result = false; @@ -2737,7 +2751,7 @@ irc_initialize_ssl (struct server *s, struct error **e) } 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; // Avoid SSL_write() returning SSL_ERROR_WANT_READ SSL_set_mode (s->ssl, SSL_MODE_AUTO_RETRY); @@ -2826,7 +2840,7 @@ irc_establish_connection (struct server *s, return false; } - s->irc_fd = sockfd; + s->socket = sockfd; return true; } @@ -2880,7 +2894,7 @@ make_prompt (struct app_context *ctx, struct str *output) { struct server *s = buffer->server; str_append_c (output, ' '); - if (s->irc_fd == -1) + if (!irc_is_connected (s)) str_append (output, "(disconnected)"); else { @@ -3599,13 +3613,13 @@ irc_process_message (const struct irc_message *msg, } // 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, "422"))) // ERR_NOMOTD { // XXX: should we really print this? buffer_send_status (s->ctx, s->buffer, "Successfully connected"); - s->irc_ready = true; + s->state = IRC_REGISTERED; refresh_prompt (s->ctx); // 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 { 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"); else return true; @@ -4399,7 +4413,7 @@ handle_command_quit (struct app_context *ctx, char *arguments) { // TODO: multiserver struct server *s = &ctx->server; - if (s->irc_fd != -1) + if (irc_is_connected (s)) { if (*arguments) irc_send (s, "QUIT :%s", arguments); @@ -4471,7 +4485,7 @@ handle_command_connect (struct app_context *ctx, char *arguments) { // TODO: multiserver struct server *s = &ctx->server; - if (s->irc_fd != -1) + if (irc_is_connected (s)) { buffer_send_error (ctx, s->buffer, "Already connected"); return true; @@ -4719,7 +4733,7 @@ static void send_message_to_target (struct server *s, 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"); return; @@ -4801,7 +4815,7 @@ start: { // 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 - struct pollfd pfd = { .fd = s->irc_fd, .events = POLLOUT }; + struct pollfd pfd = { .fd = s->socket, .events = POLLOUT }; soft_assert (poll (&pfd, 1, 0) > 0); goto start; } @@ -4818,7 +4832,7 @@ irc_fill_read_buffer (struct server *s, struct str *buf) { ssize_t n_read; 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); if (n_read > 0) @@ -4850,7 +4864,7 @@ static void irc_queue_reconnect (struct server *s) { // TODO: exponentional backoff - hard_assert (s->irc_fd == -1); + hard_assert (s->socket == -1); buffer_send_status (s->ctx, s->buffer, "Trying to reconnect in %ld seconds...", s->ctx->reconnect_delay); 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; } - xclose (s->irc_fd); - s->irc_fd = -1; - s->irc_ready = false; + xclose (s->socket); + s->socket = -1; + s->state = IRC_DISCONNECTED; user_unref (s->irc_user); s->irc_user = NULL; @@ -4897,8 +4911,8 @@ on_irc_disconnected (struct server *s) free (s->irc_user_host); s->irc_user_host = NULL; - s->irc_event.closed = true; - poller_fd_reset (&s->irc_event); + s->read_event.closed = true; + poller_fd_reset (&s->read_event); // All of our timers have lost their meaning now irc_cancel_timers (s); @@ -4943,7 +4957,7 @@ on_irc_readable (const struct pollfd *fd, struct server *s) if (fd->revents & ~(POLLIN | POLLHUP | POLLERR)) 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; 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: - (void) set_blocking (s->irc_fd, true); + (void) set_blocking (s->socket, true); irc_process_buffer (buf, irc_process_message, s); if (disconnected) @@ -5045,24 +5059,26 @@ irc_connect (struct server *s, bool *should_retry, struct error **e) error_free (error); return false; } - s->irc_fd = fd; + s->socket = fd; } else if (!irc_establish_connection (s, irc_host, irc_port, e)) return false; if (use_ssl && !irc_initialize_ssl (s, e)) { - xclose (s->irc_fd); - s->irc_fd = -1; + xclose (s->socket); + s->socket = -1; return false; } + + s->state = IRC_CONNECTED; buffer_send_status (ctx, s->buffer, "Connection established"); - poller_fd_init (&s->irc_event, &ctx->poller, s->irc_fd); - s->irc_event.dispatcher = (poller_fd_fn) on_irc_readable; - s->irc_event.user_data = s; + poller_fd_init (&s->read_event, &ctx->poller, s->socket); + s->read_event.dispatcher = (poller_fd_fn) on_irc_readable; + 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_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); // FIXME: use a normal quit message - if (s->irc_fd != -1) + if (irc_is_connected (s)) irc_send (s, "QUIT :Terminated by signal"); initiate_quit (ctx); }