Merge branch 'buf_for_stringbuffer_squashed'

This commit is contained in:
Nick Mathewson
2017-11-02 10:01:30 -04:00
7 changed files with 197 additions and 79 deletions
+93 -37
View File
@@ -4047,6 +4047,68 @@ connection_flush(connection_t *conn)
return connection_handle_write(conn, 1);
}
/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf:
*
* Return true iff it is okay to queue bytes on <b>conn</b>'s outbuf for
* writing.
*/
static int
connection_may_write_to_buf(connection_t *conn)
{
/* if it's marked for close, only allow write if we mean to flush it */
if (conn->marked_for_close && !conn->hold_open_until_flushed)
return 0;
return 1;
}
/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf:
*
* Called when an attempt to add bytes on <b>conn</b>'s outbuf has failed;
* mark the connection and warn as appropriate.
*/
static void
connection_write_to_buf_failed(connection_t *conn)
{
if (CONN_IS_EDGE(conn)) {
/* if it failed, it means we have our package/delivery windows set
wrong compared to our max outbuf size. close the whole circuit. */
log_warn(LD_NET,
"write_to_buf failed. Closing circuit (fd %d).", (int)conn->s);
circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)),
END_CIRC_REASON_INTERNAL);
} else if (conn->type == CONN_TYPE_OR) {
or_connection_t *orconn = TO_OR_CONN(conn);
log_warn(LD_NET,
"write_to_buf failed on an orconn; notifying of error "
"(fd %d)", (int)(conn->s));
connection_or_close_for_error(orconn, 0);
} else {
log_warn(LD_NET,
"write_to_buf failed. Closing connection (fd %d).",
(int)conn->s);
connection_mark_for_close(conn);
}
}
/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf:
*
* Called when an attempt to add bytes on <b>conn</b>'s outbuf has succeeded:
* record the number of bytes added.
*/
static void
connection_write_to_buf_commit(connection_t *conn, size_t len)
{
/* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING
* state, we don't want to try to write it right away, since
* conn->write_event won't be set yet. Otherwise, write data from
* this conn as the socket is available. */
if (conn->write_event) {
connection_start_writing(conn);
}
conn->outbuf_flushlen += len;
}
/** Append <b>len</b> bytes of <b>string</b> onto <b>conn</b>'s
* outbuf, and ask it to start writing.
*
@@ -4061,58 +4123,52 @@ connection_write_to_buf_impl_,(const char *string, size_t len,
{
/* XXXX This function really needs to return -1 on failure. */
int r;
size_t old_datalen;
if (!len && !(zlib<0))
return;
/* if it's marked for close, only allow write if we mean to flush it */
if (conn->marked_for_close && !conn->hold_open_until_flushed)
if (!connection_may_write_to_buf(conn))
return;
old_datalen = buf_datalen(conn->outbuf);
size_t written;
if (zlib) {
size_t old_datalen = buf_datalen(conn->outbuf);
dir_connection_t *dir_conn = TO_DIR_CONN(conn);
int done = zlib < 0;
CONN_LOG_PROTECT(conn, r = buf_add_compress(conn->outbuf,
dir_conn->compress_state,
string, len, done));
dir_conn->compress_state,
string, len, done));
written = buf_datalen(conn->outbuf) - old_datalen;
} else {
CONN_LOG_PROTECT(conn, r = buf_add(conn->outbuf, string, len));
written = len;
}
if (r < 0) {
if (CONN_IS_EDGE(conn)) {
/* if it failed, it means we have our package/delivery windows set
wrong compared to our max outbuf size. close the whole circuit. */
log_warn(LD_NET,
"write_to_buf failed. Closing circuit (fd %d).", (int)conn->s);
circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)),
END_CIRC_REASON_INTERNAL);
} else if (conn->type == CONN_TYPE_OR) {
or_connection_t *orconn = TO_OR_CONN(conn);
log_warn(LD_NET,
"write_to_buf failed on an orconn; notifying of error "
"(fd %d)", (int)(conn->s));
connection_or_close_for_error(orconn, 0);
} else {
log_warn(LD_NET,
"write_to_buf failed. Closing connection (fd %d).",
(int)conn->s);
connection_mark_for_close(conn);
}
connection_write_to_buf_failed(conn);
return;
}
connection_write_to_buf_commit(conn, written);
}
/* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING
* state, we don't want to try to write it right away, since
* conn->write_event won't be set yet. Otherwise, write data from
* this conn as the socket is available. */
if (conn->write_event) {
connection_start_writing(conn);
}
if (zlib) {
conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen;
} else {
conn->outbuf_flushlen += len;
}
/**
* Add all bytes from <b>buf</b> to <b>conn</b>'s outbuf, draining them
* from <b>buf</b>. (If the connection is marked and will soon be closed,
* nothing is drained.)
*/
void
connection_buf_add_buf(connection_t *conn, buf_t *buf)
{
tor_assert(conn);
tor_assert(buf);
size_t len = buf_datalen(buf);
if (len == 0)
return;
if (!connection_may_write_to_buf(conn))
return;
buf_move_all(conn->outbuf, buf);
connection_write_to_buf_commit(conn, len);
}
#define CONN_GET_ALL_TEMPLATE(var, test) \
+1
View File
@@ -156,6 +156,7 @@ connection_buf_add_compress(const char *string, size_t len,
{
connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1);
}
void connection_buf_add_buf(connection_t *conn, buf_t *buf);
/* DOCDOC connection_get_inbuf_len */
static size_t connection_get_inbuf_len(connection_t *conn);
+14 -30
View File
@@ -3515,63 +3515,47 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
long cache_lifetime)
{
char date[RFC1123_TIME_LEN+1];
char tmp[1024];
char *cp;
time_t now = time(NULL);
buf_t *buf = buf_new_with_capacity(1024);
tor_assert(conn);
format_rfc1123_time(date, now);
cp = tmp;
tor_snprintf(cp, sizeof(tmp),
"HTTP/1.0 200 OK\r\nDate: %s\r\n",
date);
cp += strlen(tmp);
buf_add_printf(buf, "HTTP/1.0 200 OK\r\nDate: %s\r\n", date);
if (type) {
tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type);
cp += strlen(cp);
buf_add_printf(buf, "Content-Type: %s\r\n", type);
}
if (!is_local_addr(&conn->base_.addr)) {
/* Don't report the source address for a nearby/private connection.
* Otherwise we tend to mis-report in cases where incoming ports are
* being forwarded to a Tor server running behind the firewall. */
tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
X_ADDRESS_HEADER "%s\r\n", conn->base_.address);
cp += strlen(cp);
buf_add_printf(buf, X_ADDRESS_HEADER "%s\r\n", conn->base_.address);
}
if (encoding) {
tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
"Content-Encoding: %s\r\n", encoding);
cp += strlen(cp);
buf_add_printf(buf, "Content-Encoding: %s\r\n", encoding);
}
if (length >= 0) {
tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
"Content-Length: %ld\r\n", (long)length);
cp += strlen(cp);
buf_add_printf(buf, "Content-Length: %ld\r\n", (long)length);
}
if (cache_lifetime > 0) {
char expbuf[RFC1123_TIME_LEN+1];
format_rfc1123_time(expbuf, (time_t)(now + cache_lifetime));
/* We could say 'Cache-control: max-age=%d' here if we start doing
* http/1.1 */
tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
"Expires: %s\r\n", expbuf);
cp += strlen(cp);
buf_add_printf(buf, "Expires: %s\r\n", expbuf);
} else if (cache_lifetime == 0) {
/* We could say 'Cache-control: no-cache' here if we start doing
* http/1.1 */
strlcpy(cp, "Pragma: no-cache\r\n", sizeof(tmp)-(cp-tmp));
cp += strlen(cp);
buf_add_string(buf, "Pragma: no-cache\r\n");
}
if (extra_headers) {
strlcpy(cp, extra_headers, sizeof(tmp)-(cp-tmp));
cp += strlen(cp);
buf_add_string(buf, extra_headers);
}
if (sizeof(tmp)-(cp-tmp) > 3)
memcpy(cp, "\r\n", 3);
else
tor_assert(0);
connection_buf_add(tmp, strlen(tmp), TO_CONN(conn));
buf_add_string(buf, "\r\n");
connection_buf_add_buf(TO_CONN(conn), buf);
buf_free(buf);
}
/** As write_http_response_header_impl, but sets encoding and content-typed
+10 -12
View File
@@ -30,6 +30,7 @@
#define GEOIP_PRIVATE
#include "or.h"
#include "ht.h"
#include "buffers.h"
#include "config.h"
#include "control.h"
#include "dnsserv.h"
@@ -930,9 +931,9 @@ static char *
geoip_get_dirreq_history(dirreq_type_t type)
{
char *result = NULL;
buf_t *buf = NULL;
smartlist_t *dirreq_completed = NULL;
uint32_t complete = 0, timeouts = 0, running = 0;
int bufsize = 1024, written;
dirreq_map_entry_t **ptr, **next;
struct timeval now;
@@ -965,13 +966,9 @@ geoip_get_dirreq_history(dirreq_type_t type)
DIR_REQ_GRANULARITY);
running = round_uint32_to_next_multiple_of(running,
DIR_REQ_GRANULARITY);
result = tor_malloc_zero(bufsize);
written = tor_snprintf(result, bufsize, "complete=%u,timeout=%u,"
"running=%u", complete, timeouts, running);
if (written < 0) {
tor_free(result);
goto done;
}
buf = buf_new_with_capacity(1024);
buf_add_printf(buf, "complete=%u,timeout=%u,"
"running=%u", complete, timeouts, running);
#define MIN_DIR_REQ_RESPONSES 16
if (complete >= MIN_DIR_REQ_RESPONSES) {
@@ -992,7 +989,7 @@ geoip_get_dirreq_history(dirreq_type_t type)
dltimes[ent_sl_idx] = bytes_per_second;
} SMARTLIST_FOREACH_END(ent);
median_uint32(dltimes, complete); /* sorts as a side effect. */
written = tor_snprintf(result + written, bufsize - written,
buf_add_printf(buf,
",min=%u,d1=%u,d2=%u,q1=%u,d3=%u,d4=%u,md=%u,"
"d6=%u,d7=%u,q3=%u,d8=%u,d9=%u,max=%u",
dltimes[0],
@@ -1008,14 +1005,15 @@ geoip_get_dirreq_history(dirreq_type_t type)
dltimes[8*complete/10-1],
dltimes[9*complete/10-1],
dltimes[complete-1]);
if (written<0)
tor_free(result);
tor_free(dltimes);
}
done:
result = buf_extract(buf, NULL);
SMARTLIST_FOREACH(dirreq_completed, dirreq_map_entry_t *, ent,
tor_free(ent));
smartlist_free(dirreq_completed);
buf_free(buf);
return result;
}