Kaynağa Gözat

r11741@Kushana: nickm | 2006-12-28 22:41:29 -0500
Count TLS bytes accurately: previously, we counted only the number of bytes read or transmitted via tls, not the number of extra bytes used to do so. This has been a lonstanding wart. The fix "Works for me".


svn:r9207

Nick Mathewson 18 yıl önce
ebeveyn
işleme
361998d0f3
5 değiştirilmiş dosya ile 72 ekleme ve 28 silme
  1. 3 0
      ChangeLog
  2. 1 1
      doc/TODO
  3. 21 15
      src/common/tortls.c
  4. 2 2
      src/common/tortls.h
  5. 45 10
      src/or/connection.c

+ 3 - 0
ChangeLog

@@ -16,6 +16,9 @@ Changes in version 0.1.2.5-xxxx - 200?-??-??
       same directory as tor.exe (Bug #356) and default to using the torrc
       same directory as tor.exe (Bug #356) and default to using the torrc
       located in the %appdata%\Tor\ of the user who installed the service.
       located in the %appdata%\Tor\ of the user who installed the service.
       Patch from Matt Edman.
       Patch from Matt Edman.
+    - Include TLS overhead when counting bandwidth usage; previously, we
+      would count only the bytes sent over TLS, but not the bytes used to
+      send them.
 
 
   o Minor features:
   o Minor features:
     - Start using the state file to store bandwidth accounting data:
     - Start using the state file to store bandwidth accounting data:

+ 1 - 1
doc/TODO

@@ -296,7 +296,7 @@ P - Figure out why openssl 0.9.8d "make test" fails at sha256t test.
   - a way to pick entry guards based wholly on extend_info equivalent;
   - a way to pick entry guards based wholly on extend_info equivalent;
     a way to export extend_info equivalent.
     a way to export extend_info equivalent.
 
 
-  - Count TLS bandwidth more accurately
+  o Count TLS bandwidth more accurately
 
 
   - Better estimates in the directory of whether servers have good uptime
   - Better estimates in the directory of whether servers have good uptime
     (high expected time to failure) or good guard qualities (high
     (high expected time to failure) or good guard qualities (high

+ 21 - 15
src/common/tortls.c

@@ -53,9 +53,11 @@ struct tor_tls_t {
     TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED
     TOR_TLS_ST_SENTCLOSE, TOR_TLS_ST_CLOSED
   } state; /**< The current SSL state, depending on which operations have
   } state; /**< The current SSL state, depending on which operations have
             * completed successfully. */
             * completed successfully. */
-  int isServer;
+  int isServer; /**< True iff this is a server-side connection */
   size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
   size_t wantwrite_n; /**< 0 normally, >0 if we returned wantwrite last
                        * time. */
                        * time. */
+  unsigned long last_write_count;
+  unsigned long last_read_count;
 };
 };
 
 
 static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa,
 static X509* tor_tls_create_certificate(crypto_pk_env_t *rsa,
@@ -339,7 +341,7 @@ tor_tls_context_new(crypto_pk_env_t *identity, const char *nickname,
     goto error;
     goto error;
   }
   }
 
 
-  result = tor_malloc(sizeof(tor_tls_context_t));
+  result = tor_malloc_zero(sizeof(tor_tls_context_t));
 #ifdef EVERYONE_HAS_AES
 #ifdef EVERYONE_HAS_AES
   /* Tell OpenSSL to only use TLS1 */
   /* Tell OpenSSL to only use TLS1 */
   if (!(result->ctx = SSL_CTX_new(TLSv1_method())))
   if (!(result->ctx = SSL_CTX_new(TLSv1_method())))
@@ -415,7 +417,7 @@ tor_tls_t *
 tor_tls_new(int sock, int isServer)
 tor_tls_new(int sock, int isServer)
 {
 {
   BIO *bio = NULL;
   BIO *bio = NULL;
-  tor_tls_t *result = tor_malloc(sizeof(tor_tls_t));
+  tor_tls_t *result = tor_malloc_zero(sizeof(tor_tls_t));
 
 
   tor_assert(global_tls_context); /* make sure somebody made it first */
   tor_assert(global_tls_context); /* make sure somebody made it first */
   if (!(result->ssl = SSL_new(global_tls_context->ctx))) {
   if (!(result->ssl = SSL_new(global_tls_context->ctx))) {
@@ -860,19 +862,23 @@ tor_tls_get_forced_write_size(tor_tls_t *tls)
   return tls->wantwrite_n;
   return tls->wantwrite_n;
 }
 }
 
 
-/** Return the number of bytes read across the underlying socket. */
+/** Sets n_read and n_written to the number of bytes read and written,
-unsigned long
+ * respectivey, on the raw socket used by <b>tls</b> since the last time this
-tor_tls_get_n_bytes_read(tor_tls_t *tls)
+ * function was called on <b>tls</b>. */
-{
+void
-  tor_assert(tls);
+tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written)
-  return BIO_number_read(SSL_get_rbio(tls->ssl));
-}
-/** Return the number of bytes written across the underlying socket. */
-unsigned long
-tor_tls_get_n_bytes_written(tor_tls_t *tls)
 {
 {
-  tor_assert(tls);
+  unsigned long r, w;
-  return BIO_number_written(SSL_get_wbio(tls->ssl));
+  r = BIO_number_read(SSL_get_rbio(tls->ssl));
+  w = BIO_number_written(SSL_get_wbio(tls->ssl));
+  /* If we wrapped around, this should still give us the right answer, unless
+   * we wrapped around by more than ULONG_MAX since the last time we called
+   * this function.
+   */
+  *n_read = (size_t)(r - tls->last_read_count);
+  *n_written = (size_t)(w - tls->last_write_count);
+  tls->last_read_count = r;
+  tls->last_write_count = w;
 }
 }
 
 
 /** Implement check_no_tls_errors: If there are any pending OpenSSL
 /** Implement check_no_tls_errors: If there are any pending OpenSSL

+ 2 - 2
src/common/tortls.h

@@ -43,8 +43,8 @@ int tor_tls_shutdown(tor_tls_t *tls);
 int tor_tls_get_pending_bytes(tor_tls_t *tls);
 int tor_tls_get_pending_bytes(tor_tls_t *tls);
 size_t tor_tls_get_forced_write_size(tor_tls_t *tls);
 size_t tor_tls_get_forced_write_size(tor_tls_t *tls);
 
 
-unsigned long tor_tls_get_n_bytes_read(tor_tls_t *tls);
+void tor_tls_get_n_raw_bytes(tor_tls_t *tls,
-unsigned long tor_tls_get_n_bytes_written(tor_tls_t *tls);
+                             size_t *n_read, size_t *n_written);
 
 
 /* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
 /* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
  */
  */

+ 45 - 10
src/or/connection.c

@@ -1418,6 +1418,7 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
 {
 {
   int result, at_most = *max_to_read;
   int result, at_most = *max_to_read;
   size_t bytes_in_buf, more_to_read;
   size_t bytes_in_buf, more_to_read;
+  size_t n_read = 0, n_written = 0;
 
 
   if (at_most == -1) { /* we need to initialize it */
   if (at_most == -1) { /* we need to initialize it */
     /* how many bytes are we allowed to read? */
     /* how many bytes are we allowed to read? */
@@ -1475,7 +1476,7 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
     }
     }
     pending = tor_tls_get_pending_bytes(or_conn->tls);
     pending = tor_tls_get_pending_bytes(or_conn->tls);
     if (pending) {
     if (pending) {
-      /* XXXX012 If we have any pending bytes, read them now.  This *can*
+      /* If we have any pending bytes, we read them now.  This *can*
        * take us over our read allotment, but really we shouldn't be
        * take us over our read allotment, but really we shouldn't be
        * believing that SSL bytes are the same as TCP bytes anyway. */
        * believing that SSL bytes are the same as TCP bytes anyway. */
       int r2 = read_to_buf_tls(or_conn->tls, pending, conn->inbuf);
       int r2 = read_to_buf_tls(or_conn->tls, pending, conn->inbuf);
@@ -1487,6 +1488,9 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
       }
       }
     }
     }
 
 
+    tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written);
+    log_debug(LD_GENERAL, "After TLS read of %d: %ld read, %ld written",
+              result, (long)n_read, (long)n_written);
   } else {
   } else {
     int reached_eof = 0;
     int reached_eof = 0;
     CONN_LOG_PROTECT(conn,
     CONN_LOG_PROTECT(conn,
@@ -1498,15 +1502,24 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
 
 
     if (result < 0)
     if (result < 0)
       return -1;
       return -1;
+    n_read = (size_t) result;
   }
   }
 
 
-  if (result > 0) { /* change *max_to_read */
+  if (n_read > 0) { /* change *max_to_read */
-    *max_to_read = at_most - result;
+    *max_to_read = at_most - n_read;
   }
   }
 
 
-  if (result > 0 && !is_internal_IP(conn->addr, 0)) { /* remember it */
+  if (!is_internal_IP(conn->addr, 0)) {
-    rep_hist_note_bytes_read(result, time(NULL));
+    /* For non-local IPs, remember if we flushed any bytes over the wire. */
-    connection_read_bucket_decrement(conn, result);
+    time_t now = time(NULL);
+    if (n_read > 0) {
+      rep_hist_note_bytes_read(n_read, now);
+      connection_read_bucket_decrement(conn, n_read);
+    }
+    if (n_written > 0) {
+      rep_hist_note_bytes_written(n_written, now);
+      global_write_bucket -= n_written;
+    }
   }
   }
 
 
   if (more_to_read && result == at_most) {
   if (more_to_read && result == at_most) {
@@ -1520,6 +1533,8 @@ connection_read_to_buf(connection_t *conn, int *max_to_read)
    * have reached 0 on a different conn, and this guy needs to
    * have reached 0 on a different conn, and this guy needs to
    * know to stop reading. */
    * know to stop reading. */
   connection_consider_empty_read_buckets(conn);
   connection_consider_empty_read_buckets(conn);
+  if (n_written > 0)
+    connection_consider_empty_write_buckets(conn);
 
 
   return 0;
   return 0;
 }
 }
@@ -1571,6 +1586,7 @@ connection_handle_write(connection_t *conn)
   int result;
   int result;
   int max_to_write;
   int max_to_write;
   time_t now = time(NULL);
   time_t now = time(NULL);
+  size_t n_read = 0, n_written = 0;
 
 
   tor_assert(!connection_is_listener(conn));
   tor_assert(!connection_is_listener(conn));
 
 
@@ -1664,6 +1680,10 @@ connection_handle_write(connection_t *conn)
        * is empty, so we can stop writing.
        * is empty, so we can stop writing.
        */
        */
     }
     }
