connection_exit.c 4.11 KB
Newer Older
1
2
3
/* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */
/* See LICENSE for licensing information */
/* $Id$ */
Roger Dingledine's avatar
Roger Dingledine committed
4
5
6

#include "or.h"

7
int connection_exit_begin_conn(cell_t *cell, circuit_t *circ) {
8
  connection_t *n_stream;
9
  char *colon;
10

11
  if(!memchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE,0,cell->length-RELAY_HEADER_SIZE-STREAM_ID_SIZE)) {
12
    log_fn(LOG_WARNING,"relay begin cell has no \\0. Dropping.");
13
14
    return 0;
  }
15
  colon = strchr(cell->payload+RELAY_HEADER_SIZE+STREAM_ID_SIZE, ':');
16
  if(!colon) {
17
    log_fn(LOG_WARNING,"relay begin cell has no colon. Dropping.");
18
19
    return 0;
  }
20
  *colon = 0;
21

22
  if(!atoi(colon+1)) { /* bad port */
23
    log_fn(LOG_DEBUG,"relay begin cell has invalid port. Dropping.");
24
25
26
    return 0;
  }

27
  log_fn(LOG_DEBUG,"Creating new exit connection.");
28
29
  n_stream = connection_new(CONN_TYPE_EXIT);
  if(!n_stream) {
30
    log_fn(LOG_DEBUG,"connection_new failed. Dropping.");
Roger Dingledine's avatar
   
Roger Dingledine committed
31
    return 0;
32
33
  }

34
35
36
37
38
39
40
41
42
43
  memcpy(n_stream->stream_id, cell->payload + RELAY_HEADER_SIZE, STREAM_ID_SIZE);
  n_stream->address = strdup(cell->payload + RELAY_HEADER_SIZE + STREAM_ID_SIZE);
  n_stream->port = atoi(colon+1);
  n_stream->state = EXIT_CONN_STATE_RESOLVING;
  n_stream->receiver_bucket = -1; /* edge connections don't do receiver buckets */
  n_stream->bandwidth = -1;
  n_stream->s = -1; /* not yet valid */
  n_stream->package_window = STREAMWINDOW_START;
  n_stream->deliver_window = STREAMWINDOW_START;
  if(connection_add(n_stream) < 0) { /* no space, forget it */
44
    log_fn(LOG_DEBUG,"connection_add failed. Dropping.");
45
    connection_free(n_stream);
Roger Dingledine's avatar
   
Roger Dingledine committed
46
    return 0;
47
48
  }

49
  /* add it into the linked list of streams on this circuit */
50
51
  n_stream->next_stream = circ->n_streams;
  circ->n_streams = n_stream;
52
53

  /* send it off to the gethostbyname farm */
54
55
56
57
58
59
60
61
62
63
  switch(dns_resolve(n_stream)) {
    case 1: /* resolve worked */
      if(connection_exit_connect(n_stream) >= 0)
        return 0;
      /* else fall through */
    case -1: /* resolve failed */
      log_fn(LOG_DEBUG,"Couldn't queue resolve request.");
      connection_remove(n_stream);
      connection_free(n_stream);
    case 0: /* resolve added to pending list */
64
65
66
67
68
69
70
71
  }
  return 0;
}

int connection_exit_connect(connection_t *conn) {
  int s; /* for the new socket */
  struct sockaddr_in dest_addr;

72
  if(router_compare_to_exit_policy(conn) < 0) {
73
    log_fn(LOG_INFO,"%s:%d failed exit policy. Closing.", conn->address, conn->port);
74
75
76
    return -1;
  }

77
78
79
  /* all the necessary info is here. Start the connect() */
  s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
  if (s < 0) {
80
    log_fn(LOG_ERR,"Error creating network socket.");
81
82
    return -1;
  }
83
  set_socket_nonblocking(s);
84
85
86
87
88
89

  memset((void *)&dest_addr,0,sizeof(dest_addr));
  dest_addr.sin_family = AF_INET;
  dest_addr.sin_port = htons(conn->port);
  dest_addr.sin_addr.s_addr = htonl(conn->addr);

90
  log_fn(LOG_DEBUG,"Connecting to %s:%u.",conn->address,conn->port); 
91
92
93
94
95

  if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0) {
    if(errno != EINPROGRESS){
      /* yuck. kill it. */
      perror("connect");
96
      log_fn(LOG_DEBUG,"Connect failed.");
97
98
99
100
101
102
103
      return -1;
    } else {
      /* it's in progress. set state appropriately and return. */
      conn->s = s;
      connection_set_poll_socket(conn);
      conn->state = EXIT_CONN_STATE_CONNECTING;

104
      log_fn(LOG_DEBUG,"connect in progress, socket %d.",s);
105
      connection_watch_events(conn, POLLOUT | POLLIN);
Roger Dingledine's avatar
Roger Dingledine committed
106
      return 0;
107
    }
Roger Dingledine's avatar
Roger Dingledine committed
108
109
  }

110
  /* it succeeded. we're connected. */
111
  log_fn(LOG_DEBUG,"Connection to %s:%u established.",conn->address,conn->port);
112
113
114
115
116

  conn->s = s;
  connection_set_poll_socket(conn);
  conn->state = EXIT_CONN_STATE_OPEN;
  if(connection_wants_to_flush(conn)) { /* in case there are any queued data cells */
117
    log_fn(LOG_ERR,"tell roger: newly connected conn had data waiting!");
118
119
120
121
122
123
//    connection_start_writing(conn);
  }
//   connection_process_inbuf(conn);
  connection_watch_events(conn, POLLIN);

  /* also, deliver a 'connected' cell back through the circuit. */
124
  return connection_edge_send_command(conn, circuit_get_by_conn(conn), RELAY_COMMAND_CONNECTED);
Roger Dingledine's avatar
Roger Dingledine committed
125
126
}

127
128
129
130
131
132
133
/*
  Local Variables:
  mode:c
  indent-tabs-mode:nil
  c-basic-offset:2
  End:
*/