connection.c 23 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
7
8

#include "or.h"

/********* START VARIABLES **********/

9
10
extern or_options_t options; /* command-line and config-file options */

11
12
extern int global_read_bucket;

Roger Dingledine's avatar
Roger Dingledine committed
13
char *conn_type_to_string[] = {
14
15
16
17
18
19
20
  "",            /* 0 */
  "OP listener", /* 1 */
  "OP",          /* 2 */
  "OR listener", /* 3 */
  "OR",          /* 4 */
  "Exit",        /* 5 */
  "App listener",/* 6 */
21
22
23
  "App",         /* 7 */
  "Dir listener",/* 8 */
  "Dir",         /* 9 */
Roger Dingledine's avatar
Roger Dingledine committed
24
25
  "DNS worker",  /* 10 */
  "CPU worker",  /* 11 */
Roger Dingledine's avatar
Roger Dingledine committed
26
27
};

28
char *conn_state_to_string[][_CONN_TYPE_MAX+1] = {
29
30
31
  { NULL }, /* no type associated with 0 */
  { NULL }, /* op listener, obsolete */
  { NULL }, /* op, obsolete */
Roger Dingledine's avatar
Roger Dingledine committed
32
  { "ready" }, /* or listener, 0 */
33
34
35
36
37
38
39
40
  { "",                         /* OR, 0 */
    "connect()ing",                 /* 1 */
    "handshaking",                  /* 2 */
    "open" },                       /* 3 */
  { "",                          /* exit, 0 */
    "waiting for dest info",           /* 1 */
    "connecting",                      /* 2 */
    "open" },                          /* 3 */
41
  { "ready" }, /* app listener, 0 */
42
43
44
  { "", /* 0 */
    "", /* 1 */
    "", /* 2 */
45
46
47
48
    "", /* 3 */
    "awaiting dest info",         /* app, 4 */
    "waiting for OR connection",       /* 5 */
    "open" },                          /* 6 */
49
  { "ready" }, /* dir listener, 0 */
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  { "",                           /* dir, 0 */
    "connecting (fetch)",              /* 1 */
    "connecting (upload)",             /* 2 */
    "client sending fetch",            /* 3 */
    "client sending upload",           /* 4 */
    "client reading fetch",            /* 5 */
    "client reading upload",           /* 6 */
    "awaiting command",                /* 7 */
    "writing" },                       /* 8 */
  { "",                    /* dns worker, 0 */
    "idle",                            /* 1 */
    "busy" },                          /* 2 */
  { "",                    /* cpu worker, 0 */
    "idle",                            /* 1 */
    "busy with onion",                 /* 2 */
    "busy with handshake" },           /* 3 */
Roger Dingledine's avatar
Roger Dingledine committed
66
67
68
69
};

/********* END VARIABLES ************/

70
static int connection_init_accepted_conn(connection_t *conn);
71
72
73

/**************************************************************/

Roger Dingledine's avatar
Roger Dingledine committed
74
75
connection_t *connection_new(int type) {
  connection_t *conn;
76
77
  struct timeval now;

78
  my_gettimeofday(&now);
Roger Dingledine's avatar
Roger Dingledine committed
79

80
  conn = (connection_t *)tor_malloc(sizeof(connection_t));
Roger Dingledine's avatar
Roger Dingledine committed
81
82
83
  memset(conn,0,sizeof(connection_t)); /* zero it out to start */

  conn->type = type;
84
85
  conn->inbuf = buf_new();
  conn->outbuf = buf_new();
Roger Dingledine's avatar
Roger Dingledine committed
86

87
  conn->timestamp_created = now.tv_sec;
88
89
90
  conn->timestamp_lastread = now.tv_sec;
  conn->timestamp_lastwritten = now.tv_sec;

Roger Dingledine's avatar
Roger Dingledine committed
91
92
93
94
95
96
97
98
99
100
101
  return conn;
}

