From 376bbea249f17eda9c682ff7153f102990548888 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Wed, 6 Jan 2016 23:37:30 +0100
Subject: Factor out socket_io_try_{read,write}()
To be reused in Lua connection API.
---
common.c | 68 ++++++++++++++++++++++++++++++++++
degesch.c | 125 ++++++++++++++++++++++----------------------------------------
2 files changed, 113 insertions(+), 80 deletions(-)
diff --git a/common.c b/common.c
index 8974f57..a92bae4 100644
--- a/common.c
+++ b/common.c
@@ -95,6 +95,74 @@ xwrite (int fd, const char *data, size_t len, struct error **e)
return true;
}
+// --- Simple network I/O ------------------------------------------------------
+
+// TODO: move to liberty and remove from dwmstatus.c as well
+
+#define SOCKET_IO_OVERFLOW (8 << 20) ///< How large a read buffer can be
+
+enum socket_io_result
+{
+ SOCKET_IO_OK, ///< Completed successfully
+ SOCKET_IO_EOF, ///< Connection shut down by peer
+ SOCKET_IO_ERROR ///< Connection error
+};
+
+static enum socket_io_result
+socket_io_try_read (int socket_fd, struct str *rb, struct error **e)
+{
+ // We allow buffering of a fair amount of data, however within reason,
+ // so that it's not so easy to flood us and cause an allocation failure
+ ssize_t n_read;
+ while (rb->len < SOCKET_IO_OVERFLOW)
+ {
+ str_ensure_space (rb, 4096);
+ n_read = recv (socket_fd, rb->str + rb->len,
+ rb->alloc - rb->len - 1 /* null byte */, 0);
+
+ if (n_read > 0)
+ {
+ rb->str[rb->len += n_read] = '\0';
+ continue;
+ }
+ if (n_read == 0)
+ return SOCKET_IO_EOF;
+
+ if (errno == EAGAIN)
+ return SOCKET_IO_OK;
+ if (errno == EINTR)
+ continue;
+
+ error_set (e, "%s", strerror (errno));
+ return SOCKET_IO_ERROR;
+ }
+ return SOCKET_IO_OK;
+}
+
+static enum socket_io_result
+socket_io_try_write (int socket_fd, struct str *wb, struct error **e)
+{
+ ssize_t n_written;
+ while (wb->len)
+ {
+ n_written = send (socket_fd, wb->str, wb->len, 0);
+ if (n_written >= 0)
+ {
+ str_remove_slice (wb, 0, n_written);
+ continue;
+ }
+
+ if (errno == EAGAIN)
+ return SOCKET_IO_OK;
+ if (errno == EINTR)
+ continue;
+
+ error_set (e, "%s", strerror (errno));
+ return SOCKET_IO_ERROR;
+ }
+ return SOCKET_IO_OK;
+}
+
// --- Logging -----------------------------------------------------------------
static void
diff --git a/degesch.c b/degesch.c
index 4129e07..e1ec751 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1139,13 +1139,6 @@ REF_COUNTABLE_METHODS (buffer)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-enum transport_io_result
-{
- TRANSPORT_IO_OK = 0, ///< Completed successfully
- TRANSPORT_IO_EOF, ///< Connection shut down by peer
- TRANSPORT_IO_ERROR ///< Connection error
-};
-
// The only real purpose of this is to abstract away TLS
struct transport
{
@@ -1155,9 +1148,9 @@ struct transport
void (*cleanup) (struct server *s);
/// The underlying socket may have become readable, update `read_buffer'
- enum transport_io_result (*try_read) (struct server *s);
+ enum socket_io_result (*try_read) (struct server *s);
/// The underlying socket may have become writeable, flush `write_buffer'
- enum transport_io_result (*try_write) (struct server *s);
+ enum socket_io_result (*try_write) (struct server *s);
/// Return event mask to use in the poller
int (*get_poll_events) (struct server *s);
@@ -4219,27 +4212,27 @@ irc_process_buffer_custom (struct server *s, struct str *buf)
str_remove_slice (buf, 0, start - buf->str);
}
-static enum transport_io_result
+static enum socket_io_result
irc_try_read (struct server *s)
{
- enum transport_io_result result = s->transport->try_read (s);
+ enum socket_io_result result = s->transport->try_read (s);
if (s->read_buffer.len >= (1 << 20))
{
// XXX: this is stupid; if anything, count it in dependence of time
log_server_error (s, s->buffer,
"The IRC server seems to spew out data frantically");
- return TRANSPORT_IO_ERROR;
+ return SOCKET_IO_ERROR;
}
if (s->read_buffer.len)
irc_process_buffer_custom (s, &s->read_buffer);
return result;
}
-static enum transport_io_result
+static enum socket_io_result
irc_try_write (struct server *s)
{
- enum transport_io_result result = s->transport->try_write (s);
- if (result == TRANSPORT_IO_OK)
+ enum socket_io_result result = s->transport->try_write (s);
+ if (result == SOCKET_IO_OK)
{
// If we're flushing the write buffer and our job is complete, we send
// an EOF to the server, changing the state to IRC_HALF_CLOSED
@@ -4252,10 +4245,10 @@ irc_try_write (struct server *s)
static bool
irc_try_read_write (struct server *s)
{
- enum transport_io_result read_result;
- enum transport_io_result write_result;
- if ((read_result = irc_try_read (s)) == TRANSPORT_IO_ERROR
- || (write_result = irc_try_write (s)) == TRANSPORT_IO_ERROR)
+ enum socket_io_result read_result;
+ enum socket_io_result write_result;
+ if ((read_result = irc_try_read (s)) == SOCKET_IO_ERROR
+ || (write_result = irc_try_write (s)) == SOCKET_IO_ERROR)
{
log_server_error (s, s->buffer, "Server connection failed");
return false;
@@ -4263,15 +4256,15 @@ irc_try_read_write (struct server *s)
// FIXME: this may probably fire multiple times when we're flushing,
// we should probably store a flag next to the state
- if (read_result == TRANSPORT_IO_EOF
- || write_result == TRANSPORT_IO_EOF)
+ if (read_result == SOCKET_IO_EOF
+ || write_result == SOCKET_IO_EOF)
log_server_error (s, s->buffer, "Server closed the connection");
// If the write needs to read and we receive an EOF, we can't flush
- if (write_result == TRANSPORT_IO_EOF)
+ if (write_result == SOCKET_IO_EOF)
return false;
- if (read_result == TRANSPORT_IO_EOF)
+ if (read_result == SOCKET_IO_EOF)
{
// Eventually initiate shutdown to flush the write buffer
irc_shutdown (s);
@@ -4299,60 +4292,32 @@ on_irc_ready (const struct pollfd *pfd, struct server *s)
// --- Plain transport ---------------------------------------------------------
-static enum transport_io_result
+static enum socket_io_result
transport_plain_try_read (struct server *s)
{
- struct str *buf = &s->read_buffer;
- ssize_t n_read;
-
- while (true)
+ struct error *e = NULL;
+ enum socket_io_result result =
+ socket_io_try_read (s->socket, &s->read_buffer, &e);
+ if (e)
{
- str_ensure_space (buf, 512);
- n_read = recv (s->socket, buf->str + buf->len,
- buf->alloc - buf->len - 1 /* null byte */, 0);
-
- if (n_read > 0)
- {
- buf->str[buf->len += n_read] = '\0';
- continue;
- }
- if (n_read == 0)
- return TRANSPORT_IO_EOF;
-
- if (errno == EAGAIN)
- return TRANSPORT_IO_OK;
- if (errno == EINTR)
- continue;
-
- LOG_LIBC_FAILURE ("recv");
- return TRANSPORT_IO_ERROR;
+ print_debug ("%s: %s", __func__, e->message);
+ error_free (e);
}
+ return result;
}
-static enum transport_io_result
+static enum socket_io_result
transport_plain_try_write (struct server *s)
{
- struct str *buf = &s->write_buffer;
- ssize_t n_written;
-
- while (buf->len)
+ struct error *e = NULL;
+ enum socket_io_result result =
+ socket_io_try_write (s->socket, &s->write_buffer, &e);
+ if (e)
{
- n_written = send (s->socket, buf->str, buf->len, 0);
- if (n_written >= 0)
- {
- str_remove_slice (buf, 0, n_written);
- continue;
- }
-
- if (errno == EAGAIN)
- return TRANSPORT_IO_OK;
- if (errno == EINTR)
- continue;
-
- LOG_LIBC_FAILURE ("send");
- return TRANSPORT_IO_ERROR;
+ print_debug ("%s: %s", __func__, e->message);
+ error_free (e);
}
- return TRANSPORT_IO_OK;
+ return result;
}
static int
@@ -4564,12 +4529,12 @@ transport_tls_cleanup (struct server *s)
free (data);
}
-static enum transport_io_result
+static enum socket_io_result
transport_tls_try_read (struct server *s)
{
struct transport_tls_data *data = s->transport_data;
if (data->ssl_tx_want_rx)
- return TRANSPORT_IO_OK;
+ return SOCKET_IO_OK;
struct str *buf = &s->read_buffer;
data->ssl_rx_want_tx = false;
@@ -4587,27 +4552,27 @@ transport_tls_try_read (struct server *s)
buf->str[buf->len += n_read] = '\0';
continue;
case SSL_ERROR_ZERO_RETURN:
- return TRANSPORT_IO_EOF;
+ return SOCKET_IO_EOF;
case SSL_ERROR_WANT_READ:
- return TRANSPORT_IO_OK;
+ return SOCKET_IO_OK;
case SSL_ERROR_WANT_WRITE:
data->ssl_rx_want_tx = true;
- return TRANSPORT_IO_OK;
+ return SOCKET_IO_OK;
case XSSL_ERROR_TRY_AGAIN:
continue;
default:
LOG_FUNC_FAILURE ("SSL_read", error_info);
- return TRANSPORT_IO_ERROR;
+ return SOCKET_IO_ERROR;
}
}
}
-static enum transport_io_result
+static enum socket_io_result
transport_tls_try_write (struct server *s)
{
struct transport_tls_data *data = s->transport_data;
if (data->ssl_rx_want_tx)
- return TRANSPORT_IO_OK;
+ return SOCKET_IO_OK;
struct str *buf = &s->write_buffer;
data->ssl_tx_want_rx = false;
@@ -4623,20 +4588,20 @@ transport_tls_try_write (struct server *s)
str_remove_slice (buf, 0, n_written);
continue;
case SSL_ERROR_ZERO_RETURN:
- return TRANSPORT_IO_EOF;
+ return SOCKET_IO_EOF;
case SSL_ERROR_WANT_WRITE:
- return TRANSPORT_IO_OK;
+ return SOCKET_IO_OK;
case SSL_ERROR_WANT_READ:
data->ssl_tx_want_rx = true;
- return TRANSPORT_IO_OK;
+ return SOCKET_IO_OK;
case XSSL_ERROR_TRY_AGAIN:
continue;
default:
LOG_FUNC_FAILURE ("SSL_write", error_info);
- return TRANSPORT_IO_ERROR;
+ return SOCKET_IO_ERROR;
}
}
- return TRANSPORT_IO_OK;
+ return SOCKET_IO_OK;
}
static int
--
cgit v1.2.3-70-g09d2