commit 4b754df88f8d658b4731ce93f2fcafcc34b72244 Author: George Kadianakis <desnac...@riseup.net> Date: Sat Mar 17 16:01:22 2012 -0700
Don't set bufferevent callbacks before forming the circuit. Achieve that by splitting the circuit creation into three parts: First, create the connection on the other side of the circuit. Then, build the circuit. Finally, set up bufferevent callbacks. Conflicts: src/network.c --- src/network.c | 151 +++++++++++++++++++++++++++------------------------------ 1 files changed, 72 insertions(+), 79 deletions(-) diff --git a/src/network.c b/src/network.c index e42b195..219593f 100644 --- a/src/network.c +++ b/src/network.c @@ -150,7 +150,6 @@ static void conn_free_on_flush(struct bufferevent *bev, void *arg); static void circuit_create_socks(conn_t *up); static int circuit_add_down(circuit_t *circuit, conn_t *down); static void circuit_free(circuit_t *circuit); -static conn_t *open_outbound(conn_t *conn, bufferevent_data_cb readcb); static void upstream_read_cb(struct bufferevent *bev, void *arg); static void downstream_read_cb(struct bufferevent *bev, void *arg); @@ -339,48 +338,63 @@ static int conn_connect(conn_t *addr_conn, conn_t *connect_conn, bufferevent_data_cb readcb) { - bufferevent_setcb(buf, readcb, NULL, pending_conn_cb, newconn); + char *peername; + struct evutil_addrinfo *addr = config_get_target_addr(addr_conn->cfg); + struct bufferevent *buf = connect_conn->buffer; + + if (!addr) { + log_warn("%s: no target addresses available", safe_str(addr_conn->peername)); + return -1; + } + + bufferevent_setcb(buf, readcb, NULL, pending_conn_cb, connect_conn); do { peername = printable_address(addr->ai_addr, addr->ai_addrlen); + if (bufferevent_socket_connect(buf, addr->ai_addr, addr->ai_addrlen) >= 0) goto success; log_info("%s: connection to %s failed: %s", - safe_str(conn->peername), safe_str(peername), + safe_str(addr_conn->peername), safe_str(peername), evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); free(peername); addr = addr->ai_next; } while (addr); log_warn("%s: all outbound connection attempts failed", - conn->peername); + addr_conn->peername); - conn_free(newconn); - return NULL; + return -1; success: log_info("%s (%s): Successful outbound connection to '%s'.", - safe_str(conn->peername), conn->cfg->vtable->name, safe_str(peername)); + safe_str(addr_conn->peername), + addr_conn->cfg->vtable->name, safe_str(peername)); bufferevent_enable(buf, EV_READ|EV_WRITE); - newconn->peername = peername; - obfs_assert(connections); - smartlist_add(connections, newconn); + connect_conn->peername = peername; /* If we are a server, we should note this connection and consider it in our heartbeat status messages. */ - if (conn->mode == LSN_SIMPLE_SERVER) - status_note_connection(conn->peername); + if (addr_conn->mode == LSN_SIMPLE_SERVER) + status_note_connection(addr_conn->peername); + + return 0; } /** Create the other side of connection <b>conn</b> on a circuit. */ static conn_t * create_other_side_of_conn(const conn_t *conn) { + struct event_base *base = bufferevent_get_base(conn->buffer); + struct bufferevent *buf; + conn_t *newconn; + buf = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); if (!buf) { log_warn("%s: unable to create outbound socket buffer", safe_str(conn->peername)); return NULL; } + newconn = proto_conn_create(conn->cfg); if (!newconn) { log_warn("%s: failed to allocate state for outbound connection", @@ -391,6 +405,11 @@ create_other_side_of_conn(const conn_t *conn) /* associate bufferevent with the new connection. */ newconn->buffer = buf; + + obfs_assert(connections); + smartlist_add(connections, newconn); + + return newconn; } /** @@ -406,11 +425,22 @@ simple_client_listener_cb(conn_t *conn) bufferevent_setcb(conn->buffer, upstream_read_cb, NULL, error_cb, conn); - if (circuit_create(conn, open_outbound(conn, downstream_read_cb))) { + conn_t *newconn = create_other_side_of_conn(conn); + if (!newconn) { + conn_free(conn); + return; + } + + if (circuit_create(conn, newconn)) { conn_free(conn); return; } + if (conn_connect(conn, newconn, downstream_read_cb) < 0) { + conn_free(conn); /* circuit_free() should also free newconn. */ + return; + } + log_debug("%s: setup complete", safe_str(conn->peername)); } @@ -449,7 +479,18 @@ simple_server_listener_cb(conn_t *conn) bufferevent_setcb(conn->buffer, downstream_read_cb, NULL, error_cb, conn); - if (circuit_create(open_outbound(conn, upstream_read_cb), conn)) { + conn_t *newconn = create_other_side_of_conn(conn); + if (!newconn) { + conn_free(conn); + return; + } + + if (circuit_create(newconn, conn)) { + conn_free(conn); + return; + } + + if (conn_connect(conn, newconn, upstream_read_cb) < 0) { conn_free(conn); return; } @@ -560,61 +601,6 @@ circuit_free(circuit_t *circuit) } /** - Make the outbound connection for a circuit. -*/ -static conn_t * -open_outbound(conn_t *conn, bufferevent_data_cb readcb) -{ - struct evutil_addrinfo *addr = config_get_target_addr(conn->cfg); - struct event_base *base = bufferevent_get_base(conn->buffer); - struct bufferevent *buf; - char *peername; - conn_t *newconn; - - if (!addr) { - log_warn("%s: no target addresses available", safe_str(conn->peername)); - return NULL; - } - - buf = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE); - if (!buf) { - log_warn("%s: unable to create outbound socket buffer", safe_str(conn->peername)); - return NULL; - } - - newconn = proto_conn_create(conn->cfg); - if (!newconn) { - log_warn("%s: failed to allocate state for outbound connection", - safe_str(conn->peername)); - bufferevent_free(buf); - return NULL; - } - - newconn->buffer = buf; - - return newconn; -} - -/** - As open_outbound, but uses bufferevent_socket_connect_hostname - rather than bufferevent_socket_connect. -*/ -static conn_t * -open_outbound_hostname(conn_t *conn, int af, const char *addr, uint16_t port) -{ - struct event_base *base = bufferevent_get_base(conn->buffer); - struct bufferevent *buf; - conn_t *newconn; - - /* Set up a temporary FQDN peername. When we actually connect to the - host, we will replace this peername with the IP address we - connected to. */ - obfs_asprintf(&newconn->peername, "%s:%u", addr, port); - - return newconn; -} - -/** This callback is responsible for handling SOCKS traffic. */ static void @@ -644,26 +630,33 @@ socks_read_cb(struct bufferevent *bev, void *arg) log_info("%s: socks: trying to connect to %s:%u", safe_str(conn->peername), safe_str(addr), port); - if (circuit_add_down(conn->circuit, - open_outbound_hostname(conn, af, addr, port))) { + conn_t *newconn = create_other_side_of_conn(conn); + if (!newconn) { + conn_free(conn); + return; + } + + /* Set up a temporary FQDN peername. When we actually connect to the + host, we will replace this peername with the IP address we + connected to. */ + obfs_asprintf(&newconn->peername, "%s:%u", addr, port); + + if (circuit_add_down(conn->circuit, newconn)) { /* XXXX send socks reply */ conn_free(conn); return; } - bufferevent_setcb(buf, downstream_read_cb, NULL, pending_socks_cb, newconn); - if (bufferevent_socket_connect_hostname(buf, get_evdns_base(), + bufferevent_setcb(newconn->buffer, downstream_read_cb, NULL, pending_socks_cb, newconn); + if (bufferevent_socket_connect_hostname(newconn->buffer, get_evdns_base(), af, addr, port) < 0) { log_warn("%s: outbound connection to %s:%u failed: %s", safe_str(conn->peername), addr, port, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())); - conn_free(newconn); - return NULL; + conn_free(conn); + return; } - - bufferevent_enable(buf, EV_READ|EV_WRITE); - obfs_assert(connections); - smartlist_add(connections, newconn); + bufferevent_enable(newconn->buffer, EV_READ|EV_WRITE); /* further upstream data will be processed once the downstream side is established */ _______________________________________________ tor-commits mailing list tor-commits@lists.torproject.org https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits