Browse Source

mv funcs from connections.c to connections-glue.c

connection_handle_read()
connection_handle_read_ssl()
connection_handle_read_post_state()

no code changes besides making connection_handle_read() public
(by removing 'static' and adding to connections.h)
personal/stbuehler/mod-csrf-old
Glenn Strauss 6 years ago
parent
commit
635ab6f802
  1. 322
      src/connections-glue.c
  2. 316
      src/connections.c
  3. 1
      src/connections.h

322
src/connections-glue.c

@ -2,6 +2,13 @@
#include "base.h"
#include "connections.h"
#include "joblist.h"
#include "log.h"
#ifdef USE_OPENSSL
# include <openssl/ssl.h>
# include <openssl/err.h>
#endif
const char *connection_get_state(connection_state_t state) {
switch (state) {
@ -45,3 +52,318 @@ int connection_set_state(server *srv, connection *con, connection_state_t state)
return 0;
}
#if 0
static void dump_packet(const unsigned char *data, size_t len) {
size_t i, j;
if (len == 0) return;
for (i = 0; i < len; i++) {
if (i % 16 == 0) fprintf(stderr, " ");
fprintf(stderr, "%02x ", data[i]);
if ((i + 1) % 16 == 0) {
fprintf(stderr, " ");
for (j = 0; j <= i % 16; j++) {
unsigned char c;
if (i-15+j >= len) break;
c = data[i-15+j];
fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
}
fprintf(stderr, "\n");
}
}
if (len % 16 != 0) {
for (j = i % 16; j < 16; j++) {
fprintf(stderr, " ");
}
fprintf(stderr, " ");
for (j = i & ~0xf; j < len; j++) {
unsigned char c;
c = data[j];
fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
}
fprintf(stderr, "\n");
}
}
#endif
static int connection_handle_read_ssl(server *srv, connection *con) {
#ifdef USE_OPENSSL
int r, ssl_err, len, count = 0;
char *mem = NULL;
size_t mem_len = 0;
if (!con->srv_socket->is_ssl) return -1;
ERR_clear_error();
do {
chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, SSL_pending(con->ssl));
#if 0
/* overwrite everything with 0 */
memset(mem, 0, mem_len);
#endif
len = SSL_read(con->ssl, mem, mem_len);
chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
connection_set_state(srv, con, CON_STATE_ERROR);
return -1;
}
if (len > 0) {
con->bytes_read += len;
count += len;
}
} while (len == (ssize_t) mem_len && count < MAX_READ_LIMIT);
if (len < 0) {
int oerrno = errno;
switch ((r = SSL_get_error(con->ssl, len))) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
con->is_readable = 0;
/* the manual says we have to call SSL_read with the same arguments next time.
* we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway.
*/
return 0;
case SSL_ERROR_SYSCALL:
/**
* man SSL_get_error()
*
* SSL_ERROR_SYSCALL
* Some I/O error occurred. The OpenSSL error queue may contain more
* information on the error. If the error queue is empty (i.e.
* ERR_get_error() returns 0), ret can be used to find out more about
* the error: If ret == 0, an EOF was observed that violates the
* protocol. If ret == -1, the underlying BIO reported an I/O error
* (for socket I/O on Unix systems, consult errno for details).
*
*/
while((ssl_err = ERR_get_error())) {
/* get all errors from the error-queue */
log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
r, ERR_error_string(ssl_err, NULL));
}
switch(oerrno) {
default:
log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
len, r, oerrno,
strerror(oerrno));
break;
}
break;
case SSL_ERROR_ZERO_RETURN:
/* clean shutdown on the remote side */
if (r == 0) {
/* FIXME: later */
}
/* fall thourgh */
default:
while((ssl_err = ERR_get_error())) {
switch (ERR_GET_REASON(ssl_err)) {
case SSL_R_SSL_HANDSHAKE_FAILURE:
case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
if (!con->conf.log_ssl_noise) continue;
break;
default:
break;
}
/* get all errors from the error-queue */
log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
r, ERR_error_string(ssl_err, NULL));
}
break;
}
connection_set_state(srv, con, CON_STATE_ERROR);
return -1;
} else if (len == 0) {
con->is_readable = 0;
/* the other end close the connection -> KEEP-ALIVE */
return -2;
} else {
joblist_append(srv, con);
}
return 0;
#else
UNUSED(srv);
UNUSED(con);
return -1;
#endif
}
/* 0: everything ok, -1: error, -2: con closed */
int connection_handle_read(server *srv, connection *con) {
int len;
char *mem = NULL;
size_t mem_len = 0;
int toread;
if (con->srv_socket->is_ssl) {
return connection_handle_read_ssl(srv, con);
}
/* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
* us more than 4kb is available
* if FIONREAD doesn't signal a big chunk we fill the previous buffer
* if it has >= 1kb free
*/
#if defined(__WIN32)
chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, 4096);
len = recv(con->fd, mem, mem_len, 0);
#else /* __WIN32 */
if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
toread = 4096;
}
else if (toread > MAX_READ_LIMIT) {
toread = MAX_READ_LIMIT;
}
chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, toread);
len = read(con->fd, mem, mem_len);
#endif /* __WIN32 */
chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
if (len < 0) {
con->is_readable = 0;
#if defined(__WIN32)
{
int lastError = WSAGetLastError();
switch (lastError) {
case EAGAIN:
return 0;
case EINTR:
/* we have been interrupted before we could read */
con->is_readable = 1;
return 0;
case ECONNRESET:
/* suppress logging for this error, expected for keep-alive */
break;
default:
log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - recv failed: ", lastError);
break;
}
}
#else /* __WIN32 */
switch (errno) {
case EAGAIN:
return 0;
case EINTR:
/* we have been interrupted before we could read */
con->is_readable = 1;
return 0;
case ECONNRESET:
/* suppress logging for this error, expected for keep-alive */
break;
default:
log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
break;
}
#endif /* __WIN32 */
connection_set_state(srv, con, CON_STATE_ERROR);
return -1;
} else if (len == 0) {
con->is_readable = 0;
/* the other end close the connection -> KEEP-ALIVE */
/* pipelining */
return -2;
} else if (len != (ssize_t) mem_len) {
/* we got less then expected, wait for the next fd-event */
con->is_readable = 0;
}
con->bytes_read += len;
#if 0
dump_packet(b->ptr, len);
#endif
return 0;
}
handler_t connection_handle_read_post_state(server *srv, connection *con) {
chunkqueue *cq = con->read_queue;
chunkqueue *dst_cq = con->request_content_queue;
int is_closed = 0;
if (con->is_readable) {
con->read_idle_ts = srv->cur_ts;
switch(connection_handle_read(srv, con)) {
case -1:
return HANDLER_ERROR;
case -2:
is_closed = 1;
break;
default:
break;
}
}
chunkqueue_remove_finished_chunks(cq);
if (con->request.content_length <= 64*1024) {
/* don't buffer request bodies <= 64k on disk */
chunkqueue_steal(dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in);
}
else if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in)) {
/* writing to temp file failed */
con->http_status = 500; /* Internal Server Error */
con->keep_alive = 0;
con->mode = DIRECT;
chunkqueue_reset(con->write_queue);
return HANDLER_FINISHED;
}
chunkqueue_remove_finished_chunks(cq);
if (dst_cq->bytes_in == (off_t)con->request.content_length) {
/* Content is ready */
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
return HANDLER_GO_ON;
} else if (is_closed) {
#if 0
con->http_status = 400; /* Bad Request */
con->keep_alive = 0;
con->mode = DIRECT;
chunkqueue_reset(con->write_queue);
return HANDLER_FINISHED;
#endif
return HANDLER_ERROR;
} else {
return HANDLER_WAIT_FOR_EVENT;
}
}