void connection_free(connection_t *conn) {
  assert(conn);

  buf_free(conn->inbuf);
  buf_free(conn->outbuf);
  if(conn->address)
    free(conn->address);

102
  if(connection_speaks_cells(conn)) {
103
    directory_set_dirty();
Roger Dingledine's avatar
Roger Dingledine committed
104
105
    if (conn->tls)
      tor_tls_free(conn->tls);
Roger Dingledine's avatar
Roger Dingledine committed
106
107
  }

108
109
110
111
112
113
  if (conn->onion_pkey)
    crypto_free_pk_env(conn->onion_pkey);
  if (conn->link_pkey)
    crypto_free_pk_env(conn->link_pkey);
  if (conn->identity_pkey)
    crypto_free_pk_env(conn->identity_pkey);
114
115
  if (conn->nickname) 
    free(conn->nickname);
116

117
  if(conn->s > 0) {
118
    log_fn(LOG_INFO,"closing fd %d.",conn->s);
Roger Dingledine's avatar
Roger Dingledine committed
119
    close(conn->s);
120
  }
Roger Dingledine's avatar
Roger Dingledine committed
121
122
123
  free(conn);
}

124
int connection_create_listener(struct sockaddr_in *bindaddr, int type) {
Roger Dingledine's avatar
Roger Dingledine committed
125
126
127
128
129
  connection_t *conn;
  int s;
  int one=1;

  s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
130
  if (s < 0) { 
131
    log_fn(LOG_WARNING,"Socket creation failed.");
Roger Dingledine's avatar
Roger Dingledine committed
132
133
134
    return -1;
  }

135
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&one, sizeof(one));
Roger Dingledine's avatar
Roger Dingledine committed
136

137
  if(bind(s,(struct sockaddr *)bindaddr,sizeof(*bindaddr)) < 0) {
Roger Dingledine's avatar
Roger Dingledine committed
138
    perror("bind ");
139
    log(LOG_WARNING,"Could not bind to port %u.",ntohs(bindaddr->sin_port));
Roger Dingledine's avatar
Roger Dingledine committed
140
141
142
143
    return -1;
  }

  if(listen(s,SOMAXCONN) < 0) {
144
    log(LOG_WARNING,"Could not listen on port %u.",ntohs(bindaddr->sin_port));
Roger Dingledine's avatar
Roger Dingledine committed
145
146
147
    return -1;
  }

148
  set_socket_nonblocking(s);
Roger Dingledine's avatar
Roger Dingledine committed
149
150
151
152
153

  conn = connection_new(type);
  conn->s = s;

  if(connection_add(conn) < 0) { /* no space, forget it */
154
    log_fn(LOG_WARNING,"connection_add failed. Giving up.");
Roger Dingledine's avatar
Roger Dingledine committed
155
156
157
158
    connection_free(conn);
    return -1;
  }

159
  log_fn(LOG_DEBUG,"%s listening on port %u.",conn_type_to_string[type], ntohs(bindaddr->sin_port));
Roger Dingledine's avatar
Roger Dingledine committed
160
161

  conn->state = LISTENER_STATE_READY;
162
  connection_start_reading(conn);
Roger Dingledine's avatar
Roger Dingledine committed
163
164
165
166

  return 0;
}

167
int connection_handle_listener_read(connection_t *conn, int new_type) {
Roger Dingledine's avatar
Roger Dingledine committed
168
169
170
171
  int news; /* the new socket */
  connection_t *newconn;
  struct sockaddr_in remote; /* information about the remote peer when connecting to other routers */
  int remotelen = sizeof(struct sockaddr_in); /* length of the remote address */
172
173
174
#ifdef MS_WINDOWS
  int e;
#endif
Roger Dingledine's avatar
Roger Dingledine committed
175
176
177

  news = accept(conn->s,(struct sockaddr *)&remote,&remotelen);
  if (news == -1) { /* accept() error */
178
179
180
181
182
183
    if(ERRNO_EAGAIN(errno)) {
#ifdef MS_WINDOWS
      e = correct_socket_errno(conn->s);
      if (ERRNO_EAGAIN(e))
        return 0;
#else
Roger Dingledine's avatar
Roger Dingledine committed
184
      return 0; /* he hung up before we could accept(). that's fine. */
185
186
#endif
    }
Roger Dingledine's avatar
Roger Dingledine committed
187
    /* else there was a real error. */
188
    log_fn(LOG_WARNING,"accept() failed. Closing listener.");
Roger Dingledine's avatar
Roger Dingledine committed
189
190
    return -1;
  }
191
  log(LOG_INFO,"Connection accepted on socket %d (child of fd %d).",news, conn->s);
Roger Dingledine's avatar
Roger Dingledine committed
192

193
  set_socket_nonblocking(news);
194

Roger Dingledine's avatar
Roger Dingledine committed
195
196
197
  newconn = connection_new(new_type);
  newconn->s = news;

198
  newconn->address = strdup(inet_ntoa(remote.sin_addr)); /* remember the remote address */
199
200
  newconn->addr = ntohl(remote.sin_addr.s_addr);
  newconn->port = ntohs(remote.sin_port);
Roger Dingledine's avatar
Roger Dingledine committed
201
202
203

  if(connection_add(newconn) < 0) { /* no space, forget it */
    connection_free(newconn);
204
    return 0; /* no need to tear down the parent */
Roger Dingledine's avatar
Roger Dingledine committed
205
206
  }

207
  if(connection_init_accepted_conn(newconn) < 0) {
208
    newconn->marked_for_close = 1;
209
210
211
212
213
214
215
216
217
218
219
    return 0;
  }
  return 0;
}

static int connection_init_accepted_conn(connection_t *conn) {

  connection_start_reading(conn);

  switch(conn->type) {
    case CONN_TYPE_OR:
220
      return connection_tls_start_handshake(conn, 1);
221
222
223
224
    case CONN_TYPE_AP:
      conn->state = AP_CONN_STATE_SOCKS_WAIT;
      break;
    case CONN_TYPE_DIR:
225
      conn->state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
226
227
228
229
230
      break;
  }
  return 0;
}

231
232
233
234
235
236
237
238
239
240
241
/* take conn, make a nonblocking socket; try to connect to 
 * addr:port (they arrive in *host order*). If fail, return -1. Else
 * assign s to conn->s: if connected return 1, if eagain return 0.
 * address is used to make the logs useful.
 */
int connection_connect(connection_t *conn, char *address, uint32_t addr, uint16_t port) {
  int s;
  struct sockaddr_in dest_addr;

  s=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
  if (s < 0) {
242
    log_fn(LOG_WARNING,"Error creating network socket.");
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
    return -1;
  }
  set_socket_nonblocking(s);

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

  log_fn(LOG_DEBUG,"Connecting to %s:%u.",address,port);

  if(connect(s,(struct sockaddr *)&dest_addr,sizeof(dest_addr)) < 0) {
    if(!ERRNO_CONN_EINPROGRESS(errno)) {
      /* yuck. kill it. */
      perror("connect");
258
      log_fn(LOG_INFO,"Connect() to %s:%u failed.",address,port);
259
260
261
262
263
264
265
266
267
268
      return -1;
    } else {
      /* it's in progress. set state appropriately and return. */
      conn->s = s;
      log_fn(LOG_DEBUG,"connect in progress, socket %d.",s);
      return 0;
    }
  }

  /* it succeeded. we're connected. */
269
  log_fn(LOG_INFO,"Connection to %s:%u established.",address,port);
270
271
272
273
  conn->s = s;
  return 1;
}

Roger Dingledine's avatar
Roger Dingledine committed
274
/* start all connections that should be up but aren't */
275
int retry_all_connections(uint16_t or_listenport, uint16_t ap_listenport, uint16_t dir_listenport) {
276
  struct sockaddr_in bindaddr; /* where to bind */
277

278
  if(or_listenport) {
279
    router_retry_connections();
Roger Dingledine's avatar
Roger Dingledine committed
280
281
  }

282
283
284
  memset(&bindaddr,0,sizeof(struct sockaddr_in));
  bindaddr.sin_family = AF_INET;
  bindaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* anyone can connect */
285

286
  if(or_listenport) {
287
    bindaddr.sin_port = htons(or_listenport);
288
    if(!connection_get_by_type(CONN_TYPE_OR_LISTENER)) {
289
      connection_create_listener(&bindaddr, CONN_TYPE_OR_LISTENER);
290
    }
Roger Dingledine's avatar
Roger Dingledine committed
291
  }
292

293
  if(dir_listenport) {
294
    bindaddr.sin_port = htons(dir_listenport);
295
    if(!connection_get_by_type(CONN_TYPE_DIR_LISTENER)) {
296
      connection_create_listener(&bindaddr, CONN_TYPE_DIR_LISTENER);
297
298
    }
  }
Roger Dingledine's avatar
Roger Dingledine committed
299
 
300
  if(ap_listenport) {
301
    bindaddr.sin_port = htons(ap_listenport);
302
    bindaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* the AP listens only on localhost! */
303
    if(!connection_get_by_type(CONN_TYPE_AP_LISTENER)) {
304
      connection_create_listener(&bindaddr, CONN_TYPE_AP_LISTENER);
305
306
307
    }
  }

Roger Dingledine's avatar
Roger Dingledine committed
308
309
310
  return 0;
}

