command.c 6.99 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
8
extern or_options_t options; /* command-line and config-file options */

Roger Dingledine's avatar
Roger Dingledine committed
9
10
11
12
13
14
static void command_process_create_cell(cell_t *cell, connection_t *conn);
static void command_process_created_cell(cell_t *cell, connection_t *conn);
static void command_process_relay_cell(cell_t *cell, connection_t *conn);
static void command_process_destroy_cell(cell_t *cell, connection_t *conn);

static void command_time_process_cell(cell_t *cell, connection_t *conn,
15
16
17
                               int *num, int *time,
                               void (*func)(cell_t *, connection_t *)) {
  struct timeval start, end;
18
  long time_passed; 
19
20
21

  *num += 1;

22
  my_gettimeofday(&start);
23
24
25

  (*func)(cell, conn);

26
27
  my_gettimeofday(&end);
  time_passed = tv_udiff(&start, &end) ;
28

29
  if (time_passed > 5000) { /* more than 5ms */
30
    log_fn(LOG_INFO,"That call just took %ld ms.",time_passed/1000);
31
32
33
34
  }
  *time += time_passed;
}

Roger Dingledine's avatar
Roger Dingledine committed
35
void command_process_cell(cell_t *cell, connection_t *conn) {
36
37
  static int num_create=0, num_created=0, num_relay=0, num_destroy=0;
  static int create_time=0, created_time=0, relay_time=0, destroy_time=0;
38
39
40
  static long current_second = 0; /* from previous calls to gettimeofday */
  struct timeval now;

41
  my_gettimeofday(&now);
42
43
44
45
46

  if(now.tv_sec > current_second) { /* the second has rolled over */
    /* print stats */
    log(LOG_INFO,"At end of second:"); 
    log(LOG_INFO,"Create:    %d (%d ms)", num_create, create_time/1000);
47
    log(LOG_INFO,"Created:   %d (%d ms)", num_created, created_time/1000);
48
    log(LOG_INFO,"Relay:     %d (%d ms)", num_relay, relay_time/1000);
49
50
51
    log(LOG_INFO,"Destroy:   %d (%d ms)", num_destroy, destroy_time/1000);

    /* zero out stats */
52
53
    num_create = num_created = num_relay = num_destroy = 0;
    create_time = created_time = relay_time = destroy_time = 0;
54
55
56
57

    /* remember which second it is, for next time */
    current_second = now.tv_sec; 
  }
Roger Dingledine's avatar
Roger Dingledine committed
58
59
60
61
62
63

  switch(cell->command) {
    case CELL_PADDING:
      /* do nothing */
      break;
    case CELL_CREATE:
64
65
      command_time_process_cell(cell, conn, &num_create, &create_time,
                                command_process_create_cell);
Roger Dingledine's avatar
Roger Dingledine committed
66
      break;
67
68
69
70
    case CELL_CREATED:
      command_time_process_cell(cell, conn, &num_created, &created_time,
                                command_process_created_cell);
      break;
71
72
73
    case CELL_RELAY:
      command_time_process_cell(cell, conn, &num_relay, &relay_time,
                                command_process_relay_cell);
Roger Dingledine's avatar
Roger Dingledine committed
74
75
      break;
    case CELL_DESTROY:
76
77
      command_time_process_cell(cell, conn, &num_destroy, &destroy_time,
                                command_process_destroy_cell);
Roger Dingledine's avatar
Roger Dingledine committed
78
      break;
79
80
81
    default:
      log(LOG_DEBUG,"Cell of unknown type (%d) received. Dropping.", cell->command);
      break;
Roger Dingledine's avatar
Roger Dingledine committed
82
83
84
  }
}

Roger Dingledine's avatar
Roger Dingledine committed
85
static void command_process_create_cell(cell_t *cell, connection_t *conn) {
Roger Dingledine's avatar
Roger Dingledine committed
86
87
88
89
  circuit_t *circ;

  circ = circuit_get_by_aci_conn(cell->aci, conn);

90
  if(circ) {
91
    log_fn(LOG_DEBUG,"received CREATE cell for known circ. Dropping.");
Roger Dingledine's avatar
Roger Dingledine committed
92
93
94
    return;
  }

95
96
  circ = circuit_new(cell->aci, conn);
  circ->state = CIRCUIT_STATE_ONIONSKIN_PENDING;
97
  if(cell->length != DH_ONIONSKIN_LEN) {
98
    log_fn(LOG_DEBUG,"Bad cell length %d. Dropping.", cell->length);
99
100
101
102
103
104
    circuit_close(circ);
    return;
  }

  memcpy(circ->onionskin,cell->payload,cell->length);

Roger Dingledine's avatar
Roger Dingledine committed
105
106
107
  /* hand it off to the cpuworkers, and then return */
  if(assign_to_cpuworker(NULL, CPUWORKER_TASK_ONION, circ) < 0) {
    log_fn(LOG_DEBUG,"Failed to hand off onionskin. Closing.");
108
    circuit_close(circ);
Roger Dingledine's avatar
Roger Dingledine committed
109
    return;
110
  }
Roger Dingledine's avatar
Roger Dingledine committed
111
  log_fn(LOG_DEBUG,"success: handed off onionskin.");
112
113
}

Roger Dingledine's avatar
Roger Dingledine committed
114
static void command_process_created_cell(cell_t *cell, connection_t *conn) {
115
116
117
118
119
120
  circuit_t *circ;
  cell_t newcell;

  circ = circuit_get_by_aci_conn(cell->aci, conn);

  if(!circ) {
121
    log_fn(LOG_DEBUG,"received CREATED cell for unknown circ. Dropping.");
122
123
124
125
    return;
  }

  if(circ->n_aci != cell->aci) {
126
    log_fn(LOG_DEBUG,"got created cell from OPward? Dropping.");
127
128
    return;
  }
129
  assert(cell->length == DH_KEY_LEN);
130
131

  if(circ->cpath) { /* we're the OP. Handshake this. */
132
    log_fn(LOG_DEBUG,"at OP. Finishing handshake.");
133
    if(circuit_finish_handshake(circ, cell->payload) < 0) {
134
      log_fn(LOG_INFO,"circuit_finish_handshake failed.");
Roger Dingledine's avatar
Roger Dingledine committed
135
136
137
      circuit_close(circ);
      return;
    }
138
    log_fn(LOG_DEBUG,"Moving to next skin.");
139
    if(circuit_send_next_onion_skin(circ) < 0) {
140
      log_fn(LOG_INFO,"circuit_send_next_onion_skin failed.");
Roger Dingledine's avatar
Roger Dingledine committed
141
142
143
      circuit_close(circ);
      return;
    }
144
145
146
147
148
149
150
151
  } else { /* pack it into an extended relay cell, and send it. */
    memset(&newcell, 0, sizeof(cell_t));
    newcell.command = CELL_RELAY;
    newcell.aci = circ->p_aci;
    SET_CELL_RELAY_COMMAND(newcell, RELAY_COMMAND_EXTENDED);
    SET_CELL_STREAM_ID(newcell, ZERO_STREAM);

    newcell.length = RELAY_HEADER_SIZE + cell->length;
152
    memcpy(newcell.payload+RELAY_HEADER_SIZE, cell->payload, DH_KEY_LEN);
153

154
    log_fn(LOG_DEBUG,"Sending extended relay cell.");
155
    if(circuit_deliver_relay_cell(&newcell, circ, CELL_DIRECTION_IN, NULL) < 0) {
156
      log_fn(LOG_DEBUG,"failed to deliver extended cell. Closing.");
Roger Dingledine's avatar
Roger Dingledine committed
157
158
159
      circuit_close(circ);
      return;
    }
160
161
  }
}
Roger Dingledine's avatar
Roger Dingledine committed
162

Roger Dingledine's avatar
Roger Dingledine committed
163
static void command_process_relay_cell(cell_t *cell, connection_t *conn) {
164
  circuit_t *circ;
Roger Dingledine's avatar
Roger Dingledine committed
165
166
167
168

  circ = circuit_get_by_aci_conn(cell->aci, conn);

  if(!circ) {
169
    log_fn(LOG_DEBUG,"unknown circuit %d. Dropping.", cell->aci);
Roger Dingledine's avatar
Roger Dingledine committed
170
171
172
    return;
  }

173
  if(circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
174
    log_fn(LOG_DEBUG,"circuit in create_wait. Dropping.");
175
176
    return;
  }
177

Roger Dingledine's avatar
   
Roger Dingledine committed
178
179
  if(cell->aci == circ->p_aci) { /* it's an outgoing cell */
    cell->aci = circ->n_aci; /* switch it */
180
    if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_OUT, conn->cpath_layer) < 0) {
181
      log_fn(LOG_INFO,"circuit_deliver_relay_cell (forward) failed. Closing.");
Roger Dingledine's avatar
Roger Dingledine committed
182
183
184
185
186
      circuit_close(circ);
      return;
    }
  } else { /* it's an ingoing cell */
    cell->aci = circ->p_aci; /* switch it */
187
    if(circuit_deliver_relay_cell(cell, circ, CELL_DIRECTION_IN, NULL) < 0) {
188
      log_fn(LOG_DEBUG,"circuit_deliver_relay_cell (backward) failed. Closing.");
189
190
      circuit_close(circ);
      return;
Roger Dingledine's avatar
Roger Dingledine committed
191
192
193
194
    }
  }
}

Roger Dingledine's avatar
Roger Dingledine committed
195
static void command_process_destroy_cell(cell_t *cell, connection_t *conn) {
Roger Dingledine's avatar
Roger Dingledine committed
196
197
198
199
200
  circuit_t *circ;

  circ = circuit_get_by_aci_conn(cell->aci, conn);

  if(!circ) {
201
    log_fn(LOG_DEBUG,"unknown circuit %d. Dropping.", cell->aci);
Roger Dingledine's avatar
Roger Dingledine committed
202
203
204
    return;
  }

205
  log_fn(LOG_DEBUG,"Received for aci %d.",cell->aci);
206
  if(circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
207
208
    onion_pending_remove(circ);
  }
209

210
211
  if(cell->aci == circ->p_aci || circ->cpath) {
    /* either the destroy came from behind, or we're the AP */
212
    circ->p_conn = NULL;
213
214
    circuit_close(circ);
  } else { /* the destroy came from ahead */
215
    circ->n_conn = NULL;
216
    log_fn(LOG_DEBUG, "Delivering 'truncated' back.");
217
218
    connection_edge_send_command(NULL, circ, RELAY_COMMAND_TRUNCATED);
  }
Roger Dingledine's avatar
Roger Dingledine committed
219
220
}

221
222
223
224
225
226
227
/*
  Local Variables:
  mode:c
  indent-tabs-mode:nil
  c-basic-offset:2
  End:
*/