2003-12-13 23:53:17 +01:00
/* Copyright 2001,2002,2003 Roger Dingledine. */
2002-09-26 14:09:10 +02:00
/* See LICENSE for licensing information */
/* $Id$ */
# include "or.h"
2004-04-01 00:02:13 +02:00
static void directory_send_command ( connection_t * conn , int purpose ,
const char * payload , int payload_len ) ;
2003-09-16 07:41:49 +02:00
static int directory_handle_command ( connection_t * conn ) ;
2002-09-26 14:09:10 +02:00
/********* START VARIABLES **********/
extern or_options_t options ; /* command-line and config-file options */
2004-02-29 02:31:33 +01:00
extern int has_fetched_directory ;
2002-09-26 14:09:10 +02:00
2004-04-03 05:33:57 +02:00
char rend_publish_string [ ] = " /rendezvous/publish " ;
char rend_fetch_url [ ] = " /rendezvous/ " ;
2004-03-12 13:43:13 +01:00
# define MAX_HEADERS_SIZE 2048
# define MAX_BODY_SIZE 500000
2002-09-26 14:09:10 +02:00
/********* END VARIABLES ************/
2004-04-01 00:02:13 +02:00
void directory_initiate_command ( routerinfo_t * router , int purpose ,
const char * payload , int payload_len ) {
2002-09-26 14:09:10 +02:00
connection_t * conn ;
2004-04-01 00:02:13 +02:00
if ( purpose = = DIR_PURPOSE_FETCH_DIR )
log_fn ( LOG_DEBUG , " initiating directory fetch " ) ;
2004-04-01 23:32:01 +02:00
if ( purpose = = DIR_PURPOSE_FETCH_RENDDESC )
2004-04-01 00:02:13 +02:00
log_fn ( LOG_DEBUG , " initiating hidden-service descriptor fetch " ) ;
if ( purpose = = DIR_PURPOSE_UPLOAD_DIR )
log_fn ( LOG_DEBUG , " initiating server descriptor upload " ) ;
2004-04-01 23:32:01 +02:00
if ( purpose = = DIR_PURPOSE_UPLOAD_RENDDESC )
2004-04-01 00:02:13 +02:00
log_fn ( LOG_DEBUG , " initiating hidden-service descriptor upload " ) ;
2002-09-28 07:53:00 +02:00
2003-11-10 09:06:55 +01:00
if ( ! router ) { /* i guess they didn't have one in mind for me to use */
2004-03-31 00:57:49 +02:00
log_fn ( LOG_WARN , " No running dirservers known. Not trying. (purpose %d) " , purpose ) ;
2003-11-10 09:06:55 +01:00
return ;
}
2002-09-26 14:09:10 +02:00
conn = connection_new ( CONN_TYPE_DIR ) ;
/* set up conn so it's got all the data we need to remember */
2002-10-14 08:44:48 +02:00
conn - > addr = router - > addr ;
conn - > port = router - > dir_port ;
2003-10-04 05:29:09 +02:00
conn - > address = tor_strdup ( router - > address ) ;
conn - > nickname = tor_strdup ( router - > nickname ) ;
2003-11-10 09:06:55 +01:00
assert ( router - > identity_pkey ) ;
conn - > identity_pkey = crypto_pk_dup_key ( router - > identity_pkey ) ;
2002-09-26 14:09:10 +02:00
2004-03-31 00:57:49 +02:00
conn - > purpose = purpose ;
2004-03-26 23:07:45 +01:00
2003-09-16 03:58:46 +02:00
if ( connection_add ( conn ) < 0 ) { /* no space, forget it */
2002-09-26 14:09:10 +02:00
connection_free ( conn ) ;
return ;
}
2004-03-31 00:57:49 +02:00
/* queue the command on the outbuf */
2004-04-01 00:02:13 +02:00
directory_send_command ( conn , purpose , payload , payload_len ) ;
2002-09-26 14:09:10 +02:00
2004-03-31 00:57:49 +02:00
if ( purpose = = DIR_PURPOSE_FETCH_DIR | |
purpose = = DIR_PURPOSE_UPLOAD_DIR ) {
/* then we want to connect directly */
conn - > state = DIR_CONN_STATE_CONNECTING ;
switch ( connection_connect ( conn , conn - > address , conn - > addr , conn - > port ) ) {
case - 1 :
router_mark_as_down ( conn - > nickname ) ; /* don't try him again */
connection_mark_for_close ( conn , 0 ) ;
return ;
case 1 :
conn - > state = DIR_CONN_STATE_CLIENT_SENDING ; /* start flushing conn */
/* fall through */
case 0 :
connection_set_poll_socket ( conn ) ;
connection_watch_events ( conn , POLLIN | POLLOUT | POLLERR ) ;
/* writable indicates finish, readable indicates broken link,
error indicates broken link in windowsland . */
}
} else { /* we want to connect via tor */
/* make an AP connection
* populate it and add it at the right state
* socketpair and hook up both sides
*/
2004-04-01 00:02:13 +02:00
conn - > s = connection_ap_make_bridge ( conn - > address , conn - > port ) ;
if ( conn - > s < 0 ) {
log_fn ( LOG_WARN , " Making AP bridge to dirserver failed. " ) ;
connection_mark_for_close ( conn , 0 ) ;
return ;
}
2004-03-31 00:57:49 +02:00
2004-04-07 21:57:40 +02:00
conn - > state = DIR_CONN_STATE_CLIENT_SENDING ;
2004-03-31 00:57:49 +02:00
connection_set_poll_socket ( conn ) ;
2004-04-03 03:59:53 +02:00
connection_start_reading ( conn ) ;
2002-09-26 14:09:10 +02:00
}
}
2004-04-01 00:02:13 +02:00
static void directory_send_command ( connection_t * conn , int purpose ,
const char * payload , int payload_len ) {
2004-03-12 13:43:13 +01:00
char fetchstring [ ] = " GET / HTTP/1.0 \r \n \r \n " ;
2003-09-25 12:42:07 +02:00
char tmp [ 8192 ] ;
2002-09-26 14:09:10 +02:00
assert ( conn & & conn - > type = = CONN_TYPE_DIR ) ;
2004-03-31 00:57:49 +02:00
switch ( purpose ) {
case DIR_PURPOSE_FETCH_DIR :
assert ( payload = = NULL ) ;
2003-10-04 04:38:18 +02:00
connection_write_to_buf ( fetchstring , strlen ( fetchstring ) , conn ) ;
2003-09-17 22:09:06 +02:00
break ;
2004-03-31 00:57:49 +02:00
case DIR_PURPOSE_UPLOAD_DIR :
assert ( payload ) ;
2003-09-25 12:42:07 +02:00
snprintf ( tmp , sizeof ( tmp ) , " POST / HTTP/1.0 \r \n Content-Length: %d \r \n \r \n %s " ,
2004-04-01 00:02:13 +02:00
payload_len , payload ) ;
2004-03-31 00:57:49 +02:00
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
break ;
2004-04-01 23:32:01 +02:00
case DIR_PURPOSE_FETCH_RENDDESC :
2004-03-31 00:57:49 +02:00
assert ( payload ) ;
2004-04-01 23:32:01 +02:00
/* this must be true or we wouldn't be doing the lookup */
assert ( payload_len < = REND_SERVICE_ID_LEN ) ;
memcpy ( conn - > rend_query , payload , payload_len ) ;
conn - > rend_query [ payload_len ] = 0 ;
2004-04-03 05:33:57 +02:00
snprintf ( tmp , sizeof ( tmp ) , " GET %s%s HTTP/1.0 \r \n \r \n " , rend_fetch_url , payload ) ;
2004-03-31 00:57:49 +02:00
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
break ;
2004-04-01 23:32:01 +02:00
case DIR_PURPOSE_UPLOAD_RENDDESC :
2004-03-31 00:57:49 +02:00
assert ( payload ) ;
snprintf ( tmp , sizeof ( tmp ) ,
2004-04-03 05:33:57 +02:00
" POST %s HTTP/1.0 \r \n Content-Length: %d \r \n \r \n " , rend_publish_string , payload_len ) ;
2003-10-04 04:38:18 +02:00
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
2004-04-01 00:02:13 +02:00
/* could include nuls, need to write it separately */
connection_write_to_buf ( payload , payload_len , conn ) ;
2003-09-17 22:09:06 +02:00
break ;
2002-09-26 14:09:10 +02:00
}
2004-03-31 00:57:49 +02:00
}
/* Parse "%s %s HTTP/1..."
* If it ' s well - formed , point * url to the second % s ,
* null - terminate it ( this modifies headers ! ) and return 0.
* Otherwise , return - 1.
*/
int parse_http_url ( char * headers , char * * url ) {
char * s , * tmp ;
s = ( char * ) eat_whitespace_no_nl ( headers ) ;
if ( ! * s ) return - 1 ;
s = ( char * ) find_whitespace ( s ) ; /* get past GET/POST */
if ( ! * s ) return - 1 ;
s = ( char * ) eat_whitespace_no_nl ( s ) ;
if ( ! * s ) return - 1 ;
tmp = s ; /* this is it, assuming it's valid */
s = ( char * ) find_whitespace ( s ) ;
if ( ! * s ) return - 1 ;
* s = 0 ;
* url = tmp ;
2002-09-26 14:09:10 +02:00
return 0 ;
}
2004-03-12 13:43:13 +01:00
/* Parse "HTTP/1.%d %d%s\r\n".
* If it ' s well - formed , assign * code , point * message to the first
* non - space character after code if there is one and message is non - NULL
* ( else leave it alone ) , and return 0.
* Otherwise , return - 1.
*/
int parse_http_response ( char * headers , int * code , char * * message ) {
int n1 , n2 ;
assert ( headers & & code ) ;
2004-03-19 21:50:12 +01:00
while ( isspace ( ( int ) * headers ) ) headers + + ; /* tolerate leading whitespace */
2004-03-12 13:43:13 +01:00
if ( sscanf ( headers , " HTTP/1.%d %d " , & n1 , & n2 ) < 2 | |
( n1 ! = 0 & & n1 ! = 1 ) | |
( n2 < 100 | | n2 > = 600 ) ) {
log_fn ( LOG_WARN , " Failed to parse header '%s' " , headers ) ;
return - 1 ;
}
* code = n2 ;
if ( message ) {
/* XXX should set *message correctly */
}
return 0 ;
}
2002-09-26 14:09:10 +02:00
int connection_dir_process_inbuf ( connection_t * conn ) {
2004-04-01 23:32:01 +02:00
char * body ;
2004-03-12 13:43:13 +01:00
char * headers ;
2004-04-01 23:32:01 +02:00
int body_len = 0 ;
2004-03-12 13:43:13 +01:00
int status_code ;
2002-09-26 14:09:10 +02:00
assert ( conn & & conn - > type = = CONN_TYPE_DIR ) ;
if ( conn - > inbuf_reached_eof ) {
2004-03-31 00:57:49 +02:00
if ( conn - > state ! = DIR_CONN_STATE_CLIENT_READING ) {
2004-03-12 13:43:13 +01:00
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 , 0 ) ;
return - 1 ;
}
switch ( fetch_from_buf_http ( conn - > inbuf ,
& headers , MAX_HEADERS_SIZE ,
2004-04-01 23:32:01 +02:00
& body , & body_len , MAX_DIR_SIZE ) ) {
2004-03-12 13:43:13 +01:00
case - 1 : /* overflow */
log_fn ( LOG_WARN , " 'fetch' response too large. Failing. " ) ;
2004-02-28 05:11:53 +01:00
connection_mark_for_close ( conn , 0 ) ;
2004-03-12 13:43:13 +01:00
return - 1 ;
case 0 :
log_fn ( LOG_INFO , " 'fetch' response not all here, but we're at eof. Closing. " ) ;
connection_mark_for_close ( conn , 0 ) ;
return - 1 ;
/* case 1, fall through */
}
if ( parse_http_response ( headers , & status_code , NULL ) < 0 ) {
log_fn ( LOG_WARN , " Unparseable headers. Closing. " ) ;
2004-04-01 23:32:01 +02:00
free ( body ) ; free ( headers ) ;
2004-03-12 13:43:13 +01:00
connection_mark_for_close ( conn , 0 ) ;
return - 1 ;
}
2004-03-31 00:57:49 +02:00
if ( conn - > purpose = = DIR_PURPOSE_FETCH_DIR ) {
2004-03-12 13:43:13 +01:00
/* fetch/process the directory to learn about new routers. */
2004-04-01 23:32:01 +02:00
log_fn ( LOG_INFO , " Received directory (size %d): \n %s " , body_len , body ) ;
if ( status_code = = 503 | | body_len = = 0 ) {
2004-03-12 13:43:13 +01:00
log_fn ( LOG_INFO , " Empty directory. Ignoring. " ) ;
2004-04-01 23:32:01 +02:00
free ( body ) ; free ( headers ) ;
2004-02-28 05:11:53 +01:00
connection_mark_for_close ( conn , 0 ) ;
return 0 ;
2004-03-12 13:43:13 +01:00
}
if ( status_code ! = 200 ) {
log_fn ( LOG_WARN , " Received http status code %d from dirserver. Failing. " ,
status_code ) ;
2004-04-01 23:32:01 +02:00
free ( body ) ; free ( headers ) ;
2004-02-28 05:11:53 +01:00
connection_mark_for_close ( conn , 0 ) ;
2003-09-17 22:09:06 +02:00
return - 1 ;
2004-03-12 13:43:13 +01:00
}
2004-04-01 23:32:01 +02:00
if ( router_set_routerlist_from_directory ( body , conn - > identity_pkey ) < 0 ) {
2004-03-12 13:43:13 +01:00
log_fn ( LOG_INFO , " ...but parsing failed. Ignoring. " ) ;
} else {
log_fn ( LOG_INFO , " updated routers. " ) ;
}
2004-04-01 00:02:13 +02:00
if ( has_fetched_directory = = 0 ) {
has_fetched_directory = 1 ;
directory_has_arrived ( ) ; /* do things we've been waiting to do */
}
2004-03-12 13:43:13 +01:00
if ( options . ORPort ) { /* connect to them all */
router_retry_connections ( ) ;
}
}
2004-03-31 00:57:49 +02:00
if ( conn - > purpose = = DIR_PURPOSE_UPLOAD_DIR ) {
2004-03-12 13:43:13 +01:00
switch ( status_code ) {
case 200 :
2004-04-01 23:32:01 +02:00
log_fn ( LOG_INFO , " eof (status 200) after uploading server descriptor: finished. " ) ;
2004-03-12 13:43:13 +01:00
break ;
case 400 :
2004-04-01 23:32:01 +02:00
log_fn ( LOG_WARN , " http status 400 (bad request) response from dirserver. Malformed server descriptor? " ) ;
2004-03-12 13:43:13 +01:00
break ;
case 403 :
2004-03-30 01:23:01 +02:00
log_fn ( LOG_WARN , " http status 403 (unapproved server) response from dirserver. Is your clock skewed? Have you mailed arma your identity fingerprint? Are you using the right key? " ) ;
2004-03-12 13:43:13 +01:00
2004-03-31 00:57:49 +02:00
break ;
default :
log_fn ( LOG_WARN , " http status %d response unrecognized. " , status_code ) ;
2004-03-12 13:43:13 +01:00
break ;
}
2002-09-28 02:52:59 +02:00
}
2004-03-31 00:57:49 +02:00
2004-04-01 23:32:01 +02:00
if ( conn - > purpose = = DIR_PURPOSE_FETCH_RENDDESC ) {
log_fn ( LOG_INFO , " Received rendezvous descriptor (size %d, status code %d) " ,
body_len , status_code ) ;
switch ( status_code ) {
case 200 :
if ( rend_cache_store ( body , body_len ) < 0 ) {
2004-04-08 00:41:00 +02:00
log_fn ( LOG_WARN , " Failed to store rendezvous descriptor. " ) ;
/* alice's ap_stream will notice when connection_mark_for_close
* cleans it up */
2004-04-01 23:32:01 +02:00
} else {
/* success. notify pending connections about this. */
2004-04-03 01:38:26 +02:00
rend_client_desc_fetched ( conn - > rend_query , 1 ) ;
2004-04-08 00:41:00 +02:00
conn - > purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC ;
2004-04-01 23:32:01 +02:00
}
break ;
case 404 :
2004-04-08 00:41:00 +02:00
/* not there. pending connections will be notified when
* connection_mark_for_close cleans it up . */
2004-04-01 23:32:01 +02:00
break ;
case 400 :
log_fn ( LOG_WARN , " http status 400 (bad request). Dirserver didn't like our rendezvous query? " ) ;
break ;
}
2004-03-31 00:57:49 +02:00
}
2004-04-01 23:32:01 +02:00
if ( conn - > purpose = = DIR_PURPOSE_UPLOAD_RENDDESC ) {
switch ( status_code ) {
case 200 :
log_fn ( LOG_INFO , " eof (status 200) after uploading rendezvous descriptor: finished. " ) ;
break ;
case 400 :
log_fn ( LOG_WARN , " http status 400 (bad request) response from dirserver. Malformed rendezvous descriptor? " ) ;
break ;
default :
log_fn ( LOG_WARN , " http status %d response unrecognized. " , status_code ) ;
break ;
}
2004-03-31 00:57:49 +02:00
}
2004-04-01 23:32:01 +02:00
free ( body ) ; free ( headers ) ;
connection_mark_for_close ( conn , 0 ) ;
return 0 ;
2002-09-26 14:09:10 +02:00
}
2004-03-31 00:57:49 +02:00
if ( conn - > state = = DIR_CONN_STATE_SERVER_COMMAND_WAIT ) {
if ( directory_handle_command ( conn ) < 0 ) {
connection_mark_for_close ( conn , 0 ) ;
return - 1 ;
}
2004-03-31 07:01:30 +02:00
return 0 ;
2004-03-31 00:57:49 +02:00
}
2003-09-17 22:09:06 +02:00
/* XXX for READ states, might want to make sure inbuf isn't too big */
2002-09-26 14:09:10 +02:00
2003-09-17 22:09:06 +02:00
log_fn ( LOG_DEBUG , " Got data, not eof. Leaving on inbuf. " ) ;
2002-09-26 14:09:10 +02:00
return 0 ;
}
2004-03-12 13:43:13 +01:00
static char answer200 [ ] = " HTTP/1.0 200 OK \r \n \r \n " ;
static char answer400 [ ] = " HTTP/1.0 400 Bad request \r \n \r \n " ;
static char answer403 [ ] = " HTTP/1.0 403 Unapproved server \r \n \r \n " ;
2004-03-31 00:57:49 +02:00
static char answer404 [ ] = " HTTP/1.0 404 Not found \r \n \r \n " ;
2004-03-12 13:43:13 +01:00
static char answer503 [ ] = " HTTP/1.0 503 Directory unavailable \r \n \r \n " ;
2004-03-31 00:57:49 +02:00
/* always returns 0 */
2003-12-17 10:42:28 +01:00
static int directory_handle_command_get ( connection_t * conn ,
2004-03-31 07:01:30 +02:00
char * headers , char * body ,
int body_len ) {
2003-09-28 10:06:18 +02:00
size_t dlen ;
2003-09-27 23:30:10 +02:00
const char * cp ;
2004-03-31 00:57:49 +02:00
char * url ;
2004-03-31 07:01:30 +02:00
char tmp [ 8192 ] ;
2002-09-26 14:09:10 +02:00
2003-12-17 10:42:28 +01:00
log_fn ( LOG_DEBUG , " Received GET command. " ) ;
2004-03-31 00:57:49 +02:00
conn - > state = DIR_CONN_STATE_SERVER_WRITING ;
2003-12-17 10:42:28 +01:00
2004-03-31 00:57:49 +02:00
if ( parse_http_url ( headers , & url ) < 0 ) {
connection_write_to_buf ( answer400 , strlen ( answer400 ) , conn ) ;
2004-03-12 13:43:13 +01:00
return 0 ;
2003-12-17 10:42:28 +01:00
}
2004-03-31 00:57:49 +02:00
if ( ! strcmp ( url , " / " ) ) { /* directory fetch */
dlen = dirserv_get_directory ( & cp ) ;
if ( dlen = = 0 ) {
log_fn ( LOG_WARN , " My directory is empty. Closing. " ) ;
connection_write_to_buf ( answer503 , strlen ( answer503 ) , conn ) ;
return 0 ;
}
log_fn ( LOG_DEBUG , " Dumping directory to client. " ) ;
2004-03-31 07:01:30 +02:00
snprintf ( tmp , sizeof ( tmp ) , " HTTP/1.0 200 OK \r \n Content-Length: %d \r \n \r \n %s " ,
2004-03-31 22:58:35 +02:00
( int ) dlen , cp ) ;
2004-03-31 07:01:30 +02:00
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
2004-03-31 00:57:49 +02:00
return 0 ;
}
2004-03-31 07:01:30 +02:00
if ( ! strncmp ( url , rend_fetch_url , strlen ( rend_fetch_url ) ) ) {
/* rendezvous descriptor fetch */
2004-03-31 05:42:56 +02:00
const char * descp ;
int desc_len ;
2004-03-31 00:57:49 +02:00
2004-04-08 00:00:54 +02:00
switch ( rend_cache_lookup_desc ( url + strlen ( rend_fetch_url ) , & descp , & desc_len ) ) {
2004-03-31 01:41:24 +02:00
case 1 : /* valid */
2004-03-31 07:01:30 +02:00
snprintf ( tmp , sizeof ( tmp ) , " HTTP/1.0 200 OK \r \n Content-Length: %d \r \n \r \n " ,
desc_len ) ; /* can't include descp here, because it's got nuls */
connection_write_to_buf ( tmp , strlen ( tmp ) , conn ) ;
connection_write_to_buf ( descp , desc_len , conn ) ;
2004-03-31 01:41:24 +02:00
break ;
case 0 : /* well-formed but not present */
connection_write_to_buf ( answer404 , strlen ( answer404 ) , conn ) ;
break ;
case - 1 : /* not well-formed */
connection_write_to_buf ( answer400 , strlen ( answer400 ) , conn ) ;
break ;
}
return 0 ;
2004-03-31 00:57:49 +02:00
}
/* we didn't recognize the url */
connection_write_to_buf ( answer404 , strlen ( answer404 ) , conn ) ;
2003-12-17 10:42:28 +01:00
return 0 ;
}
2004-03-31 00:57:49 +02:00
/* always returns 0 */
2003-12-17 10:42:28 +01:00
static int directory_handle_command_post ( connection_t * conn ,
2004-03-31 05:42:56 +02:00
char * headers , char * body ,
int body_len ) {
2003-12-17 10:42:28 +01:00
const char * cp ;
2004-03-31 00:57:49 +02:00
char * url ;
2003-12-17 10:42:28 +01:00
log_fn ( LOG_DEBUG , " Received POST command. " ) ;
2004-03-31 00:57:49 +02:00
2003-12-17 10:42:28 +01:00
conn - > state = DIR_CONN_STATE_SERVER_WRITING ;
2004-03-31 00:57:49 +02:00
if ( parse_http_url ( headers , & url ) < 0 ) {
connection_write_to_buf ( answer400 , strlen ( answer400 ) , conn ) ;
return 0 ;
}
2004-04-03 05:33:57 +02:00
log_fn ( LOG_INFO , " url '%s' posted to us. " , url ) ;
2004-03-31 00:57:49 +02:00
if ( ! strcmp ( url , " / " ) ) { /* server descriptor post */
cp = body ;
switch ( dirserv_add_descriptor ( & cp ) ) {
case - 1 :
/* malformed descriptor, or something wrong */
connection_write_to_buf ( answer400 , strlen ( answer400 ) , conn ) ;
break ;
case 0 :
/* descriptor was well-formed but server has not been approved */
connection_write_to_buf ( answer403 , strlen ( answer403 ) , conn ) ;
break ;
case 1 :
dirserv_get_directory ( & cp ) ; /* rebuild and write to disk */
connection_write_to_buf ( answer200 , strlen ( answer200 ) , conn ) ;
break ;
}
2004-03-31 07:01:30 +02:00
return 0 ;
2004-03-31 00:57:49 +02:00
}
2004-03-31 07:01:30 +02:00
if ( ! strncmp ( url , rend_publish_string , strlen ( rend_publish_string ) ) ) {
/* rendezvous descriptor post */
2004-03-31 06:10:10 +02:00
if ( rend_cache_store ( body , body_len ) < 0 )
2004-03-31 01:41:24 +02:00
connection_write_to_buf ( answer400 , strlen ( answer400 ) , conn ) ;
else
connection_write_to_buf ( answer200 , strlen ( answer200 ) , conn ) ;
2004-03-31 07:01:30 +02:00
return 0 ;
2004-03-31 00:57:49 +02:00
}
/* we didn't recognize the url */
connection_write_to_buf ( answer404 , strlen ( answer404 ) , conn ) ;
2003-12-17 10:42:28 +01:00
return 0 ;
}
static int directory_handle_command ( connection_t * conn ) {
char * headers = NULL , * body = NULL ;
2004-03-31 07:01:30 +02:00
int body_len = 0 ;
2003-12-17 10:42:28 +01:00
int r ;
2002-09-26 14:09:10 +02:00
assert ( conn & & conn - > type = = CONN_TYPE_DIR ) ;
2003-09-25 07:17:11 +02:00
switch ( fetch_from_buf_http ( conn - > inbuf ,
2004-03-31 07:01:30 +02:00
& headers , MAX_HEADERS_SIZE ,
& body , & body_len , MAX_BODY_SIZE ) ) {
2003-09-17 22:09:06 +02:00
case - 1 : /* overflow */
2003-10-10 03:48:32 +02:00
log_fn ( LOG_WARN , " input too large. Failing. " ) ;
2003-09-17 22:09:06 +02:00
return - 1 ;
case 0 :
log_fn ( LOG_DEBUG , " command not all here yet. " ) ;
return 0 ;
/* case 1, fall through */
2002-09-26 14:09:10 +02:00
}
2003-12-17 10:42:28 +01:00
log_fn ( LOG_DEBUG , " headers '%s', body '%s'. " , headers , body ) ;
2002-09-26 14:09:10 +02:00
2003-12-17 10:42:28 +01:00
if ( ! strncasecmp ( headers , " GET " , 3 ) )
2004-03-31 07:01:30 +02:00
r = directory_handle_command_get ( conn , headers , body , body_len ) ;
2003-12-17 10:42:28 +01:00
else if ( ! strncasecmp ( headers , " POST " , 4 ) )
2004-03-31 07:01:30 +02:00
r = directory_handle_command_post ( conn , headers , body , body_len ) ;
2003-12-17 10:42:28 +01:00
else {
log_fn ( LOG_WARN , " Got headers '%s' with unknown command. Closing. " , headers ) ;
r = - 1 ;
2002-09-26 14:09:10 +02:00
}
2003-12-17 10:42:28 +01:00
tor_free ( headers ) ; tor_free ( body ) ;
return r ;
2002-09-26 14:09:10 +02:00
}
int connection_dir_finished_flushing ( connection_t * conn ) {
int e , len = sizeof ( e ) ;
assert ( conn & & conn - > type = = CONN_TYPE_DIR ) ;
switch ( conn - > state ) {
2004-03-31 00:57:49 +02:00
case DIR_CONN_STATE_CONNECTING :
2003-08-12 05:08:41 +02:00
if ( getsockopt ( conn - > s , SOL_SOCKET , SO_ERROR , ( void * ) & e , & len ) < 0 ) { /* not yet */
2003-08-14 19:13:52 +02:00
if ( ! ERRNO_CONN_EINPROGRESS ( errno ) ) {
2003-06-18 00:18:26 +02:00
log_fn ( LOG_DEBUG , " in-progress connect failed. Removing. " ) ;
2003-09-30 23:27:16 +02:00
router_mark_as_down ( conn - > nickname ) ; /* don't try him again */
2004-02-28 05:11:53 +01:00
connection_mark_for_close ( conn , 0 ) ;
2002-09-26 14:09:10 +02:00
return - 1 ;
} else {
return 0 ; /* no change, see if next time is better */
}
}
/* the connect has finished. */
2003-09-26 12:03:50 +02:00
log_fn ( LOG_INFO , " Dir connection to router %s:%u established. " ,
2002-09-26 14:09:10 +02:00
conn - > address , conn - > port ) ;
2004-03-31 00:57:49 +02:00
conn - > state = DIR_CONN_STATE_CLIENT_SENDING ; /* start flushing conn */
2003-09-17 22:09:06 +02:00
return 0 ;
2004-03-31 00:57:49 +02:00
case DIR_CONN_STATE_CLIENT_SENDING :
log_fn ( LOG_DEBUG , " client finished sending command. " ) ;
conn - > state = DIR_CONN_STATE_CLIENT_READING ;
connection_stop_writing ( conn ) ;
2002-09-26 14:09:10 +02:00
return 0 ;
2003-09-17 22:09:06 +02:00
case DIR_CONN_STATE_SERVER_WRITING :
2003-09-26 12:03:50 +02:00
log_fn ( LOG_INFO , " Finished writing server response. Closing. " ) ;
2004-02-28 05:11:53 +01:00
connection_mark_for_close ( conn , 0 ) ;
return 0 ;
2002-09-26 14:09:10 +02:00
default :
2004-01-31 01:36:00 +01:00
log_fn ( LOG_WARN , " BUG: called in unexpected state %d. " , conn - > state ) ;
2003-09-26 12:03:50 +02:00
return - 1 ;
2002-09-26 14:09:10 +02:00
}
return 0 ;
}
2003-04-07 04:12:02 +02:00
/*
Local Variables :
mode : c
indent - tabs - mode : nil
c - basic - offset : 2
End :
*/