311
312
313
314
315
316
317
318
int connection_handle_read(connection_t *conn) {
  struct timeval now;

  my_gettimeofday(&now);
  conn->timestamp_lastread = now.tv_sec;

  switch(conn->type) {
    case CONN_TYPE_OR_LISTENER:
319
      return connection_handle_listener_read(conn, CONN_TYPE_OR);
320
    case CONN_TYPE_AP_LISTENER:
321
      return connection_handle_listener_read(conn, CONN_TYPE_AP);
322
    case CONN_TYPE_DIR_LISTENER:
323
324
      return connection_handle_listener_read(conn, CONN_TYPE_DIR);
  }
325

326
  if(connection_read_to_buf(conn) < 0) {
327
    if(conn->type == CONN_TYPE_DIR && 
328
329
      (conn->state == DIR_CONN_STATE_CONNECTING_FETCH ||
       conn->state == DIR_CONN_STATE_CONNECTING_UPLOAD)) {
330
331
       /* it's a directory server and connecting failed: forget about this router */
       /* XXX I suspect pollerr may make Windows not get to this point. :( */
332
       router_mark_as_down(conn->nickname);
333
334
335
336
    }
    return -1;
  }
  if(connection_process_inbuf(conn) < 0) {
337
//    log_fn(LOG_DEBUG,"connection_process_inbuf returned -1.");
338
339
    return -1;
  }
Roger Dingledine's avatar
Roger Dingledine committed
340
  return 0;
341
342
}

Roger Dingledine's avatar
Roger Dingledine committed
343
/* return -1 if we want to break conn, else return 0 */
Roger Dingledine's avatar
Roger Dingledine committed
344
int connection_read_to_buf(connection_t *conn) {
Roger Dingledine's avatar
Roger Dingledine committed
345
  int result;
Roger Dingledine's avatar
Roger Dingledine committed
346
  int at_most;
347

Roger Dingledine's avatar
Roger Dingledine committed
348
349
  if(options.LinkPadding) {
    at_most = global_read_bucket;
350
  } else {
Roger Dingledine's avatar
Roger Dingledine committed
351
352
353
354
355
356
357
    /* do a rudimentary round-robin so one connection can't hog a thickpipe */
    if(connection_speaks_cells(conn)) {
      at_most = 10*(CELL_NETWORK_SIZE);
    } else {
      at_most = 10*(CELL_PAYLOAD_SIZE - RELAY_HEADER_SIZE);
    }

358
359
    at_most = 103; /* an unusual number, to force bugs into the open */

Roger Dingledine's avatar
Roger Dingledine committed
360
361
    if(at_most > global_read_bucket)
      at_most = global_read_bucket;
362
  }
363

Roger Dingledine's avatar
Roger Dingledine committed
364
  if(connection_speaks_cells(conn) && conn->state != OR_CONN_STATE_CONNECTING) {
365
366
367
368
    if(conn->state == OR_CONN_STATE_HANDSHAKING)
      return connection_tls_continue_handshake(conn);

    /* else open, or closing */
369
370
    if(at_most > conn->receiver_bucket)
      at_most = conn->receiver_bucket;
371
    result = read_to_buf_tls(conn->tls, at_most, conn->inbuf);
Roger Dingledine's avatar
Roger Dingledine committed
372
373
374
375

    switch(result) {
      case TOR_TLS_ERROR:
      case TOR_TLS_CLOSE:
376
        log_fn(LOG_INFO,"tls error. breaking.");
Roger Dingledine's avatar
Roger Dingledine committed
377
        return -1; /* XXX deal with close better */
378
      case TOR_TLS_WANTWRITE:
Roger Dingledine's avatar
Roger Dingledine committed
379
380
        connection_start_writing(conn);
        return 0;
381
      case TOR_TLS_WANTREAD: /* we're already reading */
Roger Dingledine's avatar
Roger Dingledine committed
382
383
      case TOR_TLS_DONE: /* no data read, so nothing to process */
        return 0;
384
    }
385
  } else {
386
387
388
    result = read_to_buf(conn->s, at_most, conn->inbuf,
                         &conn->inbuf_reached_eof);

Roger Dingledine's avatar
Roger Dingledine committed
389
390
391
392
//  log(LOG_DEBUG,"connection_read_to_buf(): read_to_buf returned %d.",read_result);

    if(result < 0)
      return -1;
393
394
  }

Roger Dingledine's avatar
Roger Dingledine committed
395
  global_read_bucket -= result; assert(global_read_bucket >= 0);
396
397
  if(global_read_bucket == 0) {
    log_fn(LOG_DEBUG,"global bucket exhausted. Pausing.");
Roger Dingledine's avatar
Roger Dingledine committed
398
399
    conn->wants_to_read = 1;
    connection_stop_reading(conn);
400
    return 0;
Roger Dingledine's avatar
Roger Dingledine committed
401
  }
402
403
404
405
406
407
408
409
410
  if(connection_speaks_cells(conn) && conn->state == OR_CONN_STATE_OPEN) {
    conn->receiver_bucket -= result; assert(conn->receiver_bucket >= 0);
    if(conn->receiver_bucket == 0) {
      log_fn(LOG_DEBUG,"receiver bucket exhausted. Pausing.");
      conn->wants_to_read = 1;
      connection_stop_reading(conn);
      return 0;
    }
  }
Roger Dingledine's avatar
Roger Dingledine committed
411
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
412
413
414
}

