Factor out socket_io_try_{read,write}()
To be reused in Lua connection API.
This commit is contained in:
parent
a5ac0d24b8
commit
376bbea249
68
common.c
68
common.c
|
@ -95,6 +95,74 @@ xwrite (int fd, const char *data, size_t len, struct error **e)
|
||||||
return true;
|
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 -----------------------------------------------------------------
|
// --- Logging -----------------------------------------------------------------
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
125
degesch.c
125
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
|
// The only real purpose of this is to abstract away TLS
|
||||||
struct transport
|
struct transport
|
||||||
{
|
{
|
||||||
|
@ -1155,9 +1148,9 @@ struct transport
|
||||||
void (*cleanup) (struct server *s);
|
void (*cleanup) (struct server *s);
|
||||||
|
|
||||||
/// The underlying socket may have become readable, update `read_buffer'
|
/// 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'
|
/// 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
|
/// Return event mask to use in the poller
|
||||||
int (*get_poll_events) (struct server *s);
|
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);
|
str_remove_slice (buf, 0, start - buf->str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum transport_io_result
|
static enum socket_io_result
|
||||||
irc_try_read (struct server *s)
|
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))
|
if (s->read_buffer.len >= (1 << 20))
|
||||||
{
|
{
|
||||||
// XXX: this is stupid; if anything, count it in dependence of time
|
// XXX: this is stupid; if anything, count it in dependence of time
|
||||||
log_server_error (s, s->buffer,
|
log_server_error (s, s->buffer,
|
||||||
"The IRC server seems to spew out data frantically");
|
"The IRC server seems to spew out data frantically");
|
||||||
return TRANSPORT_IO_ERROR;
|
return SOCKET_IO_ERROR;
|
||||||
}
|
}
|
||||||
if (s->read_buffer.len)
|
if (s->read_buffer.len)
|
||||||
irc_process_buffer_custom (s, &s->read_buffer);
|
irc_process_buffer_custom (s, &s->read_buffer);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum transport_io_result
|
static enum socket_io_result
|
||||||
irc_try_write (struct server *s)
|
irc_try_write (struct server *s)
|
||||||
{
|
{
|
||||||
enum transport_io_result result = s->transport->try_write (s);
|
enum socket_io_result result = s->transport->try_write (s);
|
||||||
if (result == TRANSPORT_IO_OK)
|
if (result == SOCKET_IO_OK)
|
||||||
{
|
{
|
||||||
// If we're flushing the write buffer and our job is complete, we send
|
// 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
|
// an EOF to the server, changing the state to IRC_HALF_CLOSED
|
||||||
|
@ -4252,10 +4245,10 @@ irc_try_write (struct server *s)
|
||||||
static bool
|
static bool
|
||||||
irc_try_read_write (struct server *s)
|
irc_try_read_write (struct server *s)
|
||||||
{
|
{
|
||||||
enum transport_io_result read_result;
|
enum socket_io_result read_result;
|
||||||
enum transport_io_result write_result;
|
enum socket_io_result write_result;
|
||||||
if ((read_result = irc_try_read (s)) == TRANSPORT_IO_ERROR
|
if ((read_result = irc_try_read (s)) == SOCKET_IO_ERROR
|
||||||
|| (write_result = irc_try_write (s)) == TRANSPORT_IO_ERROR)
|
|| (write_result = irc_try_write (s)) == SOCKET_IO_ERROR)
|
||||||
{
|
{
|
||||||
log_server_error (s, s->buffer, "Server connection failed");
|
log_server_error (s, s->buffer, "Server connection failed");
|
||||||
return false;
|
return false;
|
||||||
|
@ -4263,15 +4256,15 @@ irc_try_read_write (struct server *s)
|
||||||
|
|
||||||
// FIXME: this may probably fire multiple times when we're flushing,
|
// FIXME: this may probably fire multiple times when we're flushing,
|
||||||
// we should probably store a flag next to the state
|
// we should probably store a flag next to the state
|
||||||
if (read_result == TRANSPORT_IO_EOF
|
if (read_result == SOCKET_IO_EOF
|
||||||
|| write_result == TRANSPORT_IO_EOF)
|
|| write_result == SOCKET_IO_EOF)
|
||||||
log_server_error (s, s->buffer, "Server closed the connection");
|
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 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;
|
return false;
|
||||||
|
|
||||||
if (read_result == TRANSPORT_IO_EOF)
|
if (read_result == SOCKET_IO_EOF)
|
||||||
{
|
{
|
||||||
// Eventually initiate shutdown to flush the write buffer
|
// Eventually initiate shutdown to flush the write buffer
|
||||||
irc_shutdown (s);
|
irc_shutdown (s);
|
||||||
|
@ -4299,60 +4292,32 @@ on_irc_ready (const struct pollfd *pfd, struct server *s)
|
||||||
|
|
||||||
// --- Plain transport ---------------------------------------------------------
|
// --- Plain transport ---------------------------------------------------------
|
||||||
|
|
||||||
static enum transport_io_result
|
static enum socket_io_result
|
||||||
transport_plain_try_read (struct server *s)
|
transport_plain_try_read (struct server *s)
|
||||||
{
|
{
|
||||||
struct str *buf = &s->read_buffer;
|
struct error *e = NULL;
|
||||||
ssize_t n_read;
|
enum socket_io_result result =
|
||||||
|
socket_io_try_read (s->socket, &s->read_buffer, &e);
|
||||||
while (true)
|
if (e)
|
||||||
{
|
{
|
||||||
str_ensure_space (buf, 512);
|
print_debug ("%s: %s", __func__, e->message);
|
||||||
n_read = recv (s->socket, buf->str + buf->len,
|
error_free (e);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum transport_io_result
|
static enum socket_io_result
|
||||||
transport_plain_try_write (struct server *s)
|
transport_plain_try_write (struct server *s)
|
||||||
{
|
{
|
||||||
struct str *buf = &s->write_buffer;
|
struct error *e = NULL;
|
||||||
ssize_t n_written;
|
enum socket_io_result result =
|
||||||
|
socket_io_try_write (s->socket, &s->write_buffer, &e);
|
||||||
while (buf->len)
|
if (e)
|
||||||
{
|
{
|
||||||
n_written = send (s->socket, buf->str, buf->len, 0);
|
print_debug ("%s: %s", __func__, e->message);
|
||||||
if (n_written >= 0)
|
error_free (e);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return TRANSPORT_IO_OK;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -4564,12 +4529,12 @@ transport_tls_cleanup (struct server *s)
|
||||||
free (data);
|
free (data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum transport_io_result
|
static enum socket_io_result
|
||||||
transport_tls_try_read (struct server *s)
|
transport_tls_try_read (struct server *s)
|
||||||
{
|
{
|
||||||
struct transport_tls_data *data = s->transport_data;
|
struct transport_tls_data *data = s->transport_data;
|
||||||
if (data->ssl_tx_want_rx)
|
if (data->ssl_tx_want_rx)
|
||||||
return TRANSPORT_IO_OK;
|
return SOCKET_IO_OK;
|
||||||
|
|
||||||
struct str *buf = &s->read_buffer;
|
struct str *buf = &s->read_buffer;
|
||||||
data->ssl_rx_want_tx = false;
|
data->ssl_rx_want_tx = false;
|
||||||
|
@ -4587,27 +4552,27 @@ transport_tls_try_read (struct server *s)
|
||||||
buf->str[buf->len += n_read] = '\0';
|
buf->str[buf->len += n_read] = '\0';
|
||||||
continue;
|
continue;
|
||||||
case SSL_ERROR_ZERO_RETURN:
|
case SSL_ERROR_ZERO_RETURN:
|
||||||
return TRANSPORT_IO_EOF;
|
return SOCKET_IO_EOF;
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
return TRANSPORT_IO_OK;
|
return SOCKET_IO_OK;
|
||||||
case SSL_ERROR_WANT_WRITE:
|
case SSL_ERROR_WANT_WRITE:
|
||||||
data->ssl_rx_want_tx = true;
|
data->ssl_rx_want_tx = true;
|
||||||
return TRANSPORT_IO_OK;
|
return SOCKET_IO_OK;
|
||||||
case XSSL_ERROR_TRY_AGAIN:
|
case XSSL_ERROR_TRY_AGAIN:
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
LOG_FUNC_FAILURE ("SSL_read", error_info);
|
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)
|
transport_tls_try_write (struct server *s)
|
||||||
{
|
{
|
||||||
struct transport_tls_data *data = s->transport_data;
|
struct transport_tls_data *data = s->transport_data;
|
||||||
if (data->ssl_rx_want_tx)
|
if (data->ssl_rx_want_tx)
|
||||||
return TRANSPORT_IO_OK;
|
return SOCKET_IO_OK;
|
||||||
|
|
||||||
struct str *buf = &s->write_buffer;
|
struct str *buf = &s->write_buffer;
|
||||||
data->ssl_tx_want_rx = false;
|
data->ssl_tx_want_rx = false;
|
||||||
|
@ -4623,20 +4588,20 @@ transport_tls_try_write (struct server *s)
|
||||||
str_remove_slice (buf, 0, n_written);
|
str_remove_slice (buf, 0, n_written);
|
||||||
continue;
|
continue;
|
||||||
case SSL_ERROR_ZERO_RETURN:
|
case SSL_ERROR_ZERO_RETURN:
|
||||||
return TRANSPORT_IO_EOF;
|
return SOCKET_IO_EOF;
|
||||||
case SSL_ERROR_WANT_WRITE:
|
case SSL_ERROR_WANT_WRITE:
|
||||||
return TRANSPORT_IO_OK;
|
return SOCKET_IO_OK;
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
data->ssl_tx_want_rx = true;
|
data->ssl_tx_want_rx = true;
|
||||||
return TRANSPORT_IO_OK;
|
return SOCKET_IO_OK;
|
||||||
case XSSL_ERROR_TRY_AGAIN:
|
case XSSL_ERROR_TRY_AGAIN:
|
||||||
continue;
|
continue;
|
||||||
default:
|
default:
|
||||||
LOG_FUNC_FAILURE ("SSL_write", error_info);
|
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
|
static int
|
||||||
|
|
Loading…
Reference in New Issue