connection_exit.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */
  2. /* See LICENSE for licensing information */
  3. /* $Id$ */
  4. #include "or.h"
  5. int connection_exit_process_inbuf(connection_t *conn) {
  6. assert(conn && conn->type == CONN_TYPE_EXIT);
  7. if(conn->inbuf_reached_eof) {
  8. /* eof reached, kill it. */
  9. log(LOG_DEBUG,"connection_exit_process_inbuf(): conn reached eof. Closing.");
  10. return -1;
  11. }
  12. log(LOG_DEBUG,"connection_exit_process_inbuf(): state %d.",conn->state);
  13. switch(conn->state) {
  14. case EXIT_CONN_STATE_CONNECTING:
  15. log(LOG_DEBUG,"connection_exit_process_inbuf(): text from server while in 'connecting' state. Leaving it on buffer.");
  16. return 0;
  17. case EXIT_CONN_STATE_OPEN:
  18. return connection_package_raw_inbuf(conn);
  19. }
  20. return 0;
  21. }
  22. int connection_exit_finished_flushing(connection_t *conn) {
  23. int e, len=sizeof(e);
  24. assert(conn && conn->type == CONN_TYPE_EXIT);
  25. switch(conn->state) {
  26. case EXIT_CONN_STATE_CONNECTING:
  27. if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0) { /* not yet */
  28. if(errno != EINPROGRESS){
  29. /* yuck. kill it. */
  30. log(LOG_DEBUG,"connection_exit_finished_flushing(): in-progress connect failed. Removing.");
  31. return -1;
  32. } else {
  33. log(LOG_DEBUG,"connection_exit_finished_flushing(): in-progress connect still waiting.");
  34. return 0; /* no change, see if next time is better */
  35. }
  36. }
  37. /* the connect has finished. */
  38. log(LOG_DEBUG,"connection_exit_finished_flushing() : Connection to %s:%u established.",
  39. conn->address,conn->port);
  40. conn->state = EXIT_CONN_STATE_OPEN;
  41. if(connection_wants_to_flush(conn)) /* in case there are any queued data cells */
  42. connection_start_writing(conn);
  43. connection_start_reading(conn);
  44. /* also, deliver a 'connected' cell back through the circuit. */
  45. return connection_exit_send_connected(conn);
  46. case EXIT_CONN_STATE_OPEN:
  47. /* FIXME down the road, we'll clear out circuits that are pending to close */
  48. connection_stop_writing(conn);
  49. connection_consider_sending_sendme(conn);
  50. return 0;
  51. default:
  52. log(LOG_DEBUG,"Bug: connection_exit_finished_flushing() called in unexpected state.");
  53. return 0;
  54. }
  55. return 0;
  56. }
  57. int connection_exit_send_connected(connection_t *conn) {
  58. circuit_t *circ;
  59. assert(conn);
  60. circ = circuit_get_by_conn(conn);
  61. assert(circ && circ->p_conn && circ->n_conn == conn); /* is this true? i guess i'll see if it breaks. */
  62. return connection_send_connected(circ->p_aci, circ->p_conn);
  63. }
  64. int connection_exit_process_data_cell(cell_t *cell, connection_t *conn) {
  65. struct hostent *rent;
  66. struct sockaddr_in dest_addr;
  67. int s; /* for the new socket, if we're on connecting_wait */
  68. /* an outgoing data cell has arrived */
  69. assert(conn && conn->type == CONN_TYPE_EXIT);
  70. switch(conn->state) {
  71. case EXIT_CONN_STATE_CONNECTING_WAIT:
  72. log(LOG_DEBUG,"connection_exit_process_data_cell(): state is connecting_wait. cell length %d.", cell->length);
  73. #if 0
  74. if(!conn->ss_received) { /* this cell contains the ss */
  75. if(cell->length != sizeof(ss_t)) {
  76. log(LOG_DEBUG,"connection_exit_process_data_cell(): Supposed to contain SS but wrong size. Closing.");
  77. return -1;
  78. }
  79. memcpy(&conn->ss, cell->payload, cell->length);
  80. if(conn->ss.addr_fmt != SS_ADDR_FMT_ASCII_HOST_PORT) { /* unrecognized address format */
  81. log(LOG_DEBUG,"connection_exit_process_data_cell(): SS has unrecognized address format. Closing.");
  82. return -1;
  83. }
  84. conn->ss_received = 1;
  85. log(LOG_DEBUG,"connection_exit_process_data_cell(): SS received.");
  86. } else
  87. #endif
  88. if (!conn->addr) { /* this cell contains the dest addr */
  89. if(!memchr(cell->payload,0,cell->length)) {
  90. log(LOG_DEBUG,"connection_exit_process_data_cell(): dest_addr cell has no \\0. Closing.");
  91. return -1;
  92. }
  93. conn->address = strdup(cell->payload);
  94. rent = gethostbyname(cell->payload);
  95. if (!rent) {
  96. log(LOG_ERR,"connection_exit_process_data_cell(): Could not resolve dest addr %s.",cell->payload);
  97. return -1;
  98. }
  99. memcpy(&conn->addr, rent->h_addr,rent->h_length);
  100. log(LOG_DEBUG,"connection_exit_process_data_cell(): addr is %s.",cell->payload);
  101. } else if (!conn->port) { /* this cell contains the dest port */
  102. if(!memchr(cell->payload,'\0',cell->length)) {
  103. log(LOG_DEBUG,"connection_exit_process_data_cell(): dest_port cell has no \\0. Closing.");
  104. return -1;
  105. }
  106. conn->port = atoi(cell->payload);
  107. if(!conn->port) { /* bad port */
  108. log(LOG_DEBUG,"connection_exit_process_data_cell(): dest_port cell isn't a valid number. Closing.");
  109. return -1;
  110. }
  111. /* all the necessary info is here. Start the connect() */
  112. s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
  113. if (s < 0)
  114. {
  115. log(LOG_ERR,"connection_exit_process_data_cell(): Error creating network socket.");
  116. return -1;
  117. }
  118. fcntl(s, F_SETFL, O_NONBLOCK); /* set s to non-blocking */
  119. memset((void *)&dest_addr,0,sizeof(dest_addr));
  120. dest_addr.sin_family = AF_INET;
  121. dest_addr.sin_port = htons(conn->port);
  122. memcpy((void *)&dest_addr.sin_addr, &conn->addr, sizeof(uint32_t));
  123. log(LOG_DEBUG,"connection_exit_process_data_cell(): Connecting to %s:%u.",conn->address,conn->port);
  124. if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0){
  125. if(errno != EINPROGRESS){
  126. /* yuck. kill it. */
  127. log(LOG_DEBUG,"connection_exit_process_data_cell(): Connect failed.");
  128. return -1;
  129. } else {
  130. /* it's in progress. set state appropriately and return. */
  131. conn->s = s;
  132. connection_set_poll_socket(conn);
  133. conn->state = EXIT_CONN_STATE_CONNECTING;
  134. log(LOG_DEBUG,"connection_exit_process_data_cell(): connect in progress, socket %d.",s);
  135. connection_watch_events(conn, POLLOUT | POLLIN);
  136. return 0;
  137. }
  138. }
  139. /* it succeeded. we're connected. */
  140. log(LOG_DEBUG,"connection_exit_process_data_cell(): Connection to %s:%u established.",conn->address,conn->port);
  141. conn->s = s;
  142. connection_set_poll_socket(conn);
  143. conn->state = EXIT_CONN_STATE_OPEN;
  144. if(connection_wants_to_flush(conn)) { /* in case there are any queued data cells */
  145. log(LOG_NOTICE,"connection_exit_process_data_cell(): tell roger: newly connected conn had data waiting!");
  146. // connection_start_writing(conn);
  147. }
  148. connection_watch_events(conn, POLLIN);
  149. /* also, deliver a 'connected' cell back through the circuit. */
  150. return connection_exit_send_connected(conn);
  151. } else {
  152. log(LOG_DEBUG,"connection_exit_process_data_cell(): in connecting_wait, but I've already received everything. Closing.");
  153. return -1;
  154. }
  155. return 0;
  156. case EXIT_CONN_STATE_CONNECTING:
  157. log(LOG_DEBUG,"connection_exit_process_data_cell(): Data receiving while connecting. Queueing.");
  158. /* we stay listening for writable, so connect() can finish */
  159. /* fall through to the next state -- write the cell and consider sending back a sendme */
  160. case EXIT_CONN_STATE_OPEN:
  161. if(connection_write_to_buf(cell->payload, cell->length, conn) < 0)
  162. return -1;
  163. return connection_consider_sending_sendme(conn);
  164. }
  165. return 0;
  166. }