int connection_fetch_from_buf(char *string, int len, connection_t *conn) {
415
  return fetch_from_buf(string, len, conn->inbuf);
Roger Dingledine's avatar
Roger Dingledine committed
416
417
}

418
int connection_find_on_inbuf(char *string, int len, connection_t *conn) {
419
  return find_on_inbuf(string, len, conn->inbuf);
420
421
}

422
423
424
425
426
427
428
429
int connection_wants_to_flush(connection_t *conn) {
  return conn->outbuf_flushlen;
}

int connection_outbuf_too_full(connection_t *conn) {
  return (conn->outbuf_flushlen > 10*CELL_PAYLOAD_SIZE);
}

Roger Dingledine's avatar
Roger Dingledine committed
430
int connection_flush_buf(connection_t *conn) {
431
  return flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen);
Roger Dingledine's avatar
Roger Dingledine committed
432
433
}

Roger Dingledine's avatar
Roger Dingledine committed
434
/* return -1 if you want to break the conn, else return 0 */
435
int connection_handle_write(connection_t *conn) {
436
  struct timeval now;
437
438

  if(connection_is_listener(conn)) {
439
    log_fn(LOG_WARNING,"Got a listener socket. Can't happen!");
440
441
    return -1;
  }
442

443
  my_gettimeofday(&now);
444
445
  conn->timestamp_lastwritten = now.tv_sec;

Roger Dingledine's avatar
Roger Dingledine committed
446
  if(connection_speaks_cells(conn) && conn->state != OR_CONN_STATE_CONNECTING) {
447
448
    if(conn->state == OR_CONN_STATE_HANDSHAKING) {
      connection_stop_writing(conn);
449
      return connection_tls_continue_handshake(conn);
450
    }
451

452
    /* else open, or closing */
453
    switch(flush_buf_tls(conn->tls, conn->outbuf, &conn->outbuf_flushlen)) {
Roger Dingledine's avatar
Roger Dingledine committed
454
455
      case TOR_TLS_ERROR:
      case TOR_TLS_CLOSE:
456
        log_fn(LOG_INFO,"tls error. breaking.");
Roger Dingledine's avatar
Roger Dingledine committed
457
        return -1; /* XXX deal with close better */
458
      case TOR_TLS_WANTWRITE:
459
        log_fn(LOG_DEBUG,"wanted write.");
Roger Dingledine's avatar
Roger Dingledine committed
460
461
        /* we're already writing */
        return 0;
462
      case TOR_TLS_WANTREAD:
Roger Dingledine's avatar
Roger Dingledine committed
463
        /* Make sure to avoid a loop if the receive buckets are empty. */
464
        log_fn(LOG_DEBUG,"wanted read.");
Roger Dingledine's avatar
Roger Dingledine committed
465
466
467
468
469
470
471
472
473
        if(!connection_is_reading(conn)) {
          connection_stop_writing(conn);
          conn->wants_to_write = 1;
          /* we'll start reading again when the next second arrives,
           * and then also start writing again.
           */
        }
        /* else no problem, we're already reading */
        return 0;
474
475
      /* case TOR_TLS_DONE:
       * for TOR_TLS_DONE, fall through to check if the flushlen
Roger Dingledine's avatar
Roger Dingledine committed
476
477
478
       * is empty, so we can stop writing.
       */  
    }
479
  } else {
480
    if(flush_buf(conn->s, conn->outbuf, &conn->outbuf_flushlen) < 0)
Roger Dingledine's avatar
Roger Dingledine committed
481
482
      return -1;
      /* conns in CONNECTING state will fall through... */
483
484
  }

Roger Dingledine's avatar
Roger Dingledine committed
485
486
487
488
489
  if(!connection_wants_to_flush(conn)) /* it's done flushing */
    if(connection_finished_flushing(conn) < 0) /* ...and get handled here. */
      return -1;

  return 0;
490
491
}

