mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-22 14:23:04 +01:00
r12763@Kushana: nickm | 2007-04-20 18:42:58 -0400
Initial version of code to stop using socket pairs for linked connections. Superficially, it seems to work, but it probably needs a lot more testing and attention. svn:r9995
This commit is contained in:
parent
227b2e0226
commit
648065fcb4
9 changed files with 420 additions and 123 deletions
|
@ -21,6 +21,11 @@ Changes in version 0.2.0.1-alpha - 2007-??-??
|
|||
- Count the number of open sockets separately from the number of active
|
||||
connection_t objects. This will let us avoid underusing our
|
||||
allocated connection limit.
|
||||
- We no longer use socket pairs to link an edge connection to an
|
||||
anonymous directory connection. Instead, we track the link
|
||||
internally and transfer the data in-process. This saves two
|
||||
sockets per anonymous directory connection (at the client and at
|
||||
the server), and avoids the nasty Windows socketpair() workaround.
|
||||
|
||||
o Minor features (build):
|
||||
- Make autoconf search for libevent, openssl, and zlib consistently.
|
||||
|
|
50
doc/TODO
50
doc/TODO
|
@ -54,6 +54,19 @@ N . Document transport and natdport
|
|||
Things we'd like to do in 0.2.0.x:
|
||||
- Proposals:
|
||||
- 101: Voting on the Tor Directory System
|
||||
- Prepare ASAP for new voting formats
|
||||
- Don't flip out with warnings when voting-related URLs are
|
||||
uploaded/downloaded.
|
||||
- Finalize proposal
|
||||
- Get authorities voting
|
||||
- Implement parsing for new document formats
|
||||
- Code to generate votes
|
||||
- Code to generate consensus from a list of votes
|
||||
- Add a signature to a consensus.
|
||||
- Code to check signatures on a consensus
|
||||
- Push/pull documents as appropriate.
|
||||
- Start caching consensus documents once authorities make them
|
||||
- Start downloading and using consensus documents once caches serve them
|
||||
. 104: Long and Short Router Descriptors (by Jun 1)
|
||||
. Finalize proposal
|
||||
o Implement parsing for extra-info documents
|
||||
|
@ -109,14 +122,24 @@ Things we'd like to do in 0.2.0.x:
|
|||
to make sure that we call the event base dispatch function enough.)
|
||||
. Implement
|
||||
o Count connections and sockets separately
|
||||
- Allow connections with s == -1
|
||||
- Add a linked_conn field; it should get marked when we're marked.
|
||||
- Add a function to move bytes from buffer to buffer.
|
||||
- Have handle_read dtrt for linked connections
|
||||
- Have an activate/deactivate_linked_connection function.
|
||||
- Have activated functions added to a list on first activation, and
|
||||
. Allow connections with s == -1
|
||||
o Add a linked_conn field; it should get marked when we're marked.
|
||||
o Add a function to move bytes from buffer to buffer.
|
||||
o Have read_to_buf dtrt for linked connections
|
||||
o Have handle_read dtrt for linked connections
|
||||
o Have an activate/deactivate_linked_connection function.
|
||||
o Have activated connections added to a list on first activation, and
|
||||
that list made active before calls to event_loop.
|
||||
- Generate torrc.{complete|sample}.in, tor.1.in, the HTML manual, and the
|
||||
o Have connections get deactivated when no more data to write on
|
||||
linked conn outbuf.
|
||||
o Handle closing connections properly.
|
||||
o Actually create and use linked connections.
|
||||
- Handle rate-limiting on directory writes to linked directory
|
||||
connections in a more sensible manner.
|
||||
- Rename want_to_read and want_to_write; they're actually about
|
||||
being blocked, not about wanting to read/write.
|
||||
- Find more ways to test this.
|
||||
D Generate torrc.{complete|sample}.in, tor.1.in, the HTML manual, and the
|
||||
online config documentation from a single source.
|
||||
- Have clients do TLS connection rotation less often than "every 10
|
||||
minutes" in the thrashy case, and more often than "once a week" in the
|
||||
|
@ -172,6 +195,8 @@ Things we'd like to do in 0.2.0.x:
|
|||
- Blocking-resistance.
|
||||
- It would be potentially helpful to https requests on the OR port by
|
||||
acting like an HTTPS server.
|
||||
- Audit how much RAM we're using for buffers and cell pools; try to
|
||||
trim down a lot.
|
||||
o Deprecations:
|
||||
o Remove v0 control protocol.
|
||||
P - Packaging:
|
||||
|
@ -280,7 +305,7 @@ M - rewrite how libevent does select() on win32 so it's not so very slow.
|
|||
|
||||
Minor items for 0.1.2.x as time permits:
|
||||
- include bandwidth breakdown by conn->type in BW events.
|
||||
- Unify autoconf search code for libevent and openssl. Make code
|
||||
o Unify autoconf search code for libevent and openssl. Make code
|
||||
suggest platform-appropriate "devel" / "dev" / whatever packages
|
||||
if we can link but we can't find the headers.
|
||||
- Recommend polipo? Please?
|
||||
|
@ -318,7 +343,7 @@ R - add d64 and fp64 along-side d and fp so people can paste status
|
|||
the solution is to have a separate 'extend-data' cell type
|
||||
which is used for the first N data cells, and only
|
||||
extend-data cells can be extend requests.
|
||||
- Specify, including thought about anonymity implications.
|
||||
. Specify, including thought about anonymity implications. [proposal 110]
|
||||
- Display the reasons in 'destroy' and 'truncated' cells under some
|
||||
circumstances?
|
||||
- If the server is spewing complaints about raising your ulimit -n,
|
||||
|
@ -373,7 +398,7 @@ Future version:
|
|||
I can say "banana" as my bandwidthcapacity, and it won't even squeak.
|
||||
o Include the output of svn info in the binary, so it's trivial to see what
|
||||
version a binary was built from.
|
||||
- Do the same for svk info.
|
||||
o Do the same for svk info.
|
||||
- Add a doxygen style checker to make check-spaces so nick doesn't drift
|
||||
too far from arma's undocumented styleguide. Also, document that
|
||||
styleguide in HACKING. (See r9634 for example.)
|
||||
|
@ -388,7 +413,10 @@ Future version:
|
|||
- Should TrackHostExits expire TrackHostExitsExpire seconds after their
|
||||
*last* use, not their *first* use?
|
||||
X Configuration format really wants sections.
|
||||
- Good RBL substitute.
|
||||
. Good RBL substitute.
|
||||
- Play with the implementations; link them from somewhere; add a
|
||||
round-robin link from torel.torproject.org; describe how to
|
||||
use them in the FAQ.
|
||||
- Authorities should try using exits for http to connect to some URLS
|
||||
(specified in a configuration file, so as not to make the List Of Things
|
||||
Not To Censor completely obvious) and ask them for results. Exits that
|
||||
|
|
|
@ -817,6 +817,32 @@ fetch_from_buf(char *string, size_t string_len, buf_t *buf)
|
|||
return buf->datalen;
|
||||
}
|
||||
|
||||
/** Move up to <b>buf_flushlen</b> bytes from <b>buf_in</b> to <b>buf_out</b>.
|
||||
* Return the number of bytes actually copied.
|
||||
*/
|
||||
int
|
||||
move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
|
||||
{
|
||||
char b[4096];
|
||||
size_t cp, len;
|
||||
len = *buf_flushlen;
|
||||
if (len > buf_in->datalen)
|
||||
len = buf_in->datalen;
|
||||
|
||||
cp = len; /* Remember the number of bytes we intend to copy. */
|
||||
while (len) {
|
||||
/* This isn't the most efficient implementation one could imagine, since
|
||||
* it does two copies instead of 1, but I kinda doubt that this will be
|
||||
* critical path. */
|
||||
size_t n = len > sizeof(b) ? sizeof(b) : len;
|
||||
fetch_from_buf(b, n, buf_in);
|
||||
write_to_buf(b, n, buf_out);
|
||||
len -= n;
|
||||
}
|
||||
*buf_flushlen -= cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
/** There is a (possibly incomplete) http statement on <b>buf</b>, of the
|
||||
* form "\%s\\r\\n\\r\\n\%s", headers, body. (body may contain nuls.)
|
||||
* If a) the headers include a Content-Length field and all bytes in
|
||||
|
|
|
@ -113,6 +113,7 @@ conn_state_to_string(int type, int state)
|
|||
case DIR_CONN_STATE_CONNECTING: return "connecting";
|
||||
case DIR_CONN_STATE_CLIENT_SENDING: return "client sending";
|
||||
case DIR_CONN_STATE_CLIENT_READING: return "client reading";
|
||||
case DIR_CONN_STATE_CLIENT_FINISHED: return "client finished";
|
||||
case DIR_CONN_STATE_SERVER_COMMAND_WAIT: return "waiting for command";
|
||||
case DIR_CONN_STATE_SERVER_WRITING: return "writing";
|
||||
}
|
||||
|
@ -212,9 +213,22 @@ connection_new(int type)
|
|||
return conn;
|
||||
}
|
||||
|
||||
/** Create a link between <b>conn_a</b> and <b>conn_b</b> */
|
||||
void
|
||||
connection_link_connections(connection_t *conn_a, connection_t *conn_b)
|
||||
{
|
||||
tor_assert(conn_a->s < 0);
|
||||
tor_assert(conn_b->s < 0);
|
||||
|
||||
conn_a->linked = 1;
|
||||
conn_b->linked = 1;
|
||||
conn_a->linked_conn = conn_b;
|
||||
conn_b->linked_conn = conn_a;
|
||||
}
|
||||
|
||||
/** Tell libevent that we don't care about <b>conn</b> any more. */
|
||||
void
|
||||
connection_unregister(connection_t *conn)
|
||||
connection_unregister_events(connection_t *conn)
|
||||
{
|
||||
if (conn->read_event) {
|
||||
if (event_del(conn->read_event))
|
||||
|
@ -260,6 +274,17 @@ _connection_free(connection_t *conn)
|
|||
break;
|
||||
}
|
||||
|
||||
if (conn->linked) {
|
||||
int severity = buf_datalen(conn->inbuf)+buf_datalen(conn->outbuf)
|
||||
? LOG_NOTICE : LOG_INFO;
|
||||
log_fn(severity, LD_GENERAL, "Freeing linked %s connection [%s] with %d "
|
||||
"bytes on inbuf, %d on outbuf.",
|
||||
conn_type_to_string(conn->type),
|
||||
conn_state_to_string(conn->type, conn->state),
|
||||
(int)buf_datalen(conn->inbuf), (int)buf_datalen(conn->outbuf));
|
||||
// tor_assert(!buf_datalen(conn->outbuf)); /*XXXX020 remove me.*/
|
||||
}
|
||||
|
||||
if (!connection_is_listener(conn)) {
|
||||
buf_free(conn->inbuf);
|
||||
buf_free(conn->outbuf);
|
||||
|
@ -325,6 +350,15 @@ connection_free(connection_t *conn)
|
|||
tor_assert(conn);
|
||||
tor_assert(!connection_is_on_closeable_list(conn));
|
||||
tor_assert(!connection_in_array(conn));
|
||||
if (conn->linked_conn) {
|
||||
log_err(LD_BUG, "Called with conn->linked_conn still set.");
|
||||
tor_fragile_assert();
|
||||
conn->linked_conn->linked_conn = NULL;
|
||||
if (! conn->linked_conn->marked_for_close &&
|
||||
conn->linked_conn->reading_from_linked_conn)
|
||||
connection_start_reading(conn->linked_conn);
|
||||
conn->linked_conn = NULL;
|
||||
}
|
||||
if (connection_speaks_cells(conn)) {
|
||||
if (conn->state == OR_CONN_STATE_OPEN)
|
||||
directory_set_dirty();
|
||||
|
@ -336,7 +370,7 @@ connection_free(connection_t *conn)
|
|||
TO_CONTROL_CONN(conn)->event_mask = 0;
|
||||
control_update_global_event_mask();
|
||||
}
|
||||
connection_unregister(conn);
|
||||
connection_unregister_events(conn);
|
||||
_connection_free(conn);
|
||||
}
|
||||
|
||||
|
@ -486,7 +520,7 @@ void
|
|||
connection_close_immediate(connection_t *conn)
|
||||
{
|
||||
assert_connection_ok(conn,0);
|
||||
if (conn->s < 0) {
|
||||
if (conn->s < 0 && !conn->linked) {
|
||||
log_err(LD_BUG,"Attempt to close already-closed connection.");
|
||||
tor_fragile_assert();
|
||||
return;
|
||||
|
@ -498,9 +532,10 @@ connection_close_immediate(connection_t *conn)
|
|||
(int)conn->outbuf_flushlen);
|
||||
}
|
||||
|
||||
connection_unregister(conn);
|
||||
connection_unregister_events(conn);
|
||||
|
||||
tor_close_socket(conn->s);
|
||||
if (conn->s >= 0)
|
||||
tor_close_socket(conn->s);
|
||||
conn->s = -1;
|
||||
if (!connection_is_listener(conn)) {
|
||||
buf_clear(conn->outbuf);
|
||||
|
@ -529,6 +564,12 @@ _connection_mark_for_close(connection_t *conn, int line, const char *file)
|
|||
conn->marked_for_close_file = file;
|
||||
add_connection_to_closeable_list(conn);
|
||||
|
||||
#if 0
|
||||
/* XXXX020 Actually, I don't think this is right. */
|
||||
if (conn->linked_conn && !conn->linked_conn->marked_for_close)
|
||||
_connection_mark_for_close(conn->linked_conn, line, file);
|
||||
#endif
|
||||
|
||||
/* in case we're going to be held-open-til-flushed, reset
|
||||
* the number of seconds since last successful write, so
|
||||
* we get our whole 15 seconds */
|
||||
|
@ -1101,11 +1142,14 @@ retry_all_listeners(int force, smartlist_t *replaced_conns,
|
|||
|
||||
/** Return 1 if we should apply rate limiting to <b>conn</b>,
|
||||
* and 0 otherwise. Right now this just checks if it's an internal
|
||||
* IP address. */
|
||||
* IP address or an internal connection. */
|
||||
static int
|
||||
connection_is_rate_limited(connection_t *conn)
|
||||
{
|
||||
return !is_internal_IP(conn->addr, 0);
|
||||
if (conn->linked || is_internal_IP(conn->addr, 0))
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern int global_read_bucket, global_write_bucket;
|
||||
|
@ -1483,6 +1527,7 @@ int
|
|||
connection_handle_read(connection_t *conn)
|
||||
{
|
||||
int max_to_read=-1, try_to_read;
|
||||
size_t before, n_read = 0;
|
||||
|
||||
if (conn->marked_for_close)
|
||||
return 0; /* do nothing */
|
||||
|
@ -1505,6 +1550,8 @@ connection_handle_read(connection_t *conn)
|
|||
loop_again:
|
||||
try_to_read = max_to_read;
|
||||
tor_assert(!conn->marked_for_close);
|
||||
|
||||
before = buf_datalen(conn->inbuf);
|
||||
if (connection_read_to_buf(conn, &max_to_read) < 0) {
|
||||
/* There's a read error; kill the connection.*/
|
||||
connection_close_immediate(conn); /* Don't flush; connection is dead. */
|
||||
|
@ -1517,6 +1564,7 @@ loop_again:
|
|||
connection_mark_for_close(conn);
|
||||
return -1;
|
||||
}
|
||||
n_read += buf_datalen(conn->inbuf) - before;
|
||||
if (CONN_IS_EDGE(conn) && try_to_read != max_to_read) {
|
||||
/* instruct it not to try to package partial cells. */
|
||||
if (connection_process_inbuf(conn, 0) < 0) {
|
||||
|
@ -1533,6 +1581,27 @@ loop_again:
|
|||
connection_process_inbuf(conn, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (conn->linked_conn) {
|
||||
/* The other side's handle_write will never actually get called, so
|
||||
* we need to invoke the appropriate callbacks ourself. */
|
||||
connection_t *linked = conn->linked_conn;
|
||||
/* XXXX020 Do we need to ensure that this stuff is called even if
|
||||
* conn dies in a way that causes us to return -1 earlier? */
|
||||
|
||||
if (n_read) {
|
||||
/* Probably a no-op, but hey. */
|
||||
connection_buckets_decrement(linked, time(NULL), 0, n_read);
|
||||
|
||||
if (connection_flushed_some(linked) < 0)
|
||||
connection_mark_for_close(linked);
|
||||
if (!connection_wants_to_flush(linked))
|
||||
connection_finished_flushing(linked);
|
||||
}
|
||||
|
||||
if (!buf_datalen(linked->outbuf) && conn->active_on_link)
|
||||
connection_stop_reading_from_linked_conn(conn);
|
||||
}
|
||||
/* If we hit the EOF, call connection_reached_eof. */
|
||||
if (!conn->marked_for_close &&
|
||||
conn->inbuf_reached_eof &&
|
||||
connection_reached_eof(conn) < 0) {
|
||||
|
@ -1541,9 +1610,9 @@ loop_again:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** Pull in new bytes from conn-\>s onto conn-\>inbuf, either
|
||||
* directly or via TLS. Reduce the token buckets by the number of
|
||||
* bytes read.
|
||||
/** Pull in new bytes from conn-\>s or conn-\>linked_conn onto conn-\>inbuf,
|
||||
* either directly or via TLS. Reduce the token buckets by the number of bytes
|
||||
* read.
|
||||
*
|
||||
* If *max_to_read is -1, then decide it ourselves, else go with the
|
||||
* value passed to us. When returning, if it's changed, subtract the
|
||||
|
@ -1633,7 +1702,24 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
|
|||
tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written);
|
||||
log_debug(LD_GENERAL, "After TLS read of %d: %ld read, %ld written",
|
||||
result, (long)n_read, (long)n_written);
|
||||
} else if (conn->linked) {
|
||||
if (conn->linked_conn) {
|
||||
result = move_buf_to_buf(conn->inbuf, conn->linked_conn->outbuf,
|
||||
&conn->linked_conn->outbuf_flushlen);
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
//log_notice(LD_GENERAL, "Moved %d bytes on an internal link!", result);
|
||||
/* If the other side has disappeared, or if it's been marked for close and
|
||||
* we flushed its outbuf, then we should set our inbuf_reached_eof. */
|
||||
if (!conn->linked_conn ||
|
||||
(conn->linked_conn->marked_for_close &&
|
||||
buf_datalen(conn->linked_conn->outbuf) == 0))
|
||||
conn->inbuf_reached_eof = 1;
|
||||
|
||||
n_read = (size_t) result;
|
||||
} else {
|
||||
/* !connection_speaks_cells, !conn->linked_conn. */
|
||||
int reached_eof = 0;
|
||||
CONN_LOG_PROTECT(conn,
|
||||
result = read_to_buf(conn->s, at_most, conn->inbuf, &reached_eof));
|
||||
|
@ -1687,7 +1773,7 @@ connection_fetch_from_buf(char *string, size_t len, connection_t *conn)
|
|||
int
|
||||
connection_wants_to_flush(connection_t *conn)
|
||||
{
|
||||
return conn->outbuf_flushlen;
|
||||
return conn->outbuf_flushlen > 0;
|
||||
}
|
||||
|
||||
/** Are there too many bytes on edge connection <b>conn</b>'s outbuf to
|
||||
|
@ -2203,6 +2289,19 @@ connection_state_is_connecting(connection_t *conn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
int
|
||||
connection_should_read_from_linked_conn(connection_t *conn)
|
||||
{
|
||||
if (conn->linked && conn->reading_from_linked_conn) {
|
||||
if (! conn->linked_conn ||
|
||||
(conn->linked_conn->writing_to_linked_conn &&
|
||||
buf_datalen(conn->linked_conn->outbuf)))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Allocates a base64'ed authenticator for use in http or https
|
||||
* auth, based on the input string <b>authenticator</b>. Returns it
|
||||
* if success, else returns NULL. */
|
||||
|
@ -2433,6 +2532,13 @@ assert_connection_ok(connection_t *conn, time_t now)
|
|||
break;
|
||||
}
|
||||
|
||||
if (conn->linked_conn) {
|
||||
tor_assert(conn->linked_conn->linked_conn == conn);
|
||||
tor_assert(conn->linked != 0);
|
||||
}
|
||||
if (conn->linked)
|
||||
tor_assert(conn->s < 0);
|
||||
|
||||
if (conn->outbuf_flushlen > 0) {
|
||||
tor_assert(connection_is_writing(conn) || conn->wants_to_write ||
|
||||
conn->edge_blocked_on_circ);
|
||||
|
|
|
@ -1860,32 +1860,21 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn)
|
|||
* and call connection_ap_handshake_attach_circuit(conn) on it.
|
||||
*
|
||||
* Return the other end of the socketpair, or -1 if error.
|
||||
*
|
||||
* DOCDOC The above is now wrong; we use links.
|
||||
* DOCDOC start_reading
|
||||
*/
|
||||
int
|
||||
edge_connection_t *
|
||||
connection_ap_make_bridge(char *address, uint16_t port,
|
||||
const char *digest, int command)
|
||||
{
|
||||
int fd[2];
|
||||
edge_connection_t *conn;
|
||||
int err;
|
||||
|
||||
log_info(LD_APP,"Making AP bridge to %s:%d ...",safe_str(address),port);
|
||||
|
||||
if ((err = tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) < 0) {
|
||||
log_warn(LD_NET,
|
||||
"Couldn't construct socketpair (%s). Network down? Delaying.",
|
||||
tor_socket_strerror(-err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tor_assert(fd[0] >= 0);
|
||||
tor_assert(fd[1] >= 0);
|
||||
|
||||
set_socket_nonblocking(fd[0]);
|
||||
set_socket_nonblocking(fd[1]);
|
||||
log_notice(LD_APP,"Making internal anonymized tunnel to %s:%d ...",
|
||||
safe_str(address),port); /* XXXX020 Downgrade back to info. */
|
||||
|
||||
conn = TO_EDGE_CONN(connection_new(CONN_TYPE_AP));
|
||||
conn->_base.s = fd[0];
|
||||
conn->_base.linked = 1; /* so that we can add it safely below. */
|
||||
|
||||
/* populate conn->socks_request */
|
||||
|
||||
|
@ -1903,28 +1892,25 @@ connection_ap_make_bridge(char *address, uint16_t port,
|
|||
digest, DIGEST_LEN);
|
||||
}
|
||||
|
||||
conn->_base.address = tor_strdup("(local bridge)");
|
||||
conn->_base.address = tor_strdup("(local bridge)"); /*XXXX020 no "bridge"*/
|
||||
conn->_base.addr = 0;
|
||||
conn->_base.port = 0;
|
||||
|
||||
if (connection_add(TO_CONN(conn)) < 0) { /* no space, forget it */
|
||||
connection_free(TO_CONN(conn)); /* this closes fd[0] */
|
||||
tor_close_socket(fd[1]);
|
||||
return -1;
|
||||
connection_free(TO_CONN(conn));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
|
||||
connection_start_reading(TO_CONN(conn));
|
||||
|
||||
/* attaching to a dirty circuit is fine */
|
||||
if (connection_ap_handshake_attach_circuit(conn) < 0) {
|
||||
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
|
||||
tor_close_socket(fd[1]);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_info(LD_APP,"... AP bridge created and connected.");
|
||||
return fd[1];
|
||||
return conn;
|
||||
}
|
||||
|
||||
/** Send an answer to an AP connection that has requested a DNS lookup
|
||||
|
@ -2406,37 +2392,19 @@ connection_exit_connect(edge_connection_t *edge_conn)
|
|||
* back an end cell for). Return -(some circuit end reason) if the circuit
|
||||
* needs to be torn down. Either connects exit_conn, frees it, or marks it,
|
||||
* as appropriate.
|
||||
*
|
||||
* DOCDOC no longer uses socketpair
|
||||
*/
|
||||
static int
|
||||
connection_exit_connect_dir(edge_connection_t *exit_conn)
|
||||
{
|
||||
int fd[2];
|
||||
int err;
|
||||
dir_connection_t *dir_conn = NULL;
|
||||
|
||||
log_info(LD_EXIT, "Opening dir bridge");
|
||||
log_info(LD_EXIT, "Opening local connection for anonymized directory exit");
|
||||
|
||||
if ((err = tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) < 0) {
|
||||
log_warn(LD_NET,
|
||||
"Couldn't construct socketpair (%s). "
|
||||
"Network down? Out of sockets?",
|
||||
tor_socket_strerror(-err));
|
||||
connection_edge_end(exit_conn, END_STREAM_REASON_RESOURCELIMIT);
|
||||
connection_free(TO_CONN(exit_conn));
|
||||
return 0;
|
||||
}
|
||||
|
||||
tor_assert(fd[0] >= 0);
|
||||
tor_assert(fd[1] >= 0);
|
||||
|
||||
set_socket_nonblocking(fd[0]);
|
||||
set_socket_nonblocking(fd[1]);
|
||||
|
||||
exit_conn->_base.s = fd[0];
|
||||
exit_conn->_base.state = EXIT_CONN_STATE_OPEN;
|
||||
|
||||
dir_conn = TO_DIR_CONN(connection_new(CONN_TYPE_DIR));
|
||||
dir_conn->_base.s = fd[1];
|
||||
|
||||
dir_conn->_base.addr = 0x7f000001;
|
||||
dir_conn->_base.port = 0;
|
||||
|
@ -2445,6 +2413,8 @@ connection_exit_connect_dir(edge_connection_t *exit_conn)
|
|||
dir_conn->_base.purpose = DIR_PURPOSE_SERVER;
|
||||
dir_conn->_base.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
|
||||
|
||||
connection_link_connections(TO_CONN(dir_conn), TO_CONN(exit_conn));
|
||||
|
||||
if (connection_add(TO_CONN(exit_conn))<0) {
|
||||
connection_edge_end(exit_conn, END_STREAM_REASON_RESOURCELIMIT);
|
||||
connection_free(TO_CONN(exit_conn));
|
||||
|
|
|
@ -451,22 +451,25 @@ directory_initiate_command(const char *address, uint32_t addr,
|
|||
error indicates broken link in windowsland. */
|
||||
}
|
||||
} else { /* we want to connect via tor */
|
||||
edge_connection_t *linked_conn;
|
||||
/* make an AP connection
|
||||
* populate it and add it at the right state
|
||||
* socketpair and hook up both sides
|
||||
*/
|
||||
conn->dirconn_direct = 0;
|
||||
conn->_base.s =
|
||||
linked_conn =
|
||||
connection_ap_make_bridge(conn->_base.address, conn->_base.port,
|
||||
digest,
|
||||
private_connection ?
|
||||
SOCKS_COMMAND_CONNECT :
|
||||
SOCKS_COMMAND_CONNECT_DIR);
|
||||
if (conn->_base.s < 0) {
|
||||
if (!linked_conn) {
|
||||
log_warn(LD_NET,"Making AP bridge to dirserver failed.");
|
||||
connection_mark_for_close(TO_CONN(conn));
|
||||
connection_mark_for_close(TO_CONN(linked_conn));
|
||||
return;
|
||||
}
|
||||
connection_link_connections(TO_CONN(conn), TO_CONN(linked_conn));
|
||||
|
||||
if (connection_add(TO_CONN(conn)) < 0) {
|
||||
log_warn(LD_NET,"Unable to add AP bridge to dirserver.");
|
||||
|
@ -478,6 +481,7 @@ directory_initiate_command(const char *address, uint32_t addr,
|
|||
directory_send_command(conn, purpose, 0, resource,
|
||||
payload, payload_len);
|
||||
connection_watch_events(TO_CONN(conn), EV_READ | EV_WRITE);
|
||||
connection_start_reading(TO_CONN(linked_conn));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1297,7 +1301,8 @@ connection_dir_reached_eof(dir_connection_t *conn)
|
|||
{
|
||||
int retval;
|
||||
if (conn->_base.state != DIR_CONN_STATE_CLIENT_READING) {
|
||||
log_info(LD_HTTP,"conn reached eof, not reading. Closing.");
|
||||
log_info(LD_HTTP,"conn reached eof, not reading. [state=%d] Closing.",
|
||||
conn->_base.state);
|
||||
connection_close_immediate(TO_CONN(conn)); /* error: give up on flushing */
|
||||
connection_mark_for_close(TO_CONN(conn));
|
||||
return -1;
|
||||
|
|
201
src/or/main.c
201
src/or/main.c
|
@ -74,6 +74,10 @@ static connection_t *connection_array[MAXCONNECTIONS+1] =
|
|||
/** List of connections that have been marked for close and need to be freed
|
||||
* and removed from connection_array. */
|
||||
static smartlist_t *closeable_connection_lst = NULL;
|
||||
/** DOCDOC */
|
||||
static smartlist_t *active_linked_connection_lst = NULL;
|
||||
/** DOCDOC */
|
||||
static int called_loop_once = 0;
|
||||
|
||||
static int n_conns=0; /**< Number of connections currently active. */
|
||||
|
||||
|
@ -155,7 +159,7 @@ int
|
|||
connection_add(connection_t *conn)
|
||||
{
|
||||
tor_assert(conn);
|
||||
tor_assert(conn->s >= 0);
|
||||
tor_assert(conn->s >= 0 || conn->linked);
|
||||
|
||||
tor_assert(conn->conn_array_index == -1); /* can only connection_add once */
|
||||
if (n_conns == MAXCONNECTIONS) {
|
||||
|
@ -198,13 +202,12 @@ connection_remove(connection_t *conn)
|
|||
|
||||
tor_assert(conn->conn_array_index >= 0);
|
||||
current_index = conn->conn_array_index;
|
||||
connection_unregister_events(conn); /* This is redundant, but cheap. */
|
||||
if (current_index == n_conns-1) { /* this is the end */
|
||||
n_conns--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
connection_unregister(conn);
|
||||
|
||||
/* replace this one with the one at the end */
|
||||
n_conns--;
|
||||
connection_array[current_index] = connection_array[n_conns];
|
||||
|
@ -213,23 +216,31 @@ connection_remove(connection_t *conn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** If it's an edge conn, remove it from the list
|
||||
/** If <b>conn</b> is an edge conn, remove it from the list
|
||||
* of conn's on this circuit. If it's not on an edge,
|
||||
* flush and send destroys for all circuits on this conn.
|
||||
*
|
||||
* If <b>remove</b> is non-zero, then remove it from the
|
||||
* connection_array and closeable_connection_lst.
|
||||
* Remove it from connection_array (if applicable) and
|
||||
* from closeable_connection_list.
|
||||
*
|
||||
* Then free it.
|
||||
*/
|
||||
static void
|
||||
connection_unlink(connection_t *conn, int remove)
|
||||
connection_unlink(connection_t *conn)
|
||||
{
|
||||
connection_about_to_close_connection(conn);
|
||||
if (remove) {
|
||||
if (conn->conn_array_index >= 0) {
|
||||
connection_remove(conn);
|
||||
}
|
||||
if (conn->linked_conn) {
|
||||
conn->linked_conn->linked_conn = NULL;
|
||||
if (! conn->linked_conn->marked_for_close &&
|
||||
conn->linked_conn->reading_from_linked_conn)
|
||||
connection_start_reading(conn->linked_conn);
|
||||
conn->linked_conn = NULL;
|
||||
}
|
||||
smartlist_remove(closeable_connection_lst, conn);
|
||||
smartlist_remove(active_linked_connection_lst, conn);
|
||||
if (conn->type == CONN_TYPE_EXIT) {
|
||||
assert_connection_edge_not_dns_pending(TO_EDGE_CONN(conn));
|
||||
}
|
||||
|
@ -286,16 +297,23 @@ get_connection_array(connection_t ***array, int *n)
|
|||
void
|
||||
connection_watch_events(connection_t *conn, short events)
|
||||
{
|
||||
int r;
|
||||
int r = 0;
|
||||
|
||||
tor_assert(conn);
|
||||
tor_assert(conn->read_event);
|
||||
tor_assert(conn->write_event);
|
||||
|
||||
if (events & EV_READ) {
|
||||
r = event_add(conn->read_event, NULL);
|
||||
if (conn->linked) {
|
||||
if (events & EV_READ)
|
||||
connection_start_reading(conn);
|
||||
else
|
||||
connection_stop_reading(conn);
|
||||
} else {
|
||||
r = event_del(conn->read_event);
|
||||
if (events & EV_READ) {
|
||||
r = event_add(conn->read_event, NULL);
|
||||
} else {
|
||||
r = event_del(conn->read_event);
|
||||
}
|
||||
}
|
||||
|
||||
if (r<0)
|
||||
|
@ -305,10 +323,17 @@ connection_watch_events(connection_t *conn, short events)
|
|||
conn->s, (events & EV_READ)?"":"un",
|
||||
tor_socket_strerror(tor_socket_errno(conn->s)));
|
||||
|
||||
if (events & EV_WRITE) {
|
||||
r = event_add(conn->write_event, NULL);
|
||||
if (conn->linked) {
|
||||
if (events & EV_WRITE)
|
||||
connection_start_writing(conn);
|
||||
else
|
||||
connection_stop_writing(conn);
|
||||
} else {
|
||||
r = event_del(conn->write_event);
|
||||
if (events & EV_WRITE) {
|
||||
r = event_add(conn->write_event, NULL);
|
||||
} else {
|
||||
r = event_del(conn->write_event);
|
||||
}
|
||||
}
|
||||
|
||||
if (r<0)
|
||||
|
@ -325,7 +350,8 @@ connection_is_reading(connection_t *conn)
|
|||
{
|
||||
tor_assert(conn);
|
||||
|
||||
return conn->read_event && event_pending(conn->read_event, EV_READ, NULL);
|
||||
return conn->reading_from_linked_conn ||
|
||||
(conn->read_event && event_pending(conn->read_event, EV_READ, NULL));
|
||||
}
|
||||
|
||||
/** Tell the main loop to stop notifying <b>conn</b> of any read events. */
|
||||
|
@ -335,12 +361,16 @@ connection_stop_reading(connection_t *conn)
|
|||
tor_assert(conn);
|
||||
tor_assert(conn->read_event);
|
||||
|
||||
log_debug(LD_NET,"entering.");
|
||||
if (event_del(conn->read_event))
|
||||
log_warn(LD_NET, "Error from libevent setting read event state for %d "
|
||||
"to unwatched: %s",
|
||||
conn->s,
|
||||
tor_socket_strerror(tor_socket_errno(conn->s)));
|
||||
if (conn->linked) {
|
||||
conn->reading_from_linked_conn = 0;
|
||||
connection_stop_reading_from_linked_conn(conn);
|
||||
} else {
|
||||
if (event_del(conn->read_event))
|
||||
log_warn(LD_NET, "Error from libevent setting read event state for %d "
|
||||
"to unwatched: %s",
|
||||
conn->s,
|
||||
tor_socket_strerror(tor_socket_errno(conn->s)));
|
||||
}
|
||||
}
|
||||
|
||||
/** Tell the main loop to start notifying <b>conn</b> of any read events. */
|
||||
|
@ -350,11 +380,17 @@ connection_start_reading(connection_t *conn)
|
|||
tor_assert(conn);
|
||||
tor_assert(conn->read_event);
|
||||
|
||||
if (event_add(conn->read_event, NULL))
|
||||
log_warn(LD_NET, "Error from libevent setting read event state for %d "
|
||||
"to watched: %s",
|
||||
conn->s,
|
||||
tor_socket_strerror(tor_socket_errno(conn->s)));
|
||||
if (conn->linked) {
|
||||
conn->reading_from_linked_conn = 1;
|
||||
if (connection_should_read_from_linked_conn(conn))
|
||||
connection_start_reading_from_linked_conn(conn);
|
||||
} else {
|
||||
if (event_add(conn->read_event, NULL))
|
||||
log_warn(LD_NET, "Error from libevent setting read event state for %d "
|
||||
"to watched: %s",
|
||||
conn->s,
|
||||
tor_socket_strerror(tor_socket_errno(conn->s)));
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true iff <b>conn</b> is listening for write events. */
|
||||
|
@ -363,7 +399,8 @@ connection_is_writing(connection_t *conn)
|
|||
{
|
||||
tor_assert(conn);
|
||||
|
||||
return conn->write_event && event_pending(conn->write_event, EV_WRITE, NULL);
|
||||
return conn->writing_to_linked_conn ||
|
||||
(conn->write_event && event_pending(conn->write_event, EV_WRITE, NULL));
|
||||
}
|
||||
|
||||
/** Tell the main loop to stop notifying <b>conn</b> of any write events. */
|
||||
|
@ -373,11 +410,17 @@ connection_stop_writing(connection_t *conn)
|
|||
tor_assert(conn);
|
||||
tor_assert(conn->write_event);
|
||||
|
||||
if (event_del(conn->write_event))
|
||||
log_warn(LD_NET, "Error from libevent setting write event state for %d "
|
||||
"to unwatched: %s",
|
||||
conn->s,
|
||||
tor_socket_strerror(tor_socket_errno(conn->s)));
|
||||
if (conn->linked) {
|
||||
conn->writing_to_linked_conn = 0;
|
||||
if (conn->linked_conn)
|
||||
connection_stop_reading_from_linked_conn(conn->linked_conn);
|
||||
} else {
|
||||
if (event_del(conn->write_event))
|
||||
log_warn(LD_NET, "Error from libevent setting write event state for %d "
|
||||
"to unwatched: %s",
|
||||
conn->s,
|
||||
tor_socket_strerror(tor_socket_errno(conn->s)));
|
||||
}
|
||||
}
|
||||
|
||||
/** Tell the main loop to start notifying <b>conn</b> of any write events. */
|
||||
|
@ -387,11 +430,58 @@ connection_start_writing(connection_t *conn)
|
|||
tor_assert(conn);
|
||||
tor_assert(conn->write_event);
|
||||
|
||||
if (event_add(conn->write_event, NULL))
|
||||
log_warn(LD_NET, "Error from libevent setting write event state for %d "
|
||||
"to watched: %s",
|
||||
conn->s,
|
||||
tor_socket_strerror(tor_socket_errno(conn->s)));
|
||||
if (conn->linked) {
|
||||
conn->writing_to_linked_conn = 1;
|
||||
if (conn->linked_conn &&
|
||||
connection_should_read_from_linked_conn(conn->linked_conn))
|
||||
connection_start_reading_from_linked_conn(conn->linked_conn);
|
||||
} else {
|
||||
if (event_add(conn->write_event, NULL))
|
||||
log_warn(LD_NET, "Error from libevent setting write event state for %d "
|
||||
"to watched: %s",
|
||||
conn->s,
|
||||
tor_socket_strerror(tor_socket_errno(conn->s)));
|
||||
}
|
||||
}
|
||||
|
||||
/** DOCDOC*/
|
||||
void
|
||||
connection_start_reading_from_linked_conn(connection_t *conn)
|
||||
{
|
||||
tor_assert(conn);
|
||||
tor_assert(conn->linked == 1);
|
||||
|
||||
if (!conn->active_on_link) {
|
||||
conn->active_on_link = 1;
|
||||
smartlist_add(active_linked_connection_lst, conn);
|
||||
if (!called_loop_once) {
|
||||
/* This is the first event on the list; we won't be in LOOP_ONCE mode,
|
||||
* so we need to make sure that the event_loop() actually exits at the
|
||||
* end of its run through the current connections and
|
||||
* lets us activate read events for linked connections. */
|
||||
struct timeval tv = { 0, 0 };
|
||||
event_loopexit(&tv);
|
||||
}
|
||||
} else {
|
||||
tor_assert(smartlist_isin(active_linked_connection_lst, conn));
|
||||
}
|
||||
}
|
||||
|
||||
/** DOCDOC*/
|
||||
void
|
||||
connection_stop_reading_from_linked_conn(connection_t *conn)
|
||||
{
|
||||
tor_assert(conn);
|
||||
tor_assert(conn->linked == 1);
|
||||
|
||||
if (conn->active_on_link) {
|
||||
conn->active_on_link = 0;
|
||||
/* XXXX020 maybe we should keep an index here so we can smartlist_del
|
||||
* cleanly. */
|
||||
smartlist_remove(active_linked_connection_lst, conn);
|
||||
} else {
|
||||
tor_assert(!smartlist_isin(active_linked_connection_lst, conn));
|
||||
}
|
||||
}
|
||||
|
||||
/** Close all connections that have been scheduled to get closed */
|
||||
|
@ -402,7 +492,7 @@ close_closeable_connections(void)
|
|||
for (i = 0; i < smartlist_len(closeable_connection_lst); ) {
|
||||
connection_t *conn = smartlist_get(closeable_connection_lst, i);
|
||||
if (conn->conn_array_index < 0) {
|
||||
connection_unlink(conn, 0); /* blow it away right now */
|
||||
connection_unlink(conn); /* blow it away right now */
|
||||
} else {
|
||||
if (!conn_close_if_marked(conn->conn_array_index))
|
||||
++i;
|
||||
|
@ -500,7 +590,7 @@ conn_close_if_marked(int i)
|
|||
assert_all_pending_dns_resolves_ok();
|
||||
|
||||
log_debug(LD_NET,"Cleaning up connection (fd %d).",conn->s);
|
||||
if (conn->s >= 0 && connection_wants_to_flush(conn)) {
|
||||
if ((conn->s >= 0 || conn->linked_conn) && connection_wants_to_flush(conn)) {
|
||||
/* s == -1 means it's an incomplete edge connection, or that the socket
|
||||
* has already been closed as unflushable. */
|
||||
int sz = connection_bucket_write_limit(conn);
|
||||
|
@ -512,7 +602,21 @@ conn_close_if_marked(int i)
|
|||
conn->s, conn_type_to_string(conn->type), conn->state,
|
||||
(int)conn->outbuf_flushlen,
|
||||
conn->marked_for_close_file, conn->marked_for_close);
|
||||
if (connection_speaks_cells(conn)) {
|
||||
if (conn->linked_conn) {
|
||||
retval = move_buf_to_buf(conn->linked_conn->inbuf, conn->outbuf,
|
||||
&conn->outbuf_flushlen);
|
||||
if (retval >= 0) {
|
||||
/* The linked conn will notice that it has data when it notices that
|
||||
* we're gone. */
|
||||
connection_start_reading_from_linked_conn(conn->linked_conn);
|
||||
}
|
||||
/* XXXX020 Downgrade to debug. */
|
||||
log_info(LD_GENERAL, "Flushed last %d bytes from a linked conn; "
|
||||
"%d left; flushlen %d; wants-to-flush==%d", retval,
|
||||
(int)buf_datalen(conn->outbuf),
|
||||
(int)conn->outbuf_flushlen,
|
||||
connection_wants_to_flush(conn));
|
||||
} else if (connection_speaks_cells(conn)) {
|
||||
if (conn->state == OR_CONN_STATE_OPEN) {
|
||||
retval = flush_buf_tls(TO_OR_CONN(conn)->tls, conn->outbuf, sz,
|
||||
&conn->outbuf_flushlen);
|
||||
|
@ -553,7 +657,7 @@ conn_close_if_marked(int i)
|
|||
conn->marked_for_close);
|
||||
}
|
||||
}
|
||||
connection_unlink(conn, 1); /* unlink, remove, free */
|
||||
connection_unlink(conn); /* unlink, remove, free */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1270,8 +1374,14 @@ do_main_loop(void)
|
|||
/* Make it easier to tell whether libevent failure is our fault or not. */
|
||||
errno = 0;
|
||||
#endif
|
||||
/* poll until we have an event, or the second ends */
|
||||
loop_result = event_dispatch();
|
||||
/* All active linked conns should get their read events activated. */
|
||||
SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn,
|
||||
event_active(conn->read_event, EV_READ, 1));
|
||||
called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0;
|
||||
|
||||
/* poll until we have an event, or the second ends, or until we have
|
||||
* some active linked connections to triggger events for. */
|
||||
loop_result = event_loop(called_loop_once ? EVLOOP_ONCE : 0);
|
||||
|
||||
/* let catch() handle things like ^c, and otherwise don't worry about it */
|
||||
if (loop_result < 0) {
|
||||
|
@ -1601,6 +1711,8 @@ tor_init(int argc, char *argv[])
|
|||
time_of_process_start = time(NULL);
|
||||
if (!closeable_connection_lst)
|
||||
closeable_connection_lst = smartlist_create();
|
||||
if (!active_linked_connection_lst)
|
||||
active_linked_connection_lst = smartlist_create();
|
||||
/* Initialize the history structures. */
|
||||
rep_hist_init();
|
||||
/* Initialize the service cache. */
|
||||
|
@ -1673,6 +1785,7 @@ tor_free_all(int postfork)
|
|||
tor_tls_free_all();
|
||||
/* stuff in main.c */
|
||||
smartlist_free(closeable_connection_lst);
|
||||
smartlist_free(active_linked_connection_lst);
|
||||
tor_free(timeout_event);
|
||||
/* Stuff in util.c */
|
||||
escaped(NULL);
|
||||
|
|
22
src/or/or.h
22
src/or/or.h
|
@ -748,6 +748,7 @@ typedef struct connection_t {
|
|||
/* The next fields are all one-bit booleans. Some are only applicable
|
||||
* to connection subtypes, but we hold them here anyway, to save space.
|
||||
* (Currently, they all fit into a single byte.) */
|
||||
/*XXXX020 rename wants_to_*; the names are misleading. */
|
||||
unsigned wants_to_read:1; /**< Boolean: should we start reading again once
|
||||
* the bandwidth throttler allows it? */
|
||||
unsigned wants_to_write:1; /**< Boolean: should we start writing again once
|
||||
|
@ -771,7 +772,7 @@ typedef struct connection_t {
|
|||
unsigned int chosen_exit_optional:1;
|
||||
|
||||
int s; /**< Our socket; -1 if this connection is closed, or has no
|
||||
* sockets. */
|
||||
* socket. */
|
||||
int conn_array_index; /**< Index into the global connection array. */
|
||||
struct event *read_event; /**< Libevent event structure. */
|
||||
struct event *write_event; /**< Libevent event structure. */
|
||||
|
@ -797,6 +798,13 @@ typedef struct connection_t {
|
|||
* we marked for close? */
|
||||
char *address; /**< FQDN (or IP) of the guy on the other end.
|
||||
* strdup into this, because free_connection frees it. */
|
||||
/** Annother connection that's connected to this one in lieu of a socket. */
|
||||
struct connection_t *linked_conn;
|
||||
/* XXXX020 NM move these up to the other 1-bit flags. */
|
||||
unsigned int linked:1; /**< True if there is, or has been, a linked_conn. */
|
||||
unsigned int reading_from_linked_conn:1; /**DOCDOC*/
|
||||
unsigned int writing_to_linked_conn:1; /**DOCDOC*/
|
||||
unsigned int active_on_link:1; /**DOCDOC*/
|
||||
|
||||
} connection_t;
|
||||
|
||||
|
@ -1967,6 +1975,7 @@ int flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen);
|
|||
int write_to_buf(const char *string, size_t string_len, buf_t *buf);
|
||||
int write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state,
|
||||
const char *data, size_t data_len, int done);
|
||||
int move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
|
||||
int fetch_from_buf(char *string, size_t string_len, buf_t *buf);
|
||||
int fetch_from_buf_http(buf_t *buf,
|
||||
char **headers_out, size_t max_headerlen,
|
||||
|
@ -2163,7 +2172,8 @@ const char *conn_type_to_string(int type);
|
|||
const char *conn_state_to_string(int type, int state);
|
||||
|
||||
connection_t *connection_new(int type);
|
||||
void connection_unregister(connection_t *conn);
|
||||
void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
|
||||
void connection_unregister_events(connection_t *conn);
|
||||
void connection_free(connection_t *conn);
|
||||
void connection_free_all(void);
|
||||
void connection_about_to_close_connection(connection_t *conn);
|
||||
|
@ -2227,6 +2237,7 @@ connection_t *connection_get_by_type_state_rendquery(int type, int state,
|
|||
int connection_is_listener(connection_t *conn);
|
||||
int connection_state_is_open(connection_t *conn);
|
||||
int connection_state_is_connecting(connection_t *conn);
|
||||
int connection_should_read_from_linked_conn(connection_t *conn);
|
||||
|
||||
char *alloc_http_authenticator(const char *authenticator);
|
||||
|
||||
|
@ -2252,8 +2263,8 @@ int connection_edge_finished_connecting(edge_connection_t *conn);
|
|||
int connection_ap_handshake_send_begin(edge_connection_t *ap_conn);
|
||||
int connection_ap_handshake_send_resolve(edge_connection_t *ap_conn);
|
||||
|
||||
int connection_ap_make_bridge(char *address, uint16_t port,
|
||||
const char *digest, int command);
|
||||
edge_connection_t *connection_ap_make_bridge(char *address, uint16_t port,
|
||||
const char *digest, int command);
|
||||
void connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply,
|
||||
size_t replylen,
|
||||
int endreason);
|
||||
|
@ -2580,6 +2591,9 @@ int connection_is_writing(connection_t *conn);
|
|||
void connection_stop_writing(connection_t *conn);
|
||||
void connection_start_writing(connection_t *conn);
|
||||
|
||||
void connection_stop_reading_from_linked_conn(connection_t *conn);
|
||||
void connection_start_reading_from_linked_conn(connection_t *conn);
|
||||
|
||||
void directory_all_unreachable(time_t now);
|
||||
void directory_info_has_arrived(time_t now, int from_cache);
|
||||
|
||||
|
|
|
@ -111,9 +111,10 @@ test_buffers(void)
|
|||
char str[256];
|
||||
char str2[256];
|
||||
|
||||
buf_t *buf;
|
||||
buf_t *buf, *buf2;
|
||||
|
||||
int j;
|
||||
size_t r;
|
||||
|
||||
/****
|
||||
* buf_new
|
||||
|
@ -218,6 +219,37 @@ test_buffers(void)
|
|||
test_memeq(str2, str, 255);
|
||||
}
|
||||
|
||||
/* Move from buf to buf. */
|
||||
buf_free(buf);
|
||||
buf = buf_new_with_capacity(4096);
|
||||
buf2 = buf_new_with_capacity(4096);
|
||||
for (j=0;j<100;++j)
|
||||
write_to_buf(str, 255, buf);
|
||||
test_eq(buf_datalen(buf), 25500);
|
||||
for (j=0;j<100;++j) {
|
||||
r = 10;
|
||||
move_buf_to_buf(buf2, buf, &r);
|
||||
test_eq(r, 0);
|
||||
}
|
||||
test_eq(buf_datalen(buf), 24500);
|
||||
test_eq(buf_datalen(buf2), 1000);
|
||||
for (j=0;j<3;++j) {
|
||||
fetch_from_buf(str2, 255, buf2);
|
||||
test_memeq(str2, str, 255);
|
||||
}
|
||||
r = 8192; /*big move*/
|
||||
move_buf_to_buf(buf2, buf, &r);
|
||||
test_eq(r, 0);
|
||||
r = 30000; /* incomplete move */
|
||||
move_buf_to_buf(buf2, buf, &r);
|
||||
test_eq(r, 13692);
|
||||
for (j=0;j<97;++j) {
|
||||
fetch_from_buf(str2, 255, buf2);
|
||||
test_memeq(str2, str, 255);
|
||||
}
|
||||
buf_free(buf);
|
||||
buf_free(buf2);
|
||||
|
||||
#if 0
|
||||
{
|
||||
int s;
|
||||
|
@ -285,8 +317,6 @@ test_buffers(void)
|
|||
test_eq(eof, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
buf_free(buf);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Add table
Reference in a new issue