connection_app.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #include "or.h"
  2. connection_t *connection_app_new(void) {
  3. return connection_new(CONN_TYPE_APP);
  4. }
  5. int connection_app_process_inbuf(connection_t *conn) {
  6. assert(conn && conn->type == CONN_TYPE_APP);
  7. if(conn->inbuf_reached_eof) {
  8. /* eof reached, kill it. */
  9. log(LOG_DEBUG,"connection_app_process_inbuf(): conn reached eof. Closing.");
  10. return -1;
  11. }
  12. log(LOG_DEBUG,"connection_app_process_inbuf(): state %d.",conn->state);
  13. switch(conn->state) {
  14. case APP_CONN_STATE_CONNECTING:
  15. log(LOG_DEBUG,"connection_app_process_inbuf(): text from app server while in 'connecting' state. Leaving it on buffer.");
  16. return 0;
  17. case APP_CONN_STATE_OPEN:
  18. return connection_app_package_inbuf(conn);
  19. }
  20. return 0;
  21. }
  22. int connection_app_package_inbuf(connection_t *conn) {
  23. int amount_to_process;
  24. cell_t cell;
  25. circuit_t *circ;
  26. assert(conn && conn->type == CONN_TYPE_APP);
  27. amount_to_process = conn->inbuf_datalen;
  28. if(!amount_to_process)
  29. return 0;
  30. if(amount_to_process > CELL_PAYLOAD_SIZE) {
  31. cell.length = CELL_PAYLOAD_SIZE;
  32. } else {
  33. cell.length = amount_to_process;
  34. }
  35. if(connection_fetch_from_buf(cell.payload,cell.length,conn) < 0) {
  36. return -1;
  37. }
  38. circ = circuit_get_by_conn(conn);
  39. if(!circ) {
  40. log(LOG_DEBUG,"connection_app_package_inbuf(): conn has no circuits!");
  41. return -1;
  42. }
  43. log(LOG_DEBUG,"connection_app_package_inbuf(): Packaging %d bytes.",cell.length);
  44. cell.aci = circ->p_aci;
  45. cell.command = CELL_DATA;
  46. if(circuit_deliver_data_cell(&cell, circ, circ->p_conn, 'e') < 0) {
  47. log(LOG_DEBUG,"connection_app_package_inbuf(): circuit_deliver_data_cell (backward) failed. Closing.");
  48. circuit_close(circ);
  49. return 0;
  50. }
  51. if(amount_to_process > CELL_PAYLOAD_SIZE)
  52. return(connection_app_package_inbuf(conn));
  53. return 0;
  54. }
  55. int connection_app_finished_flushing(connection_t *conn) {
  56. int e, len=sizeof(e);
  57. assert(conn && conn->type == CONN_TYPE_APP);
  58. switch(conn->state) {
  59. case APP_CONN_STATE_CONNECTING:
  60. if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, &e, &len) < 0) { /* not yet */
  61. if(errno != EINPROGRESS){
  62. /* yuck. kill it. */
  63. log(LOG_DEBUG,"connection_app_finished_flushing(): in-progress connect failed. Removing.");
  64. return -1;
  65. } else {
  66. return 0; /* no change, see if next time is better */
  67. }
  68. }
  69. /* the connect has finished. */
  70. log(LOG_DEBUG,"connection_app_finished_flushing() : Connection to %s:%u established.",
  71. conn->address,ntohs(conn->port));
  72. conn->state = APP_CONN_STATE_OPEN;
  73. connection_watch_events(conn, POLLIN);
  74. return 0;
  75. case APP_CONN_STATE_OPEN:
  76. /* FIXME down the road, we'll clear out circuits that are pending to close */
  77. connection_watch_events(conn, POLLIN);
  78. return 0;
  79. default:
  80. log(LOG_DEBUG,"Bug: connection_app_finished_flushing() called in unexpected state.");
  81. return 0;
  82. }
  83. return 0;
  84. }
  85. int connection_app_process_data_cell(cell_t *cell, connection_t *conn) {
  86. struct hostent *rent;
  87. struct sockaddr_in dest_addr;
  88. int s;
  89. /* an outgoing data cell has arrived */
  90. assert(conn && conn->type == CONN_TYPE_APP);
  91. switch(conn->state) {
  92. case APP_CONN_STATE_CONNECTING_WAIT:
  93. log(LOG_DEBUG,"connection_app_process_cell(): state is connecting_wait. cell length %d.", cell->length);
  94. if(!conn->ss_received) { /* this cell contains the ss */
  95. if(cell->length != sizeof(ss_t)) {
  96. log(LOG_DEBUG,"connection_app_process_cell(): Supposed to contain SS but wrong size. Closing.");
  97. return -1;
  98. }
  99. memcpy(&conn->ss, cell->payload, cell->length);
  100. if(conn->ss.addr_fmt != SS_ADDR_FMT_ASCII_HOST_PORT) { /* unrecognized address format */
  101. log(LOG_DEBUG,"connection_app_process_cell(): SS has unrecognized address format. Closing.");
  102. return -1;
  103. }
  104. conn->ss_received = 1;
  105. log(LOG_DEBUG,"connection_app_process_cell(): SS received.");
  106. } else if (!conn->addr) { /* this cell contains the dest addr */
  107. if(!memchr(cell->payload,0,cell->length)) {
  108. log(LOG_DEBUG,"connection_app_process_cell(): dest_addr cell has no \\0. Closing.");
  109. return -1;
  110. }
  111. conn->address = strdup(cell->payload);
  112. rent = gethostbyname(cell->payload);
  113. if (!rent) {
  114. log(LOG_ERR,"connection_app_process_cell(): Could not resolve dest addr %s.",cell->payload);
  115. return -1;
  116. }
  117. memcpy(&conn->addr, rent->h_addr,rent->h_length);
  118. log(LOG_DEBUG,"connection_app_process_cell(): addr %s resolves to %d.",cell->payload,conn->addr);
  119. } else if (!conn->port) { /* this cell contains the dest port */
  120. if(!memchr(cell->payload,'\0',cell->length)) {
  121. log(LOG_DEBUG,"connection_app_process_cell(): dest_port cell has no \\0. Closing.");
  122. return -1;
  123. }
  124. conn->port = atoi(cell->payload);
  125. if(!conn->port) { /* bad port */
  126. log(LOG_DEBUG,"connection_app_process_cell(): dest_port cell isn't a valid number. Closing.");
  127. return -1;
  128. }
  129. /* all the necessary info is here. Start the connect() */
  130. s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
  131. if (s < 0)
  132. {
  133. log(LOG_ERR,"connection_app_process_cell(): Error creating network socket.");
  134. return -1;
  135. }
  136. fcntl(s, F_SETFL, O_NONBLOCK); /* set s to non-blocking */
  137. memset((void *)&dest_addr,0,sizeof(dest_addr));
  138. dest_addr.sin_family = AF_INET;
  139. dest_addr.sin_port = conn->port;
  140. memcpy((void *)&dest_addr.sin_addr, &conn->addr, sizeof(uint32_t));
  141. log(LOG_DEBUG,"connection_app_process_cell(): Connecting to %s:%u.",conn->address,ntohs(conn->port));
  142. if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0){
  143. if(errno != EINPROGRESS){
  144. /* yuck. kill it. */
  145. log(LOG_DEBUG,"connection_app_process_cell(): Connect failed.");
  146. return -1;
  147. } else {
  148. /* it's in progress. set state appropriately and return. */
  149. conn->s = s;
  150. connection_set_poll_socket(conn);
  151. conn->state = APP_CONN_STATE_CONNECTING;
  152. /* i think only pollout is needed, but i'm curious if pollin ever gets caught -RD */
  153. log(LOG_DEBUG,"connection_app_process_cell(): connect in progress, socket %d.",s);
  154. connection_watch_events(conn, POLLOUT | POLLIN);
  155. return 0;
  156. }
  157. }
  158. /* it succeeded. we're connected. */
  159. log(LOG_DEBUG,"connection_app_process_cell(): Connection to %s:%u established.",conn->address,ntohs(conn->port));
  160. conn->s = s;
  161. connection_set_poll_socket(conn);
  162. conn->state = APP_CONN_STATE_OPEN;
  163. connection_watch_events(conn, POLLIN);
  164. } else { /* i'm not sure what this would be */
  165. log(LOG_DEBUG,"connection_app_process_cell(): in connecting_wait, not sure why.");
  166. }
  167. return 0;
  168. case APP_CONN_STATE_CONNECTING:
  169. log(LOG_DEBUG,"connection_app_process_cell(): Data receiving while connecting. Queueing.");
  170. /* FIXME kludge. shouldn't call write_to_buf directly. */
  171. return write_to_buf(cell->payload, cell->length, &conn->outbuf, &conn->outbuflen, &conn->outbuf_datalen);
  172. case APP_CONN_STATE_OPEN:
  173. return connection_write_to_buf(cell->payload, cell->length, conn);
  174. }
  175. return 0;
  176. }