492
void connection_write_to_buf(const char *string, int len, connection_t *conn) {
493

494
495
  if(!len || conn->marked_for_close)
    return;
496

497
  if( (!connection_speaks_cells(conn)) ||
498
499
      (!connection_state_is_open(conn)) ||
      (options.LinkPadding == 0) ) {
500
    /* connection types other than or, or or not in 'open' state, should flush immediately */
501
    /* also flush immediately if we're not doing LinkPadding, since otherwise it will never flush */
502
    connection_start_writing(conn);
503
504
505
    conn->outbuf_flushlen += len;
  }

506
507
508
509
  if(write_to_buf(string, len, conn->outbuf) < 0) {
    log_fn(LOG_WARNING,"write_to_buf failed. Closing connection (fd %d).", conn->s);
    conn->marked_for_close = 1;
  }
Roger Dingledine's avatar
Roger Dingledine committed
510
511
}

512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port) {
  int i, n;
  connection_t *conn;
  connection_t **carray;
 
  get_connection_array(&carray,&n);
  for(i=0;i<n;i++) {
    conn = carray[i];
    if(conn->addr == addr && conn->port == port && !conn->marked_for_close)
      return conn;
  }
  return NULL;
}

connection_t *connection_twin_get_by_addr_port(uint32_t addr, uint16_t port) {
  /* Find a connection to the router described by addr and port,
   *   or alternately any router which knows its key.
   * This connection *must* be in 'open' state.
   * If not, return NULL.
   */
  int i, n;
  connection_t *conn;
  routerinfo_t *router;
  connection_t **carray;

  /* first check if it's there exactly */
  conn = connection_exact_get_by_addr_port(addr,port);
  if(conn && connection_state_is_open(conn)) {
    log(LOG_INFO,"connection_twin_get_by_addr_port(): Found exact match.");
    return conn;
  }
 
  /* now check if any of the other open connections are a twin for this one */
 
  router = router_get_by_addr_port(addr,port);
  if(!router)
    return NULL;
 
  get_connection_array(&carray,&n);
  for(i=0;i<n;i++) {
    conn = carray[i];
    assert(conn);
    if(connection_state_is_open(conn) &&
       !conn->marked_for_close &&
       !crypto_pk_cmp_keys(conn->onion_pkey, router->onion_pkey)) {
      log(LOG_INFO,"connection_twin_get_by_addr_port(): Found twin (%s).",conn->address);
      return conn;
    }
  }
  return NULL;
}

connection_t *connection_get_by_type(int type) {
  int i, n;
  connection_t *conn;
  connection_t **carray;
 
  get_connection_array(&carray,&n);
  for(i=0;i<n;i++) {
    conn = carray[i];
    if(conn->type == type && !conn->marked_for_close)
      return conn;
  }
  return NULL;
}

connection_t *connection_get_by_type_state(int type, int state) {
  int i, n;
  connection_t *conn;
  connection_t **carray;
 
583
  get_connection_array(&carray,&n);
584
585
586
587
588
589
590
591
592
593
594
595
596
  for(i=0;i<n;i++) {
    conn = carray[i];
    if(conn->type == type && conn->state == state && !conn->marked_for_close)
      return conn;
  }
  return NULL;
}

connection_t *connection_get_by_type_state_lastwritten(int type, int state) {
  int i, n;
  connection_t *conn, *best=NULL;
  connection_t **carray;
 
597
  get_connection_array(&carray,&n);
598
599
600
601
602
603
604
605
606
  for(i=0;i<n;i++) {
    conn = carray[i];
    if(conn->type == type && conn->state == state && !conn->marked_for_close)
      if(!best || conn->timestamp_lastwritten < best->timestamp_lastwritten)
        best = conn;
  }
  return best;
}

