2002-06-26 22:45:49 +00:00
|
|
|
|
|
|
|
#include "or.h"
|
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
int connection_exit_process_inbuf(connection_t *conn) {
|
2002-06-26 22:45:49 +00:00
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
assert(conn && conn->type == CONN_TYPE_EXIT);
|
2002-06-26 22:45:49 +00:00
|
|
|
|
|
|
|
if(conn->inbuf_reached_eof) {
|
|
|
|
/* eof reached, kill it. */
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_inbuf(): conn reached eof. Closing.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_inbuf(): state %d.",conn->state);
|
2002-06-26 22:45:49 +00:00
|
|
|
|
|
|
|
switch(conn->state) {
|
2002-06-30 07:37:49 +00:00
|
|
|
case EXIT_CONN_STATE_CONNECTING:
|
|
|
|
log(LOG_DEBUG,"connection_exit_process_inbuf(): text from server while in 'connecting' state. Leaving it on buffer.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return 0;
|
2002-06-30 07:37:49 +00:00
|
|
|
case EXIT_CONN_STATE_OPEN:
|
Integrated onion proxy into or/
The 'or' process can now be told (by the global_role variable) what
roles this server should play -- connect to all ORs, listen for ORs,
listen for OPs, listen for APs, or any combination.
* everything in /src/op/ is now obsolete.
* connection_ap.c now handles all interactions with application proxies
* "port" is now or_port, op_port, ap_port. But routers are still always
referenced (say, in conn_get_by_addr_port()) by addr / or_port. We
should make routers.c actually read these new ports (currently I've
kludged it so op_port = or_port+10, ap_port=or_port+20)
* circuits currently know if they're at the beginning of the path because
circ->cpath is set. They use this instead for crypts (both ways),
if it's set.
* I still obey the "send a 0 back to the AP when you're ready" protocol,
but I think we should phase it out. I can simply not read from the AP
socket until I'm ready.
I need to do a lot of cleanup work here, but the code appears to work, so
now's a good time for a checkin.
svn:r22
2002-07-02 09:36:58 +00:00
|
|
|
return connection_package_raw_inbuf(conn);
|
2002-06-26 22:45:49 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
int connection_exit_finished_flushing(connection_t *conn) {
|
2002-06-26 22:45:49 +00:00
|
|
|
int e, len=sizeof(e);
|
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
assert(conn && conn->type == CONN_TYPE_EXIT);
|
2002-06-26 22:45:49 +00:00
|
|
|
|
|
|
|
switch(conn->state) {
|
2002-06-30 07:37:49 +00:00
|
|
|
case EXIT_CONN_STATE_CONNECTING:
|
2002-06-26 22:45:49 +00:00
|
|
|
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0) { /* not yet */
|
|
|
|
if(errno != EINPROGRESS){
|
|
|
|
/* yuck. kill it. */
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_finished_flushing(): in-progress connect failed. Removing.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 0; /* no change, see if next time is better */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* the connect has finished. */
|
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_finished_flushing() : Connection to %s:%u established.",
|
2002-06-26 22:45:49 +00:00
|
|
|
conn->address,ntohs(conn->port));
|
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
conn->state = EXIT_CONN_STATE_OPEN;
|
2002-06-26 22:45:49 +00:00
|
|
|
connection_watch_events(conn, POLLIN);
|
|
|
|
return 0;
|
2002-06-30 07:37:49 +00:00
|
|
|
case EXIT_CONN_STATE_OPEN:
|
2002-06-26 22:45:49 +00:00
|
|
|
/* FIXME down the road, we'll clear out circuits that are pending to close */
|
|
|
|
connection_watch_events(conn, POLLIN);
|
|
|
|
return 0;
|
|
|
|
default:
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"Bug: connection_exit_finished_flushing() called in unexpected state.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
int connection_exit_process_data_cell(cell_t *cell, connection_t *conn) {
|
2002-06-26 22:45:49 +00:00
|
|
|
struct hostent *rent;
|
|
|
|
struct sockaddr_in dest_addr;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
/* an outgoing data cell has arrived */
|
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
assert(conn && conn->type == CONN_TYPE_EXIT);
|
2002-06-26 22:45:49 +00:00
|
|
|
|
|
|
|
switch(conn->state) {
|
2002-06-30 07:37:49 +00:00
|
|
|
case EXIT_CONN_STATE_CONNECTING_WAIT:
|
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): state is connecting_wait. cell length %d.", cell->length);
|
2002-06-26 22:45:49 +00:00
|
|
|
if(!conn->ss_received) { /* this cell contains the ss */
|
|
|
|
if(cell->length != sizeof(ss_t)) {
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): Supposed to contain SS but wrong size. Closing.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(&conn->ss, cell->payload, cell->length);
|
|
|
|
if(conn->ss.addr_fmt != SS_ADDR_FMT_ASCII_HOST_PORT) { /* unrecognized address format */
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): SS has unrecognized address format. Closing.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
conn->ss_received = 1;
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): SS received.");
|
2002-06-26 22:45:49 +00:00
|
|
|
} else if (!conn->addr) { /* this cell contains the dest addr */
|
|
|
|
if(!memchr(cell->payload,0,cell->length)) {
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): dest_addr cell has no \\0. Closing.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
conn->address = strdup(cell->payload);
|
|
|
|
rent = gethostbyname(cell->payload);
|
|
|
|
if (!rent) {
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_ERR,"connection_exit_process_cell(): Could not resolve dest addr %s.",cell->payload);
|
2002-06-26 22:45:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(&conn->addr, rent->h_addr,rent->h_length);
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): addr %s resolves to %d.",cell->payload,conn->addr);
|
2002-06-26 22:45:49 +00:00
|
|
|
} else if (!conn->port) { /* this cell contains the dest port */
|
|
|
|
if(!memchr(cell->payload,'\0',cell->length)) {
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): dest_port cell has no \\0. Closing.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
conn->port = atoi(cell->payload);
|
|
|
|
if(!conn->port) { /* bad port */
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): dest_port cell isn't a valid number. Closing.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
/* all the necessary info is here. Start the connect() */
|
|
|
|
s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
|
|
|
|
if (s < 0)
|
|
|
|
{
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_ERR,"connection_exit_process_cell(): Error creating network socket.");
|
2002-06-26 22:45:49 +00:00
|
|
|
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));
|
|
|
|
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): Connecting to %s:%u.",conn->address,ntohs(conn->port));
|
2002-06-26 22:45:49 +00:00
|
|
|
|
|
|
|
if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0){
|
|
|
|
if(errno != EINPROGRESS){
|
|
|
|
/* yuck. kill it. */
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): Connect failed.");
|
2002-06-26 22:45:49 +00:00
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
/* it's in progress. set state appropriately and return. */
|
|
|
|
conn->s = s;
|
|
|
|
connection_set_poll_socket(conn);
|
2002-06-30 07:37:49 +00:00
|
|
|
conn->state = EXIT_CONN_STATE_CONNECTING;
|
2002-06-26 22:45:49 +00:00
|
|
|
|
|
|
|
/* i think only pollout is needed, but i'm curious if pollin ever gets caught -RD */
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): connect in progress, socket %d.",s);
|
2002-06-26 22:45:49 +00:00
|
|
|
connection_watch_events(conn, POLLOUT | POLLIN);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* it succeeded. we're connected. */
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): Connection to %s:%u established.",conn->address,ntohs(conn->port));
|
2002-06-26 22:45:49 +00:00
|
|
|
|
|
|
|
conn->s = s;
|
|
|
|
connection_set_poll_socket(conn);
|
2002-06-30 07:37:49 +00:00
|
|
|
conn->state = EXIT_CONN_STATE_OPEN;
|
2002-06-26 22:45:49 +00:00
|
|
|
connection_watch_events(conn, POLLIN);
|
|
|
|
} else { /* i'm not sure what this would be */
|
2002-06-30 07:37:49 +00:00
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): in connecting_wait, not sure why.");
|
2002-06-26 22:45:49 +00:00
|
|
|
}
|
|
|
|
return 0;
|
2002-06-30 07:37:49 +00:00
|
|
|
case EXIT_CONN_STATE_CONNECTING:
|
|
|
|
log(LOG_DEBUG,"connection_exit_process_cell(): Data receiving while connecting. Queueing.");
|
2002-06-26 22:45:49 +00:00
|
|
|
/* FIXME kludge. shouldn't call write_to_buf directly. */
|
|
|
|
return write_to_buf(cell->payload, cell->length, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen);
|
2002-06-30 07:37:49 +00:00
|
|
|
case EXIT_CONN_STATE_OPEN:
|
2002-06-26 22:45:49 +00:00
|
|
|
return connection_write_to_buf(cell->payload, cell->length, conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|