+
+    tor_tls_get_n_raw_bytes(or_conn->tls, &n_read, &n_written);
+    log_debug(LD_GENERAL, "After TLS write of %d: %ld read, %ld written",
+              result, (long)n_read, (long)n_written);
   } else {
   } else {
     CONN_LOG_PROTECT(conn,
     CONN_LOG_PROTECT(conn,
              result = flush_buf(conn->s, conn->outbuf,
              result = flush_buf(conn->s, conn->outbuf,
@@ -1677,13 +1697,25 @@ connection_handle_write(connection_t *conn)
       connection_mark_for_close(conn);
       connection_mark_for_close(conn);
       return -1;
       return -1;
     }
     }
+    n_written = (size_t) result;
   }
   }
 
 
-  if (result > 0) {
+  if (!is_internal_IP(conn->addr, 0)) {
-    if (!is_internal_IP(conn->addr, 0)) { /* remember it */
+    /* For non-local IPs, remember if we flushed any bytes over the wire. */
-      rep_hist_note_bytes_written(result, time(NULL));
+    time_t now = time(NULL);
-      global_write_bucket -= result;
+    if (n_written > 0) {
+      rep_hist_note_bytes_written(n_written, now);
+      global_write_bucket -= n_written;
+    }
+    if (n_read > 0) {
+      rep_hist_note_bytes_read(n_read, now);
+      global_read_bucket -= n_read;
     }
     }
+  }
+
+  if (result > 0) {
+    /* If we wrote any bytes from our buffer, then call the appropriate
+     * functions. */
     if (connection_flushed_some(conn) < 0)
     if (connection_flushed_some(conn) < 0)
       connection_mark_for_close(conn);
       connection_mark_for_close(conn);
   }
   }
@@ -1700,6 +1732,9 @@ connection_handle_write(connection_t *conn)
    * have reached 0 on a different conn, and this guy needs to
    * have reached 0 on a different conn, and this guy needs to
    * know to stop writing. */
    * know to stop writing. */
   connection_consider_empty_write_buckets(conn);
   connection_consider_empty_write_buckets(conn);
+  if (n_read > 0)
+    connection_consider_empty_read_buckets(conn);
+
   return 0;
   return 0;
 }
 }