607
608
609
int connection_receiver_bucket_should_increase(connection_t *conn) {
  assert(conn);

610
611
  if(!connection_speaks_cells(conn))
    return 0; /* edge connections don't use receiver_buckets */
612
613
  if(conn->state != OR_CONN_STATE_OPEN)
    return 0; /* only open connections play the rate limiting game */  
614

615
  assert(conn->bandwidth > 0);
616
  if(conn->receiver_bucket > 9*conn->bandwidth)
617
618
619
620
621
    return 0;

  return 1;
}

622
int connection_is_listener(connection_t *conn) {
623
  if(conn->type == CONN_TYPE_OR_LISTENER ||
624
625
     conn->type == CONN_TYPE_AP_LISTENER ||
     conn->type == CONN_TYPE_DIR_LISTENER)
626
627
628
629
    return 1;
  return 0;
}

630
631
632
633
634
635
636
637
638
639
640
int connection_state_is_open(connection_t *conn) {
  assert(conn);

  if((conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_OPEN) ||
     (conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN) ||
     (conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN))
    return 1;

  return 0;
}

Roger Dingledine's avatar
Roger Dingledine committed
641
642
643
int connection_send_destroy(aci_t aci, connection_t *conn) {
  cell_t cell;

644
  assert(conn);
Roger Dingledine's avatar
Roger Dingledine committed
645

646
  if(!connection_speaks_cells(conn)) {
647
     log_fn(LOG_INFO,"Aci %d: At an edge. Marking connection for close.", aci);
648
/*ENDCLOSE*/ conn->marked_for_close = 1;
Roger Dingledine's avatar
Roger Dingledine committed
649
650
651
     return 0;
  }

652
  memset(&cell, 0, sizeof(cell_t));
Roger Dingledine's avatar
Roger Dingledine committed
653
654
  cell.aci = aci;
  cell.command = CELL_DESTROY;
655
  log_fn(LOG_INFO,"Sending destroy (aci %d).",aci);
656
657
  connection_write_cell_to_buf(&cell, conn);
  return 0;
Roger Dingledine's avatar
Roger Dingledine committed
658
659
}

Roger Dingledine's avatar
Roger Dingledine committed
660
661
662
663
664
665
666
int connection_process_inbuf(connection_t *conn) {

  assert(conn);

  switch(conn->type) {
    case CONN_TYPE_OR:
      return connection_or_process_inbuf(conn);
667
    case CONN_TYPE_EXIT:
668
    case CONN_TYPE_AP:
669
      return connection_edge_process_inbuf(conn);
670
671
    case CONN_TYPE_DIR:
      return connection_dir_process_inbuf(conn);
672
    case CONN_TYPE_DNSWORKER:
673
      return connection_dns_process_inbuf(conn); 
Roger Dingledine's avatar
Roger Dingledine committed
674
675
    case CONN_TYPE_CPUWORKER:
      return connection_cpu_process_inbuf(conn); 
Roger Dingledine's avatar
Roger Dingledine committed
676
    default:
677
      log_fn(LOG_WARNING,"got unexpected conn->type %d.", conn->type);
Roger Dingledine's avatar
Roger Dingledine committed
678
679
680
681
682
683
684
685
      return -1;
  }
}

int connection_finished_flushing(connection_t *conn) {

  assert(conn);

686
//  log_fn(LOG_DEBUG,"entered. Socket %u.", conn->s);
Roger Dingledine's avatar
Roger Dingledine committed
687
688
689
690

  switch(conn->type) {
    case CONN_TYPE_OR:
      return connection_or_finished_flushing(conn);
691
    case CONN_TYPE_AP:
692
    case CONN_TYPE_EXIT:
693
      return connection_edge_finished_flushing(conn);
694
695
    case CONN_TYPE_DIR:
      return connection_dir_finished_flushing(conn);
696
    case CONN_TYPE_DNSWORKER:
697
      return connection_dns_finished_flushing(conn);
Roger Dingledine's avatar
Roger Dingledine committed
698
699
    case CONN_TYPE_CPUWORKER:
      return connection_cpu_finished_flushing(conn);
Roger Dingledine's avatar
Roger Dingledine committed
700
    default:
701
      log_fn(LOG_WARNING,"got unexpected conn->type %d.", conn->type);
Roger Dingledine's avatar
Roger Dingledine committed
702
703
704
705
      return -1;
  }
}

