static int connection_receiver_bucket_should_increase(connection_t *conn);
static int connection_finished_flushing(connection_t *conn);
static int connection_finished_connecting(connection_t *conn);
+static int connection_reached_eof(connection_t *conn);
static int connection_read_to_buf(connection_t *conn, int *max_to_read);
static int connection_process_inbuf(connection_t *conn, int package_partial);
static int connection_bucket_read_limit(connection_t *conn);
if (connection_process_inbuf(conn, 1) < 0) {
return -1;
}
+ if (conn->inbuf_reached_eof && connection_reached_eof(conn) < 0) {
+ return -1;
+ }
return 0;
}
case CONN_TYPE_CONTROL:
return connection_control_process_inbuf(conn);
default:
- log_fn(LOG_WARN,"got unexpected conn->type %d.", conn->type);
+ log_fn(LOG_WARN,"got unexpected conn type %d.", conn->type);
return -1;
}
}
case CONN_TYPE_CONTROL:
return connection_control_finished_flushing(conn);
default:
- log_fn(LOG_WARN,"got unexpected conn->type %d.", conn->type);
+ log_fn(LOG_WARN,"got unexpected conn type %d.", conn->type);
return -1;
}
}
case CONN_TYPE_DIR:
return connection_dir_finished_connecting(conn);
default:
- tor_assert(0);
+ log_fn(LOG_WARN,"got unexpected conn type %d.", conn->type);
+ return -1;
+ }
+}
+
+static int connection_reached_eof(connection_t *conn)
+{
+ switch (conn->type) {
+ case CONN_TYPE_OR:
+ return connection_or_reached_eof(conn);
+ case CONN_TYPE_AP:
+ case CONN_TYPE_EXIT:
+ return connection_edge_reached_eof(conn);
+ case CONN_TYPE_DIR:
+ return connection_dir_reached_eof(conn);
+ case CONN_TYPE_DNSWORKER:
+ return connection_dns_reached_eof(conn);
+ case CONN_TYPE_CPUWORKER:
+ return connection_cpu_reached_eof(conn);
+ case CONN_TYPE_CONTROL:
+ return connection_control_reached_eof(conn);
+ default:
+ log_fn(LOG_WARN,"got unexpected conn type %d.", conn->type);
return -1;
}
}
static int connection_ap_handshake_process_socks(connection_t *conn);
-/** Handle new bytes on conn->inbuf, or notification of eof.
- *
- * If there was an EOF, then send an end and mark the connection
- * for close.
- *
- * Otherwise handle it based on state:
+/** There was an EOF. Send an end and mark the connection for close.
+ */
+int connection_edge_reached_eof(connection_t *conn) {
+#ifdef HALF_OPEN
+ /* eof reached; we're done reading, but we might want to write more. */
+ conn->done_receiving = 1;
+ shutdown(conn->s, 0); /* XXX check return, refactor NM */
+ if (conn->done_sending) {
+ connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
+ connection_mark_for_close(conn);
+ } else {
+ connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_END,
+ NULL, 0, conn->cpath_layer);
+ }
+ return 0;
+#else
+ /* eof reached, kill it. */
+ log_fn(LOG_INFO,"conn (fd %d) reached eof (stream size %d). Closing.", conn->s, (int)conn->stream_size);
+ connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
+ if(!conn->marked_for_close) {
+ /* only mark it if not already marked. it's possible to
+ * get the 'end' right around when the client hangs up on us. */
+ connection_mark_for_close(conn);
+ }
+ conn->hold_open_until_flushed = 1; /* just because we shouldn't read
+ doesn't mean we shouldn't write */
+ return 0;
+#endif
+}
+
+/** Handle new bytes on conn->inbuf based on state:
* - If it's waiting for socks info, try to read another step of the
* socks handshake out of conn->inbuf.
* - If it's open, then package more relay cells from the stream.
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_AP || conn->type == CONN_TYPE_EXIT);
- if(conn->inbuf_reached_eof) {
-#ifdef HALF_OPEN
- /* eof reached; we're done reading, but we might want to write more. */
- conn->done_receiving = 1;
- shutdown(conn->s, 0); /* XXX check return, refactor NM */
- if (conn->done_sending) {
- connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
- connection_mark_for_close(conn);
- } else {
- connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_END,
- NULL, 0, conn->cpath_layer);
- }
- return 0;
-#else
- /* eof reached, kill it. */
- log_fn(LOG_INFO,"conn (fd %d) reached eof (stream size %d). Closing.", conn->s, (int)conn->stream_size);
- connection_edge_end(conn, END_STREAM_REASON_DONE, conn->cpath_layer);
- if(!conn->marked_for_close) {
- /* only mark it if not already marked. it's possible to
- * get the 'end' right around when the client hangs up on us. */
- connection_mark_for_close(conn);
- }
- conn->hold_open_until_flushed = 1; /* just because we shouldn't read
- doesn't mean we shouldn't write */
- return 0;
-#endif
- }
-
switch(conn->state) {
case AP_CONN_STATE_SOCKS_WAIT:
if(connection_ap_handshake_process_socks(conn) < 0) {
memcpy(dest->payload, src+3, CELL_PAYLOAD_SIZE);
}
+int connection_or_reached_eof(connection_t *conn) {
+ log_fn(LOG_INFO,"OR connection reached EOF. Closing.");
+ connection_mark_for_close(conn);
+ return 0;
+}
+
/** Handle any new bytes that have come in on connection <b>conn</b>.
* If conn is in 'open' state, hand it to
* connection_or_process_cells_from_inbuf()
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_OR);
- if(conn->inbuf_reached_eof) {
- log_fn(LOG_INFO,"OR connection reached EOF. Closing.");
- connection_mark_for_close(conn);
- return 0;
- }
-
if(conn->state != OR_CONN_STATE_OPEN)
return 0; /* don't do anything */
return connection_or_process_cells_from_inbuf(conn);
return 0;
}
-/** Called when <b>conn</b> has received more bytes on its inbuf, or has
- * gotten its socket closed. */
+/** Called when <b>conn</b> has gotten its socket closed. */
+int connection_control_reached_eof(connection_t *conn) {
+ log_fn(LOG_INFO,"Control connection reached EOF. Closing.");
+ connection_mark_for_close(conn);
+ return 0;
+}
+
+/** Called when <b>conn</b> has received more bytes on its inbuf.
+ */
int
connection_control_process_inbuf(connection_t *conn) {
uint16_t body_len, command_type;
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_CONTROL);
- if(conn->inbuf_reached_eof) {
- log_fn(LOG_INFO,"Control connection reached EOF. Closing.");
- connection_mark_for_close(conn);
- return 0;
- }
-
again:
/* Try to suck a control message from the buffer. */
switch(fetch_from_buf_control(conn->inbuf, &body_len, &command_type, &body))
spawn_enough_cpuworkers();
}
+/** If the cpuworker closes the connection,
+ * mark it as closed and spawn a new one as needed. */
+int connection_cpu_reached_eof(connection_t *conn) {
+ log_fn(LOG_WARN,"Read eof. Worker died unexpectedly.");
+ if(conn->state != CPUWORKER_STATE_IDLE) {
+ /* the circ associated with this cpuworker will have to wait until
+ * it gets culled in run_connection_housekeeping(), since we have
+ * no way to find out which circ it was. */
+ log_fn(LOG_WARN,"...and it left a circuit queued; abandoning circ.");
+ num_cpuworkers_busy--;
+ }
+ num_cpuworkers--;
+ spawn_enough_cpuworkers(); /* try to regrow. hope we don't end up spinning. */
+ connection_mark_for_close(conn);
+ return 0;
+}
+
/** Called when we get data from a cpuworker. If the answer is not complete,
- * wait for a complete answer. If the cpuworker closes the connection,
- * mark it as closed and spawn a new one as needed. If the answer is complete,
+ * wait for a complete answer. If the answer is complete,
* process it as appropriate.
*/
int connection_cpu_process_inbuf(connection_t *conn) {
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_CPUWORKER);
- if(conn->inbuf_reached_eof) {
- log_fn(LOG_WARN,"Read eof. Worker died unexpectedly.");
- if(conn->state != CPUWORKER_STATE_IDLE) {
- /* the circ associated with this cpuworker will have to wait until
- * it gets culled in run_connection_housekeeping(), since we have
- * no way to find out which circ it was. */
- log_fn(LOG_WARN,"...and it left a circuit queued; abandoning circ.");
- num_cpuworkers_busy--;
- }
- num_cpuworkers--;
- spawn_enough_cpuworkers(); /* try to regrow. hope we don't end up spinning. */
- connection_mark_for_close(conn);
- return 0;
- }
-
if(conn->state == CPUWORKER_STATE_BUSY_ONION) {
if(buf_datalen(conn->inbuf) < LEN_ONION_RESPONSE) /* entire answer available? */
return 0; /* not yet */
return 0;
}
+int connection_dir_reached_eof(connection_t *conn) {
+ int retval;
+ if(conn->state != DIR_CONN_STATE_CLIENT_READING) {
+ log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
+ connection_close_immediate(conn); /* it was an error; give up on flushing */
+ connection_mark_for_close(conn);
+ return -1;
+ }
+
+ retval = connection_dir_client_reached_eof(conn);
+ connection_mark_for_close(conn);
+ return retval;
+}
+
/** Read handler for directory connections. (That's connections <em>to</em>
* directory servers and connections <em>at</em> directory servers.)
*/
int connection_dir_process_inbuf(connection_t *conn) {
- int retval;
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_DIR);
* write their response (when it's finished flushing, they mark for
* close).
*/
- if(conn->inbuf_reached_eof) {
- if(conn->state != DIR_CONN_STATE_CLIENT_READING) {
- log_fn(LOG_INFO,"conn reached eof, not reading. Closing.");
- connection_close_immediate(conn); /* it was an error; give up on flushing */
- connection_mark_for_close(conn);
- return -1;
- }
-
- retval = connection_dir_client_reached_eof(conn);
- connection_mark_for_close(conn);
- return retval;
- } /* endif 'reached eof' */
/* If we're on the dirserver side, look for a command. */
if(conn->state == DIR_CONN_STATE_SERVER_COMMAND_WAIT) {
return 0;
}
-/** Read handler: called when we get data from a dnsworker. If the
- * connection is closed, mark the dnsworker as dead. Otherwise, see
+int connection_dns_reached_eof(connection_t *conn) {
+ log_fn(LOG_WARN,"Read eof. Worker died unexpectedly.");
+ if(conn->state == DNSWORKER_STATE_BUSY) {
+ dns_cancel_pending_resolve(conn->address);
+ num_dnsworkers_busy--;
+ }
+ num_dnsworkers--;
+ connection_mark_for_close(conn);
+ return 0;
+}
+
+/** Read handler: called when we get data from a dnsworker. See
* if we have a complete answer. If so, call dns_found_answer on the
* result. If not, wait. Returns 0. */
int connection_dns_process_inbuf(connection_t *conn) {
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_DNSWORKER);
- if(conn->inbuf_reached_eof) {
- log_fn(LOG_WARN,"Read eof. Worker died unexpectedly.");
- if(conn->state == DNSWORKER_STATE_BUSY) {
- dns_cancel_pending_resolve(conn->address);
- num_dnsworkers_busy--;
- }
- num_dnsworkers--;
- connection_mark_for_close(conn);
- return 0;
- }
-
if(conn->state != DNSWORKER_STATE_BUSY) {
log_fn(LOG_WARN,"Bug: poll() indicated than an idle dns worker was readable. Please report.");
return 0;
/********************************* connection_edge.c ***************************/
+int connection_edge_reached_eof(connection_t *conn);
int connection_edge_process_inbuf(connection_t *conn, int package_partial);
int connection_edge_destroy(uint16_t circ_id, connection_t *conn);
int connection_edge_end(connection_t *conn, char reason, crypt_path_t *cpath_layer);
/********************************* connection_or.c ***************************/
+int connection_or_reached_eof(connection_t *conn);
int connection_or_process_inbuf(connection_t *conn);
int connection_or_finished_flushing(connection_t *conn);
int connection_or_finished_connecting(connection_t *conn);
} or_conn_status_event_t;
int connection_control_finished_flushing(connection_t *conn);
+int connection_control_reached_eof(connection_t *conn);
int connection_control_process_inbuf(connection_t *conn);
int control_event_circuit_status(circuit_t *circ, circuit_status_event_t e);
void cpu_init(void);
void cpuworkers_rotate(void);
int connection_cpu_finished_flushing(connection_t *conn);
+int connection_cpu_reached_eof(connection_t *conn);
int connection_cpu_process_inbuf(connection_t *conn);
int assign_to_cpuworker(connection_t *cpuworker, unsigned char question_type,
void *task);
void directory_post_to_dirservers(uint8_t purpose, const char *payload,
size_t payload_len);
void directory_get_from_dirserver(uint8_t purpose, const char *resource);
+int connection_dir_reached_eof(connection_t *conn);
int connection_dir_process_inbuf(connection_t *conn);
int connection_dir_finished_flushing(connection_t *conn);
int connection_dir_finished_connecting(connection_t *conn);
void dns_init(void);
int connection_dns_finished_flushing(connection_t *conn);
+int connection_dns_reached_eof(connection_t *conn);
int connection_dns_process_inbuf(connection_t *conn);
void dnsworkers_rotate(void);
void connection_dns_remove(connection_t *conn);