316
src/connections.c

@ -156,322 +156,6 @@ static int connection_close(server *srv, connection *con) {
return 0;
}
#if 0
static void dump_packet(const unsigned char *data, size_t len) {
size_t i, j;
if (len == 0) return;
for (i = 0; i < len; i++) {
if (i % 16 == 0) fprintf(stderr, " ");
fprintf(stderr, "%02x ", data[i]);
if ((i + 1) % 16 == 0) {
fprintf(stderr, " ");
for (j = 0; j <= i % 16; j++) {
unsigned char c;
if (i-15+j >= len) break;
c = data[i-15+j];
fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
}
fprintf(stderr, "\n");
}
}
if (len % 16 != 0) {
for (j = i % 16; j < 16; j++) {
fprintf(stderr, " ");
}
fprintf(stderr, " ");
for (j = i & ~0xf; j < len; j++) {
unsigned char c;
c = data[j];
fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
}
fprintf(stderr, "\n");
}
}
#endif
static int connection_handle_read_ssl(server *srv, connection *con) {
#ifdef USE_OPENSSL
int r, ssl_err, len, count = 0;
char *mem = NULL;
size_t mem_len = 0;
if (!con->srv_socket->is_ssl) return -1;
ERR_clear_error();
do {
chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, SSL_pending(con->ssl));
#if 0
/* overwrite everything with 0 */
memset(mem, 0, mem_len);
#endif
len = SSL_read(con->ssl, mem, mem_len);
chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
if (con->renegotiations > 1 && con->conf.ssl_disable_client_renegotiation) {
log_error_write(srv, __FILE__, __LINE__, "s", "SSL: renegotiation initiated by client, killing connection");
connection_set_state(srv, con, CON_STATE_ERROR);
return -1;
}
if (len > 0) {
con->bytes_read += len;
count += len;
}
} while (len == (ssize_t) mem_len && count < MAX_READ_LIMIT);
if (len < 0) {
int oerrno = errno;
switch ((r = SSL_get_error(con->ssl, len))) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
con->is_readable = 0;
/* the manual says we have to call SSL_read with the same arguments next time.
* we ignore this restriction; no one has complained about it in 1.5 yet, so it probably works anyway.
*/
return 0;
case SSL_ERROR_SYSCALL:
/**
* man SSL_get_error()
*
* SSL_ERROR_SYSCALL
* Some I/O error occurred. The OpenSSL error queue may contain more
* information on the error. If the error queue is empty (i.e.
* ERR_get_error() returns 0), ret can be used to find out more about
* the error: If ret == 0, an EOF was observed that violates the
* protocol. If ret == -1, the underlying BIO reported an I/O error
* (for socket I/O on Unix systems, consult errno for details).
*
*/
while((ssl_err = ERR_get_error())) {
/* get all errors from the error-queue */
log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
r, ERR_error_string(ssl_err, NULL));
}
switch(oerrno) {
default:
log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
len, r, oerrno,
strerror(oerrno));
break;
}
break;
case SSL_ERROR_ZERO_RETURN:
/* clean shutdown on the remote side */
if (r == 0) {
/* FIXME: later */
}
/* fall thourgh */
default:
while((ssl_err = ERR_get_error())) {
switch (ERR_GET_REASON(ssl_err)) {
case SSL_R_SSL_HANDSHAKE_FAILURE:
case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
if (!con->conf.log_ssl_noise) continue;
break;
default:
break;
}
/* get all errors from the error-queue */
log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
r, ERR_error_string(ssl_err, NULL));
}
break;
}
connection_set_state(srv, con, CON_STATE_ERROR);
return -1;
} else if (len == 0) {
con->is_readable = 0;
/* the other end close the connection -> KEEP-ALIVE */
return -2;
} else {
joblist_append(srv, con);
}
return 0;
#else
UNUSED(srv);
UNUSED(con);
return -1;
#endif
}
/* 0: everything ok, -1: error, -2: con closed */
static int connection_handle_read(server *srv, connection *con) {
int len;
char *mem = NULL;
size_t mem_len = 0;
int toread;
if (con->srv_socket->is_ssl) {
return connection_handle_read_ssl(srv, con);
}
/* default size for chunks is 4kb; only use bigger chunks if FIONREAD tells
* us more than 4kb is available
* if FIONREAD doesn't signal a big chunk we fill the previous buffer
* if it has >= 1kb free
*/
#if defined(__WIN32)
chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, 4096);
len = recv(con->fd, mem, mem_len, 0);
#else /* __WIN32 */
if (ioctl(con->fd, FIONREAD, &toread) || toread == 0 || toread <= 4*1024) {
toread = 4096;
}
else if (toread > MAX_READ_LIMIT) {
toread = MAX_READ_LIMIT;
}
chunkqueue_get_memory(con->read_queue, &mem, &mem_len, 0, toread);
len = read(con->fd, mem, mem_len);
#endif /* __WIN32 */
chunkqueue_use_memory(con->read_queue, len > 0 ? len : 0);
if (len < 0) {
con->is_readable = 0;
#if defined(__WIN32)
{
int lastError = WSAGetLastError();
switch (lastError) {
case EAGAIN:
return 0;
case EINTR:
/* we have been interrupted before we could read */
con->is_readable = 1;
return 0;
case ECONNRESET:
/* suppress logging for this error, expected for keep-alive */
break;
default:
log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - recv failed: ", lastError);
break;
}
}
#else /* __WIN32 */
switch (errno) {
case EAGAIN:
return 0;
case EINTR:
/* we have been interrupted before we could read */
con->is_readable = 1;
return 0;
case ECONNRESET:
/* suppress logging for this error, expected for keep-alive */
break;
default:
log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
break;
}
#endif /* __WIN32 */
connection_set_state(srv, con, CON_STATE_ERROR);
return -1;
} else if (len == 0) {
con->is_readable = 0;
/* the other end close the connection -> KEEP-ALIVE */
/* pipelining */
return -2;
} else if (len != (ssize_t) mem_len) {
/* we got less then expected, wait for the next fd-event */
con->is_readable = 0;
}
con->bytes_read += len;
#if 0
dump_packet(b->ptr, len);
#endif
return 0;
}
handler_t connection_handle_read_post_state(server *srv, connection *con) {
chunkqueue *cq = con->read_queue;
chunkqueue *dst_cq = con->request_content_queue;
int is_closed = 0;
if (con->is_readable) {
con->read_idle_ts = srv->cur_ts;
switch(connection_handle_read(srv, con)) {
case -1:
return HANDLER_ERROR;
case -2:
is_closed = 1;
break;
default:
break;
}
}
chunkqueue_remove_finished_chunks(cq);
if (con->request.content_length <= 64*1024) {
/* don't buffer request bodies <= 64k on disk */
chunkqueue_steal(dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in);
}
else if (0 != chunkqueue_steal_with_tempfiles(srv, dst_cq, cq, (off_t)con->request.content_length - dst_cq->bytes_in)) {
/* writing to temp file failed */
con->http_status = 500; /* Internal Server Error */
con->keep_alive = 0;
con->mode = DIRECT;
chunkqueue_reset(con->write_queue);
return HANDLER_FINISHED;
}
chunkqueue_remove_finished_chunks(cq);
if (dst_cq->bytes_in == (off_t)con->request.content_length) {
/* Content is ready */
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
return HANDLER_GO_ON;
} else if (is_closed) {
#if 0
con->http_status = 400; /* Bad Request */
con->keep_alive = 0;
con->mode = DIRECT;
chunkqueue_reset(con->write_queue);
return HANDLER_FINISHED;
#endif
return HANDLER_ERROR;
} else {
return HANDLER_WAIT_FOR_EVENT;
}
}
static void connection_handle_errdoc_init(connection *con) {
/* reset caching response headers potentially added by mod_expire */
data_string *ds;

1
src/connections.h

@ -15,6 +15,7 @@ int connection_set_state(server *srv, connection *con, connection_state_t state)
const char * connection_get_state(connection_state_t state);
const char * connection_get_short_state(connection_state_t state);
int connection_state_machine(server *srv, connection *con);
int connection_handle_read(server *srv, connection *con);
handler_t connection_handle_read_post_state(server *srv, connection *con);
#endif

Loading…
Cancel
Save