706
707
void assert_connection_ok(connection_t *conn, time_t now)
{
708
  return;
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
  assert(conn);
  assert(conn->type >= _CONN_TYPE_MIN);
  assert(conn->type <= _CONN_TYPE_MAX);

  /* XXX check: wants_to_read, wants_to_write, s, poll_index,
   * marked_for_close. */
  
  /* buffers */
  assert(conn->inbuf);
  assert(conn->outbuf);

  assert(!now || conn->timestamp_lastread <= now);
  assert(!now || conn->timestamp_lastwritten <= now);
  assert(conn->timestamp_created <= conn->timestamp_lastread);
  assert(conn->timestamp_created <= conn->timestamp_lastwritten);
  
725
726
  /* XXX Fix this; no longer so.*/
#if 0
727
728
729
730
731
  if(conn->type != CONN_TYPE_OR && conn->type != CONN_TYPE_DIR)
    assert(!conn->pkey);
  /* pkey is set if we're a dir client, or if we're an OR in state OPEN
   * connected to another OR.
   */
732
#endif
733

734
735
736
  if (conn->type != CONN_TYPE_OR) {
    assert(!conn->tls);
  } else {
737
738
739
740
741
    if(conn->state == OR_CONN_STATE_OPEN) {
      assert(conn->bandwidth > 0);
      assert(conn->receiver_bucket >= 0);
      assert(conn->receiver_bucket <= 10*conn->bandwidth);
    }
742
743
744
745
746
747
    assert(conn->addr && conn->port);
    assert(conn->address);
    if (conn->state != OR_CONN_STATE_CONNECTING)
      assert(conn->tls);
  }
  
748
  if (conn->type != CONN_TYPE_EXIT && conn->type != CONN_TYPE_AP) {
749
750
751
752
753
754
755
756
757
    assert(!conn->stream_id[0]);
    assert(!conn->next_stream);
    assert(!conn->cpath_layer);
    assert(!conn->package_window);
    assert(!conn->deliver_window);
    assert(!conn->done_sending);
    assert(!conn->done_receiving);
  } else {
    assert(!conn->next_stream || 
758
759
           conn->next_stream->type == CONN_TYPE_EXIT ||
           conn->next_stream->type == CONN_TYPE_AP);
760
761
762
763
    if(conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN)
      assert(conn->cpath_layer);
    if(conn->cpath_layer)
      assert_cpath_layer_ok(conn->cpath_layer);
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
    /* XXX unchecked, package window, deliver window. */
  }

  switch(conn->type) 
    {
    case CONN_TYPE_OR_LISTENER:
    case CONN_TYPE_AP_LISTENER:
    case CONN_TYPE_DIR_LISTENER:
      assert(conn->state == LISTENER_STATE_READY);
      break;
    case CONN_TYPE_OR:
      assert(conn->state >= _OR_CONN_STATE_MIN &&
             conn->state <= _OR_CONN_STATE_MAX);
      break;
    case CONN_TYPE_EXIT:
      assert(conn->state >= _EXIT_CONN_STATE_MIN &&
             conn->state <= _EXIT_CONN_STATE_MAX);
      break;
    case CONN_TYPE_AP:
Roger Dingledine's avatar
Roger Dingledine committed
783
      assert(conn->state >= _AP_CONN_STATE_MIN &&
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
             conn->state <= _AP_CONN_STATE_MAX);
      break;
    case CONN_TYPE_DIR:
      assert(conn->state >= _DIR_CONN_STATE_MIN &&
             conn->state <= _DIR_CONN_STATE_MAX);
      break;
    case CONN_TYPE_DNSWORKER:
      assert(conn->state == DNSWORKER_STATE_IDLE ||
             conn->state == DNSWORKER_STATE_BUSY);
    case CONN_TYPE_CPUWORKER:
      assert(conn->state >= _CPUWORKER_STATE_MIN &&
             conn->state <= _CPUWORKER_STATE_MAX);
      break;
    default:
      assert(0);
  }
}

802
803
804
805
806
807
808
/*
  Local Variables:
  mode:c
  indent-tabs-mode:nil
  c-basic-offset:2
  End:
*/
809