tor/src/or/connection_app.c

213 lines
7.3 KiB
C
Raw Normal View History

2002-06-26 22:45:49 +00:00
#include "or.h"
connection_t *connection_app_new(void) {
return connection_new(CONN_TYPE_APP);
}
int connection_app_process_inbuf(connection_t *conn) {
assert(conn && conn->type == CONN_TYPE_APP);
if(conn->inbuf_reached_eof) {
/* eof reached, kill it. */
log(LOG_DEBUG,"connection_app_process_inbuf(): conn reached eof. Closing.");
return -1;
}
log(LOG_DEBUG,"connection_app_process_inbuf(): state %d.",conn->state);
switch(conn->state) {
case APP_CONN_STATE_CONNECTING:
log(LOG_DEBUG,"connection_app_process_inbuf(): text from app server while in 'connecting' state. Leaving it on buffer.");
return 0;
case APP_CONN_STATE_OPEN:
return connection_app_package_inbuf(conn);
}
return 0;
}
int connection_app_package_inbuf(connection_t *conn) {
int amount_to_process;
cell_t cell;
circuit_t *circ;
assert(conn && conn->type == CONN_TYPE_APP);
amount_to_process = conn->inbuf_datalen;
if(!amount_to_process)
return 0;
if(amount_to_process > CELL_PAYLOAD_SIZE) {
cell.length = CELL_PAYLOAD_SIZE;
} else {
cell.length = amount_to_process;
}
if(connection_fetch_from_buf(cell.payload,cell.length,conn) < 0) {
return -1;
}
circ = circuit_get_by_conn(conn);
if(!circ) {
log(LOG_DEBUG,"connection_app_package_inbuf(): conn has no circuits!");
return -1;
}
log(LOG_DEBUG,"connection_app_package_inbuf(): Packaging %d bytes.",cell.length);
cell.aci = circ->p_aci;
cell.command = CELL_DATA;
if(circuit_deliver_data_cell(&cell, circ, circ->p_conn, 'e') < 0) {
log(LOG_DEBUG,"connection_app_package_inbuf(): circuit_deliver_data_cell (backward) failed. Closing.");
circuit_close(circ);
return 0;
}
if(amount_to_process > CELL_PAYLOAD_SIZE)
return(connection_app_package_inbuf(conn));
return 0;
}
int connection_app_finished_flushing(connection_t *conn) {
int e, len=sizeof(e);
assert(conn && conn->type == CONN_TYPE_APP);
switch(conn->state) {
case APP_CONN_STATE_CONNECTING:
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0) { /* not yet */
if(errno != EINPROGRESS){
/* yuck. kill it. */
log(LOG_DEBUG,"connection_app_finished_flushing(): in-progress connect failed. Removing.");
return -1;
} else {
return 0; /* no change, see if next time is better */
}
}
/* the connect has finished. */
log(LOG_DEBUG,"connection_app_finished_flushing() : Connection to %s:%u established.",
conn->address,ntohs(conn->port));
conn->state = APP_CONN_STATE_OPEN;
connection_watch_events(conn, POLLIN);
return 0;
case APP_CONN_STATE_OPEN:
/* FIXME down the road, we'll clear out circuits that are pending to close */
connection_watch_events(conn, POLLIN);
return 0;
default:
log(LOG_DEBUG,"Bug: connection_app_finished_flushing() called in unexpected state.");
return 0;
}
return 0;
}
int connection_app_process_data_cell(cell_t *cell, connection_t *conn) {
struct hostent *rent;
struct sockaddr_in dest_addr;
int s;
/* an outgoing data cell has arrived */
assert(conn && conn->type == CONN_TYPE_APP);
switch(conn->state) {
case APP_CONN_STATE_CONNECTING_WAIT:
log(LOG_DEBUG,"connection_app_process_cell(): state is connecting_wait. cell length %d.", cell->length);
if(!conn->ss_received) { /* this cell contains the ss */
if(cell->length != sizeof(ss_t)) {
log(LOG_DEBUG,"connection_app_process_cell(): Supposed to contain SS but wrong size. Closing.");
return -1;
}
memcpy(&conn->ss, cell->payload, cell->length);
if(conn->ss.addr_fmt != SS_ADDR_FMT_ASCII_HOST_PORT) { /* unrecognized address format */
log(LOG_DEBUG,"connection_app_process_cell(): SS has unrecognized address format. Closing.");
return -1;
}
conn->ss_received = 1;
log(LOG_DEBUG,"connection_app_process_cell(): SS received.");
} else if (!conn->addr) { /* this cell contains the dest addr */
if(!memchr(cell->payload,0,cell->length)) {
log(LOG_DEBUG,"connection_app_process_cell(): dest_addr cell has no \\0. Closing.");
return -1;
}
conn->address = strdup(cell->payload);
rent = gethostbyname(cell->payload);
if (!rent) {
log(LOG_ERR,"connection_app_process_cell(): Could not resolve dest addr %s.",cell->payload);
return -1;
}
memcpy(&conn->addr, rent->h_addr,rent->h_length);
log(LOG_DEBUG,"connection_app_process_cell(): addr %s resolves to %d.",cell->payload,conn->addr);
} else if (!conn->port) { /* this cell contains the dest port */
if(!memchr(cell->payload,'\0',cell->length)) {
log(LOG_DEBUG,"connection_app_process_cell(): dest_port cell has no \\0. Closing.");
return -1;
}
conn->port = atoi(cell->payload);
if(!conn->port) { /* bad port */
log(LOG_DEBUG,"connection_app_process_cell(): dest_port cell isn't a valid number. Closing.");
return -1;
}
/* all the necessary info is here. Start the connect() */
s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
if (s < 0)
{
log(LOG_ERR,"connection_app_process_cell(): Error creating network socket.");
return -1;
}
fcntl(s, F_SETFL, O_NONBLOCK); /* set s to non-blocking */
memset((void *)&dest_addr,0,sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = conn->port;
memcpy((void *)&dest_addr.sin_addr, &conn->addr, sizeof(uint32_t));
log(LOG_DEBUG,"connection_app_process_cell(): Connecting to %s:%u.",conn->address,ntohs(conn->port));
if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0){
if(errno != EINPROGRESS){
/* yuck. kill it. */
log(LOG_DEBUG,"connection_app_process_cell(): Connect failed.");
return -1;
} else {
/* it's in progress. set state appropriately and return. */
conn->s = s;
connection_set_poll_socket(conn);
conn->state = APP_CONN_STATE_CONNECTING;
/* i think only pollout is needed, but i'm curious if pollin ever gets caught -RD */
log(LOG_DEBUG,"connection_app_process_cell(): connect in progress, socket %d.",s);
connection_watch_events(conn, POLLOUT | POLLIN);
return 0;
}
}
/* it succeeded. we're connected. */
log(LOG_DEBUG,"connection_app_process_cell(): Connection to %s:%u established.",conn->address,ntohs(conn->port));
conn->s = s;
connection_set_poll_socket(conn);
conn->state = APP_CONN_STATE_OPEN;
connection_watch_events(conn, POLLIN);
} else { /* i'm not sure what this would be */
log(LOG_DEBUG,"connection_app_process_cell(): in connecting_wait, not sure why.");
}
return 0;
case APP_CONN_STATE_CONNECTING:
log(LOG_DEBUG,"connection_app_process_cell(): Data receiving while connecting. Queueing.");
/* FIXME kludge. shouldn't call write_to_buf directly. */
return write_to_buf(cell->payload, cell->length, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen);
case APP_CONN_STATE_OPEN:
return connection_write_to_buf(cell->payload, cell->length, conn);
}
return 0;
}