aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore14
-rw-r--r--ChangeLog1397
-rw-r--r--LICENSE65
-rw-r--r--Makefile.am28
-rw-r--r--README3
-rw-r--r--ReleaseNotes985
-rw-r--r--acinclude.m42
-rw-r--r--changes/132955
-rw-r--r--changes/151883
-rw-r--r--changes/buf-sentinel11
-rw-r--r--changes/bufferevent_compilation6
-rw-r--r--changes/bug1038-36
-rw-r--r--changes/bug11200-caching7
-rw-r--r--changes/bug114475
-rw-r--r--changes/bug114546
-rw-r--r--changes/bug114575
-rw-r--r--changes/bug121604
-rw-r--r--changes/bug126025
-rw-r--r--changes/bug1270010
-rw-r--r--changes/bug127185
-rw-r--r--changes/bug12730-systemd-verify-config3
-rw-r--r--changes/bug12731-systemd-no-run-as-daemon9
-rw-r--r--changes/bug128304
-rw-r--r--changes/bug128484
-rw-r--r--changes/bug128647
-rw-r--r--changes/bug128783
-rw-r--r--changes/bug129084
-rw-r--r--changes/bug129488
-rw-r--r--changes/bug129965
-rw-r--r--changes/bug129973
-rw-r--r--changes/bug130713
-rw-r--r--changes/bug130813
-rw-r--r--changes/bug130853
-rw-r--r--changes/bug130964
-rw-r--r--changes/bug131003
-rw-r--r--changes/bug131248
-rw-r--r--changes/bug13151-client13
-rw-r--r--changes/bug132965
-rw-r--r--changes/bug133254
-rw-r--r--changes/bug134715
-rw-r--r--changes/bug139883
-rw-r--r--changes/bug140136
-rw-r--r--changes/bug141255
-rw-r--r--changes/bug141297
-rw-r--r--changes/bug14142-parse-virtual-addr7
-rw-r--r--changes/bug141953
-rw-r--r--changes/bug142204
-rw-r--r--changes/bug142615
-rw-r--r--changes/bug14848_redux5
-rw-r--r--changes/bug149503
-rw-r--r--changes/bug149804
-rw-r--r--changes/bug149884
-rw-r--r--changes/bug149894
-rw-r--r--changes/bug150033
-rw-r--r--changes/bug150334
-rw-r--r--changes/bug150374
-rw-r--r--changes/bug150644
-rw-r--r--changes/bug151513
-rw-r--r--changes/bug152406
-rw-r--r--changes/bug152455
-rw-r--r--changes/bug154364
-rw-r--r--changes/bug158504
-rw-r--r--changes/bug160135
-rw-r--r--changes/bug160303
-rw-r--r--changes/bug161644
-rw-r--r--changes/bug162125
-rw-r--r--changes/bug162447
-rw-r--r--changes/bug162475
-rw-r--r--changes/bug163634
-rw-r--r--changes/bug1638113
-rw-r--r--changes/bug164005
-rw-r--r--changes/bug80933
-rw-r--r--changes/bug838711
-rw-r--r--changes/bug9495_redux4
-rw-r--r--changes/curve25519-donna32-bug12
-rw-r--r--changes/disable_sslv34
-rw-r--r--changes/feature150064
-rw-r--r--changes/further-12184-diagnostic2
-rw-r--r--changes/geoip-august20143
-rw-r--r--changes/geoip-january20153
-rw-r--r--changes/geoip-july20143
-rw-r--r--changes/geoip-november20143
-rw-r--r--changes/geoip6-august20143
-rw-r--r--changes/geoip6-january20152
-rw-r--r--changes/geoip6-july20142
-rw-r--r--changes/geoip6-november20143
-rw-r--r--changes/test.h_msvc3
-rw-r--r--changes/ticket126886
-rw-r--r--changes/ticket126909
-rw-r--r--changes/ticket130365
-rw-r--r--changes/ticket141285
-rw-r--r--changes/ticket151763
-rw-r--r--changes/ticket152126
-rw-r--r--changes/ticket82437
-rw-r--r--configure.ac348
-rw-r--r--contrib/dist/tor.service.in19
-rw-r--r--contrib/win32build/tor-mingw.nsi.in2
-rw-r--r--doc/HACKING55
-rw-r--r--doc/TUNING86
-rw-r--r--doc/building-tor-msvc.txt122
-rw-r--r--doc/tor-resolve.1.txt5
-rw-r--r--doc/tor.1.txt255
-rw-r--r--m4/pkg.m4214
-rw-r--r--scripts/README5
-rw-r--r--scripts/coccinelle/calloc.cocci23
-rw-r--r--scripts/coccinelle/malloc_cast.cocci38
-rw-r--r--scripts/coccinelle/uncalloc.cocci13
-rwxr-xr-xscripts/codegen/gen_server_ciphers.py2
-rw-r--r--scripts/codegen/get_mozilla_ciphers.py2
-rw-r--r--scripts/codegen/makedesc.py218
-rwxr-xr-xscripts/codegen/run_trunnel.sh11
-rwxr-xr-xscripts/maint/checkSpace.pl33
-rwxr-xr-xscripts/maint/format_changelog.py298
-rwxr-xr-xscripts/maint/lintChanges.py55
-rwxr-xr-xscripts/maint/redox.py2
-rwxr-xr-xscripts/maint/sortChanges.py8
-rwxr-xr-xscripts/maint/updateCopyright.pl7
-rwxr-xr-xscripts/test/cov-diff4
-rw-r--r--src/common/address.c328
-rw-r--r--src/common/address.h73
-rw-r--r--src/common/aes.c2
-rw-r--r--src/common/aes.h2
-rw-r--r--src/common/backtrace.c3
-rw-r--r--src/common/backtrace.h2
-rw-r--r--src/common/compat.c516
-rw-r--r--src/common/compat.h112
-rw-r--r--src/common/compat_libevent.c25
-rw-r--r--src/common/compat_libevent.h10
-rw-r--r--src/common/compat_pthreads.c291
-rw-r--r--src/common/compat_threads.c306
-rw-r--r--src/common/compat_threads.h115
-rw-r--r--src/common/compat_winthreads.c196
-rw-r--r--src/common/container.c725
-rw-r--r--src/common/container.h50
-rw-r--r--src/common/crypto.c95
-rw-r--r--src/common/crypto.h10
-rw-r--r--src/common/crypto_curve25519.c178
-rw-r--r--src/common/crypto_curve25519.h18
-rw-r--r--src/common/crypto_ed25519.c353
-rw-r--r--src/common/crypto_ed25519.h113
-rw-r--r--src/common/crypto_format.c24
-rw-r--r--src/common/crypto_pwbox.c187
-rw-r--r--src/common/crypto_pwbox.h20
-rw-r--r--src/common/crypto_s2k.c460
-rw-r--r--src/common/crypto_s2k.h73
-rw-r--r--src/common/di_ops.c4
-rw-r--r--src/common/di_ops.h2
-rw-r--r--src/common/include.am37
-rw-r--r--src/common/log.c289
-rw-r--r--src/common/memarea.c2
-rw-r--r--src/common/memarea.h2
-rw-r--r--src/common/mempool.c628
-rw-r--r--src/common/mempool.h65
-rw-r--r--src/common/procmon.c2
-rw-r--r--src/common/procmon.h2
-rw-r--r--src/common/sandbox.c233
-rw-r--r--src/common/sandbox.h40
-rw-r--r--src/common/testsupport.h6
-rw-r--r--src/common/torgzip.c114
-rw-r--r--src/common/torgzip.h17
-rw-r--r--src/common/torint.h26
-rw-r--r--src/common/torlog.h13
-rw-r--r--src/common/tortls.c83
-rw-r--r--src/common/tortls.h2
-rw-r--r--src/common/util.c431
-rw-r--r--src/common/util.h22
-rw-r--r--src/common/util_process.c6
-rw-r--r--src/common/util_process.h2
-rw-r--r--src/common/workqueue.c495
-rw-r--r--src/common/workqueue.h48
-rw-r--r--src/config/include.am2
-rw-r--r--src/config/torrc.minimal.in192
-rw-r--r--src/config/torrc.minimal.in-staging193
-rw-r--r--src/config/torrc.sample.in17
-rw-r--r--src/ext/OpenBSD_malloc_Linux.c12
-rw-r--r--src/ext/README12
-rw-r--r--src/ext/csiphash.c18
-rw-r--r--src/ext/ed25519/ref10/Makefile41
-rw-r--r--src/ext/ed25519/ref10/README.tor23
-rw-r--r--src/ext/ed25519/ref10/api.h4
-rw-r--r--src/ext/ed25519/ref10/base.h1344
-rw-r--r--src/ext/ed25519/ref10/base.py65
-rw-r--r--src/ext/ed25519/ref10/base2.h40
-rw-r--r--src/ext/ed25519/ref10/base2.py60
-rw-r--r--src/ext/ed25519/ref10/blinding.c76
-rw-r--r--src/ext/ed25519/ref10/crypto_hash_sha512.h30
-rw-r--r--src/ext/ed25519/ref10/crypto_int32.h25
-rw-r--r--src/ext/ed25519/ref10/crypto_int64.h23
-rw-r--r--src/ext/ed25519/ref10/crypto_sign.h9
-rw-r--r--src/ext/ed25519/ref10/crypto_uint32.h3
-rw-r--r--src/ext/ed25519/ref10/crypto_uint64.h3
-rw-r--r--src/ext/ed25519/ref10/crypto_verify_32.h5
-rw-r--r--src/ext/ed25519/ref10/d.h1
-rw-r--r--src/ext/ed25519/ref10/d.py28
-rw-r--r--src/ext/ed25519/ref10/d2.h1
-rw-r--r--src/ext/ed25519/ref10/d2.py28
-rw-r--r--src/ext/ed25519/ref10/ed25519_ref10.h30
-rw-r--r--src/ext/ed25519/ref10/fe.h56
-rw-r--r--src/ext/ed25519/ref10/fe_0.c19
-rw-r--r--src/ext/ed25519/ref10/fe_1.c19
-rw-r--r--src/ext/ed25519/ref10/fe_add.c57
-rw-r--r--src/ext/ed25519/ref10/fe_cmov.c63
-rw-r--r--src/ext/ed25519/ref10/fe_copy.c29
-rw-r--r--src/ext/ed25519/ref10/fe_frombytes.c73
-rw-r--r--src/ext/ed25519/ref10/fe_invert.c14
-rw-r--r--src/ext/ed25519/ref10/fe_isnegative.c16
-rw-r--r--src/ext/ed25519/ref10/fe_isnonzero.c19
-rw-r--r--src/ext/ed25519/ref10/fe_mul.c253
-rw-r--r--src/ext/ed25519/ref10/fe_neg.c45
-rw-r--r--src/ext/ed25519/ref10/fe_pow22523.c13
-rw-r--r--src/ext/ed25519/ref10/fe_sq.c149
-rw-r--r--src/ext/ed25519/ref10/fe_sq2.c160
-rw-r--r--src/ext/ed25519/ref10/fe_sub.c57
-rw-r--r--src/ext/ed25519/ref10/fe_tobytes.c119
-rw-r--r--src/ext/ed25519/ref10/ge.h95
-rw-r--r--src/ext/ed25519/ref10/ge_add.c11
-rw-r--r--src/ext/ed25519/ref10/ge_add.h97
-rw-r--r--src/ext/ed25519/ref10/ge_add.q49
-rw-r--r--src/ext/ed25519/ref10/ge_double_scalarmult.c96
-rw-r--r--src/ext/ed25519/ref10/ge_frombytes.c50
-rw-r--r--src/ext/ed25519/ref10/ge_madd.c11
-rw-r--r--src/ext/ed25519/ref10/ge_madd.h88
-rw-r--r--src/ext/ed25519/ref10/ge_madd.q46
-rw-r--r--src/ext/ed25519/ref10/ge_msub.c11
-rw-r--r--src/ext/ed25519/ref10/ge_msub.h88
-rw-r--r--src/ext/ed25519/ref10/ge_msub.q46
-rw-r--r--src/ext/ed25519/ref10/ge_p1p1_to_p2.c12
-rw-r--r--src/ext/ed25519/ref10/ge_p1p1_to_p3.c13
-rw-r--r--src/ext/ed25519/ref10/ge_p2_0.c8
-rw-r--r--src/ext/ed25519/ref10/ge_p2_dbl.c11
-rw-r--r--src/ext/ed25519/ref10/ge_p2_dbl.h73
-rw-r--r--src/ext/ed25519/ref10/ge_p2_dbl.q41
-rw-r--r--src/ext/ed25519/ref10/ge_p3_0.c9
-rw-r--r--src/ext/ed25519/ref10/ge_p3_dbl.c12
-rw-r--r--src/ext/ed25519/ref10/ge_p3_to_cached.c17
-rw-r--r--src/ext/ed25519/ref10/ge_p3_to_p2.c12
-rw-r--r--src/ext/ed25519/ref10/ge_p3_tobytes.c14
-rw-r--r--src/ext/ed25519/ref10/ge_precomp_0.c8
-rw-r--r--src/ext/ed25519/ref10/ge_scalarmult_base.c109
-rw-r--r--src/ext/ed25519/ref10/ge_sub.c11
-rw-r--r--src/ext/ed25519/ref10/ge_sub.h97
-rw-r--r--src/ext/ed25519/ref10/ge_sub.q49
-rw-r--r--src/ext/ed25519/ref10/ge_tobytes.c14
-rw-r--r--src/ext/ed25519/ref10/keyconv.c37
-rw-r--r--src/ext/ed25519/ref10/keypair.c51
-rw-r--r--src/ext/ed25519/ref10/open.c42
-rw-r--r--src/ext/ed25519/ref10/pow22523.h161
-rw-r--r--src/ext/ed25519/ref10/pow22523.q61
-rw-r--r--src/ext/ed25519/ref10/pow225521.h161
-rw-r--r--src/ext/ed25519/ref10/pow225521.q61
-rwxr-xr-xsrc/ext/ed25519/ref10/q2h.sh4
-rw-r--r--src/ext/ed25519/ref10/randombytes.h4
-rw-r--r--src/ext/ed25519/ref10/sc.h15
-rw-r--r--src/ext/ed25519/ref10/sc_muladd.c368
-rw-r--r--src/ext/ed25519/ref10/sc_reduce.c275
-rw-r--r--src/ext/ed25519/ref10/sign.c29
-rw-r--r--src/ext/ed25519/ref10/sqrtm1.h1
-rw-r--r--src/ext/ed25519/ref10/sqrtm1.py28
-rw-r--r--src/ext/ht.h57
-rw-r--r--src/ext/include.am76
-rw-r--r--src/ext/tinytest.c2
-rw-r--r--src/ext/tinytest_demo.c16
-rw-r--r--src/ext/tor_queue.h23
-rw-r--r--src/ext/trunnel/trunnel-impl.h310
-rw-r--r--src/ext/trunnel/trunnel.c247
-rw-r--r--src/ext/trunnel/trunnel.h64
-rw-r--r--src/include.am2
-rw-r--r--src/or/Makefile.nmake1
-rw-r--r--src/or/addressmap.c80
-rw-r--r--src/or/addressmap.h9
-rw-r--r--src/or/buffers.c299
-rw-r--r--src/or/buffers.h11
-rw-r--r--src/or/channel.c614
-rw-r--r--src/or/channel.h124
-rw-r--r--src/or/channeltls.c167
-rw-r--r--src/or/channeltls.h4
-rw-r--r--src/or/circpathbias.c10
-rw-r--r--src/or/circpathbias.h2
-rw-r--r--src/or/circuitbuild.c173
-rw-r--r--src/or/circuitbuild.h10
-rw-r--r--src/or/circuitlist.c344
-rw-r--r--src/or/circuitlist.h9
-rw-r--r--src/or/circuitmux.c64
-rw-r--r--src/or/circuitmux.h14
-rw-r--r--src/or/circuitmux_ewma.c64
-rw-r--r--src/or/circuitmux_ewma.h2
-rw-r--r--src/or/circuitstats.c34
-rw-r--r--src/or/circuitstats.h2
-rw-r--r--src/or/circuituse.c230
-rw-r--r--src/or/circuituse.h2
-rw-r--r--src/or/command.c14
-rw-r--r--src/or/command.h2
-rw-r--r--src/or/config.c1117
-rw-r--r--src/or/config.h9
-rw-r--r--src/or/confparse.c2
-rw-r--r--src/or/confparse.h2
-rw-r--r--src/or/connection.c517
-rw-r--r--src/or/connection.h13
-rw-r--r--src/or/connection_edge.c538
-rw-r--r--src/or/connection_edge.h26
-rw-r--r--src/or/connection_or.c99
-rw-r--r--src/or/connection_or.h10
-rw-r--r--src/or/control.c189
-rw-r--r--src/or/control.h10
-rw-r--r--src/or/cpuworker.c778
-rw-r--r--src/or/cpuworker.h12
-rw-r--r--src/or/directory.c208
-rw-r--r--src/or/directory.h14
-rw-r--r--src/or/dirserv.c926
-rw-r--r--src/or/dirserv.h14
-rw-r--r--src/or/dirvote.c657
-rw-r--r--src/or/dirvote.h73
-rw-r--r--src/or/dns.c6
-rw-r--r--src/or/dns.h2
-rw-r--r--src/or/dnsserv.c22
-rw-r--r--src/or/dnsserv.h2
-rw-r--r--src/or/entrynodes.c365
-rw-r--r--src/or/entrynodes.h52
-rw-r--r--src/or/eventdns_tor.h2
-rw-r--r--src/or/ext_orport.c2
-rw-r--r--src/or/ext_orport.h2
-rw-r--r--src/or/fp_pair.c8
-rw-r--r--src/or/fp_pair.h2
-rw-r--r--src/or/geoip.c65
-rw-r--r--src/or/geoip.h11
-rw-r--r--src/or/hibernate.c53
-rw-r--r--src/or/hibernate.h3
-rw-r--r--src/or/include.am17
-rw-r--r--src/or/main.c498
-rw-r--r--src/or/main.h6
-rw-r--r--src/or/microdesc.c81
-rw-r--r--src/or/microdesc.h4
-rw-r--r--src/or/networkstatus.c89
-rw-r--r--src/or/networkstatus.h19
-rw-r--r--src/or/nodelist.c304
-rw-r--r--src/or/nodelist.h37
-rw-r--r--src/or/ntmain.c2
-rw-r--r--src/or/ntmain.h4
-rw-r--r--src/or/onion.c67
-rw-r--r--src/or/onion.h11
-rw-r--r--src/or/onion_fast.c12
-rw-r--r--src/or/onion_fast.h5
-rw-r--r--src/or/onion_ntor.c21
-rw-r--r--src/or/onion_ntor.h8
-rw-r--r--src/or/onion_tap.c12
-rw-r--r--src/or/onion_tap.h5
-rw-r--r--src/or/or.h374
-rw-r--r--src/or/policies.c162
-rw-r--r--src/or/policies.h21
-rw-r--r--src/or/reasons.c8
-rw-r--r--src/or/reasons.h2
-rw-r--r--src/or/relay.c141
-rw-r--r--src/or/relay.h12
-rw-r--r--src/or/rendclient.c59
-rw-r--r--src/or/rendclient.h2
-rw-r--r--src/or/rendcommon.c165
-rw-r--r--src/or/rendcommon.h7
-rw-r--r--src/or/rendmid.c13
-rw-r--r--src/or/rendmid.h2
-rw-r--r--src/or/rendservice.c503
-rw-r--r--src/or/rendservice.h8
-rw-r--r--src/or/rephist.c281
-rw-r--r--src/or/rephist.h13
-rw-r--r--src/or/replaycache.c2
-rw-r--r--src/or/replaycache.h2
-rw-r--r--src/or/router.c147
-rw-r--r--src/or/router.h6
-rw-r--r--src/or/routerlist.c919
-rw-r--r--src/or/routerlist.h33
-rw-r--r--src/or/routerparse.c278
-rw-r--r--src/or/routerparse.h28
-rw-r--r--src/or/routerset.c41
-rw-r--r--src/or/routerset.h42
-rw-r--r--src/or/scheduler.c711
-rw-r--r--src/or/scheduler.h50
-rw-r--r--src/or/statefile.c5
-rw-r--r--src/or/statefile.h2
-rw-r--r--src/or/status.c57
-rw-r--r--src/or/status.h2
-rw-r--r--src/or/tor_main.c2
-rw-r--r--src/or/transports.c131
-rw-r--r--src/or/transports.h20
-rw-r--r--src/test/Makefile.nmake11
-rw-r--r--src/test/bench.c79
-rwxr-xr-xsrc/test/bt_test.py2
-rw-r--r--src/test/ed25519_exts_ref.py234
-rw-r--r--src/test/ed25519_vectors.inc150
-rw-r--r--src/test/example_extrainfo.inc192
-rw-r--r--src/test/failing_routerdescs.inc668
-rw-r--r--src/test/fakechans.h26
-rw-r--r--src/test/include.am87
-rwxr-xr-xsrc/test/ntor_ref.py2
-rw-r--r--src/test/slow_ed25519.py115
-rw-r--r--src/test/test-child.c2
-rwxr-xr-xsrc/test/test-network.sh17
-rw-r--r--src/test/test.c699
-rw-r--r--src/test/test.h32
-rw-r--r--src/test/test_accounting.c76
-rw-r--r--src/test/test_addr.c547
-rw-r--r--src/test/test_address.c473
-rw-r--r--src/test/test_bt_cl.c9
-rw-r--r--src/test/test_buffers.c362
-rw-r--r--src/test/test_cell_formats.c785
-rw-r--r--src/test/test_cell_queue.c76
-rw-r--r--src/test/test_channel.c1673
-rw-r--r--src/test/test_channeltls.c333
-rw-r--r--src/test/test_checkdir.c143
-rw-r--r--src/test/test_circuitlist.c146
-rw-r--r--src/test/test_circuitmux.c24
-rwxr-xr-xsrc/test/test_cmdline_args.py45
-rw-r--r--src/test/test_config.c1022
-rw-r--r--src/test/test_containers.c631
-rw-r--r--src/test/test_controller_events.c54
-rw-r--r--src/test/test_crypto.c843
-rw-r--r--src/test/test_crypto_slow.c409
-rw-r--r--src/test/test_data.c2
-rw-r--r--src/test/test_descriptors.inc305
-rw-r--r--src/test/test_dir.c1811
-rw-r--r--src/test/test_entryconn.c769
-rw-r--r--src/test/test_entrynodes.c662
-rw-r--r--src/test/test_extorport.c193
-rw-r--r--src/test/test_guardfraction.c418
-rw-r--r--src/test/test_helpers.c86
-rw-r--r--src/test/test_helpers.h17
-rw-r--r--src/test/test_hs.c108
-rw-r--r--src/test/test_introduce.c78
-rw-r--r--src/test/test_logging.c38
-rw-r--r--src/test/test_microdesc.c500
-rw-r--r--src/test/test_nodelist.c10
-rw-r--r--src/test/test_ntor_cl.c8
-rw-r--r--src/test/test_oom.c96
-rw-r--r--src/test/test_options.c8
-rw-r--r--src/test/test_policy.c134
-rw-r--r--src/test/test_pt.c202
-rw-r--r--src/test/test_relay.c126
-rw-r--r--src/test/test_relaycell.c68
-rw-r--r--src/test/test_replay.c121
-rw-r--r--src/test/test_routerkeys.c18
-rw-r--r--src/test/test_routerlist.c103
-rw-r--r--src/test/test_routerset.c2122
-rw-r--r--src/test/test_scheduler.c763
-rw-r--r--src/test/test_slow.c29
-rw-r--r--src/test/test_socks.c393
-rw-r--r--src/test/test_status.c358
-rw-r--r--src/test/test_threads.c316
-rw-r--r--src/test/test_util.c3588
-rw-r--r--src/test/test_util_slow.c389
-rw-r--r--src/test/test_workqueue.c409
-rw-r--r--src/test/testing_common.c301
-rwxr-xr-xsrc/test/zero_length_keys.sh120
-rw-r--r--src/tools/tor-checkkey.c4
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-natpmp.c2
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-natpmp.h2
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-upnp.c2
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper-upnp.h2
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper.c2
-rw-r--r--src/tools/tor-fw-helper/tor-fw-helper.h2
-rw-r--r--src/tools/tor-gencert.c16
-rw-r--r--src/tools/tor-resolve.c31
-rw-r--r--src/trunnel/include.am29
-rw-r--r--src/trunnel/pwbox.c515
-rw-r--r--src/trunnel/pwbox.h173
-rw-r--r--src/trunnel/pwbox.trunnel14
-rw-r--r--src/trunnel/trunnel-local.h18
-rw-r--r--src/win32/orconfig.h14
465 files changed, 44599 insertions, 12761 deletions
diff --git a/.gitignore b/.gitignore
index 1a479903dc..0cdf2c4e61 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,6 +57,7 @@ cscope.*
/mkinstalldirs
/Tor*Bundle.dmg
/tor-*-win32.exe
+/coverage_html/
# /contrib/
/contrib/dist/tor.sh
@@ -135,6 +136,11 @@ cscope.*
/src/config/sample-server-torrc
/src/config/torrc
/src/config/torrc.sample
+/src/config/torrc.minimal
+
+# /src/ext/
+/src/ext/ed25519/ref10/libed25519_ref10.a
+/src/ext/ed25519/ref10/libed25519_ref10.lib
# /src/or/
/src/or/Makefile
@@ -154,13 +160,17 @@ cscope.*
/src/test/bench
/src/test/bench.exe
/src/test/test
+/src/test/test-slow
/src/test/test-bt-cl
/src/test/test-child
/src/test/test-ntor-cl
+/src/test/test_workqueue
/src/test/test.exe
+/src/test/test-slow.exe
/src/test/test-bt-cl.exe
/src/test/test-child.exe
/src/test/test-ntor-cl.exe
+/src/test/test_workqueue.exe
# /src/tools/
/src/tools/tor-checkkey
@@ -172,6 +182,10 @@ cscope.*
/src/tools/Makefile
/src/tools/Makefile.in
+# /src/trunnel/
+/src/trunnel/libor-trunnel-testing.a
+/src/trunnel/libor-trunnel.a
+
# /src/tools/tor-fw-helper/
/src/tools/tor-fw-helper/tor-fw-helper
/src/tools/tor-fw-helper/tor-fw-helper.exe
diff --git a/ChangeLog b/ChangeLog
index 4a2918490e..4d93e1987e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1386 @@
+Changes in version 0.2.6.4-?? - 2015-0?-??
+
+
+
+Changes in version 0.2.6.3-alpha - 2015-02-19
+ Tor 0.2.6.3-alpha is the third (and hopefully final) alpha release in
+ the 0.2.6.x series. It introduces support for more kinds of sockets,
+ makes it harder to accidentally run an exit, improves our
+ multithreading backend, incorporates several fixes for the
+ AutomapHostsOnResolve option, and fixes numerous other bugs besides.
+
+ If no major regressions or security holes are found in this version,
+ the next version will be a release candidate.
+
+ o Deprecated versions:
+ - Tor relays older than 0.2.4.18-rc are no longer allowed to
+ advertise themselves on the network. Closes ticket 13555.
+
+ o Major features (security, unix domain sockets):
+ - Allow SocksPort to be an AF_UNIX Unix Domain Socket. Now high risk
+ applications can reach Tor without having to create AF_INET or
+ AF_INET6 sockets, meaning they can completely disable their
+ ability to make non-Tor network connections. To create a socket of
+ this type, use "SocksPort unix:/path/to/socket". Implements
+ ticket 12585.
+ - Support mapping hidden service virtual ports to AF_UNIX sockets.
+ The syntax is "HiddenServicePort 80 unix:/path/to/socket".
+ Implements ticket 11485.
+
+ o Major features (changed defaults):
+ - Prevent relay operators from unintentionally running exits: When a
+ relay is configured as an exit node, we now warn the user unless
+ the "ExitRelay" option is set to 1. We warn even more loudly if
+ the relay is configured with the default exit policy, since this
+ can indicate accidental misconfiguration. Setting "ExitRelay 0"
+ stops Tor from running as an exit relay. Closes ticket 10067.
+
+ o Major features (directory system):
+ - When downloading server- or microdescriptors from a directory
+ server, we no longer launch multiple simultaneous requests to the
+ same server. This reduces load on the directory servers,
+ especially when directory guards are in use. Closes ticket 9969.
+ - When downloading server- or microdescriptors over a tunneled
+ connection, do not limit the length of our requests to what the
+ Squid proxy is willing to handle. Part of ticket 9969.
+ - Authorities can now vote on the correct digests and latest
+ versions for different software packages. This allows packages
+ that include Tor to use the Tor authority system as a way to get
+ notified of updates and their correct digests. Implements proposal
+ 227. Closes ticket 10395.
+
+ o Major features (performance):
+ - Make the CPU worker implementation more efficient by avoiding the
+ kernel and lengthening pipelines. The original implementation used
+ sockets to transfer data from the main thread to the workers, and
+ didn't allow any thread to be assigned more than a single piece of
+ work at once. The new implementation avoids communications
+ overhead by making requests in shared memory, avoiding kernel IO
+ where possible, and keeping more requests in flight at once.
+ Implements ticket 9682.
+
+ o Major features (relay):
+ - Raise the minimum acceptable configured bandwidth rate for bridges
+ to 50 KiB/sec and for relays to 75 KiB/sec. (The old values were
+ 20 KiB/sec.) Closes ticket 13822.
+
+ o Major bugfixes (exit node stability):
+ - Fix an assertion failure that could occur under high DNS load.
+ Fixes bug 14129; bugfix on Tor 0.0.7rc1. Found by "jowr";
+ diagnosed and fixed by "cypherpunks".
+
+ o Major bugfixes (mixed relay-client operation):
+ - When running as a relay and client at the same time (not
+ recommended), if we decide not to use a new guard because we want
+ to retry older guards, only close the locally-originating circuits
+ passing through that guard. Previously we would close all the
+ circuits through that guard. Fixes bug 9819; bugfix on
+ 0.2.1.1-alpha. Reported by "skruffy".
+
+ o Minor features (build):
+ - New --disable-system-torrc compile-time option to prevent Tor from
+ looking for the system-wide torrc or torrc-defaults files.
+ Resolves ticket 13037.
+
+ o Minor features (controller):
+ - Include SOCKS_USERNAME and SOCKS_PASSWORD values in controller
+ events so controllers can observe circuit isolation inputs. Closes
+ ticket 8405.
+ - ControlPort now supports the unix:/path/to/socket syntax as an
+ alternative to the ControlSocket option, for consistency with
+ SocksPort and HiddenServicePort. Closes ticket 14451.
+ - New "GETINFO bw-event-cache" to get information about recent
+ bandwidth events. Closes ticket 14128. Useful for controllers to
+ get recent bandwidth history after the fix for ticket 13988.
+
+ o Minor features (Denial of service resistance):
+ - Count the total number of bytes used storing hidden service
+ descriptors against the value of MaxMemInQueues. If we're low on
+ memory, and more than 20% of our memory is used holding hidden
+ service descriptors, free them until no more than 10% of our
+ memory holds hidden service descriptors. Free the least recently
+ fetched descriptors first. Resolves ticket 13806.
+ - When we have recently been under memory pressure (over 3/4 of
+ MaxMemInQueues is allocated), then allocate smaller zlib objects
+ for small requests. Closes ticket 11791.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 files to the January 7 2015 Maxmind
+ GeoLite2 Country database.
+
+ o Minor features (guard nodes):
+ - Reduce the time delay before saving guard status to disk from 10
+ minutes to 30 seconds (or from one hour to 10 minutes if
+ AvoidDiskWrites is set). Closes ticket 12485.
+
+ o Minor features (hidden service):
+ - Make Sybil attacks against hidden services harder by changing the
+ minimum time required to get the HSDir flag from 25 hours up to 96
+ hours. Addresses ticket 14149.
+ - New option "HiddenServiceAllowUnknownPorts" to allow hidden
+ services to disable the anti-scanning feature introduced in
+ 0.2.6.2-alpha. With this option not set, a connection to an
+ unlisted port closes the circuit. With this option set, only a
+ RELAY_DONE cell is sent. Closes ticket 14084.
+
+ o Minor features (interface):
+ - Implement "-f -" command-line option to read torrc configuration
+ from standard input, if you don't want to store the torrc file in
+ the file system. Implements feature 13865.
+
+ o Minor features (logging):
+ - Add a count of unique clients to the bridge heartbeat message.
+ Resolves ticket 6852.
+ - Suppress "router info incompatible with extra info" message when
+ reading extrainfo documents from cache. (This message got loud
+ around when we closed bug 9812 in 0.2.6.2-alpha.) Closes
+ ticket 13762.
+ - Elevate hidden service authorized-client message from DEBUG to
+ INFO. Closes ticket 14015.
+
+ o Minor features (stability):
+ - Add assertions in our hash-table iteration code to check for
+ corrupted values that could cause infinite loops. Closes
+ ticket 11737.
+
+ o Minor features (systemd):
+ - Various improvements and modernizations in systemd hardening
+ support. Closes ticket 13805. Patch from Craig Andrews.
+
+ o Minor features (testing networks):
+ - Drop the minimum RendPostPeriod on a testing network to 5 seconds,
+ and the default on a testing network to 2 minutes. Drop the
+ MIN_REND_INITIAL_POST_DELAY on a testing network to 5 seconds, but
+ keep the default on a testing network at 30 seconds. This reduces
+ HS bootstrap time to around 25 seconds. Also, change the default
+ time in test-network.sh to match. Closes ticket 13401. Patch
+ by "teor".
+ - Create TestingDirAuthVoteHSDir to correspond to
+ TestingDirAuthVoteExit/Guard. Ensures that authorities vote the
+ HSDir flag for the listed relays regardless of uptime or ORPort
+ connectivity. Respects the value of VoteOnHidServDirectoriesV2.
+ Partial implementation for ticket 14067. Patch by "teor".
+
+ o Minor features (tor2web mode):
+ - Introduce the config option Tor2webRendezvousPoints, which allows
+ clients in Tor2webMode to select a specific Rendezvous Point to be
+ used in HS circuits. This might allow better performance for
+ Tor2Web nodes. Implements ticket 12844.
+
+ o Minor bugfixes (client DNS):
+ - Report the correct cached DNS expiration times on SOCKS port or in
+ DNS replies. Previously, we would report everything as "never
+ expires." Fixes bug 14193; bugfix on 0.2.3.17-beta.
+ - Avoid a small memory leak when we find a cached answer for a
+ reverse DNS lookup in a client-side DNS cache. (Remember, client-
+ side DNS caching is off by default, and is not recommended.) Fixes
+ bug 14259; bugfix on 0.2.0.1-alpha.
+
+ o Minor bugfixes (client, automapping):
+ - Avoid crashing on torrc lines for VirtualAddrNetworkIPv[4|6] when
+ no value follows the option. Fixes bug 14142; bugfix on
+ 0.2.4.7-alpha. Patch by "teor".
+ - Fix a memory leak when using AutomapHostsOnResolve. Fixes bug
+ 14195; bugfix on 0.1.0.1-rc.
+ - Prevent changes to other options from removing the wildcard value
+ "." from "AutomapHostsSuffixes". Fixes bug 12509; bugfix
+ on 0.2.0.1-alpha.
+ - Allow MapAddress and AutomapHostsOnResolve to work together when
+ an address is mapped into another address type (like .onion) that
+ must be automapped at resolve time. Fixes bug 7555; bugfix
+ on 0.2.0.1-alpha.
+
+ o Minor bugfixes (client, bridges):
+ - When we are using bridges and we had a network connectivity
+ problem, only retry connecting to our currently configured
+ bridges, not all bridges we know about and remember using. Fixes
+ bug 14216; bugfix on 0.2.2.17-alpha.
+
+ o Minor bugfixes (client, IPv6):
+ - Reject socks requests to literal IPv6 addresses when IPv6Traffic
+ flag is not set; and not because the NoIPv4Traffic flag was set.
+ Previously we'd looked at the NoIPv4Traffic flag for both types of
+ literal addresses. Fixes bug 14280; bugfix on 0.2.4.7-alpha.
+
+ o Minor bugfixes (compilation):
+ - The address of an array in the middle of a structure will always
+ be non-NULL. clang recognises this and complains. Disable the
+ tautologous and redundant check to silence this warning. Fixes bug
+ 14001; bugfix on 0.2.1.2-alpha.
+ - Avoid warnings when building with systemd 209 or later. Fixes bug
+ 14072; bugfix on 0.2.6.2-alpha. Patch from "h.venev".
+ - Compile correctly with (unreleased) OpenSSL 1.1.0 headers.
+ Addresses ticket 14188.
+ - Build without warnings with the stock OpenSSL srtp.h header, which
+ has a duplicate declaration of SSL_get_selected_srtp_profile().
+ Fixes bug 14220; this is OpenSSL's bug, not ours.
+ - Do not compile any code related to Tor2Web mode when Tor2Web mode
+ is not enabled at compile time. Previously, this code was included
+ in a disabled state. See discussion on ticket 12844.
+ - Remove the --disable-threads configure option again. It was
+ accidentally partially reintroduced in 29ac883606d6d. Fixes bug
+ 14819; bugfix on 0.2.6.2-alpha.
+
+ o Minor bugfixes (controller):
+ - Report "down" in response to the "GETINFO entry-guards" command
+ when relays are down with an unreachable_since value. Previously,
+ we would report "up". Fixes bug 14184; bugfix on 0.1.2.2-alpha.
+ - Avoid crashing on a malformed EXTENDCIRCUIT command. Fixes bug
+ 14116; bugfix on 0.2.2.9-alpha.
+ - Add a code for the END_CIRC_REASON_IP_NOW_REDUNDANT circuit close
+ reason. Fixes bug 14207; bugfix on 0.2.6.2-alpha.
+
+ o Minor bugfixes (directory authority):
+ - Allow directory authorities to fetch more data from one another if
+ they find themselves missing lots of votes. Previously, they had
+ been bumping against the 10 MB queued data limit. Fixes bug 14261;
+ bugfix on 0.1.2.5-alpha.
+ - Do not attempt to download extrainfo documents which we will be
+ unable to validate with a matching server descriptor. Fixes bug
+ 13762; bugfix on 0.2.0.1-alpha.
+ - Fix a bug that was truncating AUTHDIR_NEWDESC events sent to the
+ control port. Fixes bug 14953; bugfix on 0.2.0.1-alpha.
+ - Enlarge the buffer to read bwauth generated files to avoid an
+ issue when parsing the file in dirserv_read_measured_bandwidths().
+ Fixes bug 14125; bugfix on 0.2.2.1-alpha.
+
+ o Minor bugfixes (file handling):
+ - Stop failing when key files are zero-length. Instead, generate new
+ keys, and overwrite the empty key files. Fixes bug 13111; bugfix
+ on all versions of Tor. Patch by "teor".
+ - Stop generating a fresh .old RSA onion key file when the .old file
+ is missing. Fixes part of 13111; bugfix on 0.0.6rc1.
+ - Avoid overwriting .old key files with empty key files.
+ - Skip loading zero-length extrainfo store, router store, stats,
+ state, and key files.
+ - Avoid crashing when trying to reload a torrc specified as a
+ relative path with RunAsDaemon turned on. Fixes bug 13397; bugfix
+ on 0.2.3.11-alpha.
+
+ o Minor bugfixes (hidden services):
+ - Close the introduction circuit when we have no more usable intro
+ points, instead of waiting for it to time out. This also ensures
+ that no follow-up HS descriptor fetch is triggered when the
+ circuit eventually times out. Fixes bug 14224; bugfix on 0.0.6.
+ - When fetching a hidden service descriptor for a down service that
+ was recently up, do not keep refetching until we try the same
+ replica twice in a row. Fixes bug 14219; bugfix on 0.2.0.10-alpha.
+ - Successfully launch Tor with a nonexistent hidden service
+ directory. Our fix for bug 13942 didn't catch this case. Fixes bug
+ 14106; bugfix on 0.2.6.2-alpha.
+
+ o Minor bugfixes (logging):
+ - Avoid crashing when there are more log domains than entries in
+ domain_list. Bugfix on 0.2.3.1-alpha.
+ - Add a string representation for LD_SCHED. Fixes bug 14740; bugfix
+ on 0.2.6.1-alpha.
+ - Don't log messages to stdout twice when starting up. Fixes bug
+ 13993; bugfix on 0.2.6.1-alpha.
+
+ o Minor bugfixes (parsing):
+ - Stop accepting milliseconds (or other junk) at the end of
+ descriptor publication times. Fixes bug 9286; bugfix on 0.0.2pre25.
+ - Support two-number and three-number version numbers correctly, in
+ case we change the Tor versioning system in the future. Fixes bug
+ 13661; bugfix on 0.0.8pre1.
+
+ o Minor bugfixes (path counting):
+ - When deciding whether the consensus lists any exit nodes, count
+ the number listed in the consensus, not the number we have
+ descriptors for. Fixes part of bug 14918; bugfix on 0.2.6.2-alpha.
+ - When deciding whether we have any exit nodes, only examine
+ ExitNodes when the ExitNodes option is actually set. Fixes part of
+ bug 14918; bugfix on 0.2.6.2-alpha.
+ - Get rid of redundant and possibly scary warnings that we are
+ missing directory information while we bootstrap. Fixes part of
+ bug 14918; bugfix on 0.2.6.2-alpha.
+
+ o Minor bugfixes (portability):
+ - Fix the ioctl()-based network interface lookup code so that it
+ will work on systems that have variable-length struct ifreq, for
+ example Mac OS X.
+ - Fix scheduler compilation on targets where char is unsigned. Fixes
+ bug 14764; bugfix on 0.2.6.2-alpha. Reported by Christian Kujau.
+
+ o Minor bugfixes (sandbox):
+ - Allow glibc fatal errors to be sent to stderr before Tor exits.
+ Previously, glibc would try to write them to /dev/tty, and the
+ sandbox would trap the call and make Tor exit prematurely. Fixes
+ bug 14759; bugfix on 0.2.5.1-alpha.
+
+ o Minor bugfixes (shutdown):
+ - When shutting down, always call event_del() on lingering read or
+ write events before freeing them. Otherwise, we risk double-frees
+ or read-after-frees in event_base_free(). Fixes bug 12985; bugfix
+ on 0.1.0.2-rc.
+
+ o Minor bugfixes (small memory leaks):
+ - Avoid leaking memory when using IPv6 virtual address mappings.
+ Fixes bug 14123; bugfix on 0.2.4.7-alpha. Patch by Tom van
+ der Woerdt.
+
+ o Minor bugfixes (statistics):
+ - Increase period over which bandwidth observations are aggregated
+ from 15 minutes to 4 hours. Fixes bug 13988; bugfix on 0.0.8pre1.
+
+ o Minor bugfixes (systemd support):
+ - Fix detection and operation of systemd watchdog. Fixes part of bug
+ 14141; bugfix on 0.2.6.2-alpha. Patch from Tomasz Torcz.
+ - Run correctly under systemd with the RunAsDaemon option set. Fixes
+ part of bug 14141; bugfix on 0.2.5.7-rc. Patch from Tomasz Torcz.
+ - Inform the systemd supervisor about more changes in the Tor
+ process status. Implements part of ticket 14141. Patch from
+ Tomasz Torcz.
+ - Cause the "--disable-systemd" option to actually disable systemd
+ support. Fixes bug 14350; bugfix on 0.2.6.2-alpha. Patch
+ from "blueness".
+
+ o Minor bugfixes (TLS):
+ - Check more thoroughly throughout the TLS code for possible
+ unlogged TLS errors. Possible diagnostic or fix for bug 13319.
+
+ o Minor bugfixes (transparent proxy):
+ - Use getsockname, not getsockopt, to retrieve the address for a
+ TPROXY-redirected connection. Fixes bug 13796; bugfix
+ on 0.2.5.2-alpha.
+
+ o Code simplification and refactoring:
+ - Move fields related to isolating and configuring client ports into
+ a shared structure. Previously, they were duplicated across
+ port_cfg_t, listener_connection_t, and edge_connection_t. Failure
+ to copy them correctly had been the cause of at least one bug in
+ the past. Closes ticket 8546.
+ - Refactor the get_interface_addresses_raw() doom-function into
+ multiple smaller and simpler subfunctions. Cover the resulting
+ subfunctions with unit-tests. Fixes a significant portion of
+ issue 12376.
+ - Remove workaround in dirserv_thinks_router_is_hs_dir() that was
+ only for version <= 0.2.2.24 which is now deprecated. Closes
+ ticket 14202.
+ - Remove a test for a long-defunct broken version-one
+ directory server.
+
+ o Documentation:
+ - Adding section on OpenBSD to our TUNING document. Thanks to mmcc
+ for writing the OpenBSD-specific tips. Resolves ticket 13702.
+ - Make the tor-resolve documentation match its help string and its
+ options. Resolves part of ticket 14325.
+ - Log a more useful error message from tor-resolve when failing to
+ look up a hidden service address. Resolves part of ticket 14325.
+
+ o Downgraded warnings:
+ - Don't warn when we've attempted to contact a relay using the wrong
+ ntor onion key. Closes ticket 9635.
+
+ o Removed features:
+ - To avoid confusion with the "ExitRelay" option, "ExitNode" is no
+ longer silently accepted as an alias for "ExitNodes".
+ - The --enable-mempool and --enable-buf-freelists options, which
+ were originally created to work around bad malloc implementations,
+ no longer exist. They were off-by-default in 0.2.5. Closes
+ ticket 14848.
+
+ o Testing:
+ - Make the checkdir/perms test complete successfully even if the
+ global umask is not 022. Fixes bug 14215; bugfix on 0.2.6.2-alpha.
+ - Test that tor does not fail when key files are zero-length. Check
+ that tor generates new keys, and overwrites the empty key files.
+ - Test that tor generates new keys when keys are missing
+ (existing behavior).
+ - Test that tor does not overwrite key files that already contain
+ data (existing behavior). Tests bug 13111. Patch by "teor".
+ - New "make test-stem" target to run stem integration tests.
+ Requires that the "STEM_SOURCE_DIR" environment variable be set.
+ Closes ticket 14107.
+ - Make the test_cmdline_args.py script work correctly on Windows.
+ Patch from Gisle Vanem.
+ - Move the slower unit tests into a new "./src/test/test-slow"
+ binary that can be run independently of the other tests. Closes
+ ticket 13243.
+ - Avoid undefined behavior when sampling huge values from the
+ Laplace distribution. This made unittests fail on Raspberry Pi.
+ Bug found by Device. Fixes bug 14090; bugfix on 0.2.6.2-alpha.
+
+
+Changes in version 0.2.6.2-alpha - 2014-12-31
+ Tor 0.2.6.2-alpha is the second alpha release in the 0.2.6.x series.
+ It introduces a major new backend for deciding when to send cells on
+ channels, which should lead down the road to big performance
+ increases. It contains security and statistics features for better
+ work on hidden services, and numerous bugfixes.
+
+ This release contains many new unit tests, along with major
+ performance improvements for running testing networks using Chutney.
+ Thanks to a series of patches contributed by "teor", testing networks
+ should now bootstrap in seconds, rather than minutes.
+
+ o Major features (relay, infrastructure):
+ - Complete revision of the code that relays use to decide which cell
+ to send next. Formerly, we selected the best circuit to write on
+ each channel, but we didn't select among channels in any
+ sophisticated way. Now, we choose the best circuits globally from
+ among those whose channels are ready to deliver traffic.
+
+ This patch implements a new inter-cmux comparison API, a global
+ high/low watermark mechanism and a global scheduler loop for
+ transmission prioritization across all channels as well as among
+ circuits on one channel. This schedule is currently tuned to
+ (tolerantly) avoid making changes in network performance, but it
+ should form the basis for major circuit performance increases in
+ the future. Code by Andrea; tuning by Rob Jansen; implements
+ ticket 9262.
+
+ o Major features (hidden services):
+ - Make HS port scanning more difficult by immediately closing the
+ circuit when a user attempts to connect to a nonexistent port.
+ Closes ticket 13667.
+ - Add a HiddenServiceStatistics option that allows Tor relays to
+ gather and publish statistics about the overall size and volume of
+ hidden service usage. Specifically, when this option is turned on,
+ an HSDir will publish an approximate number of hidden services
+ that have published descriptors to it the past 24 hours. Also, if
+ a relay has acted as a hidden service rendezvous point, it will
+ publish the approximate amount of rendezvous cells it has relayed
+ the past 24 hours. The statistics themselves are obfuscated so
+ that the exact values cannot be derived. For more details see
+ proposal 238, "Better hidden service stats from Tor relays". This
+ feature is currently disabled by default. Implements feature 13192.
+
+ o Major bugfixes (client, automap):
+ - Repair automapping with IPv6 addresses. This automapping should
+ have worked previously, but one piece of debugging code that we
+ inserted to detect a regression actually caused the regression to
+ manifest itself again. Fixes bug 13811 and bug 12831; bugfix on
+ 0.2.4.7-alpha. Diagnosed and fixed by Francisco Blas
+ Izquierdo Riera.
+
+ o Major bugfixes (hidden services):
+ - When closing an introduction circuit that was opened in parallel
+ with others, don't mark the introduction point as unreachable.
+ Previously, the first successful connection to an introduction
+ point would make the other introduction points get marked as
+ having timed out. Fixes bug 13698; bugfix on 0.0.6rc2.
+
+ o Directory authority changes:
+ - Remove turtles as a directory authority.
+ - Add longclaw as a new (v3) directory authority. This implements
+ ticket 13296. This keeps the directory authority count at 9.
+
+ o Major removed features:
+ - Tor clients no longer support connecting to hidden services
+ running on Tor 0.2.2.x and earlier; the Support022HiddenServices
+ option has been removed. (There shouldn't be any hidden services
+ running these versions on the network.) Closes ticket 7803.
+
+ o Minor features (client):
+ - Validate hostnames in SOCKS5 requests more strictly. If SafeSocks
+ is enabled, reject requests with IP addresses as hostnames.
+ Resolves ticket 13315.
+
+ o Minor features (controller):
+ - Add a "SIGNAL HEARTBEAT" controller command that tells Tor to
+ write an unscheduled heartbeat message to the log. Implements
+ feature 9503.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 15 2014 Maxmind GeoLite2
+ Country database.
+
+ o Minor features (hidden services):
+ - When re-enabling the network, don't try to build introduction
+ circuits until we have successfully built a circuit. This makes
+ hidden services come up faster when the network is re-enabled.
+ Patch from "akwizgran". Closes ticket 13447.
+ - When we fail to retrieve a hidden service descriptor, send the
+ controller an "HS_DESC FAILED" controller event. Implements
+ feature 13212.
+ - New HiddenServiceDirGroupReadable option to cause hidden service
+ directories and hostname files to be created group-readable. Patch
+ from "anon", David Stainton, and "meejah". Closes ticket 11291.
+
+ o Minor features (systemd):
+ - Where supported, when running with systemd, report successful
+ startup to systemd. Part of ticket 11016. Patch by Michael Scherer.
+ - When running with systemd, support systemd watchdog messages. Part
+ of ticket 11016. Patch by Michael Scherer.
+
+ o Minor features (transparent proxy):
+ - Update the transparent proxy option checks to allow for both ipfw
+ and pf on OS X. Closes ticket 14002.
+ - Use the correct option when using IPv6 with transparent proxy
+ support on Linux. Resolves 13808. Patch by Francisco Blas
+ Izquierdo Riera.
+
+ o Minor bugfixes (preventative security, C safety):
+ - When reading a hexadecimal, base-32, or base-64 encoded value from
+ a string, always overwrite the whole output buffer. This prevents
+ some bugs where we would look at (but fortunately, not reveal)
+ uninitialized memory on the stack. Fixes bug 14013; bugfix on all
+ versions of Tor.
+ - Clear all memory targetted by tor_addr_{to,from}_sockaddr(), not
+ just the part that's used. This makes it harder for data leak bugs
+ to occur in the event of other programming failures. Resolves
+ ticket 14041.
+
+ o Minor bugfixes (client, microdescriptors):
+ - Use a full 256 bits of the SHA256 digest of a microdescriptor when
+ computing which microdescriptors to download. This keeps us from
+ erroneous download behavior if two microdescriptor digests ever
+ have the same first 160 bits. Fixes part of bug 13399; bugfix
+ on 0.2.3.1-alpha.
+ - Reset a router's status if its microdescriptor digest changes,
+ even if the first 160 bits remain the same. Fixes part of bug
+ 13399; bugfix on 0.2.3.1-alpha.
+
+ o Minor bugfixes (compilation):
+ - Silence clang warnings under --enable-expensive-hardening,
+ including implicit truncation of 64 bit values to 32 bit, const
+ char assignment to self, tautological compare, and additional
+ parentheses around equality tests. Fixes bug 13577; bugfix
+ on 0.2.5.4-alpha.
+ - Fix a clang warning about checking whether an address in the
+ middle of a structure is NULL. Fixes bug 14001; bugfix
+ on 0.2.1.2-alpha.
+
+ o Minor bugfixes (hidden services):
+ - Correctly send a controller event when we find that a rendezvous
+ circuit has finished. Fixes bug 13936; bugfix on 0.1.1.5-alpha.
+ - Pre-check directory permissions for new hidden-services to avoid
+ at least one case of "Bug: Acting on config options left us in a
+ broken state. Dying." Fixes bug 13942; bugfix on 0.0.6pre1.
+ - When adding a new hidden service (for example, via SETCONF), Tor
+ no longer congratulates the user for running a relay. Fixes bug
+ 13941; bugfix on 0.2.6.1-alpha.
+ - When fetching hidden service descriptors, we now check not only
+ for whether we got the hidden service we had in mind, but also
+ whether we got the particular descriptors we wanted. This prevents
+ a class of inefficient but annoying DoS attacks by hidden service
+ directories. Fixes bug 13214; bugfix on 0.2.1.6-alpha. Reported
+ by "special".
+
+ o Minor bugfixes (Linux seccomp2 sandbox):
+ - Make transparent proxy support work along with the seccomp2
+ sandbox. Fixes part of bug 13808; bugfix on 0.2.5.1-alpha. Patch
+ by Francisco Blas Izquierdo Riera.
+ - Fix a memory leak in tor-resolve when running with the sandbox
+ enabled. Fixes bug 14050; bugfix on 0.2.5.9-rc.
+
+ o Minor bugfixes (logging):
+ - Downgrade warnings about RSA signature failures to info log level.
+ Emit a warning when an extra info document is found incompatible
+ with a corresponding router descriptor. Fixes bug 9812; bugfix
+ on 0.0.6rc3.
+ - Make connection_ap_handshake_attach_circuit() log the circuit ID
+ correctly. Fixes bug 13701; bugfix on 0.0.6.
+
+ o Minor bugfixes (misc):
+ - Stop allowing invalid address patterns like "*/24" that contain
+ both a wildcard address and a bit prefix length. This affects all
+ our address-range parsing code. Fixes bug 7484; bugfix
+ on 0.0.2pre14.
+
+ o Minor bugfixes (testing networks, fast startup):
+ - Allow Tor to build circuits using a consensus with no exits. If
+ the consensus has no exits (typical of a bootstrapping test
+ network), allow Tor to build circuits once enough descriptors have
+ been downloaded. This assists in bootstrapping a testing Tor
+ network. Fixes bug 13718; bugfix on 0.2.4.10-alpha. Patch
+ by "teor".
+ - When V3AuthVotingInterval is low, give a lower If-Modified-Since
+ header to directory servers. This allows us to obtain consensuses
+ promptly when the consensus interval is very short. This assists
+ in bootstrapping a testing Tor network. Fixes parts of bugs 13718
+ and 13963; bugfix on 0.2.0.3-alpha. Patch by "teor".
+ - Stop assuming that private addresses are local when checking
+ reachability in a TestingTorNetwork. Instead, when testing, assume
+ all OR connections are remote. (This is necessary due to many test
+ scenarios running all relays on localhost.) This assists in
+ bootstrapping a testing Tor network. Fixes bug 13924; bugfix on
+ 0.1.0.1-rc. Patch by "teor".
+ - Avoid building exit circuits from a consensus with no exits. Now
+ thanks to our fix for 13718, we accept a no-exit network as not
+ wholly lost, but we need to remember not to try to build exit
+ circuits on it. Closes ticket 13814; patch by "teor".
+ - Stop requiring exits to have non-zero bandwithcapacity in a
+ TestingTorNetwork. Instead, when TestingMinExitFlagThreshold is 0,
+ ignore exit bandwidthcapacity. This assists in bootstrapping a
+ testing Tor network. Fixes parts of bugs 13718 and 13839; bugfix
+ on 0.2.0.3-alpha. Patch by "teor".
+ - Add "internal" to some bootstrap statuses when no exits are
+ available. If the consensus does not contain Exits, Tor will only
+ build internal circuits. In this case, relevant statuses will
+ contain the word "internal" as indicated in the Tor control-
+ spec.txt. When bootstrap completes, Tor will be ready to build
+ internal circuits. If a future consensus contains Exits, exit
+ circuits may become available. Fixes part of bug 13718; bugfix on
+ 0.2.4.10-alpha. Patch by "teor".
+ - Decrease minimum consensus interval to 10 seconds when
+ TestingTorNetwork is set, or 5 seconds for the first consensus.
+ Fix assumptions throughout the code that assume larger intervals.
+ Fixes bugs 13718 and 13823; bugfix on 0.2.0.3-alpha. Patch
+ by "teor".
+ - Avoid excluding guards from path building in minimal test
+ networks, when we're in a test network and excluding guards would
+ exclude all relays. This typically occurs in incredibly small tor
+ networks, and those using "TestingAuthVoteGuard *". Fixes part of
+ bug 13718; bugfix on 0.1.1.11-alpha. Patch by "teor".
+
+ o Code simplification and refactoring:
+ - Stop using can_complete_circuits as a global variable; access it
+ with a function instead.
+ - Avoid using operators directly as macro arguments: this lets us
+ apply coccinelle transformations to our codebase more directly.
+ Closes ticket 13172.
+ - Combine the functions used to parse ClientTransportPlugin and
+ ServerTransportPlugin into a single function. Closes ticket 6456.
+ - Add inline functions and convenience macros for inspecting channel
+ state. Refactor the code to use convenience macros instead of
+ checking channel state directly. Fixes issue 7356.
+ - Document all members of was_router_added_t and rename
+ ROUTER_WAS_NOT_NEW to ROUTER_IS_ALREADY_KNOWN to make it less
+ confusable with ROUTER_WAS_TOO_OLD. Fixes issue 13644.
+ - In connection_exit_begin_conn(), use END_CIRC_REASON_TORPROTOCOL
+ constant instead of hardcoded value. Fixes issue 13840.
+ - Refactor our generic strmap and digestmap types into a single
+ implementation, so that we can add a new digest256map
+ type trivially.
+
+ o Documentation:
+ - Document the bridge-authority-only 'networkstatus-bridges' file.
+ Closes ticket 13713; patch from "tom".
+ - Fix typo in PredictedPortsRelevanceTime option description in
+ manpage. Resolves issue 13707.
+ - Stop suggesting that users specify relays by nickname: it isn't a
+ good idea. Also, properly cross-reference how to specify relays in
+ all parts of manual documenting options that take a list of
+ relays. Closes ticket 13381.
+ - Clarify the HiddenServiceDir option description in manpage to make
+ it clear that relative paths are taken with respect to the current
+ working directory. Also clarify that this behavior is not
+ guaranteed to remain indefinitely. Fixes issue 13913.
+
+ o Testing:
+ - New tests for many parts of channel, relay, and circuitmux
+ functionality. Code by Andrea; part of 9262.
+ - New tests for parse_transport_line(). Part of ticket 6456.
+ - In the unit tests, use chgrp() to change the group of the unit
+ test temporary directory to the current user, so that the sticky
+ bit doesn't interfere with tests that check directory groups.
+ Closes 13678.
+ - Add unit tests for resolve_my_addr(). Part of ticket 12376; patch
+ by 'rl1987'.
+
+
+Changes in version 0.2.6.1-alpha - 2014-10-30
+ Tor 0.2.6.1-alpha is the first release in the Tor 0.2.6.x series. It
+ includes numerous code cleanups and new tests, and fixes a large
+ number of annoying bugs. Out-of-memory conditions are handled better
+ than in 0.2.5, pluggable transports have improved proxy support, and
+ clients now use optimistic data for contacting hidden services. Also,
+ we are now more robust to changes in what we consider a parseable
+ directory object, so that tightening restrictions does not have a risk
+ of introducing infinite download loops.
+
+ This is the first alpha release in a new series, so expect there to be
+ bugs. Users who would rather test out a more stable branch should stay
+ with 0.2.5.x for now.
+
+ o New compiler and system requirements:
+ - Tor 0.2.6.x requires that your compiler support more of the C99
+ language standard than before. The 'configure' script now detects
+ whether your compiler supports C99 mid-block declarations and
+ designated initializers. If it does not, Tor will not compile.
+
+ We may revisit this requirement if it turns out that a significant
+ number of people need to build Tor with compilers that don't
+ bother implementing a 15-year-old standard. Closes ticket 13233.
+ - Tor no longer supports systems without threading support. When we
+ began working on Tor, there were several systems that didn't have
+ threads, or where the thread support wasn't able to run the
+ threads of a single process on multiple CPUs. That no longer
+ holds: every system where Tor needs to run well now has threading
+ support. Resolves ticket 12439.
+
+ o Removed platform support:
+ - We no longer include special code to build on Windows CE; as far
+ as we know, nobody has used Tor on Windows CE in a very long time.
+ Closes ticket 11446.
+
+ o Major features (bridges):
+ - Expose the outgoing upstream HTTP/SOCKS proxy to pluggable
+ transports if they are configured via the "TOR_PT_PROXY"
+ environment variable. Implements proposal 232. Resolves
+ ticket 8402.
+
+ o Major features (client performance, hidden services):
+ - Allow clients to use optimistic data when connecting to a hidden
+ service, which should remove a round-trip from hidden service
+ initialization. See proposal 181 for details. Implements
+ ticket 13211.
+
+ o Major features (directory system):
+ - Upon receiving an unparseable directory object, if its digest
+ matches what we expected, then don't try to download it again.
+ Previously, when we got a descriptor we didn't like, we would keep
+ trying to download it over and over. Closes ticket 11243.
+
+ o Major features (sample torrc):
+ - Add a new, infrequently-changed "torrc.minimal". This file is
+ similar to torrc.sample, but it will change as infrequently as
+ possible, for the benefit of users whose systems prompt them for
+ intervention whenever a default configuration file is changed.
+ Making this change allows us to update torrc.sample to be a more
+ generally useful "sample torrc".
+
+ o Major bugfixes (directory authorities):
+ - Do not assign the HSDir flag to relays if they are not Valid, or
+ currently hibernating. Fixes 12573; bugfix on 0.2.0.10-alpha.
+
+ o Major bugfixes (directory bandwidth performance):
+ - Don't flush the zlib buffer aggressively when compressing
+ directory information for clients. This should save about 7% of
+ the bandwidth currently used for compressed descriptors and
+ microdescriptors. Fixes bug 11787; bugfix on 0.1.1.23.
+
+ o Minor features (security, memory wiping):
+ - Ensure we securely wipe keys from memory after
+ crypto_digest_get_digest and init_curve25519_keypair_from_file
+ have finished using them. Resolves ticket 13477.
+
+ o Minor features (security, out-of-memory handling):
+ - When handling an out-of-memory condition, allocate less memory for
+ temporary data structures. Fixes issue 10115.
+ - When handling an out-of-memory condition, consider more types of
+ buffers, including those on directory connections, and zlib
+ buffers. Resolves ticket 11792.
+
+ o Minor features:
+ - When identity keypair is generated for first time, log a
+ congratulatory message that links to the new relay lifecycle
+ document. Implements feature 10427.
+
+ o Minor features (client):
+ - Clients are now willing to send optimistic data (before they
+ receive a 'connected' cell) to relays of any version. (Relays
+ without support for optimistic data are no longer supported on the
+ Tor network.) Resolves ticket 13153.
+
+ o Minor features (directory authorities):
+ - Don't list relays with a bandwidth estimate of 0 in the consensus.
+ Implements a feature proposed during discussion of bug 13000.
+ - In tor-gencert, report an error if the user provides the same
+ argument more than once.
+ - If a directory authority can't find a best consensus method in the
+ votes that it holds, it now falls back to its favorite consensus
+ method. Previously, it fell back to method 1. Neither of these is
+ likely to get enough signatures, but "fall back to favorite"
+ doesn't require us to maintain support an obsolete consensus
+ method. Implements part of proposal 215.
+
+ o Minor features (logging):
+ - On Unix-like systems, you can now use named pipes as the target of
+ the Log option, and other options that try to append to files.
+ Closes ticket 12061. Patch from "carlo von lynX".
+ - When opening a log file at startup, send it every log message that
+ we generated between startup and opening it. Previously, log
+ messages that were generated before opening the log file were only
+ logged to stdout. Closes ticket 6938.
+ - Add a TruncateLogFile option to overwrite logs instead of
+ appending to them. Closes ticket 5583.
+
+ o Minor features (portability, Solaris):
+ - Threads are no longer disabled by default on Solaris; we believe
+ that the versions of Solaris with broken threading support are all
+ obsolete by now. Resolves ticket 9495.
+
+ o Minor features (relay):
+ - Re-check our address after we detect a changed IP address from
+ getsockname(). This ensures that the controller command "GETINFO
+ address" will report the correct value. Resolves ticket 11582.
+ Patch from "ra".
+ - A new AccountingRule option lets Relays set whether they'd like
+ AccountingMax to be applied separately to inbound and outbound
+ traffic, or applied to the sum of inbound and outbound traffic.
+ Resolves ticket 961. Patch by "chobe".
+
+ o Minor features (testing networks):
+ - Add the TestingDirAuthVoteExit option, which lists nodes to assign
+ the "Exit" flag regardless of their uptime, bandwidth, or exit
+ policy. TestingTorNetwork must be set for this option to have any
+ effect. Previously, authorities would take up to 35 minutes to
+ give nodes the Exit flag in a test network. Partially implements
+ ticket 13161.
+
+ o Minor features (validation):
+ - Check all date/time values passed to tor_timegm and
+ parse_rfc1123_time for validity, taking leap years into account.
+ Improves HTTP header validation. Implemented with bug 13476.
+ - In correct_tm(), limit the range of values returned by system
+ localtime(_r) and gmtime(_r) to be between the years 1 and 8099.
+ This means we don't have to deal with negative or too large dates,
+ even if a clock is wrong. Otherwise we might fail to read a file
+ written by us which includes such a date. Fixes bug 13476.
+
+ o Minor bugfixes (bridge clients):
+ - When configured to use a bridge without an identity digest (not
+ recommended), avoid launching an extra channel to it when
+ bootstrapping. Fixes bug 7733; bugfix on 0.2.4.4-alpha.
+
+ o Minor bugfixes (bridges):
+ - When DisableNetwork is set, do not launch pluggable transport
+ plugins, and if any are running, terminate them. Fixes bug 13213;
+ bugfix on 0.2.3.6-alpha.
+
+ o Minor bugfixes (C correctness):
+ - Fix several instances of possible integer overflow/underflow/NaN.
+ Fixes bug 13104; bugfix on 0.2.3.1-alpha and later. Patches
+ from "teor".
+ - In circuit_build_times_calculate_timeout() in circuitstats.c,
+ avoid dividing by zero in the pareto calculations. This traps
+ under clang's "undefined-trap" sanitizer. Fixes bug 13290; bugfix
+ on 0.2.2.2-alpha.
+ - Fix an integer overflow in format_time_interval(). Fixes bug
+ 13393; bugfix on 0.2.0.10-alpha.
+ - Set the correct day of year value when the system's localtime(_r)
+ or gmtime(_r) functions fail to set struct tm. Not externally
+ visible. Fixes bug 13476; bugfix on 0.0.2pre14.
+ - Avoid unlikely signed integer overflow in tor_timegm on systems
+ with 32-bit time_t. Fixes bug 13476; bugfix on 0.0.2pre14.
+
+ o Minor bugfixes (client):
+ - Fix smartlist_choose_node_by_bandwidth() so that relays with the
+ BadExit flag are not considered worthy candidates. Fixes bug
+ 13066; bugfix on 0.1.2.3-alpha.
+ - Use the consensus schedule for downloading consensuses, and not
+ the generic schedule. Fixes bug 11679; bugfix on 0.2.2.6-alpha.
+ - Handle unsupported or malformed SOCKS5 requests properly by
+ responding with the appropriate error message before closing the
+ connection. Fixes bugs 12971 and 13314; bugfix on 0.0.2pre13.
+
+ o Minor bugfixes (client, torrc):
+ - Stop modifying the value of our DirReqStatistics torrc option just
+ because we're not a bridge or relay. This bug was causing Tor
+ Browser users to write "DirReqStatistics 0" in their torrc files
+ as if they had chosen to change the config. Fixes bug 4244; bugfix
+ on 0.2.3.1-alpha.
+ - When GeoIPExcludeUnknown is enabled, do not incorrectly decide
+ that our options have changed every time we SIGHUP. Fixes bug
+ 9801; bugfix on 0.2.4.10-alpha. Patch from "qwerty1".
+
+ o Minor bugfixes (controller):
+ - Return an error when the second or later arguments of the
+ "setevents" controller command are invalid events. Previously we
+ would return success while silently skipping invalid events. Fixes
+ bug 13205; bugfix on 0.2.3.2-alpha. Reported by "fpxnns".
+
+ o Minor bugfixes (directory system):
+ - Always believe that v3 directory authorities serve extra-info
+ documents, whether they advertise "caches-extra-info" or not.
+ Fixes part of bug 11683; bugfix on 0.2.0.1-alpha.
+ - When running as a v3 directory authority, advertise that you serve
+ extra-info documents so that clients who want them can find them
+ from you too. Fixes part of bug 11683; bugfix on 0.2.0.1-alpha.
+ - Check the BRIDGE_DIRINFO flag bitwise rather than using equality.
+ Previously, directories offering BRIDGE_DIRINFO and some other
+ flag (i.e. microdescriptors or extrainfo) would be ignored when
+ looking for bridges. Partially fixes bug 13163; bugfix
+ on 0.2.0.7-alpha.
+
+ o Minor bugfixes (networking):
+ - Check for orconns and use connection_or_close_for_error() rather
+ than connection_mark_for_close() directly in the getsockopt()
+ failure case of connection_handle_write_impl(). Fixes bug 11302;
+ bugfix on 0.2.4.4-alpha.
+
+ o Minor bugfixes (relay):
+ - When generating our family list, remove spaces from around the
+ entries. Fixes bug 12728; bugfix on 0.2.1.7-alpha.
+ - If our previous bandwidth estimate was 0 bytes, allow publishing a
+ new relay descriptor immediately. Fixes bug 13000; bugfix
+ on 0.1.1.6-alpha.
+
+ o Minor bugfixes (testing networks):
+ - Fix TestingDirAuthVoteGuard to properly give out Guard flags in a
+ testing network. Fixes bug 13064; bugfix on 0.2.5.2-alpha.
+ - Stop using the default authorities in networks which provide both
+ AlternateDirAuthority and AlternateBridgeAuthority. Partially
+ fixes bug 13163; bugfix on 0.2.0.13-alpha.
+
+ o Minor bugfixes (testing):
+ - Stop spawn test failures due to a race condition between the
+ SIGCHLD handler updating the process status, and the test reading
+ it. Fixes bug 13291; bugfix on 0.2.3.3-alpha.
+
+ o Minor bugfixes (testing, Windows):
+ - Avoid passing an extra backslash when creating a temporary
+ directory for running the unit tests on Windows. Fixes bug 12392;
+ bugfix on 0.2.2.25-alpha. Patch from Gisle Vanem.
+
+ o Minor bugfixes (windows):
+ - Remove code to special-case handling of NTE_BAD_KEYSET when
+ acquiring windows CryptoAPI context. This error can't actually
+ occur for the parameters we're providing. Fixes bug 10816; bugfix
+ on 0.0.2pre26.
+
+ o Minor bugfixes (zlib):
+ - Avoid truncating a zlib stream when trying to finalize it with an
+ empty output buffer. Fixes bug 11824; bugfix on 0.1.1.23.
+
+ o Build fixes:
+ - Allow our configure script to build correctly with autoconf 2.62
+ again. Fixes bug 12693; bugfix on 0.2.5.2-alpha.
+ - Improve the error message from ./configure to make it clear that
+ when asciidoc has not been found, the user will have to either add
+ --disable-asciidoc argument or install asciidoc. Resolves
+ ticket 13228.
+
+ o Code simplification and refactoring:
+ - Change the entry_is_live() function to take named bitfield
+ elements instead of an unnamed list of booleans. Closes
+ ticket 12202.
+ - Refactor and unit-test entry_is_time_to_retry() in entrynodes.c.
+ Resolves ticket 12205.
+ - Use calloc and reallocarray functions instead of multiply-
+ then-malloc. This makes it less likely for us to fall victim to an
+ integer overflow attack when allocating. Resolves ticket 12855.
+ - Use the standard macro name SIZE_MAX, instead of our
+ own SIZE_T_MAX.
+ - Document usage of the NO_DIRINFO and ALL_DIRINFO flags clearly in
+ functions which take them as arguments. Replace 0 with NO_DIRINFO
+ in a function call for clarity. Seeks to prevent future issues
+ like 13163.
+ - Avoid 4 null pointer errors under clang static analysis by using
+ tor_assert() to prove that the pointers aren't null. Fixes
+ bug 13284.
+ - Rework the API of policies_parse_exit_policy() to use a bitmask to
+ represent parsing options, instead of a confusing mess of
+ booleans. Resolves ticket 8197.
+ - Introduce a helper function to parse ExitPolicy in
+ or_options_t structure.
+
+ o Documentation:
+ - Add a doc/TUNING document with tips for handling large numbers of
+ TCP connections when running busy Tor relay. Update the warning
+ message to point to this file when running out of sockets
+ operating system is allowing to use simultaneously. Resolves
+ ticket 9708.
+
+ o Removed features:
+ - We no longer remind the user about configuration options that have
+ been obsolete since 0.2.3.x or earlier. Patch by Adrien Bak.
+ - Remove our old, non-weighted bandwidth-based node selection code.
+ Previously, we used it as a fallback when we couldn't perform
+ weighted bandwidth-based node selection. But that would only
+ happen in the cases where we had no consensus, or when we had a
+ consensus generated by buggy or ancient directory authorities. In
+ either case, it's better to use the more modern, better maintained
+ algorithm, with reasonable defaults for the weights. Closes
+ ticket 13126.
+ - Remove the --disable-curve25519 configure option. Relays and
+ clients now are required to support curve25519 and the
+ ntor handshake.
+ - The old "StrictEntryNodes" and "StrictExitNodes" options, which
+ used to be deprecated synonyms for "StrictNodes", are now marked
+ obsolete. Resolves ticket 12226.
+ - Clients don't understand the BadDirectory flag in the consensus
+ anymore, and ignore it.
+
+ o Testing:
+ - Refactor the function that chooses guard nodes so that it can more
+ easily be tested; write some tests for it.
+ - Fix and re-enable the fgets_eagain unit test. Fixes bug 12503;
+ bugfix on 0.2.3.1-alpha. Patch from "cypherpunks."
+ - Create unit tests for format_time_interval(). With bug 13393.
+ - Add unit tests for tor_timegm signed overflow, tor_timegm and
+ parse_rfc1123_time validity checks, correct_tm year clamping. Unit
+ tests (visible) fixes in bug 13476.
+ - Add a "coverage-html" make target to generate HTML-visualized
+ coverage results when building with --enable-coverage. (Requires
+ lcov.) Patch from Kevin Murray.
+ - Enable the backtrace handler (where supported) when running the
+ unit tests.
+ - Revise all unit tests that used the legacy test_* macros to
+ instead use the recommended tt_* macros. This patch was generated
+ with coccinelle, to avoid manual errors. Closes ticket 13119.
+
+ o Distribution (systemd):
+ - systemd unit file: only allow tor to write to /var/lib/tor and
+ /var/log/tor. The rest of the filesystem is accessible for reading
+ only. Patch by intrigeri; resolves ticket 12751.
+ - systemd unit file: ensure that the process and all its children
+ can never gain new privileges. Patch by intrigeri; resolves
+ ticket 12939.
+ - systemd unit file: set up /var/run/tor as writable for the Tor
+ service. Patch by intrigeri; resolves ticket 13196.
+
+ o Removed features (directory authorities):
+ - Remove code that prevented authorities from listing Tor relays
+ affected by CVE-2011-2769 as guards. These relays are already
+ rejected altogether due to the minimum version requirement of
+ 0.2.3.16-alpha. Closes ticket 13152.
+ - The "AuthDirRejectUnlisted" option no longer has any effect, as
+ the fingerprints file (approved-routers) has been deprecated.
+ - Directory authorities do not support being Naming dirauths anymore.
+ The "NamingAuthoritativeDir" config option is now obsolete.
+ - Directory authorities do not support giving out the BadDirectory
+ flag anymore.
+ - Directory authorities no longer advertise or support consensus
+ methods 1 through 12 inclusive. These consensus methods were
+ obsolete and/or insecure: maintaining the ability to support them
+ served no good purpose. Implements part of proposal 215; closes
+ ticket 10163.
+
+ o Testing (test-network.sh):
+ - Stop using "echo -n", as some shells' built-in echo doesn't
+ support "-n". Instead, use "/bin/echo -n". Partially fixes
+ bug 13161.
+ - Stop an apparent test-network hang when used with make -j2. Fixes
+ bug 13331.
+ - Add a --delay option to test-network.sh, which configures the
+ delay before the chutney network tests for data transmission.
+ Partially implements ticket 13161.
+
+
+Changes in version 0.2.5.10 - 2014-10-24
+ Tor 0.2.5.10 is the first stable release in the 0.2.5 series.
+
+ It adds several new security features, including improved
+ denial-of-service resistance for relays, new compiler hardening
+ options, and a system-call sandbox for hardened installations on Linux
+ (requires seccomp2). The controller protocol has several new features,
+ resolving IPv6 addresses should work better than before, and relays
+ should be a little more CPU-efficient. We've added support for more
+ OpenBSD and FreeBSD transparent proxy types. We've improved the build
+ system and testing infrastructure to allow unit testing of more parts
+ of the Tor codebase. Finally, we've addressed several nagging pluggable
+ transport usability issues, and included numerous other small bugfixes
+ and features mentioned below.
+
+ This release marks end-of-life for Tor 0.2.3.x; those Tor versions
+ have accumulated many known flaws; everyone should upgrade.
+
+ o Deprecated versions:
+ - Tor 0.2.3.x has reached end-of-life; it has received no patches or
+ attention for some while.
+
+
+Changes in version 0.2.5.9-rc - 2014-10-20
+ Tor 0.2.5.9-rc is the third release candidate for the Tor 0.2.5.x
+ series. It disables SSL3 in response to the recent "POODLE" attack
+ (even though POODLE does not affect Tor). It also works around a crash
+ bug caused by some operating systems' response to the "POODLE" attack
+ (which does affect Tor). It also contains a few miscellaneous fixes.
+
+ o Major security fixes:
+ - Disable support for SSLv3. All versions of OpenSSL in use with Tor
+ today support TLS 1.0 or later, so we can safely turn off support
+ for this old (and insecure) protocol. Fixes bug 13426.
+
+ o Major bugfixes (openssl bug workaround):
+ - Avoid crashing when using OpenSSL version 0.9.8zc, 1.0.0o, or
+ 1.0.1j, built with the 'no-ssl3' configuration option. Fixes bug
+ 13471. This is a workaround for an OpenSSL bug.
+
+ o Minor bugfixes:
+ - Disable the sandbox name resolver cache when running tor-resolve:
+ tor-resolve doesn't use the sandbox code, and turning it on was
+ breaking attempts to do tor-resolve on a non-default server on
+ Linux. Fixes bug 13295; bugfix on 0.2.5.3-alpha.
+
+ o Compilation fixes:
+ - Build and run correctly on systems like OpenBSD-current that have
+ patched OpenSSL to remove get_cipher_by_char and/or its
+ implementations. Fixes issue 13325.
+
+ o Downgraded warnings:
+ - Downgrade the severity of the 'unexpected sendme cell from client'
+ from 'warn' to 'protocol warning'. Closes ticket 8093.
+
+
+Changes in version 0.2.4.25 - 2014-10-20
+ Tor 0.2.4.25 disables SSL3 in response to the recent "POODLE" attack
+ (even though POODLE does not affect Tor). It also works around a crash
+ bug caused by some operating systems' response to the "POODLE" attack
+ (which does affect Tor).
+
+ o Major security fixes (also in 0.2.5.9-rc):
+ - Disable support for SSLv3. All versions of OpenSSL in use with Tor
+ today support TLS 1.0 or later, so we can safely turn off support
+ for this old (and insecure) protocol. Fixes bug 13426.
+
+ o Major bugfixes (openssl bug workaround, also in 0.2.5.9-rc):
+ - Avoid crashing when using OpenSSL version 0.9.8zc, 1.0.0o, or
+ 1.0.1j, built with the 'no-ssl3' configuration option. Fixes bug
+ 13471. This is a workaround for an OpenSSL bug.
+
+
+Changes in version 0.2.5.8-rc - 2014-09-22
+ Tor 0.2.5.8-rc is the second release candidate for the Tor 0.2.5.x
+ series. It fixes a bug that affects consistency and speed when
+ connecting to hidden services, and it updates the location of one of
+ the directory authorities.
+
+ o Major bugfixes:
+ - Clients now send the correct address for their chosen rendezvous
+ point when trying to access a hidden service. They used to send
+ the wrong address, which would still work some of the time because
+ they also sent the identity digest of the rendezvous point, and if
+ the hidden service happened to try connecting to the rendezvous
+ point from a relay that already had a connection open to it,
+ the relay would reuse that connection. Now connections to hidden
+ services should be more robust and faster. Also, this bug meant
+ that clients were leaking to the hidden service whether they were
+ on a little-endian (common) or big-endian (rare) system, which for
+ some users might have reduced their anonymity. Fixes bug 13151;
+ bugfix on 0.2.1.5-alpha.
+
+ o Directory authority changes:
+ - Change IP address for gabelmoo (v3 directory authority).
+
+
+Changes in version 0.2.4.24 - 2014-09-22
+ Tor 0.2.4.24 fixes a bug that affects consistency and speed when
+ connecting to hidden services, and it updates the location of one of
+ the directory authorities.
+
+ o Major bugfixes:
+ - Clients now send the correct address for their chosen rendezvous
+ point when trying to access a hidden service. They used to send
+ the wrong address, which would still work some of the time because
+ they also sent the identity digest of the rendezvous point, and if
+ the hidden service happened to try connecting to the rendezvous
+ point from a relay that already had a connection open to it,
+ the relay would reuse that connection. Now connections to hidden
+ services should be more robust and faster. Also, this bug meant
+ that clients were leaking to the hidden service whether they were
+ on a little-endian (common) or big-endian (rare) system, which for
+ some users might have reduced their anonymity. Fixes bug 13151;
+ bugfix on 0.2.1.5-alpha.
+
+ o Directory authority changes:
+ - Change IP address for gabelmoo (v3 directory authority).
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the August 7 2014 Maxmind GeoLite2
+ Country database.
+
+
+Changes in version 0.2.5.7-rc - 2014-09-11
+ Tor 0.2.5.7-rc fixes several regressions from earlier in the 0.2.5.x
+ release series, and some long-standing bugs related to ORPort reachability
+ testing and failure to send CREATE cells. It is the first release
+ candidate for the Tor 0.2.5.x series.
+
+ o Major bugfixes (client, startup):
+ - Start making circuits as soon as DisabledNetwork is turned off.
+ When Tor started with DisabledNetwork set, it would correctly
+ conclude that it shouldn't build circuits, but it would mistakenly
+ cache this conclusion, and continue believing it even when
+ DisableNetwork is set to 0. Fixes the bug introduced by the fix
+ for bug 11200; bugfix on 0.2.5.4-alpha.
+ - Resume expanding abbreviations for command-line options. The fix
+ for bug 4647 accidentally removed our hack from bug 586 that
+ rewrote HashedControlPassword to __HashedControlSessionPassword
+ when it appears on the commandline (which allowed the user to set
+ her own HashedControlPassword in the torrc file while the
+ controller generates a fresh session password for each run). Fixes
+ bug 12948; bugfix on 0.2.5.1-alpha.
+ - Warn about attempts to run hidden services and relays in the same
+ process: that's probably not a good idea. Closes ticket 12908.
+
+ o Major bugfixes (relay):
+ - Avoid queuing or sending destroy cells for circuit ID zero when we
+ fail to send a CREATE cell. Fixes bug 12848; bugfix on 0.0.8pre1.
+ Found and fixed by "cypherpunks".
+ - Fix ORPort reachability detection on relays running behind a
+ proxy, by correctly updating the "local" mark on the controlling
+ channel when changing the address of an or_connection_t after the
+ handshake. Fixes bug 12160; bugfix on 0.2.4.4-alpha.
+
+ o Minor features (bridge):
+ - Add an ExtORPortCookieAuthFileGroupReadable option to make the
+ cookie file for the ExtORPort g+r by default.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the August 7 2014 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (logging):
+ - Reduce the log severity of the "Pluggable transport proxy does not
+ provide any needed transports and will not be launched." message,
+ since Tor Browser includes several ClientTransportPlugin lines in
+ its torrc-defaults file, leading every Tor Browser user who looks
+ at her logs to see these notices and wonder if they're dangerous.
+ Resolves bug 13124; bugfix on 0.2.5.3-alpha.
+ - Downgrade "Unexpected onionskin length after decryption" warning
+ to a protocol-warn, since there's nothing relay operators can do
+ about a client that sends them a malformed create cell. Resolves
+ bug 12996; bugfix on 0.0.6rc1.
+ - Log more specific warnings when we get an ESTABLISH_RENDEZVOUS
+ cell on a cannibalized or non-OR circuit. Resolves ticket 12997.
+ - When logging information about an EXTEND2 or EXTENDED2 cell, log
+ their names correctly. Fixes part of bug 12700; bugfix
+ on 0.2.4.8-alpha.
+ - When logging information about a relay cell whose command we don't
+ recognize, log its command as an integer. Fixes part of bug 12700;
+ bugfix on 0.2.1.10-alpha.
+ - Escape all strings from the directory connection before logging
+ them. Fixes bug 13071; bugfix on 0.1.1.15. Patch from "teor".
+
+ o Minor bugfixes (controller):
+ - Restore the functionality of CookieAuthFileGroupReadable. Fixes
+ bug 12864; bugfix on 0.2.5.1-alpha.
+ - Actually send TRANSPORT_LAUNCHED and HS_DESC events to
+ controllers. Fixes bug 13085; bugfix on 0.2.5.1-alpha. Patch
+ by "teor".
+
+ o Minor bugfixes (compilation):
+ - Fix compilation of test.h with MSVC. Patch from Gisle Vanem;
+ bugfix on 0.2.5.5-alpha.
+ - Make the nmake make files work again. Fixes bug 13081. Bugfix on
+ 0.2.5.1-alpha. Patch from "NewEraCracker".
+ - In routerlist_assert_ok(), don't take the address of a
+ routerinfo's cache_info member unless that routerinfo is non-NULL.
+ Fixes bug 13096; bugfix on 0.1.1.9-alpha. Patch by "teor".
+ - Fix a large number of false positive warnings from the clang
+ analyzer static analysis tool. This should make real warnings
+ easier for clang analyzer to find. Patch from "teor". Closes
+ ticket 13036.
+
+ o Distribution (systemd):
+ - Verify configuration file via ExecStartPre in the systemd unit
+ file. Patch from intrigeri; resolves ticket 12730.
+ - Explicitly disable RunAsDaemon in the systemd unit file. Our
+ current systemd unit uses "Type = simple", so systemd does not
+ expect tor to fork. If the user has "RunAsDaemon 1" in their
+ torrc, then things won't work as expected. This is e.g. the case
+ on Debian (and derivatives), since there we pass "--defaults-torrc
+ /usr/share/tor/tor-service-defaults-torrc" (that contains
+ "RunAsDaemon 1") by default. Patch by intrigeri; resolves
+ ticket 12731.
+
+ o Documentation:
+ - Adjust the URLs in the README to refer to the new locations of
+ several documents on the website. Fixes bug 12830. Patch from
+ Matt Pagan.
+ - Document 'reject6' and 'accept6' ExitPolicy entries. Resolves
+ ticket 12878.
+
+
+Changes in version 0.2.5.6-alpha - 2014-07-28
+ Tor 0.2.5.6-alpha brings us a big step closer to slowing down the
+ risk from guard rotation, and fixes a variety of other issues to get
+ us closer to a release candidate.
+
+ o Major features (also in 0.2.4.23):
+ - Make the number of entry guards configurable via a new
+ NumEntryGuards consensus parameter, and the number of directory
+ guards configurable via a new NumDirectoryGuards consensus
+ parameter. Implements ticket 12688.
+
+ o Major bugfixes (also in 0.2.4.23):
+ - Fix a bug in the bounds-checking in the 32-bit curve25519-donna
+ implementation that caused incorrect results on 32-bit
+ implementations when certain malformed inputs were used along with
+ a small class of private ntor keys. This bug does not currently
+ appear to allow an attacker to learn private keys or impersonate a
+ Tor server, but it could provide a means to distinguish 32-bit Tor
+ implementations from 64-bit Tor implementations. Fixes bug 12694;
+ bugfix on 0.2.4.8-alpha. Bug found by Robert Ransom; fix from
+ Adam Langley.
+
+ o Major bugfixes:
+ - Perform circuit cleanup operations even when circuit
+ construction operations are disabled (because the network is
+ disabled, or because there isn't enough directory information).
+ Previously, when we were not building predictive circuits, we
+ were not closing expired circuits either. Fixes bug 8387; bugfix on
+ 0.1.1.11-alpha. This bug became visible in 0.2.4.10-alpha when we
+ became more strict about when we have "enough directory information
+ to build circuits".
+
+ o Minor features:
+ - Authorities now assign the Guard flag to the fastest 25% of the
+ network (it used to be the fastest 50%). Also raise the consensus
+ weight that guarantees the Guard flag from 250 to 2000. For the
+ current network, this results in about 1100 guards, down from 2500.
+ This step paves the way for moving the number of entry guards
+ down to 1 (proposal 236) while still providing reasonable expected
+ performance for most users. Implements ticket 12690.
+ - Update geoip and geoip6 to the July 10 2014 Maxmind GeoLite2
+ Country database.
+ - Slightly enhance the diagnostic message for bug 12184.
+
+ o Minor bugfixes (also in 0.2.4.23):
+ - Warn and drop the circuit if we receive an inbound 'relay early'
+ cell. Those used to be normal to receive on hidden service circuits
+ due to bug 1038, but the buggy Tor versions are long gone from
+ the network so we can afford to resume watching for them. Resolves
+ the rest of bug 1038; bugfix on 0.2.1.19.
+ - Correct a confusing error message when trying to extend a circuit
+ via the control protocol but we don't know a descriptor or
+ microdescriptor for one of the specified relays. Fixes bug 12718;
+ bugfix on 0.2.3.1-alpha.
+
+ o Minor bugfixes:
+ - Fix compilation when building with bufferevents enabled. (This
+ configuration is still not expected to work, however.)
+ Fixes bugs 12438, 12474, 11578; bugfixes on 0.2.5.1-alpha and
+ 0.2.5.3-alpha. Patches from Anthony G. Basile and Sathyanarayanan
+ Gunasekaran.
+ - Compile correctly with builds and forks of OpenSSL (such as
+ LibreSSL) that disable compression. Fixes bug 12602; bugfix on
+ 0.2.1.1-alpha. Patch from "dhill".
+
+
+Changes in version 0.2.4.23 - 2014-07-28
+ Tor 0.2.4.23 brings us a big step closer to slowing down the risk from
+ guard rotation, and also backports several important fixes from the
+ Tor 0.2.5 alpha release series.
+
+ o Major features:
+ - Clients now look at the "usecreatefast" consensus parameter to
+ decide whether to use CREATE_FAST or CREATE cells for the first hop
+ of their circuit. This approach can improve security on connections
+ where Tor's circuit handshake is stronger than the available TLS
+ connection security levels, but the tradeoff is more computational
+ load on guard relays. Implements proposal 221. Resolves ticket 9386.
+ - Make the number of entry guards configurable via a new
+ NumEntryGuards consensus parameter, and the number of directory
+ guards configurable via a new NumDirectoryGuards consensus
+ parameter. Implements ticket 12688.
+
+ o Major bugfixes:
+ - Fix a bug in the bounds-checking in the 32-bit curve25519-donna
+ implementation that caused incorrect results on 32-bit
+ implementations when certain malformed inputs were used along with
+ a small class of private ntor keys. This bug does not currently
+ appear to allow an attacker to learn private keys or impersonate a
+ Tor server, but it could provide a means to distinguish 32-bit Tor
+ implementations from 64-bit Tor implementations. Fixes bug 12694;
+ bugfix on 0.2.4.8-alpha. Bug found by Robert Ransom; fix from
+ Adam Langley.
+
+ o Minor bugfixes:
+ - Warn and drop the circuit if we receive an inbound 'relay early'
+ cell. Those used to be normal to receive on hidden service circuits
+ due to bug 1038, but the buggy Tor versions are long gone from
+ the network so we can afford to resume watching for them. Resolves
+ the rest of bug 1038; bugfix on 0.2.1.19.
+ - Correct a confusing error message when trying to extend a circuit
+ via the control protocol but we don't know a descriptor or
+ microdescriptor for one of the specified relays. Fixes bug 12718;
+ bugfix on 0.2.3.1-alpha.
+ - Avoid an illegal read from stack when initializing the TLS
+ module using a version of OpenSSL without all of the ciphers
+ used by the v2 link handshake. Fixes bug 12227; bugfix on
+ 0.2.4.8-alpha. Found by "starlight".
+
+ o Minor features:
+ - Update geoip and geoip6 to the July 10 2014 Maxmind GeoLite2
+ Country database.
+
+
Changes in version 0.2.5.5-alpha - 2014-06-18
Tor 0.2.5.5-alpha fixes a wide variety of remaining issues in the Tor
0.2.5.x release series, including a couple of DoS issues, some
@@ -293,7 +1676,7 @@ Changes in version 0.2.5.5-alpha - 2014-06-18
o Removed code:
- Remove /tor/dbg-stability.txt URL that was meant to help debug WFU
- and MTBF calculations, but that nobody was using. Fixes #11742.
+ and MTBF calculations, but that nobody was using. Fixes ticket 11742.
- The TunnelDirConns and PreferTunnelledDirConns options no longer
exist; tunneled directory connections have been available since
0.1.2.5-alpha, and turning them off is not a good idea. This is a
@@ -2936,7 +4319,7 @@ Changes in version 0.2.3.23-rc - 2012-10-20
- Correct file sizes when reading binary files on Cygwin, to avoid
a bug where Tor would fail to read its state file. Fixes bug 6844;
bugfix on 0.1.2.7-alpha.
- - Avoid undefined behaviour when parsing the list of supported
+ - Avoid undefined behavior when parsing the list of supported
rendezvous/introduction protocols in a hidden service descriptor.
Previously, Tor would have confused (as-yet-unused) protocol version
numbers greater than 32 with lower ones on many platforms. Fixes
@@ -3012,7 +4395,7 @@ Changes in version 0.2.4.3-alpha - 2012-09-22
- Reject consensus votes with more than 64 known-flags. We aren't even
close to that limit yet, and our code doesn't handle it correctly.
Fixes bug 6833; bugfix on 0.2.0.1-alpha.
- - Avoid undefined behaviour when parsing the list of supported
+ - Avoid undefined behavior when parsing the list of supported
rendezvous/introduction protocols in a hidden service descriptor.
Previously, Tor would have confused (as-yet-unused) protocol version
numbers greater than 32 with lower ones on many platforms. Fixes
@@ -4449,7 +5832,7 @@ Changes in version 0.2.3.11-alpha - 2012-01-22
be disabled using the new CloseHSClientCircuitsImmediatelyOnTimeout
option. Fixes part of bug 1297; bugfix on 0.2.2.2-alpha.
- Don't close hidden-service-side rendezvous circuits when they
- reach the normal circuit-build timeout. This behaviour change can
+ reach the normal circuit-build timeout. This behavior change can
be disabled using the new
CloseHSServiceRendCircuitsImmediatelyOnTimeout option. Fixes the
remaining part of bug 1297; bugfix on 0.2.2.2-alpha.
@@ -6030,14 +7413,14 @@ Changes in version 0.2.2.29-beta - 2011-06-20
directory's group would be checked against the current group, not
the configured group. Patch by Jérémy Bobbio. Fixes bug 3393;
bugfix on 0.2.2.26-beta.
- - Make connection_printf_to_buf()'s behaviour sane. Its callers
+ - Make connection_printf_to_buf()'s behavior sane. Its callers
expect it to emit a CRLF iff the format string ends with CRLF;
it actually emitted a CRLF iff (a) the format string ended with
CRLF or (b) the resulting string was over 1023 characters long or
(c) the format string did not end with CRLF *and* the resulting
string was 1021 characters long or longer. Bugfix on 0.1.1.9-alpha;
fixes part of bug 3407.
- - Make send_control_event_impl()'s behaviour sane. Its callers
+ - Make send_control_event_impl()'s behavior sane. Its callers
expect it to always emit a CRLF at the end of the string; it
might have emitted extra control characters as well. Bugfix on
0.1.1.9-alpha; fixes another part of bug 3407.
@@ -8138,7 +9521,7 @@ Changes in version 0.2.2.9-alpha - 2010-02-22
- Avoid a bogus overlapped memcpy in tor_addr_copy(). Reported by
"memcpyfail".
- Make the DNSPort option work with libevent 2.x. Don't alter the
- behaviour for libevent 1.x. Fixes bug 1143. Found by SwissTorExit.
+ behavior for libevent 1.x. Fixes bug 1143. Found by SwissTorExit.
- Emit a GUARD DROPPED controller event for a case we missed.
- Make more fields in the controller protocol case-insensitive, since
control-spec.txt said they were.
diff --git a/LICENSE b/LICENSE
index 4ebab1823f..48602c13c6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -13,7 +13,7 @@ Tor is distributed under this license:
Copyright (c) 2001-2004, Roger Dingledine
Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
-Copyright (c) 2007-2013, The Tor Project, Inc.
+Copyright (c) 2007-2015, The Tor Project, Inc.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -122,6 +122,38 @@ src/ext/csiphash.c is licensed under the following license:
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+===============================================================================
+Trunnel is distributed under this license:
+
+Copyright 2014 The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===============================================================================
src/config/geoip is licensed under the following license:
@@ -159,7 +191,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
DATABASE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===============================================================================
m4/pc_from_ucontext.m4 is available under the following license. Note that
-it is *not* built into the Tor license.
+it is *not* built into the Tor software.
Copyright (c) 2005, Google Inc.
All rights reserved.
@@ -191,6 +223,35 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
===============================================================================
+m4/pkg.m4 is available under the following license. Note that
+it is *not* built into the Tor software.
+
+pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+serial 1 (pkg-config-0.24)
+
+Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+As a special exception to the GNU General Public License, if you
+distribute this file as part of a program that contains a
+configuration script generated by Autoconf, you may include it under
+the same distribution terms that you use for the rest of that program.
+
+
+===============================================================================
If you got Tor as a static binary with OpenSSL included, then you should know:
"This product includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit (http://www.openssl.org/)"
diff --git a/Makefile.am b/Makefile.am
index 6eceb761f4..b1f92f5b34 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
# Copyright (c) 2001-2004, Roger Dingledine
# Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
-# Copyright (c) 2007-2011, The Tor Project, Inc.
+# Copyright (c) 2007-2015, The Tor Project, Inc.
# See LICENSE for licensing information
# "foreign" means we don't follow GNU package layout standards
@@ -19,11 +19,11 @@ noinst_PROGRAMS=
DISTCLEANFILES=
bin_SCRIPTS=
AM_CPPFLAGS=
+AM_CFLAGS = @TOR_SYSTEMD_CFLAGS@
include src/include.am
include doc/include.am
include contrib/include.am
-
EXTRA_DIST+= \
ChangeLog \
INSTALL \
@@ -71,8 +71,28 @@ test: all
test-network: all
./src/test/test-network.sh
+test-stem: $(TESTING_TOR_BINARY)
+ @if test -d "$$STEM_SOURCE_DIR"; then \
+ $(PYTHON) "$$STEM_SOURCE_DIR"/run_tests.py --tor $(TESTING_TOR_BINARY) --all --log notice --target RUN_ALL; \
+ else \
+ echo '$$STEM_SOURCE_DIR was not set.'; echo; \
+ echo "To run these tests, git clone https://git.torproject.org/stem.git/ ; export STEM_SOURCE_DIR=\`pwd\`/stem"; \
+ fi
+
+
reset-gcov:
- rm -f src/*/*.gcda
+ rm -f src/*/*.gcda src/*/*/*.gcda
+
+HTML_COVER_DIR=./coverage_html
+coverage-html: all
+ test -e "`which lcov`" || (echo "lcov must be installed. See <http://ltp.sourceforge.net/coverage/lcov.php>." && false)
+ test -d "$(HTML_COVER_DIR)" || mkdir -p "$(HTML_COVER_DIR)"
+ lcov --rc lcov_branch_coverage=1 --directory ./src --zerocounters
+ $(MAKE) reset-gcov
+ $(MAKE) check
+ lcov --capture --rc lcov_branch_coverage=1 --no-external --directory . --output-file "$(HTML_COVER_DIR)/lcov.tmp"
+ lcov --remove "$(HTML_COVER_DIR)/lcov.tmp" --rc lcov_branch_coverage=1 'test/*' 'ext/tinytest*' '/usr/*' --output-file "$(HTML_COVER_DIR)/lcov.info"
+ genhtml --branch-coverage -o "$(HTML_COVER_DIR)" "$(HTML_COVER_DIR)/lcov.info"
# Avoid strlcpy.c, strlcat.c, aes.c, OpenBSD_malloc_Linux.c, sha256.c,
# eventdns.[hc], tinytest*.[ch]
@@ -99,4 +119,4 @@ version:
fi
mostlyclean-local:
- rm -f src/*/*.gc{da,no}
+ rm -f src/*/*.gc{da,no} src/*/*/*.gc{da,no}
diff --git a/README b/README
index e878476aa6..342376faf4 100644
--- a/README
+++ b/README
@@ -6,6 +6,9 @@ configure it properly.
To build Tor from source:
./configure && make && make install
+To build Tor from a just-cloned git repository:
+ sh autogen.sh && ./configure && make && make install
+
Home page:
https://www.torproject.org/
diff --git a/ReleaseNotes b/ReleaseNotes
index 19185a2968..a9c8ceefdd 100644
--- a/ReleaseNotes
+++ b/ReleaseNotes
@@ -3,6 +3,981 @@ This document summarizes new features and bugfixes in each stable release
of Tor. If you want to see more detailed descriptions of the changes in
each development snapshot, see the ChangeLog file.
+Changes in version 0.2.5.10 - 2014-10-24
+ Tor 0.2.5.10 is the first stable release in the 0.2.5 series.
+
+ It adds several new security features, including improved
+ denial-of-service resistance for relays, new compiler hardening
+ options, and a system-call sandbox for hardened installations on Linux
+ (requires seccomp2). The controller protocol has several new features,
+ resolving IPv6 addresses should work better than before, and relays
+ should be a little more CPU-efficient. We've added support for more
+ OpenBSD and FreeBSD transparent proxy types. We've improved the build
+ system and testing infrastructure to allow unit testing of more parts
+ of the Tor codebase. Finally, we've addressed several nagging pluggable
+ transport usability issues, and included numerous other small bugfixes
+ and features mentioned below.
+
+ This release marks end-of-life for Tor 0.2.3.x; those Tor versions
+ have accumulated many known flaws; everyone should upgrade.
+
+ o Major features (security):
+ - The ntor handshake is now on-by-default, no matter what the
+ directory authorities recommend. Implements ticket 8561.
+ - Make the "tor-gencert" tool used by directory authority operators
+ create 2048-bit signing keys by default (rather than 1024-bit, since
+ 1024-bit is uncomfortably small these days). Addresses ticket 10324.
+ - Warn about attempts to run hidden services and relays in the same
+ process: that's probably not a good idea. Closes ticket 12908.
+ - Disable support for SSLv3. All versions of OpenSSL in use with Tor
+ today support TLS 1.0 or later, so we can safely turn off support
+ for this old (and insecure) protocol. Fixes bug 13426.
+
+ o Major features (relay security, DoS-resistance):
+ - When deciding whether we have run out of memory and we need to
+ close circuits, also consider memory allocated in buffers for
+ streams attached to each circuit.
+
+ This change, which extends an anti-DoS feature introduced in
+ 0.2.4.13-alpha and improved in 0.2.4.14-alpha, lets Tor exit relays
+ better resist more memory-based DoS attacks than before. Since the
+ MaxMemInCellQueues option now applies to all queues, it is renamed
+ to MaxMemInQueues. This feature fixes bug 10169.
+ - Avoid hash-flooding denial-of-service attacks by using the secure
+ SipHash-2-4 hash function for our hashtables. Without this
+ feature, an attacker could degrade performance of a targeted
+ client or server by flooding their data structures with a large
+ number of entries to be stored at the same hash table position,
+ thereby slowing down the Tor instance. With this feature, hash
+ table positions are derived from a randomized cryptographic key,
+ and an attacker cannot predict which entries will collide. Closes
+ ticket 4900.
+ - If you don't specify MaxMemInQueues yourself, Tor now tries to
+ pick a good value based on your total system memory. Previously,
+ the default was always 8 GB. You can still override the default by
+ setting MaxMemInQueues yourself. Resolves ticket 11396.
+
+ o Major features (bridges and pluggable transports):
+ - Add support for passing arguments to managed pluggable transport
+ proxies. Implements ticket 3594.
+ - Bridges now track GeoIP information and the number of their users
+ even when pluggable transports are in use, and report usage
+ statistics in their extra-info descriptors. Resolves tickets 4773
+ and 5040.
+ - Don't launch pluggable transport proxies if we don't have any
+ bridges configured that would use them. Now we can list many
+ pluggable transports, and Tor will dynamically start one when it
+ hears a bridge address that needs it. Resolves ticket 5018.
+ - The bridge directory authority now assigns status flags (Stable,
+ Guard, etc) to bridges based on thresholds calculated over all
+ Running bridges. Now bridgedb can finally make use of its features
+ to e.g. include at least one Stable bridge in its answers. Fixes
+ bug 9859.
+
+ o Major features (controller):
+ - Extend ORCONN controller event to include an "ID" parameter,
+ and add four new controller event types CONN_BW, CIRC_BW,
+ CELL_STATS, and TB_EMPTY that show connection and circuit usage.
+ The new events are emitted in private Tor networks only, with the
+ goal of being able to better track performance and load during
+ full-network simulations. Implements proposal 218 and ticket 7359.
+
+ o Major features (relay performance):
+ - Speed up server-side lookups of rendezvous and introduction point
+ circuits by using hashtables instead of linear searches. These
+ functions previously accounted between 3 and 7% of CPU usage on
+ some busy relays. Resolves ticket 9841.
+ - Avoid wasting CPU when extending a circuit over a channel that is
+ nearly out of circuit IDs. Previously, we would do a linear scan
+ over possible circuit IDs before finding one or deciding that we
+ had exhausted our possibilities. Now, we try at most 64 random
+ circuit IDs before deciding that we probably won't succeed. Fixes
+ a possible root cause of ticket 11553.
+
+ o Major features (seccomp2 sandbox, Linux only):
+ - Use the seccomp2 syscall filtering facility on Linux to limit
+ which system calls Tor can invoke. This is an experimental,
+ Linux-only feature to provide defense-in-depth against unknown
+ attacks. To try turning it on, set "Sandbox 1" in your torrc
+ file. Please be ready to report bugs. We hope to add support
+ for better sandboxing in the future, including more fine-grained
+ filters, better division of responsibility, and support for more
+ platforms. This work has been done by Cristian-Matei Toader for
+ Google Summer of Code. Resolves tickets 11351 and 11465.
+
+ o Major features (testing networks):
+ - Make testing Tor networks bootstrap better: lower directory fetch
+ retry schedules and maximum interval without directory requests,
+ and raise maximum download tries. Implements ticket 6752.
+ - Add make target 'test-network' to run tests on a Chutney network.
+ Implements ticket 8530.
+
+ o Major features (other):
+ - On some platforms (currently: recent OSX versions, glibc-based
+ platforms that support the ELF format, and a few other
+ Unix-like operating systems), Tor can now dump stack traces
+ when a crash occurs or an assertion fails. By default, traces
+ are dumped to stderr (if possible) and to any logs that are
+ reporting errors. Implements ticket 9299.
+
+ o Deprecated versions:
+ - Tor 0.2.3.x has reached end-of-life; it has received no patches or
+ attention for some while.
+
+ o Major bugfixes (security, directory authorities):
+ - Directory authorities now include a digest of each relay's
+ identity key as a part of its microdescriptor.
+
+ This is a workaround for bug 11743 (reported by "cypherpunks"),
+ where Tor clients do not support receiving multiple
+ microdescriptors with the same SHA256 digest in the same
+ consensus. When clients receive a consensus like this, they only
+ use one of the relays. Without this fix, a hostile relay could
+ selectively disable some client use of target relays by
+ constructing a router descriptor with a different identity and the
+ same microdescriptor parameters and getting the authorities to
+ list it in a microdescriptor consensus. This fix prevents an
+ attacker from causing a microdescriptor collision, because the
+ router's identity is not forgeable.
+
+ o Major bugfixes (openssl bug workaround):
+ - Avoid crashing when using OpenSSL version 0.9.8zc, 1.0.0o, or
+ 1.0.1j, built with the 'no-ssl3' configuration option. Fixes
+ bug 13471. This is a workaround for an OpenSSL bug.
+
+ o Major bugfixes (client):
+ - Perform circuit cleanup operations even when circuit
+ construction operations are disabled (because the network is
+ disabled, or because there isn't enough directory information).
+ Previously, when we were not building predictive circuits, we
+ were not closing expired circuits either. Fixes bug 8387; bugfix on
+ 0.1.1.11-alpha. This bug became visible in 0.2.4.10-alpha when we
+ became more strict about when we have "enough directory information
+ to build circuits".
+
+ o Major bugfixes (client, pluggable transports):
+ - When managing pluggable transports, use OS notification facilities
+ to learn if they have crashed, and don't attempt to kill any
+ process that has already exited. Fixes bug 8746; bugfix
+ on 0.2.3.6-alpha.
+
+ o Major bugfixes (relay denial of service):
+ - Instead of writing destroy cells directly to outgoing connection
+ buffers, queue them and intersperse them with other outgoing cells.
+ This can prevent a set of resource starvation conditions where too
+ many pending destroy cells prevent data cells from actually getting
+ delivered. Reported by "oftc_must_be_destroyed". Fixes bug 7912;
+ bugfix on 0.2.0.1-alpha.
+
+ o Major bugfixes (relay):
+ - Avoid queuing or sending destroy cells for circuit ID zero when we
+ fail to send a CREATE cell. Fixes bug 12848; bugfix on 0.0.8pre1.
+ Found and fixed by "cypherpunks".
+ - Fix ORPort reachability detection on relays running behind a
+ proxy, by correctly updating the "local" mark on the controlling
+ channel when changing the address of an or_connection_t after the
+ handshake. Fixes bug 12160; bugfix on 0.2.4.4-alpha.
+ - Use a direct dirport connection when uploading non-anonymous
+ descriptors to the directory authorities. Previously, relays would
+ incorrectly use tunnel connections under a fairly wide variety of
+ circumstances. Fixes bug 11469; bugfix on 0.2.4.3-alpha.
+ - When a circuit accidentally has the same circuit ID for its
+ forward and reverse direction, correctly detect the direction of
+ cells using that circuit. Previously, this bug made roughly one
+ circuit in a million non-functional. Fixes bug 12195; this is a
+ bugfix on every version of Tor.
+
+ o Minor features (security):
+ - New --enable-expensive-hardening option to enable security
+ hardening options that consume nontrivial amounts of CPU and
+ memory. Right now, this includes AddressSanitizer and UbSan, which
+ are supported in newer versions of GCC and Clang. Closes ticket
+ 11477.
+ - Authorities now assign the Guard flag to the fastest 25% of the
+ network (it used to be the fastest 50%). Also raise the consensus
+ weight that guarantees the Guard flag from 250 to 2000. For the
+ current network, this results in about 1100 guards, down from 2500.
+ This step paves the way for moving the number of entry guards
+ down to 1 (proposal 236) while still providing reasonable expected
+ performance for most users. Implements ticket 12690.
+
+ o Minor features (security, memory management):
+ - Memory allocation tricks (mempools and buffer freelists) are now
+ disabled by default. You can turn them back on with
+ --enable-mempools and --enable-buf-freelists respectively. We're
+ disabling these features because malloc performance is good enough
+ on most platforms, and a similar feature in OpenSSL exacerbated
+ exploitation of the Heartbleed attack. Resolves ticket 11476.
+
+ o Minor features (bridge client):
+ - Report a more useful failure message when we can't connect to a
+ bridge because we don't have the right pluggable transport
+ configured. Resolves ticket 9665. Patch from Fábio J. Bertinatto.
+
+ o Minor features (bridge):
+ - Add an ExtORPortCookieAuthFileGroupReadable option to make the
+ cookie file for the ExtORPort g+r by default.
+
+ o Minor features (bridges, pluggable transports):
+ - Bridges now write the SHA1 digest of their identity key
+ fingerprint (that is, a hash of a hash of their public key) to
+ notice-level logs, and to a new hashed-fingerprint file. This
+ information will help bridge operators look up their bridge in
+ Globe and similar tools. Resolves ticket 10884.
+ - Improve the message that Tor displays when running as a bridge
+ using pluggable transports without an Extended ORPort listener.
+ Also, log the message in the log file too. Resolves ticket 11043.
+ - Add threshold cutoffs to the networkstatus document created by
+ the Bridge Authority. Fixes bug 1117.
+ - On Windows, spawn background processes using the CREATE_NO_WINDOW
+ flag. Now Tor Browser Bundle 3.5 with pluggable transports enabled
+ doesn't pop up a blank console window. (In Tor Browser Bundle 2.x,
+ Vidalia set this option for us.) Implements ticket 10297.
+
+ o Minor features (build):
+ - The configure script has a --disable-seccomp option to turn off
+ support for libseccomp on systems that have it, in case it (or
+ Tor's use of it) is broken. Resolves ticket 11628.
+ - Assume that a user using ./configure --host wants to cross-compile,
+ and give an error if we cannot find a properly named
+ tool-chain. Add a --disable-tool-name-check option to proceed
+ nevertheless. Addresses ticket 9869. Patch by Benedikt Gollatz.
+ - If we run ./configure and the compiler recognizes -fstack-protector
+ but the linker rejects it, warn the user about a potentially missing
+ libssp package. Addresses ticket 9948. Patch from Benedikt Gollatz.
+ - Add support for `--library-versions` flag. Implements ticket 6384.
+ - Return the "unexpected sendme" warnings to a warn severity, but make
+ them rate limited, to help diagnose ticket 8093.
+ - Detect a missing asciidoc, and warn the user about it, during
+ configure rather than at build time. Fixes issue 6506. Patch from
+ Arlo Breault.
+
+ o Minor features (client):
+ - Add a new option, PredictedPortsRelevanceTime, to control how long
+ after having received a request to connect to a given port Tor
+ will try to keep circuits ready in anticipation of future requests
+ for that port. Patch from "unixninja92"; implements ticket 9176.
+
+ o Minor features (config options and command line):
+ - Add an --allow-missing-torrc commandline option that tells Tor to
+ run even if the configuration file specified by -f is not available.
+ Implements ticket 10060.
+ - Add support for the TPROXY transparent proxying facility on Linux.
+ See documentation for the new TransProxyType option for more
+ details. Implementation by "thomo". Closes ticket 10582.
+
+ o Minor features (config options):
+ - Config (torrc) lines now handle fingerprints which are missing
+ their initial '$'. Resolves ticket 4341; improvement over 0.0.9pre5.
+ - Support a --dump-config option to print some or all of the
+ configured options. Mainly useful for debugging the command-line
+ option parsing code. Helps resolve ticket 4647.
+ - Raise awareness of safer logging: notify user of potentially
+ unsafe config options, like logging more verbosely than severity
+ "notice" or setting SafeLogging to 0. Resolves ticket 5584.
+ - Add a new configuration option TestingV3AuthVotingStartOffset
+ that bootstraps a network faster by changing the timing for
+ consensus votes. Addresses ticket 8532.
+ - Add a new torrc option "ServerTransportOptions" that allows
+ bridge operators to pass configuration parameters to their
+ pluggable transports. Resolves ticket 8929.
+ - The config (torrc) file now accepts bandwidth and space limits in
+ bits as well as bytes. (Anywhere that you can say "2 Kilobytes",
+ you can now say "16 kilobits", and so on.) Resolves ticket 9214.
+ Patch by CharlieB.
+
+ o Minor features (controller):
+ - Make the entire exit policy available from the control port via
+ GETINFO exit-policy/*. Implements enhancement 7952. Patch from
+ "rl1987".
+ - Because of the fix for ticket 11396, the real limit for memory
+ usage may no longer match the configured MaxMemInQueues value. The
+ real limit is now exposed via GETINFO limits/max-mem-in-queues.
+ - Add a new "HS_DESC" controller event that reports activities
+ related to hidden service descriptors. Resolves ticket 8510.
+ - New "DROPGUARDS" controller command to forget all current entry
+ guards. Not recommended for ordinary use, since replacing guards
+ too frequently makes several attacks easier. Resolves ticket 9934;
+ patch from "ra".
+ - Implement the TRANSPORT_LAUNCHED control port event that
+ notifies controllers about new launched pluggable
+ transports. Resolves ticket 5609.
+
+ o Minor features (diagnostic):
+ - When logging a warning because of bug 7164, additionally check the
+ hash table for consistency (as proposed on ticket 11737). This may
+ help diagnose bug 7164.
+ - When we log a heartbeat, log how many one-hop circuits we have
+ that are at least 30 minutes old, and log status information about
+ a few of them. This is an attempt to track down bug 8387.
+ - When encountering an unexpected CR while writing text to a file on
+ Windows, log the name of the file. Should help diagnosing
+ bug 11233.
+ - Give more specific warnings when a client notices that an onion
+ handshake has failed. Fixes ticket 9635.
+ - Add significant new logging code to attempt to diagnose bug 12184,
+ where relays seem to run out of available circuit IDs.
+ - Improve the diagnostic log message for bug 8387 even further to
+ try to improve our odds of figuring out why one-hop directory
+ circuits sometimes do not get closed.
+ - Add more log messages to diagnose bug 7164, which causes
+ intermittent "microdesc_free() called but md was still referenced"
+ warnings. We now include more information, to figure out why we
+ might be cleaning a microdescriptor for being too old if it's
+ still referenced by a live node_t object.
+ - Log current accounting state (bytes sent and received + remaining
+ time for the current accounting period) in the relay's heartbeat
+ message. Implements ticket 5526; patch from Peter Retzlaff.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the August 7 2014 Maxmind GeoLite2
+ Country database.
+
+ o Minor features (interface):
+ - Generate a warning if any ports are listed in the SocksPolicy,
+ DirPolicy, AuthDirReject, AuthDirInvalid, AuthDirBadDir, or
+ AuthDirBadExit options. (These options only support address
+ ranges.) Fixes part of ticket 11108.
+
+ o Minor features (kernel API usage):
+ - Use the SOCK_NONBLOCK socket type, if supported, to open nonblocking
+ sockets in a single system call. Implements ticket 5129.
+
+ o Minor features (log messages):
+ - When ServerTransportPlugin is set on a bridge, Tor can write more
+ useful statistics about bridge use in its extrainfo descriptors,
+ but only if the Extended ORPort ("ExtORPort") is set too. Add a
+ log message to inform the user in this case. Resolves ticket 9651.
+ - When receiving a new controller connection, log the origin address.
+ Resolves ticket 9698; patch from "sigpipe".
+ - When logging OpenSSL engine status at startup, log the status of
+ more engines. Fixes ticket 10043; patch from Joshua Datko.
+
+ o Minor features (log verbosity):
+ - Demote the message that we give when a flushing connection times
+ out for too long from NOTICE to INFO. It was usually meaningless.
+ Resolves ticket 5286.
+ - Don't log so many notice-level bootstrapping messages at startup
+ about downloading descriptors. Previously, we'd log a notice
+ whenever we learned about more routers. Now, we only log a notice
+ at every 5% of progress. Fixes bug 9963.
+ - Warn less verbosely when receiving a malformed
+ ESTABLISH_RENDEZVOUS cell. Fixes ticket 11279.
+
+ o Minor features (performance):
+ - If we're using the pure-C 32-bit curve25519_donna implementation
+ of curve25519, build it with the -fomit-frame-pointer option to
+ make it go faster on register-starved hosts. This improves our
+ handshake performance by about 6% on i386 hosts without nacl.
+ Closes ticket 8109.
+
+ o Minor features (relay):
+ - If a circuit timed out for at least 3 minutes, check if we have a
+ new external IP address, and publish a new descriptor with the new
+ IP address if it changed. Resolves ticket 2454.
+
+ o Minor features (testing):
+ - If Python is installed, "make check" now runs extra tests beyond
+ the unit test scripts.
+ - When bootstrapping a test network, sometimes very few relays get
+ the Guard flag. Now a new option "TestingDirAuthVoteGuard" can
+ specify a set of relays which should be voted Guard regardless of
+ their uptime or bandwidth. Addresses ticket 9206.
+
+ o Minor features (transparent proxy, *BSD):
+ - Support FreeBSD's ipfw firewall interface for TransPort ports on
+ FreeBSD. To enable it, set "TransProxyType ipfw". Resolves ticket
+ 10267; patch from "yurivict".
+ - Support OpenBSD's divert-to rules with the pf firewall for
+ transparent proxy ports. To enable it, set "TransProxyType
+ pf-divert". This allows Tor to run a TransPort transparent proxy
+ port on OpenBSD 4.4 or later without root privileges. See the
+ pf.conf(5) manual page for information on configuring pf to use
+ divert-to rules. Closes ticket 10896; patch from Dana Koch.
+
+ o Minor bugfixes (bridge client):
+ - Stop accepting bridge lines containing hostnames. Doing so would
+ cause clients to perform DNS requests on the hostnames, which was
+ not sensible behavior. Fixes bug 10801; bugfix on 0.2.0.1-alpha.
+
+ o Minor bugfixes (bridges):
+ - Avoid potential crashes or bad behavior when launching a
+ server-side managed proxy with ORPort or ExtORPort temporarily
+ disabled. Fixes bug 9650; bugfix on 0.2.3.16-alpha.
+ - Fix a bug where the first connection works to a bridge that uses a
+ pluggable transport with client-side parameters, but we don't send
+ the client-side parameters on subsequent connections. (We don't
+ use any pluggable transports with client-side parameters yet,
+ but ScrambleSuit will soon become the first one.) Fixes bug 9162;
+ bugfix on 0.2.0.3-alpha. Based on a patch from "rl1987".
+
+ o Minor bugfixes (build, auxiliary programs):
+ - Stop preprocessing the "torify" script with autoconf, since
+ it no longer refers to LOCALSTATEDIR. Fixes bug 5505; patch
+ from Guilhem.
+ - The tor-fw-helper program now follows the standard convention and
+ exits with status code "0" on success. Fixes bug 9030; bugfix on
+ 0.2.3.1-alpha. Patch by Arlo Breault.
+ - Corrected ./configure advice for what openssl dev package you should
+ install on Debian. Fixes bug 9207; bugfix on 0.2.0.1-alpha.
+
+ o Minor bugfixes (client):
+ - Avoid "Tried to open a socket with DisableNetwork set" warnings
+ when starting a client with bridges configured and DisableNetwork
+ set. (Tor launcher starts Tor with DisableNetwork set the first
+ time it runs.) Fixes bug 10405; bugfix on 0.2.3.9-alpha.
+ - Improve the log message when we can't connect to a hidden service
+ because all of the hidden service directory nodes hosting its
+ descriptor are excluded. Improves on our fix for bug 10722, which
+ was a bugfix on 0.2.0.10-alpha.
+ - Raise a control port warning when we fail to connect to all of
+ our bridges. Previously, we didn't inform the controller, and
+ the bootstrap process would stall. Fixes bug 11069; bugfix on
+ 0.2.1.2-alpha.
+ - Exit immediately when a process-owning controller exits.
+ Previously, tor relays would wait for a little while after their
+ controller exited, as if they had gotten an INT signal -- but this
+ was problematic, since there was no feedback for the user. To do a
+ clean shutdown, controllers should send an INT signal and give Tor
+ a chance to clean up. Fixes bug 10449; bugfix on 0.2.2.28-beta.
+ - Stop attempting to connect to bridges before our pluggable
+ transports are configured (harmless but resulted in some erroneous
+ log messages). Fixes bug 11156; bugfix on 0.2.3.2-alpha.
+ - Fix connections to IPv6 addresses over SOCKS5. Previously, we were
+ generating incorrect SOCKS5 responses, and confusing client
+ applications. Fixes bug 10987; bugfix on 0.2.4.7-alpha.
+
+ o Minor bugfixes (client, DNSPort):
+ - When using DNSPort, try to respond to AAAA requests with AAAA
+ answers. Previously, we hadn't looked at the request type when
+ deciding which answer type to prefer. Fixes bug 10468; bugfix on
+ 0.2.4.7-alpha.
+ - When receiving a DNS query for an unsupported record type, reply
+ with no answer rather than with a NOTIMPL error. This behavior
+ isn't correct either, but it will break fewer client programs, we
+ hope. Fixes bug 10268; bugfix on 0.2.0.1-alpha. Original patch
+ from "epoch".
+
+ o Minor bugfixes (client, logging during bootstrap):
+ - Only report the first fatal bootstrap error on a given OR
+ connection. This stops us from telling the controller bogus error
+ messages like "DONE". Fixes bug 10431; bugfix on 0.2.1.1-alpha.
+ - Avoid generating spurious warnings when starting with
+ DisableNetwork enabled. Fixes bug 11200 and bug 10405; bugfix on
+ 0.2.3.9-alpha.
+
+ o Minor bugfixes (closing OR connections):
+ - If write_to_buf() in connection_write_to_buf_impl_() ever fails,
+ check if it's an or_connection_t and correctly call
+ connection_or_close_for_error() rather than
+ connection_mark_for_close() directly. Fixes bug 11304; bugfix on
+ 0.2.4.4-alpha.
+ - When closing all connections on setting DisableNetwork to 1, use
+ connection_or_close_normally() rather than closing OR connections
+ out from under the channel layer. Fixes bug 11306; bugfix on
+ 0.2.4.4-alpha.
+
+ o Minor bugfixes (code correctness):
+ - Previously we used two temporary files when writing descriptors to
+ disk; now we only use one. Fixes bug 1376.
+ - Remove an erroneous (but impossible and thus harmless) pointer
+ comparison that would have allowed compilers to skip a bounds
+ check in channeltls.c. Fixes bugs 10313 and 9980; bugfix on
+ 0.2.0.10-alpha. Noticed by Jared L Wong and David Fifield.
+ - Fix an always-true assertion in pluggable transports code so it
+ actually checks what it was trying to check. Fixes bug 10046;
+ bugfix on 0.2.3.9-alpha. Found by "dcb".
+
+ o Minor bugfixes (command line):
+ - Use a single command-line parser for parsing torrc options on the
+ command line and for finding special command-line options to avoid
+ inconsistent behavior for torrc option arguments that have the same
+ names as command-line options. Fixes bugs 4647 and 9578; bugfix on
+ 0.0.9pre5.
+ - No longer allow 'tor --hash-password' with no arguments. Fixes bug
+ 9573; bugfix on 0.0.9pre5.
+
+ o Minor bugfixes (compilation):
+ - Compile correctly with builds and forks of OpenSSL (such as
+ LibreSSL) that disable compression. Fixes bug 12602; bugfix on
+ 0.2.1.1-alpha. Patch from "dhill".
+ - Restore the ability to compile Tor with V2_HANDSHAKE_SERVER
+ turned off (that is, without support for v2 link handshakes). Fixes
+ bug 4677; bugfix on 0.2.3.2-alpha. Patch from "piet".
+ - In routerlist_assert_ok(), don't take the address of a
+ routerinfo's cache_info member unless that routerinfo is non-NULL.
+ Fixes bug 13096; bugfix on 0.1.1.9-alpha. Patch by "teor".
+ - Fix a large number of false positive warnings from the clang
+ analyzer static analysis tool. This should make real warnings
+ easier for clang analyzer to find. Patch from "teor". Closes
+ ticket 13036.
+ - Resolve GCC complaints on OpenBSD about discarding constness in
+ TO_{ORIGIN,OR}_CIRCUIT functions. Fixes part of bug 11633; bugfix
+ on 0.1.1.23. Patch from Dana Koch.
+ - Resolve clang complaints on OpenBSD with -Wshorten-64-to-32 due to
+ treatment of long and time_t as comparable types. Fixes part of
+ bug 11633. Patch from Dana Koch.
+ - When deciding whether to build the 64-bit curve25519
+ implementation, detect platforms where we can compile 128-bit
+ arithmetic but cannot link it. Fixes bug 11729; bugfix on
+ 0.2.4.8-alpha. Patch from "conradev".
+ - Fix compilation when DNS_CACHE_DEBUG is enabled. Fixes bug 11761;
+ bugfix on 0.2.3.13-alpha. Found by "cypherpunks".
+ - Fix compilation with dmalloc. Fixes bug 11605; bugfix
+ on 0.2.4.10-alpha.
+ - Build and run correctly on systems like OpenBSD-current that have
+ patched OpenSSL to remove get_cipher_by_char and/or its
+ implementations. Fixes issue 13325.
+
+ o Minor bugfixes (controller and command-line):
+ - If changing a config option via "setconf" fails in a recoverable
+ way, we used to nonetheless write our new control ports to the
+ file described by the "ControlPortWriteToFile" option. Now we only
+ write out that file if we successfully switch to the new config
+ option. Fixes bug 5605; bugfix on 0.2.2.26-beta. Patch from "Ryman".
+
+ o Minor bugfixes (directory server):
+ - No longer accept malformed http headers when parsing urls from
+ headers. Now we reply with Bad Request ("400"). Fixes bug 2767;
+ bugfix on 0.0.6pre1.
+ - When sending a compressed set of descriptors or microdescriptors,
+ make sure to finalize the zlib stream. Previously, we would write
+ all the compressed data, but if the last descriptor we wanted to
+ send was missing or too old, we would not mark the stream as
+ finished. This caused problems for decompression tools. Fixes bug
+ 11648; bugfix on 0.1.1.23.
+
+ o Minor bugfixes (hidden service):
+ - Only retry attempts to connect to a chosen rendezvous point 8
+ times, not 30. Fixes bug 4241; bugfix on 0.1.0.1-rc.
+
+ o Minor bugfixes (interface):
+ - Reject relative control socket paths and emit a warning. Previously,
+ single-component control socket paths would be rejected, but Tor
+ would not log why it could not validate the config. Fixes bug 9258;
+ bugfix on 0.2.3.16-alpha.
+
+ o Minor bugfixes (log messages):
+ - Fix a bug where clients using bridges would report themselves
+ as 50% bootstrapped even without a live consensus document.
+ Fixes bug 9922; bugfix on 0.2.1.1-alpha.
+ - Suppress a warning where, if there's only one directory authority
+ in the network, we would complain that votes and signatures cannot
+ be uploaded to other directory authorities. Fixes bug 10842;
+ bugfix on 0.2.2.26-beta.
+ - Report bootstrapping progress correctly when we're downloading
+ microdescriptors. We had updated our "do we have enough microdescs
+ to begin building circuits?" logic most recently in 0.2.4.10-alpha
+ (see bug 5956), but we left the bootstrap status event logic at
+ "how far through getting 1/4 of them are we?" Fixes bug 9958;
+ bugfix on 0.2.2.36, which is where they diverged (see bug 5343).
+
+ o Minor bugfixes (logging):
+ - Downgrade "Unexpected onionskin length after decryption" warning
+ to a protocol-warn, since there's nothing relay operators can do
+ about a client that sends them a malformed create cell. Resolves
+ bug 12996; bugfix on 0.0.6rc1.
+ - Log more specific warnings when we get an ESTABLISH_RENDEZVOUS
+ cell on a cannibalized or non-OR circuit. Resolves ticket 12997.
+ - When logging information about an EXTEND2 or EXTENDED2 cell, log
+ their names correctly. Fixes part of bug 12700; bugfix
+ on 0.2.4.8-alpha.
+ - When logging information about a relay cell whose command we don't
+ recognize, log its command as an integer. Fixes part of bug 12700;
+ bugfix on 0.2.1.10-alpha.
+ - Escape all strings from the directory connection before logging
+ them. Fixes bug 13071; bugfix on 0.1.1.15. Patch from "teor".
+ - Squelch a spurious LD_BUG message "No origin circuit for
+ successful SOCKS stream" in certain hidden service failure cases;
+ fixes bug 10616.
+ - Downgrade the severity of the 'unexpected sendme cell from client'
+ from 'warn' to 'protocol warning'. Closes ticket 8093.
+
+ o Minor bugfixes (misc code correctness):
+ - In munge_extrainfo_into_routerinfo(), check the return value of
+ memchr(). This would have been a serious issue if we ever passed
+ it a non-extrainfo. Fixes bug 8791; bugfix on 0.2.0.6-alpha. Patch
+ from Arlo Breault.
+ - On the chance that somebody manages to build Tor on a
+ platform where time_t is unsigned, correct the way that
+ microdesc_add_to_cache() handles negative time arguments.
+ Fixes bug 8042; bugfix on 0.2.3.1-alpha.
+ - Fix various instances of undefined behavior in channeltls.c,
+ tor_memmem(), and eventdns.c that would cause us to construct
+ pointers to memory outside an allocated object. (These invalid
+ pointers were not accessed, but C does not even allow them to
+ exist.) Fixes bug 10363; bugfixes on 0.1.1.1-alpha, 0.1.2.1-alpha,
+ 0.2.0.10-alpha, and 0.2.3.6-alpha. Reported by "bobnomnom".
+ - Use the AddressSanitizer and Ubsan sanitizers (in clang-3.4) to
+ fix some miscellaneous errors in our tests and codebase. Fixes bug
+ 11232. Bugfixes on versions back as far as 0.2.1.11-alpha.
+ - Always check return values for unlink, munmap, UnmapViewOfFile;
+ check strftime return values more often. In some cases all we can
+ do is report a warning, but this may help prevent deeper bugs from
+ going unnoticed. Closes ticket 8787; bugfixes on many, many tor
+ versions.
+ - Fix numerous warnings from the clang "scan-build" static analyzer.
+ Some of these are programming style issues; some of them are false
+ positives that indicated awkward code; some are undefined behavior
+ cases related to constructing (but not using) invalid pointers;
+ some are assumptions about API behavior; some are (harmlessly)
+ logging sizeof(ptr) bytes from a token when sizeof(*ptr) would be
+ correct; and one or two are genuine bugs that weren't reachable
+ from the rest of the program. Fixes bug 8793; bugfixes on many,
+ many tor versions.
+
+ o Minor bugfixes (node selection):
+ - If ExcludeNodes is set, consider non-excluded hidden service
+ directory servers before excluded ones. Do not consider excluded
+ hidden service directory servers at all if StrictNodes is
+ set. (Previously, we would sometimes decide to connect to those
+ servers, and then realize before we initiated a connection that
+ we had excluded them.) Fixes bug 10722; bugfix on 0.2.0.10-alpha.
+ Reported by "mr-4".
+ - If we set the ExitNodes option but it doesn't include any nodes
+ that have the Exit flag, we would choose not to bootstrap. Now we
+ bootstrap so long as ExitNodes includes nodes which can exit to
+ some port. Fixes bug 10543; bugfix on 0.2.4.10-alpha.
+
+ o Minor bugfixes (performance):
+ - Avoid a bug where every successful connection made us recompute
+ the flag telling us whether we have sufficient information to
+ build circuits. Previously, we would forget our cached value
+ whenever we successfully opened a channel (or marked a router as
+ running or not running for any other reason), regardless of
+ whether we had previously believed the router to be running. This
+ forced us to run an expensive update operation far too often.
+ Fixes bug 12170; bugfix on 0.1.2.1-alpha.
+ - Avoid using tor_memeq() for checking relay cell integrity. This
+ removes a possible performance bottleneck. Fixes part of bug
+ 12169; bugfix on 0.2.1.31.
+
+ o Minor bugfixes (platform-specific):
+ - When dumping a malformed directory object to disk, save it in
+ binary mode on Windows, not text mode. Fixes bug 11342; bugfix on
+ 0.2.2.1-alpha.
+ - Don't report failures from make_socket_reuseable() on incoming
+ sockets on OSX: this can happen when incoming connections close
+ early. Fixes bug 10081.
+
+ o Minor bugfixes (pluggable transports):
+ - Avoid another 60-second delay when starting Tor in a pluggable-
+ transport-using configuration when we already have cached
+ descriptors for our bridges. Fixes bug 11965; bugfix
+ on 0.2.3.6-alpha.
+
+ o Minor bugfixes (protocol correctness):
+ - When receiving a VERSIONS cell with an odd number of bytes, close
+ the connection immediately since the cell is malformed. Fixes bug
+ 10365; bugfix on 0.2.0.10-alpha. Spotted by "bobnomnom"; fix by
+ "rl1987".
+
+ o Minor bugfixes (relay, other):
+ - We now drop CREATE cells for already-existent circuit IDs and for
+ zero-valued circuit IDs, regardless of other factors that might
+ otherwise have called for DESTROY cells. Fixes bug 12191; bugfix
+ on 0.0.8pre1.
+ - When rejecting DATA cells for stream_id zero, still count them
+ against the circuit's deliver window so that we don't fail to send
+ a SENDME. Fixes bug 11246; bugfix on 0.2.4.10-alpha.
+
+ o Minor bugfixes (relay, threading):
+ - Check return code on spawn_func() in cpuworker code, so that we
+ don't think we've spawned a nonworking cpuworker and write junk to
+ it forever. Fix related to bug 4345; bugfix on all released Tor
+ versions. Found by "skruffy".
+ - Use a pthread_attr to make sure that spawn_func() cannot return an
+ error while at the same time launching a thread. Fix related to
+ bug 4345; bugfix on all released Tor versions. Reported
+ by "cypherpunks".
+
+ o Minor bugfixes (relays and bridges):
+ - Avoid crashing on a malformed resolv.conf file when running a
+ relay using Libevent 1. Fixes bug 8788; bugfix on 0.1.1.23.
+ - Non-exit relays no longer launch mock DNS requests to check for
+ DNS hijacking. This has been unnecessary since 0.2.1.7-alpha, when
+ non-exit relays stopped servicing DNS requests. Fixes bug 965;
+ bugfix on 0.2.1.7-alpha. Patch from Matt Pagan.
+ - Bridges now report complete directory request statistics. Related
+ to bug 5824; bugfix on 0.2.2.1-alpha.
+ - Bridges now never collect statistics that were designed for
+ relays. Fixes bug 5824; bugfix on 0.2.3.8-alpha.
+
+ o Minor bugfixes (testing):
+ - Fix all valgrind warnings produced by the unit tests. There were
+ over a thousand memory leak warnings previously, mostly produced
+ by forgetting to free things in the unit test code. Fixes bug
+ 11618, bugfixes on many versions of Tor.
+
+ o Minor bugfixes (tor-fw-helper):
+ - Give a correct log message when tor-fw-helper fails to launch.
+ (Previously, we would say something like "tor-fw-helper sent us a
+ string we could not parse".) Fixes bug 9781; bugfix
+ on 0.2.4.2-alpha.
+
+ o Minor bugfixes (trivial memory leaks):
+ - Fix a small memory leak when signing a directory object. Fixes bug
+ 11275; bugfix on 0.2.4.13-alpha.
+ - Resolve some memory leaks found by coverity in the unit tests, on
+ exit in tor-gencert, and on a failure to compute digests for our
+ own keys when generating a v3 networkstatus vote. These leaks
+ should never have affected anyone in practice.
+
+ o Code simplification and refactoring:
+ - Remove some old fallback code designed to keep Tor clients working
+ in a network with only two working relays. Elsewhere in the code we
+ have long since stopped supporting such networks, so there wasn't
+ much point in keeping it around. Addresses ticket 9926.
+ - Reject 0-length EXTEND2 cells more explicitly. Fixes bug 10536;
+ bugfix on 0.2.4.8-alpha. Reported by "cypherpunks".
+ - Extract the common duplicated code for creating a subdirectory
+ of the data directory and writing to a file in it. Fixes ticket
+ 4282; patch from Peter Retzlaff.
+ - Since OpenSSL 0.9.7, the i2d_*() functions support allocating output
+ buffer. Avoid calling twice: i2d_RSAPublicKey(), i2d_DHparams(),
+ i2d_X509(), and i2d_PublicKey(). Resolves ticket 5170.
+ - Add a set of accessor functions for the circuit timeout data
+ structure. Fixes ticket 6153; patch from "piet".
+ - Clean up exit paths from connection_listener_new(). Closes ticket
+ 8789. Patch from Arlo Breault.
+ - Since we rely on OpenSSL 0.9.8 now, we can use EVP_PKEY_cmp()
+ and drop our own custom pkey_eq() implementation. Fixes bug 9043.
+ - Use a doubly-linked list to implement the global circuit list.
+ Resolves ticket 9108. Patch from Marek Majkowski.
+ - Remove contrib/id_to_fp.c since it wasn't used anywhere.
+ - Remove constants and tests for PKCS1 padding; it's insecure and
+ shouldn't be used for anything new. Fixes bug 8792; patch
+ from Arlo Breault.
+ - Remove instances of strcpy() from the unit tests. They weren't
+ hurting anything, since they were only in the unit tests, but it's
+ embarassing to have strcpy() in the code at all, and some analysis
+ tools don't like it. Fixes bug 8790; bugfix on 0.2.3.6-alpha and
+ 0.2.3.8-alpha. Patch from Arlo Breault.
+ - Remove is_internal_IP() function. Resolves ticket 4645.
+ - Remove unused function circuit_dump_by_chan from circuitlist.c.
+ Closes issue 9107; patch from "marek".
+ - Change our use of the ENUM_BF macro to avoid declarations that
+ confuse Doxygen.
+ - Get rid of router->address, since in all cases it was just the
+ string representation of router->addr. Resolves ticket 5528.
+
+ o Documentation:
+ - Adjust the URLs in the README to refer to the new locations of
+ several documents on the website. Fixes bug 12830. Patch from
+ Matt Pagan.
+ - Document 'reject6' and 'accept6' ExitPolicy entries. Resolves
+ ticket 12878.
+ - Update manpage to describe some of the files you can expect to
+ find in Tor's DataDirectory. Addresses ticket 9839.
+ - Clean up several option names in the manpage to match their real
+ names, add the missing documentation for a couple of testing and
+ directory authority options, remove the documentation for a
+ V2-directory fetching option that no longer exists. Resolves
+ ticket 11634.
+ - Correct the documenation so that it lists the correct directory
+ for the stats files. (They are in a subdirectory called "stats",
+ not "status".)
+ - In the manpage, move more authority-only options into the
+ directory authority section so that operators of regular directory
+ caches don't get confused.
+ - Fix the layout of the SOCKSPort flags in the manpage. Fixes bug
+ 11061; bugfix on 0.2.4.7-alpha.
+ - Resolve warnings from Doxygen.
+ - Document in the manpage that "KBytes" may also be written as
+ "kilobytes" or "KB", that "Kbits" may also be written as
+ "kilobits", and so forth. Closes ticket 9222.
+ - Document that the ClientOnly config option overrides ORPort.
+ Our old explanation made ClientOnly sound as though it did
+ nothing at all. Resolves bug 9059.
+ - Explain that SocksPolicy, DirPolicy, and similar options don't
+ take port arguments. Fixes the other part of ticket 11108.
+ - Fix a comment about the rend_server_descriptor_t.protocols field
+ to more accurately describe its range. Also, make that field
+ unsigned, to more accurately reflect its usage. Fixes bug 9099;
+ bugfix on 0.2.1.5-alpha.
+ - Fix the manpage's description of HiddenServiceAuthorizeClient:
+ the maximum client name length is 16, not 19. Fixes bug 11118;
+ bugfix on 0.2.1.6-alpha.
+
+ o Package cleanup:
+ - The contrib directory has been sorted and tidied. Before, it was
+ an unsorted dumping ground for useful and not-so-useful things.
+ Now, it is divided based on functionality, and the items which
+ seemed to be nonfunctional or useless have been removed. Resolves
+ ticket 8966; based on patches from "rl1987".
+
+ o Removed code and features:
+ - Clients now reject any directory authority certificates lacking
+ a dir-key-crosscert element. These have been included since
+ 0.2.1.9-alpha, so there's no real reason for them to be optional
+ any longer. Completes proposal 157. Resolves ticket 10162.
+ - Remove all code that existed to support the v2 directory system,
+ since there are no longer any v2 directory authorities. Resolves
+ ticket 10758.
+ - Remove the HSAuthoritativeDir and AlternateHSAuthority torrc
+ options, which were used for designating authorities as "Hidden
+ service authorities". There has been no use of hidden service
+ authorities since 0.2.2.1-alpha, when we stopped uploading or
+ downloading v0 hidden service descriptors. Fixes bug 10881; also
+ part of a fix for bug 10841.
+ - Remove /tor/dbg-stability.txt URL that was meant to help debug WFU
+ and MTBF calculations, but that nobody was using. Fixes bug 11742.
+ - The TunnelDirConns and PreferTunnelledDirConns options no longer
+ exist; tunneled directory connections have been available since
+ 0.1.2.5-alpha, and turning them off is not a good idea. This is a
+ brute-force fix for 10849, where "TunnelDirConns 0" would break
+ hidden services.
+ - Remove all code for the long unused v1 directory protocol.
+ Resolves ticket 11070.
+ - Remove all remaining code related to version-0 hidden service
+ descriptors: they have not been in use since 0.2.2.1-alpha. Fixes
+ the rest of bug 10841.
+ - Remove migration code from when we renamed the "cached-routers"
+ file to "cached-descriptors" back in 0.2.0.8-alpha. This
+ incidentally resolves ticket 6502 by cleaning up the related code
+ a bit. Patch from Akshay Hebbar.
+
+ o Test infrastructure:
+ - Tor now builds each source file in two modes: a mode that avoids
+ exposing identifiers needlessly, and another mode that exposes
+ more identifiers for testing. This lets the compiler do better at
+ optimizing the production code, while enabling us to take more
+ radical measures to let the unit tests test things.
+ - The production builds no longer include functions used only in
+ the unit tests; all functions exposed from a module only for
+ unit-testing are now static in production builds.
+ - Add an --enable-coverage configuration option to make the unit
+ tests (and a new src/or/tor-cov target) to build with gcov test
+ coverage support.
+ - Update to the latest version of tinytest.
+ - Improve the tinytest implementation of string operation tests so
+ that comparisons with NULL strings no longer crash the tests; they
+ now just fail, normally. Fixes bug 9004; bugfix on 0.2.2.4-alpha.
+ - New macros in test.h to simplify writing mock-functions for unit
+ tests. Part of ticket 11507. Patch from Dana Koch.
+ - We now have rudimentary function mocking support that our unit
+ tests can use to test functions in isolation. Function mocking
+ lets the tests temporarily replace a function's dependencies with
+ stub functions, so that the tests can check the function without
+ invoking the other functions it calls.
+
+ o Testing:
+ - Complete tests for the status.c module. Resolves ticket 11507.
+ Patch from Dana Koch.
+ - Add more unit tests for the <circid,channel>->circuit map, and
+ the destroy-cell-tracking code to fix bug 7912.
+ - Unit tests for failing cases of the TAP onion handshake.
+ - More unit tests for address-manipulation functions.
+
+ o Distribution (systemd):
+ - Include a tor.service file in contrib/dist for use with systemd.
+ Some distributions will be able to use this file unmodified;
+ others will need to tweak it, or write their own. Patch from Jamie
+ Nguyen; resolves ticket 8368.
+ - Verify configuration file via ExecStartPre in the systemd unit
+ file. Patch from intrigeri; resolves ticket 12730.
+ - Explicitly disable RunAsDaemon in the systemd unit file. Our
+ current systemd unit uses "Type = simple", so systemd does not
+ expect tor to fork. If the user has "RunAsDaemon 1" in their
+ torrc, then things won't work as expected. This is e.g. the case
+ on Debian (and derivatives), since there we pass "--defaults-torrc
+ /usr/share/tor/tor-service-defaults-torrc" (that contains
+ "RunAsDaemon 1") by default. Patch by intrigeri; resolves
+ ticket 12731.
+
+
+Changes in version 0.2.4.25 - 2014-10-20
+ Tor 0.2.4.25 disables SSL3 in response to the recent "POODLE" attack
+ (even though POODLE does not affect Tor). It also works around a crash
+ bug caused by some operating systems' response to the "POODLE" attack
+ (which does affect Tor).
+
+ o Major security fixes (also in 0.2.5.9-rc):
+ - Disable support for SSLv3. All versions of OpenSSL in use with Tor
+ today support TLS 1.0 or later, so we can safely turn off support
+ for this old (and insecure) protocol. Fixes bug 13426.
+
+ o Major bugfixes (openssl bug workaround, also in 0.2.5.9-rc):
+ - Avoid crashing when using OpenSSL version 0.9.8zc, 1.0.0o, or
+ 1.0.1j, built with the 'no-ssl3' configuration option. Fixes bug
+ 13471. This is a workaround for an OpenSSL bug.
+
+
+Changes in version 0.2.4.24 - 2014-09-22
+ Tor 0.2.4.24 fixes a bug that affects consistency and speed when
+ connecting to hidden services, and it updates the location of one of
+ the directory authorities.
+
+ o Major bugfixes:
+ - Clients now send the correct address for their chosen rendezvous
+ point when trying to access a hidden service. They used to send
+ the wrong address, which would still work some of the time because
+ they also sent the identity digest of the rendezvous point, and if
+ the hidden service happened to try connecting to the rendezvous
+ point from a relay that already had a connection open to it,
+ the relay would reuse that connection. Now connections to hidden
+ services should be more robust and faster. Also, this bug meant
+ that clients were leaking to the hidden service whether they were
+ on a little-endian (common) or big-endian (rare) system, which for
+ some users might have reduced their anonymity. Fixes bug 13151;
+ bugfix on 0.2.1.5-alpha.
+
+ o Directory authority changes:
+ - Change IP address for gabelmoo (v3 directory authority).
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the August 7 2014 Maxmind GeoLite2
+ Country database.
+
+
+Changes in version 0.2.4.23 - 2014-07-28
+ Tor 0.2.4.23 brings us a big step closer to slowing down the risk from
+ guard rotation, and also backports several important fixes from the
+ Tor 0.2.5 alpha release series.
+
+ o Major features:
+ - Clients now look at the "usecreatefast" consensus parameter to
+ decide whether to use CREATE_FAST or CREATE cells for the first hop
+ of their circuit. This approach can improve security on connections
+ where Tor's circuit handshake is stronger than the available TLS
+ connection security levels, but the tradeoff is more computational
+ load on guard relays. Implements proposal 221. Resolves ticket 9386.
+ - Make the number of entry guards configurable via a new
+ NumEntryGuards consensus parameter, and the number of directory
+ guards configurable via a new NumDirectoryGuards consensus
+ parameter. Implements ticket 12688.
+
+ o Major bugfixes:
+ - Fix a bug in the bounds-checking in the 32-bit curve25519-donna
+ implementation that caused incorrect results on 32-bit
+ implementations when certain malformed inputs were used along with
+ a small class of private ntor keys. This bug does not currently
+ appear to allow an attacker to learn private keys or impersonate a
+ Tor server, but it could provide a means to distinguish 32-bit Tor
+ implementations from 64-bit Tor implementations. Fixes bug 12694;
+ bugfix on 0.2.4.8-alpha. Bug found by Robert Ransom; fix from
+ Adam Langley.
+
+ o Minor bugfixes:
+ - Warn and drop the circuit if we receive an inbound 'relay early'
+ cell. Those used to be normal to receive on hidden service circuits
+ due to bug 1038, but the buggy Tor versions are long gone from
+ the network so we can afford to resume watching for them. Resolves
+ the rest of bug 1038; bugfix on 0.2.1.19.
+ - Correct a confusing error message when trying to extend a circuit
+ via the control protocol but we don't know a descriptor or
+ microdescriptor for one of the specified relays. Fixes bug 12718;
+ bugfix on 0.2.3.1-alpha.
+ - Avoid an illegal read from stack when initializing the TLS
+ module using a version of OpenSSL without all of the ciphers
+ used by the v2 link handshake. Fixes bug 12227; bugfix on
+ 0.2.4.8-alpha. Found by "starlight".
+
+ o Minor features:
+ - Update geoip and geoip6 to the July 10 2014 Maxmind GeoLite2
+ Country database.
+
+
Changes in version 0.2.4.22 - 2014-05-16
Tor 0.2.4.22 backports numerous high-priority fixes from the Tor 0.2.5
alpha release series. These include blocking all authority signing
@@ -1908,7 +2883,7 @@ Changes in version 0.2.3.25 - 2012-11-19
but not that other sensitive operations on the client and service
side are not performed using single-hop circuits. Fixes bug 3332;
bugfix on 0.0.6.
- - Avoid undefined behaviour when parsing the list of supported
+ - Avoid undefined behavior when parsing the list of supported
rendezvous/introduction protocols in a hidden service descriptor.
Previously, Tor would have confused (as-yet-unused) protocol version
numbers greater than 32 with lower ones on many platforms. Fixes
@@ -1926,7 +2901,7 @@ Changes in version 0.2.3.25 - 2012-11-19
o Minor bugfixes (hidden services, service-side):
- Don't close hidden-service-side rendezvous circuits when they
- reach the normal circuit-build timeout. This behaviour change can
+ reach the normal circuit-build timeout. This behavior change can
be disabled using the new
CloseHSServiceRendCircuitsImmediatelyOnTimeout option. Fixes the
remaining part of bug 1297; bugfix on 0.2.2.2-alpha.
@@ -3755,7 +4730,7 @@ Changes in version 0.2.2.32 - 2011-08-27
- Resolve an edge case in path weighting that could make us misweight
our relay selection. Fixes bug 1203; bugfix on 0.0.8rc1.
- Make the DNSPort option work with libevent 2.x. Don't alter the
- behaviour for libevent 1.x. Fixes bug 1143. Found by SwissTorExit.
+ behavior for libevent 1.x. Fixes bug 1143. Found by SwissTorExit.
o Minor bugfixes (directory authorities):
- Make directory authorities more accurate at recording when
@@ -3970,14 +4945,14 @@ Changes in version 0.2.2.32 - 2011-08-27
passing it to the kernel. (Not a security issue: kernels are
smart enough to reject bad sockaddr_uns.) Found by Coverity;
CID #428. Bugfix on Tor 0.2.0.3-alpha.
- - Make connection_printf_to_buf()'s behaviour sane. Its callers
+ - Make connection_printf_to_buf()'s behavior sane. Its callers
expect it to emit a CRLF iff the format string ends with CRLF;
it actually emitted a CRLF iff (a) the format string ended with
CRLF or (b) the resulting string was over 1023 characters long or
(c) the format string did not end with CRLF *and* the resulting
string was 1021 characters long or longer. Bugfix on 0.1.1.9-alpha;
fixes part of bug 3407.
- - Make send_control_event_impl()'s behaviour sane. Its callers
+ - Make send_control_event_impl()'s behavior sane. Its callers
expect it to always emit a CRLF at the end of the string; it
might have emitted extra control characters as well. Bugfix on
0.1.1.9-alpha; fixes another part of bug 3407.
diff --git a/acinclude.m4 b/acinclude.m4
index 7401e0b242..8782a3eeaa 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -2,7 +2,7 @@ dnl Helper macros for Tor configure.ac
dnl Copyright (c) 2001-2004, Roger Dingledine
dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
dnl Copyright (c) 2007-2008, Roger Dingledine, Nick Mathewson
-dnl Copyright (c) 2007-2013, The Tor Project, Inc.
+dnl Copyright (c) 2007-2015, The Tor Project, Inc.
dnl See LICENSE for licensing information
AC_DEFUN([TOR_EXTEND_CODEPATH],
diff --git a/changes/13295 b/changes/13295
deleted file mode 100644
index 433432595f..0000000000
--- a/changes/13295
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes:
- - Disable sandbox name resolver cache when running tor-resolve:
- tor-resolve doesn't use the sandbox code, and turning it on was
- breaking attempts to do tor-resolve on a non-default server on
- Linux. Fixes bug 13295; bugfix on 0.2.5.3-alpha.
diff --git a/changes/15188 b/changes/15188
new file mode 100644
index 0000000000..2065b3974c
--- /dev/null
+++ b/changes/15188
@@ -0,0 +1,3 @@
+ o Minor bugfixes (testing):
+ - Avoid a side-effect in a tor_assert() in the unit tests. Fixes bug
+ 15188; bugfix on 0.1.2.3-alpha. Patch from Tom van der Woerdt.
diff --git a/changes/buf-sentinel b/changes/buf-sentinel
new file mode 100644
index 0000000000..7c5b829c19
--- /dev/null
+++ b/changes/buf-sentinel
@@ -0,0 +1,11 @@
+ o Major features (security fixes):
+
+ - Prevent a class of security bugs caused by treating the contents
+ of a buffer chunk as if they were a NUL-terminated string. At
+ least one such bug seems to be present in all currently used
+ versions of Tor, and would allow an attacker to remotely crash
+ most Tor instances, especially those compiled with extra compiler
+ hardening. With this defense in place, such bugs can't crash Tor,
+ though we should still fix them as they occur. Closes ticket 20384
+ (TROVE-2016-10-001).
+
diff --git a/changes/bufferevent_compilation b/changes/bufferevent_compilation
deleted file mode 100644
index 3a328731fe..0000000000
--- a/changes/bufferevent_compilation
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes:
- - Fix compilation when building with bufferevents enabled. (This
- configuration is still not expected to work, however.)
- Fixes bugs 12438, 12474, 11578; bugfixes on 0.2.5.1-alpha and
- 0.2.5.3-alpha. Patches from Anthony G. Basile and Sathyanarayanan
- Gunasekaran.
diff --git a/changes/bug1038-3 b/changes/bug1038-3
deleted file mode 100644
index 5af4afa46f..0000000000
--- a/changes/bug1038-3
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes:
- - Warn and drop the circuit if we receive an inbound 'relay early'
- cell. Those used to be normal to receive on hidden service circuits
- due to bug 1038, but the buggy Tor versions are long gone from
- the network so we can afford to resume watching for them. Resolves
- the rest of bug 1038; bugfix on 0.2.1.19.
diff --git a/changes/bug11200-caching b/changes/bug11200-caching
deleted file mode 100644
index e3fbaeca73..0000000000
--- a/changes/bug11200-caching
+++ /dev/null
@@ -1,7 +0,0 @@
- o Major bugfixes:
- - When Tor starts with DisabledNetwork set, it would correctly
- conclude that it shouldn't try making circuits, but it would
- mistakenly cache this conclusion and continue believing it even
- when DisableNetwork is set to 0. Fixes the bug introduced by the
- fix for bug 11200; bugfix on 0.2.5.4-alpha.
-
diff --git a/changes/bug11447 b/changes/bug11447
new file mode 100644
index 0000000000..8cd4f5b467
--- /dev/null
+++ b/changes/bug11447
@@ -0,0 +1,5 @@
+ o Minor features (DoS-resistance):
+ - Decrease the amount of reattempts that a hidden service is
+ willing to perform when its rendezvous circuits fail. This
+ reduces the computational cost for hidden service under heavy
+ load. Resolves ticket #11447. \ No newline at end of file
diff --git a/changes/bug11454 b/changes/bug11454
new file mode 100644
index 0000000000..b37a7d9728
--- /dev/null
+++ b/changes/bug11454
@@ -0,0 +1,6 @@
+ o Minor bugfixes (certificate handling):
+ - Remove any old authority certificates that have been superseded
+ for at least two days. Previously, we would keep superseded
+ certificates until they expired, if they were published close
+ in time to the certificate that superseded them.
+ Fixes bug 11454; bugfix on 0.2.1.8-alpha.
diff --git a/changes/bug11457 b/changes/bug11457
new file mode 100644
index 0000000000..cf64c1d10d
--- /dev/null
+++ b/changes/bug11457
@@ -0,0 +1,5 @@
+ o Minor bugfixes (certificate handling):
+ - If an authority operator accidentally makes a signing certificate with
+ a future publication time, do not discard its real signing
+ certificates. Fixes bug 11457; bugfix on 0.2.0.3-alpha.
+
diff --git a/changes/bug12160 b/changes/bug12160
deleted file mode 100644
index 2a7ace3410..0000000000
--- a/changes/bug12160
+++ /dev/null
@@ -1,4 +0,0 @@
- o Bugfixes
- - Correctly update the local mark on the controlling channel when changing
- the address of an or_connection_t after the handshake. Fixes bug #12160;
- bugfix on 0.2.4.4-alpha.
diff --git a/changes/bug12602 b/changes/bug12602
deleted file mode 100644
index 29fa49ac45..0000000000
--- a/changes/bug12602
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes (portability):
- - Compile correctly with builds and forks of OpenSSL (such as
- LibreSSL) that disable compression. Fixes bug 12602; bugfix on
- 0.2.1.1-alpha. Patch from "dhill".
-
diff --git a/changes/bug12700 b/changes/bug12700
deleted file mode 100644
index 1d8caeb8bd..0000000000
--- a/changes/bug12700
+++ /dev/null
@@ -1,10 +0,0 @@
- o Minor bugfixes:
- - When logging information about an EXTEND2 or EXTENDED2 cell, log
- their names correctly. Fixes part of bug 12700; bugfix on
- 0.2.4.8-alpha.
-
- o Minor bugfixes:
- - When logging information about a relay cell whose command we
- don't recognize, log its command as an integer. Fixes part of
- bug 12700; bugfix on 0.2.1.10-alpha.
-
diff --git a/changes/bug12718 b/changes/bug12718
deleted file mode 100644
index 0c5f708446..0000000000
--- a/changes/bug12718
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes:
- - Correct a confusing error message when trying to extend a circuit
- via the control protocol but we don't know a descriptor or
- microdescriptor for one of the specified relays. Fixes bug 12718;
- bugfix on 0.2.3.1-alpha.
diff --git a/changes/bug12730-systemd-verify-config b/changes/bug12730-systemd-verify-config
deleted file mode 100644
index 221633c78e..0000000000
--- a/changes/bug12730-systemd-verify-config
+++ /dev/null
@@ -1,3 +0,0 @@
- o Distribution:
- - Verify configuration file via ExecStartPre in the systemd unit file.
- Patch from intrigeri; resolves ticket 12730.
diff --git a/changes/bug12731-systemd-no-run-as-daemon b/changes/bug12731-systemd-no-run-as-daemon
deleted file mode 100644
index f92e5aff00..0000000000
--- a/changes/bug12731-systemd-no-run-as-daemon
+++ /dev/null
@@ -1,9 +0,0 @@
- o Distribution:
- - Explicitly disable RunAsDaemon in the systemd unit file.
- Our current systemd unit uses "Type = simple", so systemd does
- not expect tor to fork. If the user has "RunAsDaemon 1" in their
- torrc, then things won't work as expected. This is e.g. the case
- on Debian (and derivatives), since there we pass
- "--defaults-torrc /usr/share/tor/tor-service-defaults-torrc"
- (that contains "RunAsDaemon 1") by default.
- Patch by intrigeri; resolves ticket 12731.
diff --git a/changes/bug12830 b/changes/bug12830
deleted file mode 100644
index 835ebe2fa7..0000000000
--- a/changes/bug12830
+++ /dev/null
@@ -1,4 +0,0 @@
- o Documentation:
- - Adjust the URLs in the README to refer to the new locations of
- several documents on the website. Patch from Matt Pagan. Fixes
- bug 12830.
diff --git a/changes/bug12848 b/changes/bug12848
deleted file mode 100644
index 7aa79c395e..0000000000
--- a/changes/bug12848
+++ /dev/null
@@ -1,4 +0,0 @@
- o Major bugfixes (relay):
- - Avoid queuing or sending destroy cells for circuit ID zero when
- we fail to send a CREATE cell. Fixes bug 12848; bugfix on
- 0.0.8pre1. Found and fixed by "cypherpunks".
diff --git a/changes/bug12864 b/changes/bug12864
deleted file mode 100644
index 79e751f427..0000000000
--- a/changes/bug12864
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor bugfixes:
- - Restore the functionality of CookieAuthFileGroupReadable. Fixes bug
- 12864; bugfix on 0.2.5.1-alpha.
-
- o Minor features:
- - Add an ExtORPortCookieAuthFileGroupReadable option to make the
- cookie file for the ExtORPort g+r by default.
diff --git a/changes/bug12878 b/changes/bug12878
deleted file mode 100644
index a05fc446b9..0000000000
--- a/changes/bug12878
+++ /dev/null
@@ -1,3 +0,0 @@
- o Documentation:
- - Document 'reject6' and 'accept6' ExitPolicy entries. Resolves
- ticket 12878.
diff --git a/changes/bug12908 b/changes/bug12908
deleted file mode 100644
index bd6784cbd2..0000000000
--- a/changes/bug12908
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features:
- - Warn about attempts to run hidden services and relays in the
- same process: that's probably not a good idea. Closes ticket
- 12908.
diff --git a/changes/bug12948 b/changes/bug12948
deleted file mode 100644
index 431c0a1019..0000000000
--- a/changes/bug12948
+++ /dev/null
@@ -1,8 +0,0 @@
- o Major bugfixes:
- - Resume expanding abbreviations for command-line options. The fix
- for bug 4647 accidentally removed our hack from bug 586 that rewrote
- HashedControlPassword to __HashedControlSessionPassword when it
- appears on the commandline (which allowed the user to set her
- own HashedControlPassword in the torrc file while the controller
- generates a fresh session password for each run). Fixes bug 12948;
- bugfix on 0.2.5.1-alpha.
diff --git a/changes/bug12996 b/changes/bug12996
deleted file mode 100644
index 4b4fb0dceb..0000000000
--- a/changes/bug12996
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes:
- - Downgrade "Unexpected onionskin length after decryption" warning
- to a protocol-warn, since there's nothing relay operators can do
- about a client that sends them a malformed create cell. Resolves
- bug 12996; bugfix on 0.0.6rc1.
diff --git a/changes/bug12997 b/changes/bug12997
deleted file mode 100644
index fb6e7a8459..0000000000
--- a/changes/bug12997
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Log more specific warnings when we get an ESTABLISH_RENDEZVOUS cell
- on a cannibalized or non-OR circuit. Resolves ticket 12997.
diff --git a/changes/bug13071 b/changes/bug13071
deleted file mode 100644
index 8212b6c049..0000000000
--- a/changes/bug13071
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (relay):
- - Escape all strings from the directory connection before logging them.
- Fixes bug 13071; bugfix on 0.1.1.15. Patch from "teor".
diff --git a/changes/bug13081 b/changes/bug13081
deleted file mode 100644
index 154f73fb0a..0000000000
--- a/changes/bug13081
+++ /dev/null
@@ -1,3 +0,0 @@
- o Compilation fixes:
- - Make the nmake make files work again. Fixes bug 13081. Bugfix on 0.2.5.1-alpha. Patch
- from "NewEraCracker".
diff --git a/changes/bug13085 b/changes/bug13085
deleted file mode 100644
index a46457c797..0000000000
--- a/changes/bug13085
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (controller):
- - Actually send TRANSPORT_LAUNCHED and HS_DESC events to controllers.
- Fixes bug 13085; bugfix on 0.2.5.1-alpha. Patch by "teor".
diff --git a/changes/bug13096 b/changes/bug13096
deleted file mode 100644
index 521faaf143..0000000000
--- a/changes/bug13096
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (conformance):
- - In routerlist_assert_ok(), don't take the address of a routerinfo's
- cache_info member unless that routerinfo is non-NULL. Fixes bug
- 13096; bugfix on 0.1.1.9-alpha. Patch by "teor".
diff --git a/changes/bug13100 b/changes/bug13100
deleted file mode 100644
index bbe43e65a7..0000000000
--- a/changes/bug13100
+++ /dev/null
@@ -1,3 +0,0 @@
- o Directory authority changes:
- - Change IP address for gabelmoo (v3 directory authority).
-
diff --git a/changes/bug13124 b/changes/bug13124
deleted file mode 100644
index be7df70347..0000000000
--- a/changes/bug13124
+++ /dev/null
@@ -1,8 +0,0 @@
- o Minor bugfixes:
- - Reduce the log severity of the "Pluggable transport proxy does
- not provide any needed transports and will not be launched."
- message, since Tor Browser includes several ClientTransportPlugin
- lines in its torrc-defaults file, leading every Tor Browser user
- who looks at her logs to see these notices and wonder if they're
- dangerous. Resolves bug 13124; bugfix on 0.2.5.3-alpha.
-
diff --git a/changes/bug13151-client b/changes/bug13151-client
deleted file mode 100644
index 1218dfdfab..0000000000
--- a/changes/bug13151-client
+++ /dev/null
@@ -1,13 +0,0 @@
- o Major bugfixes:
- - Clients now send the correct address for their chosen rendezvous
- point when trying to access a hidden service. They used to send
- the wrong address, which would still work some of the time because
- they also sent the identity digest of the rendezvous point, and if
- the hidden service happened to try connecting to the rendezvous
- point from a relay that already had a connection open to it,
- the relay would reuse that connection. Now connections to hidden
- services should be more robust and faster. Also, this bug meant
- that clients were leaking to the hidden service whether they were
- on a little-endian (common) or big-endian (rare) system, which for
- some users might have reduced their anonymity. Fixes bug 13151;
- bugfix on 0.2.1.5-alpha.
diff --git a/changes/bug13296 b/changes/bug13296
deleted file mode 100644
index d6fe038c30..0000000000
--- a/changes/bug13296
+++ /dev/null
@@ -1,5 +0,0 @@
- o Directory authority changes:
- - Remove turtles as a directory authority.
- - Add longclaw as a new (v3) directory authority. This implements
- ticket 13296. This keeps the directory authority count at 9.
-
diff --git a/changes/bug13325 b/changes/bug13325
deleted file mode 100644
index b1da4d0bd5..0000000000
--- a/changes/bug13325
+++ /dev/null
@@ -1,4 +0,0 @@
- o Compilation fixes:
- - Build and run correctly on systems like OpenBSD-current that
- have patched OpenSSL to remove get_cipher_by_char and/or its
- implementations. Fixes issue 13325.
diff --git a/changes/bug13471 b/changes/bug13471
deleted file mode 100644
index c116a4aeeb..0000000000
--- a/changes/bug13471
+++ /dev/null
@@ -1,5 +0,0 @@
- o Major bugfixes (openssl bug workaround):
- - Avoid crashing when using OpenSSL version 0.9.8zc, 1.0.0o, or
- 1.0.1j, built with the 'no-ssl3' configuration option. Fixes
- bug 13471. This is a workaround for an OpenSSL bug.
-
diff --git a/changes/bug13988 b/changes/bug13988
deleted file mode 100644
index e816335a3b..0000000000
--- a/changes/bug13988
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (statistics):
- - Increase period over which bandwidth observations are aggregated
- from 15 minutes to 4 hours. Fixes bug 13988; bugfix on 0.0.8pre1.
diff --git a/changes/bug14013 b/changes/bug14013
deleted file mode 100644
index 640cf859f5..0000000000
--- a/changes/bug14013
+++ /dev/null
@@ -1,6 +0,0 @@
- o Major bugfixes:
- - When reading a hexadecimal, base-32, or base-64 encoded value
- from a string, always overwrite the complete output buffer. This
- prevents some bugs where we would look at (but fortunately, not
- reveal) uninitialized memory on the stack. Fixes bug 14013;
- bugfix on all versions of Tor.
diff --git a/changes/bug14125 b/changes/bug14125
deleted file mode 100644
index fe6821a332..0000000000
--- a/changes/bug14125
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes (dirauth):
- - Enlarge the buffer to read bw-auth generated files to avoid an
- issue when parsing the file in dirserv_read_measured_bandwidths().
- Bugfix on 0.2.2.1-alpha, fixes #14125.
-
diff --git a/changes/bug14129 b/changes/bug14129
deleted file mode 100644
index 6153cd84fd..0000000000
--- a/changes/bug14129
+++ /dev/null
@@ -1,7 +0,0 @@
- o Major bugfixes (exit node stability):
-
- - Fix an assertion failure that could occur under high DNS load. Fixes
- bug 14129; bugfix on Tor 0.0.7rc1. Found by "jowr"; diagnosed and fixed
- by "cypherpunks".
-
-
diff --git a/changes/bug14142-parse-virtual-addr b/changes/bug14142-parse-virtual-addr
deleted file mode 100644
index f78b7c7d81..0000000000
--- a/changes/bug14142-parse-virtual-addr
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor bugfixes (client):
- - Check for a missing option value in parse_virtual_addr_network
- before asserting on the NULL in tor_addr_parse_mask_ports.
- This avoids crashing on torrc lines like
- Vi[rtualAddrNetworkIPv[4|6]] when no value follows the option.
- Bugfix on 0.2.3 (de4cc126cbb5 on 24 November 2012), fixes #14142.
- Patch by "teor".
diff --git a/changes/bug14195 b/changes/bug14195
deleted file mode 100644
index d2b82f31b0..0000000000
--- a/changes/bug14195
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (client):
- - Fix a memory leak when using AutomapHostsOnResolve.
- Fixes bug 14195; bugfix on 0.1.0.1-rc.
diff --git a/changes/bug14220 b/changes/bug14220
deleted file mode 100644
index 51cfa502bc..0000000000
--- a/changes/bug14220
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (compilation):
- - Build without warnings with the stock OpenSSL srtp.h header,
- which has a duplicate declaration of SSL_get_selected_srtp_profile().
- Fixes bug 14220; this is OpenSSL's bug, not ours.
diff --git a/changes/bug14261 b/changes/bug14261
deleted file mode 100644
index 1260ccba1e..0000000000
--- a/changes/bug14261
+++ /dev/null
@@ -1,5 +0,0 @@
- O Minor bugfixes (directory authority):
- - Allow directory authorities to fetch more data from one
- another if they find themselves missing lots of votes.
- Previously, they had been bumping against the 10 MB queued
- data limit. Fixes bug 14261. Bugfix on 0.1.2.5-alpha.
diff --git a/changes/bug14848_redux b/changes/bug14848_redux
new file mode 100644
index 0000000000..c10320fb23
--- /dev/null
+++ b/changes/bug14848_redux
@@ -0,0 +1,5 @@
+ o Removed code:
+ - Remove some lingering dead code that once supported mempools. Mempools
+ were disabled by default in 0.2.5, and removed entirely in
+ 0.2.6.3-alpha. Closes more of ticket 14848; patch by "cypherpunks".
+
diff --git a/changes/bug14950 b/changes/bug14950
new file mode 100644
index 0000000000..33cea9cb58
--- /dev/null
+++ b/changes/bug14950
@@ -0,0 +1,3 @@
+ o Minor features (logs):
+ - Quiet some log messages in the heartbeat and at startup. Closes
+ ticket 14950. \ No newline at end of file
diff --git a/changes/bug14980 b/changes/bug14980
new file mode 100644
index 0000000000..b873bb009c
--- /dev/null
+++ b/changes/bug14980
@@ -0,0 +1,4 @@
+ o Minor bugfixes (testing):
+ - Fix endianness issues in unit test for resolve_my_address() to
+ have it pass on big endian systems. Fixes bug 14980; bugfix on
+ Tor 0.2.6.3-alpha.
diff --git a/changes/bug14988 b/changes/bug14988
new file mode 100644
index 0000000000..67dc96e443
--- /dev/null
+++ b/changes/bug14988
@@ -0,0 +1,4 @@
+ o Minor bugfixes (compilation):
+ - Fix a compilation warning on s390. Fixes bug 14988; bugfix on
+ 0.2.5.2-alpha.
+
diff --git a/changes/bug14989 b/changes/bug14989
new file mode 100644
index 0000000000..f4432d468b
--- /dev/null
+++ b/changes/bug14989
@@ -0,0 +1,4 @@
+ o Major bugfixes (Linux seccomp2 sandbox):
+ - Pass IPPROTO_TCP rather than 0 to socket(), so that the
+ Linux seccomp2 sandbox doesn't fail. Fixes bug 14989;
+ bugfix on 0.2.6.3-alpha.
diff --git a/changes/bug15003 b/changes/bug15003
new file mode 100644
index 0000000000..2dcce74dfe
--- /dev/null
+++ b/changes/bug15003
@@ -0,0 +1,3 @@
+ o Major bugfixes (linux seccomp2 sandbox):
+ - Allow AF_UNIX hidden services to be used with the seccomp2 sandbox.
+ Fixes bug 15003; bugfix on 0.2.6.3-alpha.
diff --git a/changes/bug15033 b/changes/bug15033
new file mode 100644
index 0000000000..953e6c3d59
--- /dev/null
+++ b/changes/bug15033
@@ -0,0 +1,4 @@
+ o Minor bugfixes (tests):
+ - When running the zero-length-keys check, do not use the default
+ torrc file. Fixes bug 15033; bugfix on 0.2.6.3-alpha. Reported
+ by "reezer".
diff --git a/changes/bug15037 b/changes/bug15037
new file mode 100644
index 0000000000..587d63186e
--- /dev/null
+++ b/changes/bug15037
@@ -0,0 +1,4 @@
+ o Minor bugfixes (testing):
+ - When running the new 'make test-stem' target, use the configured
+ python binary. Fixes bug 15037; bugfix on 0.2.6.3-alpha. Patch
+ from "cypherpunks".
diff --git a/changes/bug15064 b/changes/bug15064
new file mode 100644
index 0000000000..e6bd747b1f
--- /dev/null
+++ b/changes/bug15064
@@ -0,0 +1,4 @@
+ o Major bugfixes (FreeBSD IPFW transparent proxy):
+ - Fix address detection with FreeBSD transparent proxies,
+ when "TransProxyType ipfw" is in use.
+ Fixes bug 15064; bugfix on 0.2.5.4-alpha.
diff --git a/changes/bug15151 b/changes/bug15151
new file mode 100644
index 0000000000..b9c3061554
--- /dev/null
+++ b/changes/bug15151
@@ -0,0 +1,3 @@
+ o Minor bugfixes (compilation):
+ - Fix a compilation warning on FreeBSD. Fixes bug 15151; bugfix on
+ 0.2.6.2-alpha.
diff --git a/changes/bug15240 b/changes/bug15240
new file mode 100644
index 0000000000..e11f804a12
--- /dev/null
+++ b/changes/bug15240
@@ -0,0 +1,6 @@
+ o Minor bugfixes (pluggable transports):
+ - Initialize the extended OR Port authentication cookie before launching
+ pluggable transports. This prevents a race condition that occured when
+ server-side pluggable transports would cache the authentication cookie
+ before it has been (re)generated. Fixes bug 15240; bugfix on
+ 0.2.5.1-alpha.
diff --git a/changes/bug15245 b/changes/bug15245
new file mode 100644
index 0000000000..520a370eeb
--- /dev/null
+++ b/changes/bug15245
@@ -0,0 +1,5 @@
+ o Major bugfixes:
+ - Avoid crashing when making certain configuration option changes
+ on clients. Fixes bug 15245; bugfix on 0.2.6.3-alpha. Reported
+ by "anonym".
+
diff --git a/changes/bug15436 b/changes/bug15436
new file mode 100644
index 0000000000..4fa44d1e16
--- /dev/null
+++ b/changes/bug15436
@@ -0,0 +1,4 @@
+ o Minor bugfixes (portability):
+ - Use the correct datatype in the SipHash-2-4 function to prevent compilers
+ from assuming any sort of alignment. Fixes bug 15436; bugfix on
+ 0.2.5.3-alpha.
diff --git a/changes/bug15850 b/changes/bug15850
new file mode 100644
index 0000000000..48a7c7bdd7
--- /dev/null
+++ b/changes/bug15850
@@ -0,0 +1,4 @@
+ o Major bugfix
+ - Revert commit that made directory authority assign the HSDir flag to
+ relay without a DirPort which is bad because relay can't handle
+ BEGIN_DIR cells. Fixes #15850. Bugfix on tor-0.2.6.3-alpha;
diff --git a/changes/bug16013 b/changes/bug16013
new file mode 100644
index 0000000000..d194c609f8
--- /dev/null
+++ b/changes/bug16013
@@ -0,0 +1,5 @@
+ o Major bugfixes (hidden service, stability):
+ - Stop randomly crashing with an assertion failure when connecting to a
+ busy hidden service, or connecting to a hidden service while a NEWNYM
+ is in progress. Fixes bug 16013; bugfix on 0.1.0.1-rc.
+
diff --git a/changes/bug16030 b/changes/bug16030
new file mode 100644
index 0000000000..c14fd62303
--- /dev/null
+++ b/changes/bug16030
@@ -0,0 +1,3 @@
+ o Minor bugfixes (tests):
+ - Fix a crash in the unit tests on MSVC2013. Fixes bug 16030; bugfix on
+ 0.2.6.2-alpha. Patch from "NewEraCracker". \ No newline at end of file
diff --git a/changes/bug16164 b/changes/bug16164
new file mode 100644
index 0000000000..fbb383c26d
--- /dev/null
+++ b/changes/bug16164
@@ -0,0 +1,4 @@
+ o Minor bugfixes (compilation):
+ - Build with --enable-systemd correctly when libsystemd is installed,
+ but systemd is not. Fixes bug 16164, bugfix on 0.2.6.3-alpha. Patch
+ from Peter Palfrader.
diff --git a/changes/bug16212 b/changes/bug16212
new file mode 100644
index 0000000000..bc1246376d
--- /dev/null
+++ b/changes/bug16212
@@ -0,0 +1,5 @@
+ o Minor bugfixes (sandbox, systemd):
+ - Allow systemd connections to work with the Linux seccomp2 sandbox
+ code. Fixes bug 16212; bugfix on 0.2.6.2-alpha.
+ Patch by Peter Palfrader.
+
diff --git a/changes/bug16244 b/changes/bug16244
new file mode 100644
index 0000000000..00bc557983
--- /dev/null
+++ b/changes/bug16244
@@ -0,0 +1,7 @@
+ o Minor bugfixes (sandbox, relay):
+ - Fix sandboxing to work when running as a relay again. This
+ includes correctly allowing renaming secret_id_key and
+ allowing the eventfd2 and futex syscalls.
+ Fixes bug 16244; bugfix on 0.2.6.1-alpha.
+ Patch by Peter Palfrader.
+
diff --git a/changes/bug16247 b/changes/bug16247
new file mode 100644
index 0000000000..9464b1cb24
--- /dev/null
+++ b/changes/bug16247
@@ -0,0 +1,5 @@
+ o Minor bugfixes (client-side privacy):
+ - Properly separate out each SOCKSPort when applying stream isolation.
+ The error occured because each port's session group was being
+ overwritten by a default value. Fixes bug 16247; bugfix on
+ 0.2.6.3-alpha. Patch by "jojelino".
diff --git a/changes/bug16363 b/changes/bug16363
new file mode 100644
index 0000000000..1a6f8c6eff
--- /dev/null
+++ b/changes/bug16363
@@ -0,0 +1,4 @@
+ o Minor bugfixes (Linux seccomp2 sandbox):
+ - Allow pipe() and pipe2() syscalls; we need these when eventfd2()
+ support is missing. Fixes bug 16363; bugfix on 0.2.6.3-alpha.
+ Patch from "teor".
diff --git a/changes/bug16381 b/changes/bug16381
new file mode 100644
index 0000000000..51a9b53007
--- /dev/null
+++ b/changes/bug16381
@@ -0,0 +1,13 @@
+ o Major bugfix (Hidden service client)
+ - Revert commit 9407040c592184e05e45a3c1a00739c2dd302288 of bug #14219
+ that indeed fixed an issue but introduced a major hidden service
+ reachability regression detailed in bug #16381. This is a temporary
+ fix since we can live with the minor issue in #14219 but the
+ regression introduced is too much of a set back.
+
+ To be clear, #14219 bug just results in some load on the network, and
+ some delay for the client when visiting a hidden service that will
+ ultimately fail.
+
+ This is only a bandaid for #16381 thus it does _not_ fixes it. bugfix
+ on tor-0.2.6.3-alpha~138.
diff --git a/changes/bug16400 b/changes/bug16400
new file mode 100644
index 0000000000..3e5f9c5843
--- /dev/null
+++ b/changes/bug16400
@@ -0,0 +1,5 @@
+ o Major bugfixes:
+ - Do not crash with an assertion error when parsing certain kinds
+ of malformed or truncated microdescriptors. Fixes bug 16400;
+ bugfix on 0.2.6.1-alpha. Found by "torkeln"; fix based on a patch by
+ "cypherpunks_backup".
diff --git a/changes/bug8093 b/changes/bug8093
deleted file mode 100644
index f0fbc618c2..0000000000
--- a/changes/bug8093
+++ /dev/null
@@ -1,3 +0,0 @@
- o Downgraded warnings:
- - Downgrade the severity of the 'unexpected sendme cell from client' from
- 'warn' to 'protocol warning'. Closes ticket 8093.
diff --git a/changes/bug8387 b/changes/bug8387
deleted file mode 100644
index 2ec0487bf8..0000000000
--- a/changes/bug8387
+++ /dev/null
@@ -1,11 +0,0 @@
- o Major bugfixes (client):
-
- - Perform circuit cleanup operations even when circuit
- construction operations are disabled (because the network is
- disabled, or because there isn't enough directory information).
- Previously, when we were not building predictive circuits, we
- were not closing expired circuits either.
-
- Fixes bug 8387; bugfix on 0.1.1.11-alpha. This bug became visible
- in 0.2.4.10-alpha when we became more strict about when we have
- "enough directory information to build circuits".
diff --git a/changes/bug9495_redux b/changes/bug9495_redux
new file mode 100644
index 0000000000..74b0cdf2a8
--- /dev/null
+++ b/changes/bug9495_redux
@@ -0,0 +1,4 @@
+ o Major bugfixes (portability):
+ - Do not crash on startup when running on Solaris. Fixes a bug
+ related to our fix for 9495; bugfix on 0.2.6.1-alpha. Reported
+ by "ruebezahl".
diff --git a/changes/curve25519-donna32-bug b/changes/curve25519-donna32-bug
deleted file mode 100644
index 7fccab1b0c..0000000000
--- a/changes/curve25519-donna32-bug
+++ /dev/null
@@ -1,12 +0,0 @@
- o Major bugfixes:
-
- - Fix a bug in the bounds-checking in the 32-bit curve25519-donna
- implementation that caused incorrect results on 32-bit
- implementations when certain malformed inputs were used along with
- a small class of private ntor keys. This bug does not currently
- appear to allow an attacker to learn private keys or impersonate a
- Tor server, but it could provide a means to distinguish 32-bit Tor
- implementations from 64-bit Tor implementations. Fixes bug 12694;
- bugfix on 0.2.4.8-alpha. Bug found by Robert Ransom; fix from
- Adam Langley.
-
diff --git a/changes/disable_sslv3 b/changes/disable_sslv3
deleted file mode 100644
index bb4c2df7a2..0000000000
--- a/changes/disable_sslv3
+++ /dev/null
@@ -1,4 +0,0 @@
- o Major security fixes:
- - Disable support for SSLv3. All versions of OpenSSL in use with
- Tor today support TLS 1.0 or later, so we can safely turn off
- support for this old (and insecure) protocol. Fixes bug 13426.
diff --git a/changes/feature15006 b/changes/feature15006
new file mode 100644
index 0000000000..168a440ba0
--- /dev/null
+++ b/changes/feature15006
@@ -0,0 +1,4 @@
+ o Minor features (controller):
+ - Messages about problems in the bootstrap process now include
+ information about the server we were trying to connect to when we
+ noticed the problem. Closes ticket 15006.
diff --git a/changes/further-12184-diagnostic b/changes/further-12184-diagnostic
deleted file mode 100644
index 89e9f4612f..0000000000
--- a/changes/further-12184-diagnostic
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor features (diagnostic):
- - Slightly enhance the diagnostic message for bug 12184.
diff --git a/changes/geoip-august2014 b/changes/geoip-august2014
deleted file mode 100644
index 90d8ecb300..0000000000
--- a/changes/geoip-august2014
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Update geoip to the August 7 2014 Maxmind GeoLite2 Country database.
-
diff --git a/changes/geoip-january2015 b/changes/geoip-january2015
deleted file mode 100644
index 67324f27f2..0000000000
--- a/changes/geoip-january2015
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Update geoip to the January 7 2015 Maxmind GeoLite2 Country database.
-
diff --git a/changes/geoip-july2014 b/changes/geoip-july2014
deleted file mode 100644
index a0523ecac9..0000000000
--- a/changes/geoip-july2014
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Update geoip to the July 10 2014 Maxmind GeoLite2 Country database.
-
diff --git a/changes/geoip-november2014 b/changes/geoip-november2014
deleted file mode 100644
index 52cbeb3e41..0000000000
--- a/changes/geoip-november2014
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Update geoip to the November 15 2014 Maxmind GeoLite2 Country database.
-
diff --git a/changes/geoip6-august2014 b/changes/geoip6-august2014
deleted file mode 100644
index 7e7c9a975d..0000000000
--- a/changes/geoip6-august2014
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Update geoip6 to the August 7 2014 Maxmind GeoLite2 Country database.
-
diff --git a/changes/geoip6-january2015 b/changes/geoip6-january2015
deleted file mode 100644
index b86fe2be57..0000000000
--- a/changes/geoip6-january2015
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor features:
- - Update geoip6 to the January 7 2015 Maxmind GeoLite2 Country database.
diff --git a/changes/geoip6-july2014 b/changes/geoip6-july2014
deleted file mode 100644
index 155788ef88..0000000000
--- a/changes/geoip6-july2014
+++ /dev/null
@@ -1,2 +0,0 @@
- o Minor features:
- - Update geoip6 to the July 10 2014 Maxmind GeoLite2 Country database.
diff --git a/changes/geoip6-november2014 b/changes/geoip6-november2014
deleted file mode 100644
index e91fcc0d3b..0000000000
--- a/changes/geoip6-november2014
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features:
- - Update geoip6 to the November 15 2014 Maxmind GeoLite2 Country database.
-
diff --git a/changes/test.h_msvc b/changes/test.h_msvc
deleted file mode 100644
index 3afbc13aaa..0000000000
--- a/changes/test.h_msvc
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (compilation):
- - Fix compilation of test.h with MSVC. Patch from Gisle Vanem;
- bugfix on 0.2.5.5-alpha.
diff --git a/changes/ticket12688 b/changes/ticket12688
deleted file mode 100644
index 88228e5506..0000000000
--- a/changes/ticket12688
+++ /dev/null
@@ -1,6 +0,0 @@
- Major features:
- - Make the number of entry guards configurable via a new
- NumEntryGuards consensus parameter, and the number of directory
- guards configurable via a new NumDirectoryGuards consensus
- parameter. Implements ticket 12688.
-
diff --git a/changes/ticket12690 b/changes/ticket12690
deleted file mode 100644
index 5091883602..0000000000
--- a/changes/ticket12690
+++ /dev/null
@@ -1,9 +0,0 @@
- o Minor features:
- - Authorities now assign the Guard flag to the fastest 25% of the
- network (it used to be the fastest 50%). Also raise the consensus
- weight that guarantees the Guard flag from 250 to 2000. For the
- current network, this results in about 1100 guards, down from 2500.
- This step paves the way for moving the number of entry guards
- down to 1 (proposal 236) while still providing reasonable expected
- performance for most users. Implements ticket 12690.
-
diff --git a/changes/ticket13036 b/changes/ticket13036
deleted file mode 100644
index 1b4784358a..0000000000
--- a/changes/ticket13036
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes:
- - Fix a large number of false positive warnings from the clang
- analyzer static analysis tool. This should make real warnings
- easier for clang analyzer to find. Patch from "teor". Closes
- ticket 13036.
diff --git a/changes/ticket14128 b/changes/ticket14128
deleted file mode 100644
index 38b25fa7dc..0000000000
--- a/changes/ticket14128
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor features (controller):
- - New "GETINFO bw-event-cache" to get information about recent bandwidth
- events. Closes ticket 14128. Useful for controllers to get recent
- bandwidth history after the fix for 13988.
-
diff --git a/changes/ticket15176 b/changes/ticket15176
new file mode 100644
index 0000000000..6d12723728
--- /dev/null
+++ b/changes/ticket15176
@@ -0,0 +1,3 @@
+ o Code simplification and refactoring:
+ - Refactor main loop to extract the 'loop' part. This makes it easier
+ to run Tor under Shadow. Closes ticket 15176.
diff --git a/changes/ticket15212 b/changes/ticket15212
new file mode 100644
index 0000000000..2c41e3865c
--- /dev/null
+++ b/changes/ticket15212
@@ -0,0 +1,6 @@
+ o Minor features (heartbeat):
+
+ - On relays, report how many connections we negotiated using each
+ version of the Tor link protocols. This information will let us
+ know if removing support for very old versions of the Tor
+ protocols is harming the network. Closes ticket 15212.
diff --git a/changes/ticket8243 b/changes/ticket8243
new file mode 100644
index 0000000000..8946a21a59
--- /dev/null
+++ b/changes/ticket8243
@@ -0,0 +1,7 @@
+ o Minor feature:
+ - The HSDir flag given by authorities now requires the Stable flag. For
+ the current network, this results in going from 2887 to 2806 HSDirs.
+ Also, it makes it harder for an attacker to launch a sybil attack by
+ raising the effort for a relay to become Stable which takes at the
+ very least 7 days to do so and by keeping the 96 hours uptime
+ requirement for HSDir. Implements ticket #8243.
diff --git a/configure.ac b/configure.ac
index 4eeb34dca8..63f4f1f757 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,9 +1,9 @@
dnl Copyright (c) 2001-2004, Roger Dingledine
dnl Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
-dnl Copyright (c) 2007-2013, The Tor Project, Inc.
+dnl Copyright (c) 2007-2015, The Tor Project, Inc.
dnl See LICENSE for licensing information
-AC_INIT([tor],[0.2.5.14-dev])
+AC_INIT([tor],[0.2.6.12-dev])
AC_CONFIG_SRCDIR([src/or/main.c])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE
@@ -12,6 +12,8 @@ AC_CONFIG_HEADERS([orconfig.h])
AC_CANONICAL_HOST
+PKG_PROG_PKG_CONFIG
+
if test -f /etc/redhat-release ; then
if test -f /usr/kerberos/include ; then
CPPFLAGS="$CPPFLAGS -I/usr/kerberos/include"
@@ -23,10 +25,6 @@ fi
CPPFLAGS="$CPPFLAGS -I\${top_srcdir}/src/common"
#XXXX020 We should make these enabled or not, before 0.2.0.x-final
-AC_ARG_ENABLE(buf-freelists,
- AS_HELP_STRING(--enable-buf-freelists, enable freelists for buffer RAM))
-AC_ARG_ENABLE(mempools,
- AS_HELP_STRING(--enable-mempools, enable mempools for relay cells))
AC_ARG_ENABLE(openbsd-malloc,
AS_HELP_STRING(--enable-openbsd-malloc, Use malloc code from openbsd. Linux only))
AC_ARG_ENABLE(instrument-downloads,
@@ -39,12 +37,12 @@ AC_ARG_ENABLE(static-zlib,
AS_HELP_STRING(--enable-static-zlib, Link against a static zlib library. Requires --with-zlib-dir))
AC_ARG_ENABLE(static-tor,
AS_HELP_STRING(--enable-static-tor, Create an entirely static Tor binary. Requires --with-openssl-dir and --with-libevent-dir and --with-zlib-dir))
-AC_ARG_ENABLE(curve25519,
- AS_HELP_STRING(--disable-curve25519, Build Tor with no curve25519 elliptic-curve crypto support))
AC_ARG_ENABLE(unittests,
AS_HELP_STRING(--disable-unittests, [Don't build unit tests for Tor. Risky!]))
AC_ARG_ENABLE(coverage,
AS_HELP_STRING(--enable-coverage, [Enable coverage support in the unit-test build]))
+AC_ARG_ENABLE(system-torrc,
+ AS_HELP_STRING(--disable-system-torrc, [Don't look for a system-wide torrc file]))
AM_CONDITIONAL(UNITTESTS_ENABLED, test x$enable_unittests != xno)
AM_CONDITIONAL(COVERAGE_ENABLED, test x$enable_coverage = xyes)
@@ -56,15 +54,9 @@ if test "$enable_static_tor" = "yes"; then
CFLAGS="$CFLAGS -static"
fi
-if test x$enable_buf_freelists = xyes; then
- AC_DEFINE(ENABLE_BUF_FREELISTS, 1,
- [Defined if we try to use freelists for buffer RAM chunks])
-fi
-
-AM_CONDITIONAL(USE_MEMPOOLS, test x$enable_mempools = xyes)
-if test x$enable_mempools = xyes; then
- AC_DEFINE(ENABLE_MEMPOOLS, 1,
- [Defined if we try to use mempools for cells being relayed])
+if test "$enable_system_torrc" = "no"; then
+ AC_DEFINE(DISABLE_SYSTEM_TORRC, 1,
+ [Defined if we're not going to look for a torrc in SYSCONF])
fi
AM_CONDITIONAL(USE_OPENBSD_MALLOC, test x$enable_openbsd_malloc = xyes)
@@ -107,24 +99,46 @@ AC_ARG_ENABLE(upnp,
* ) AC_MSG_ERROR(bad value for --enable-upnp) ;;
esac], [upnp=false])
+# systemd notify support
+AC_ARG_ENABLE(systemd,
+ AS_HELP_STRING(--enable-systemd, enable systemd notification support),
+ [case "${enableval}" in
+ yes) systemd=true ;;
+ no) systemd=false ;;
+ * ) AC_MSG_ERROR(bad value for --enable-systemd) ;;
+ esac], [systemd=auto])
-AC_ARG_ENABLE(threads,
- AS_HELP_STRING(--disable-threads, disable multi-threading support))
-if test x$enable_threads = x; then
- case $host in
- *-*-solaris* )
- # Don't try multithreading on solaris -- cpuworkers seem to lock.
- AC_MSG_NOTICE([You are running Solaris; Sometimes threading makes
-cpu workers lock up here, so I will disable threads.])
- enable_threads="no";;
- *)
- enable_threads="yes";;
- esac
+
+# systemd support
+if test x$enable_systemd = xno ; then
+ have_systemd=no;
+else
+ PKG_CHECK_MODULES(SYSTEMD,
+ [libsystemd-daemon],
+ have_systemd=yes,
+ have_systemd=no)
+ if test x$have_systemd=xno; then
+ AC_MSG_NOTICE([Okay, checking for systemd a different way...])
+ PKG_CHECK_MODULES(SYSTEMD,
+ [libsystemd],
+ have_systemd=yes,
+ have_systemd=no)
+ fi
fi
-if test "$enable_threads" = "yes"; then
- AC_DEFINE(ENABLE_THREADS, 1, [Defined if we will try to use multithreading])
+if test x$have_systemd = xyes; then
+ AC_DEFINE(HAVE_SYSTEMD,1,[Have systemd])
+ TOR_SYSTEMD_CFLAGS="${SYSTEMD_CFLAGS}"
+ TOR_SYSTEMD_LIBS="${SYSTEMD_LIBS}"
+ PKG_CHECK_MODULES(LIBSYSTEMD209, [libsystemd >= 209],
+ [AC_DEFINE(HAVE_SYSTEMD_209,1,[Have systemd v209 or more])], [])
+fi
+AC_SUBST(TOR_SYSTEMD_CFLAGS)
+AC_SUBST(TOR_SYSTEMD_LIBS)
+
+if test x$enable_systemd = xyes -a x$have_systemd != xyes ; then
+ AC_MSG_ERROR([Explicitly requested systemd support, but systemd not found])
fi
case $host in
@@ -173,6 +187,9 @@ AC_ARG_ENABLE(tool-name-check,
AC_ARG_ENABLE(seccomp,
AS_HELP_STRING(--disable-seccomp, do not attempt to use libseccomp))
+AC_ARG_ENABLE(libscrypt,
+ AS_HELP_STRING(--disable-libscrypt, do not attempt to use libscrypt))
+
dnl check for the correct "ar" when cross-compiling
AN_MAKEVAR([AR], [AC_PROG_AR])
AN_PROGRAM([ar], [AC_PROG_AR])
@@ -211,8 +228,9 @@ AM_CONDITIONAL(USE_FW_HELPER, test x$natpmp = xtrue || test x$upnp = xtrue)
AM_CONDITIONAL(NAT_PMP, test x$natpmp = xtrue)
AM_CONDITIONAL(MINIUPNPC, test x$upnp = xtrue)
AM_PROG_CC_C_O
+AC_PROG_CC_C99
-AC_ARG_VAR(PYTHON)
+AC_ARG_VAR([PYTHON], [path to Python binary])
AC_CHECK_PROGS(PYTHON, [python python2 python2.7 python3 python3.3])
if test "x$PYTHON" = "x"; then
AC_MSG_WARN([Python unavailable; some tests will not be run.])
@@ -241,6 +259,28 @@ AC_C_FLEXIBLE_ARRAY_MEMBER
fi
])
+AC_CACHE_CHECK([for working C99 mid-block declaration syntax],
+ tor_cv_c_c99_decl,
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([], [int x; x = 3; int y; y = 4 + x;])],
+ [tor_cv_c_c99_decl=yes],
+ [tor_cv_c_c99_decl=no] )])
+if test "$tor_cv_c_c99_decl" != "yes"; then
+ AC_MSG_ERROR([Your compiler doesn't support c99 mid-block declarations. This is required as of Tor 0.2.6.x])
+fi
+
+AC_CACHE_CHECK([for working C99 designated initializers],
+ tor_cv_c_c99_designated_init,
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([struct s { int a; int b; };],
+ [[ struct s ss = { .b = 5, .a = 6 }; ]])],
+ [tor_cv_c_c99_designated_init=yes],
+ [tor_cv_c_c99_designated_init=no] )])
+
+if test "$tor_cv_c_c99_designated_init" != "yes"; then
+ AC_MSG_ERROR([Your compiler doesn't support c99 designated initializers. This is required as of Tor 0.2.6.x])
+fi
+
AC_PATH_PROG([SHA1SUM], [sha1sum], none)
AC_PATH_PROG([OPENSSL], [openssl], none)
@@ -326,10 +366,11 @@ if test "$LIBS" != "$saved_LIBS"; then
have_rt=yes
fi
-if test "$enable_threads" = "yes"; then
- AC_SEARCH_LIBS(pthread_create, [pthread])
- AC_SEARCH_LIBS(pthread_detach, [pthread])
-fi
+AC_SEARCH_LIBS(pthread_create, [pthread])
+AC_SEARCH_LIBS(pthread_detach, [pthread])
+
+AM_CONDITIONAL(THREADS_WIN32, test "$bwin32" = "true")
+AM_CONDITIONAL(THREADS_PTHREADS, test "$bwin32" = "false")
dnl -------------------------------------------------------------------
dnl Check for functions before libevent, since libevent-1.2 apparently
@@ -341,6 +382,7 @@ AC_CHECK_FUNCS(
backtrace \
backtrace_symbols_fd \
clock_gettime \
+ eventfd \
flock \
ftime \
getaddrinfo \
@@ -355,24 +397,27 @@ AC_CHECK_FUNCS(
localtime_r \
lround \
memmem \
+ pipe \
+ pipe2 \
prctl \
rint \
sigaction \
socketpair \
strlcat \
strlcpy \
+ strnlen \
strptime \
strtok_r \
strtoull \
sysconf \
sysctl \
uname \
- usleep \
+ usleep \
vasprintf \
_vscprintf
)
-if test "$enable_threads" = "yes"; then
+if test "$bwin32" != true; then
AC_CHECK_HEADERS(pthread.h)
AC_CHECK_FUNCS(pthread_create)
fi
@@ -615,7 +660,7 @@ dnl since sometimes the linker will like an option but not be willing to
dnl use it with a build of a library.
all_ldflags_for_check="$TOR_LDFLAGS_zlib $TOR_LDFLAGS_openssl $TOR_LDFLAGS_libevent"
-all_libs_for_check="$TOR_ZLIB_LIBS $TOR_LIB_MATH $TOR_LIBEVENT_LIBS $TOR_OPENSSL_LIBS $TOR_LIB_WS32 $TOR_LIB_GDI"
+all_libs_for_check="$TOR_ZLIB_LIBS $TOR_LIB_MATH $TOR_LIBEVENT_LIBS $TOR_OPENSSL_LIBS $TOR_SYSTEMD_LIBS $TOR_LIB_WS32 $TOR_LIB_GDI"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [
#if !defined(__clang__)
@@ -630,11 +675,12 @@ if test x$enable_gcc_hardening != xno; then
TOR_CHECK_CFLAGS(-fstack-protector-all, also_link)
AS_VAR_PUSHDEF([can_compile], [tor_cv_cflags_-fstack-protector-all])
AS_VAR_PUSHDEF([can_link], [tor_can_link_-fstack-protector-all])
+m4_ifdef([AS_VAR_IF],[
AS_VAR_IF(can_compile, [yes],
AS_VAR_IF(can_link, [yes],
[],
AC_MSG_ERROR([We tried to build with stack protection; it looks like your compiler supports it but your libc does not provide it. Are you missing libssp? (You can --disable-gcc-hardening to ignore this error.)]))
- )
+ )])
AS_VAR_POPDEF([can_link])
AS_VAR_POPDEF([can_compile])
TOR_CHECK_CFLAGS(-Wstack-protector)
@@ -748,104 +794,103 @@ if test "x$enable_seccomp" != "xno"; then
fi
dnl ============================================================
+dnl Check for libscrypt
+
+if test "x$enable_libscrypt" != "xno"; then
+ AC_CHECK_HEADERS([libscrypt.h])
+ AC_SEARCH_LIBS(libscrypt_scrypt, [scrypt])
+fi
+
+dnl ============================================================
dnl We need an implementation of curve25519.
dnl set these defaults.
-have_a_curve25519=no
build_curve25519_donna=no
build_curve25519_donna_c64=no
use_curve25519_donna=no
use_curve25519_nacl=no
CURVE25519_LIBS=
-if test x$enable_curve25519 != xno; then
-
- dnl The best choice is using curve25519-donna-c64, but that requires
- dnl that we
- AC_CACHE_CHECK([whether we can use curve25519-donna-c64],
- tor_cv_can_use_curve25519_donna_c64,
- [AC_RUN_IFELSE(
- [AC_LANG_PROGRAM([dnl
- #include <stdint.h>
- typedef unsigned uint128_t __attribute__((mode(TI)));
- int func(uint64_t a, uint64_t b) {
- uint128_t c = ((uint128_t)a) * b;
- int ok = ((uint64_t)(c>>96)) == 522859 &&
- (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L &&
- (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L &&
- (((uint64_t)(c))&0xffffffffL) == 0;
- return ok;
- }
- ], [dnl
- int ok = func( ((uint64_t)2000000000) * 1000000000,
- ((uint64_t)1234567890) << 24);
- return !ok;
- ])],
- [tor_cv_can_use_curve25519_donna_c64=yes],
- [tor_cv_can_use_curve25519_donna_c64=no],
- [AC_LINK_IFELSE(
- [AC_LANG_PROGRAM([dnl
- #include <stdint.h>
- typedef unsigned uint128_t __attribute__((mode(TI)));
- int func(uint64_t a, uint64_t b) {
- uint128_t c = ((uint128_t)a) * b;
- int ok = ((uint64_t)(c>>96)) == 522859 &&
- (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L &&
- (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L &&
- (((uint64_t)(c))&0xffffffffL) == 0;
- return ok;
- }
- ], [dnl
- int ok = func( ((uint64_t)2000000000) * 1000000000,
- ((uint64_t)1234567890) << 24);
- return !ok;
- ])],
- [tor_cv_can_use_curve25519_donna_c64=cross],
- [tor_cv_can_use_curve25519_donna_c64=no])])])
-
- AC_CHECK_HEADERS([crypto_scalarmult_curve25519.h \
- nacl/crypto_scalarmult_curve25519.h])
-
- AC_CACHE_CHECK([for nacl compiled with a fast curve25519 implementation],
- tor_cv_can_use_curve25519_nacl,
- [tor_saved_LIBS="$LIBS"
- LIBS="$LIBS -lnacl"
- AC_LINK_IFELSE(
- [AC_LANG_PROGRAM([dnl
- #ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H
- #include <crypto_scalarmult_curve25519.h>
- #elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H)
- #include <nacl/crypto_scalarmult_curve25519.h>
- #endif
- #ifdef crypto_scalarmult_curve25519_ref_BYTES
- #error Hey, this is the reference implementation! That's not fast.
- #endif
- ], [
- unsigned char *a, *b, *c; crypto_scalarmult_curve25519(a,b,c);
- ])], [tor_cv_can_use_curve25519_nacl=yes],
- [tor_cv_can_use_curve25519_nacl=no])
- LIBS="$tor_saved_LIBS" ])
-
- dnl Okay, now we need to figure out which one to actually use. Fall back
- dnl to curve25519-donna.c
-
- if test x$tor_cv_can_use_curve25519_donna_c64 != xno; then
- build_curve25519_donna_c64=yes
- use_curve25519_donna=yes
- elif test x$tor_cv_can_use_curve25519_nacl = xyes; then
- use_curve25519_nacl=yes
- CURVE25519_LIBS=-lnacl
- else
- build_curve25519_donna=yes
- use_curve25519_donna=yes
- fi
- have_a_curve25519=yes
-fi
+dnl The best choice is using curve25519-donna-c64, but that requires
+dnl that we
+AC_CACHE_CHECK([whether we can use curve25519-donna-c64],
+ tor_cv_can_use_curve25519_donna_c64,
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([dnl
+ #include <stdint.h>
+ typedef unsigned uint128_t __attribute__((mode(TI)));
+ int func(uint64_t a, uint64_t b) {
+ uint128_t c = ((uint128_t)a) * b;
+ int ok = ((uint64_t)(c>>96)) == 522859 &&
+ (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L &&
+ (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L &&
+ (((uint64_t)(c))&0xffffffffL) == 0;
+ return ok;
+ }
+ ], [dnl
+ int ok = func( ((uint64_t)2000000000) * 1000000000,
+ ((uint64_t)1234567890) << 24);
+ return !ok;
+ ])],
+ [tor_cv_can_use_curve25519_donna_c64=yes],
+ [tor_cv_can_use_curve25519_donna_c64=no],
+ [AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([dnl
+ #include <stdint.h>
+ typedef unsigned uint128_t __attribute__((mode(TI)));
+ int func(uint64_t a, uint64_t b) {
+ uint128_t c = ((uint128_t)a) * b;
+ int ok = ((uint64_t)(c>>96)) == 522859 &&
+ (((uint64_t)(c>>64))&0xffffffffL) == 3604448702L &&
+ (((uint64_t)(c>>32))&0xffffffffL) == 2351960064L &&
+ (((uint64_t)(c))&0xffffffffL) == 0;
+ return ok;
+ }
+ ], [dnl
+ int ok = func( ((uint64_t)2000000000) * 1000000000,
+ ((uint64_t)1234567890) << 24);
+ return !ok;
+ ])],
+ [tor_cv_can_use_curve25519_donna_c64=cross],
+ [tor_cv_can_use_curve25519_donna_c64=no])])])
+
+AC_CHECK_HEADERS([crypto_scalarmult_curve25519.h \
+ nacl/crypto_scalarmult_curve25519.h])
+
+AC_CACHE_CHECK([for nacl compiled with a fast curve25519 implementation],
+ tor_cv_can_use_curve25519_nacl,
+ [tor_saved_LIBS="$LIBS"
+ LIBS="$LIBS -lnacl"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([dnl
+ #ifdef HAVE_CRYPTO_SCALARMULT_CURVE25519_H
+ #include <crypto_scalarmult_curve25519.h>
+ #elif defined(HAVE_NACL_CRYPTO_SCALARMULT_CURVE25519_H)
+ #include <nacl/crypto_scalarmult_curve25519.h>
+ #endif
+ #ifdef crypto_scalarmult_curve25519_ref_BYTES
+ #error Hey, this is the reference implementation! That's not fast.
+ #endif
+ ], [
+ unsigned char *a, *b, *c; crypto_scalarmult_curve25519(a,b,c);
+ ])], [tor_cv_can_use_curve25519_nacl=yes],
+ [tor_cv_can_use_curve25519_nacl=no])
+ LIBS="$tor_saved_LIBS" ])
+
+ dnl Okay, now we need to figure out which one to actually use. Fall back
+ dnl to curve25519-donna.c
+
+ if test x$tor_cv_can_use_curve25519_donna_c64 != xno; then
+ build_curve25519_donna_c64=yes
+ use_curve25519_donna=yes
+ elif test x$tor_cv_can_use_curve25519_nacl = xyes; then
+ use_curve25519_nacl=yes
+ CURVE25519_LIBS=-lnacl
+ else
+ build_curve25519_donna=yes
+ use_curve25519_donna=yes
+ fi
-if test x$have_a_curve25519 = xyes; then
- AC_DEFINE(CURVE25519_ENABLED, 1,
- [Defined if we have a curve25519 implementation])
-fi
if test x$use_curve25519_donna = xyes; then
AC_DEFINE(USE_CURVE25519_DONNA, 1,
[Defined if we should use an internal curve25519_donna{,_c64} implementation])
@@ -856,7 +901,6 @@ if test x$use_curve25519_nacl = xyes; then
fi
AM_CONDITIONAL(BUILD_CURVE25519_DONNA, test x$build_curve25519_donna = xyes)
AM_CONDITIONAL(BUILD_CURVE25519_DONNA_C64, test x$build_curve25519_donna_c64 = xyes)
-AM_CONDITIONAL(CURVE25519_ENABLED, test x$have_a_curve25519 = xyes)
AC_SUBST(CURVE25519_LIBS)
dnl Make sure to enable support for large off_t if available.
@@ -896,6 +940,7 @@ AC_CHECK_HEADERS(
netinet/in6.h \
pwd.h \
stdint.h \
+ sys/eventfd.h \
sys/file.h \
sys/ioctl.h \
sys/limits.h \
@@ -935,6 +980,14 @@ AC_CHECK_HEADERS(net/pfvar.h, net_pfvar_found=1, net_pfvar_found=0,
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif])
+
+AC_CHECK_HEADERS(linux/if.h,[],[],
+[
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+
AC_CHECK_HEADERS(linux/netfilter_ipv4.h,
linux_netfilter_ipv4=1, linux_netfilter_ipv4=0,
[#ifdef HAVE_SYS_TYPES_H
@@ -956,6 +1009,30 @@ AC_CHECK_HEADERS(linux/netfilter_ipv4.h,
#include <netinet/in.h>
#endif])
+AC_CHECK_HEADERS(linux/netfilter_ipv6/ip6_tables.h,
+ linux_netfilter_ipv6_ip6_tables=1, linux_netfilter_ipv6_ip6_tables=0,
+[#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_LINUX_TYPES_H
+#include <linux/types.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_LINUX_IF_H
+#include <linux/if.h>
+#endif])
+
if test x$transparent = xtrue ; then
transparent_ok=0
if test x$net_if_found = x1 && test x$net_pfvar_found = x1 ; then
@@ -964,6 +1041,9 @@ if test x$transparent = xtrue ; then
if test x$linux_netfilter_ipv4 = x1 ; then
transparent_ok=1
fi
+ if test x$linux_netfilter_ipv6_ip6_tables = x1 ; then
+ transparent_ok=1
+ fi
if test x$transparent_ok = x1 ; then
AC_DEFINE(USE_TRANSPARENT, 1, "Define to enable transparent proxy support")
case $host in
@@ -1454,8 +1534,7 @@ if test "$GCC" = yes; then
# accident waiting to happen.
CFLAGS="$CFLAGS -Wall -fno-strict-aliasing"
else
- # Autoconf sets -g -O2 by default. Override optimization level
- # for non-gcc compilers
+ # Override optimization level for non-gcc compilers
CFLAGS="$CFLAGS -O"
enable_gcc_warnings=no
enable_gcc_warnings_advisory=no
@@ -1525,7 +1604,7 @@ if test x$enable_gcc_warnings = xyes || test x$enable_gcc_warnings_advisory = xy
if test x$have_gcc4 = xyes ; then
# These warnings break gcc 3.3.5 and work on gcc 4.0.2
- CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wdeclaration-after-statement -Wold-style-definition"
+ CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wold-style-definition"
fi
if test x$have_gcc42 = xyes ; then
@@ -1581,6 +1660,7 @@ AC_CONFIG_FILES([
contrib/dist/torctl
contrib/dist/tor.service
src/config/torrc.sample
+ src/config/torrc.minimal
])
if test x$asciidoc = xtrue && test "$ASCIIDOC" = "none" ; then
@@ -1589,7 +1669,9 @@ if test x$asciidoc = xtrue && test "$ASCIIDOC" = "none" ; then
if ! [[ -f "$srcdir/$file.1.in" ]] || ! [[ -f "$srcdir/$file.html.in" ]] ; then
echo "==================================";
echo;
- echo "You need asciidoc installed to be able to build the manpage.";
+ echo "Building Tor has failed since manpages cannot be built.";
+ echo;
+ echo "You need asciidoc installed to be able to build the manpages.";
echo "To build without manpages, use the --disable-asciidoc argument";
echo "when calling configure.";
echo;
diff --git a/contrib/dist/tor.service.in b/contrib/dist/tor.service.in
index 2fe51c75d9..c251158d9a 100644
--- a/contrib/dist/tor.service.in
+++ b/contrib/dist/tor.service.in
@@ -3,22 +3,27 @@ Description = Anonymizing overlay network for TCP
After = syslog.target network.target nss-lookup.target
[Service]
-Type = simple
+Type = notify
+NotifyAccess = all
ExecStartPre = @BINDIR@/tor -f @CONFDIR@/torrc --verify-config
-# A torrc that has "RunAsDaemon 1" won't work with the "simple" service type;
-# let's explicitly override it.
-ExecStart = @BINDIR@/tor -f @CONFDIR@/torrc --RunAsDaemon 0
+ExecStart = @BINDIR@/tor -f @CONFDIR@/torrc
ExecReload = /bin/kill -HUP ${MAINPID}
KillSignal = SIGINT
TimeoutSec = 30
Restart = on-failure
+WatchdogSec = 1m
LimitNOFILE = 32768
# Hardening
PrivateTmp = yes
-DeviceAllow = /dev/null rw
-DeviceAllow = /dev/urandom r
-InaccessibleDirectories = /home
+PrivateDevices = yes
+ProtectHome = yes
+ProtectSystem = full
+ReadOnlyDirectories = /
+ReadWriteDirectories = -@LOCALSTATEDIR@/lib/tor
+ReadWriteDirectories = -@LOCALSTATEDIR@/log/tor
+NoNewPrivileges = yes
+CapabilityBoundingSet = CAP_SETUID CAP_SETGID CAP_NET_BIND_SERVICE
[Install]
WantedBy = multi-user.target
diff --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in
index af09326f12..576abd2364 100644
--- a/contrib/win32build/tor-mingw.nsi.in
+++ b/contrib/win32build/tor-mingw.nsi.in
@@ -8,7 +8,7 @@
!include "LogicLib.nsh"
!include "FileFunc.nsh"
!insertmacro GetParameters
-!define VERSION "0.2.5.14-dev"
+!define VERSION "0.2.6.12-dev"
!define INSTALLER "tor-${VERSION}-win32.exe"
!define WEBSITE "https://www.torproject.org/"
!define LICENSE "LICENSE"
diff --git a/doc/HACKING b/doc/HACKING
index c69b2a6fee..5c71b74bd1 100644
--- a/doc/HACKING
+++ b/doc/HACKING
@@ -114,6 +114,47 @@ valgrind --leak-check=yes --error-limit=no --show-reachable=yes src/or/tor
pass --undef-value-errors=no to valgrind, or rebuild your openssl
with -DPURIFY.)
+Running lcov for unit test coverage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Lcov is a utility that generates pretty HTML reports of test code coverage.
+To generate such a report:
+
+-----
+ ./configure --enable-coverage
+ make
+ make coverage-html
+ $BROWSER ./coverage_html/index.html
+-----
+
+This will run the tor unit test suite `./src/test/test` and generate the HTML
+coverage code report under the directory ./coverage_html/. To change the
+output directory, use `make coverage-html HTML_COVER_DIR=./funky_new_cov_dir`.
+
+Coverage diffs using lcov are not currently implemented, but are being
+investigated (as of July 2014).
+
+Running the unit tests
+~~~~~~~~~~~~~~~~~~~~~~
+
+To quickly run all tests:
+-----
+ make check
+-----
+
+To run unit tests only:
+-----
+ make test
+-----
+
+To selectively run just some tests (the following can be combined
+arbitrarily):
+-----
+ ./src/test/test <name_of_test> [<name of test 2>] ...
+ ./src/test/test <prefix_of_name_of_test>.. [<prefix_of_name_of_test2>..] ...
+ ./src/test/test :<name_of_excluded_test> [:<name_of_excluded_test2]...
+-----
+
Running gcov for unit test coverage
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -460,7 +501,7 @@ interesting and understandable.
Standard idioms:
"Fixes bug 9999; bugfix on 0.3.3.3-alpha."
- One period after a space.
+ One space after a period.
Make stuff very terse
@@ -492,7 +533,7 @@ interesting and understandable.
2.6) Clean everything one last time.
- 2.7) Run it through fmt to make it pretty.
+ 2.7) Run ./scripts/maint/format_changelog.py to make it prettier.
3) Compose a short release blurb to highlight the user-facing
changes. Insert said release blurb into the ChangeLog stanza. If it's
@@ -514,10 +555,12 @@ in their approved versions list.
git tag -u <keyid> tor-0.2.x.y-status
git push origin tag tor-0.2.x.y-status
-8) scp the tarball and its sig to the website in the dist/ directory
-(i.e. /srv/www-master.torproject.org/htdocs/dist/ on vescum). Edit
-"include/versions.wmi" and "Makefile" to note the new version. From your
-website checkout, run ./publish to build and publish the website.
+8a) scp the tarball and its sig to the dist website, i.e.
+/srv/dist-master.torproject.org/htdocs/ on dist-master. When you want
+it to go live, you run "static-update-component dist.torproject.org"
+on dist-master.
+
+8b) Edit "include/versions.wmi" and "Makefile" to note the new version.
9) Email the packagers (cc'ing tor-assistants) that a new tarball is up.
diff --git a/doc/TUNING b/doc/TUNING
new file mode 100644
index 0000000000..24552a38cb
--- /dev/null
+++ b/doc/TUNING
@@ -0,0 +1,86 @@
+Most operating systems limit an amount of TCP sockets that can be used
+simultaneously. It is possible for a busy Tor relay to run into these
+limits, thus being unable to fully utilize the bandwidth resources it
+has at its disposal. Following system-specific tips might be helpful
+to alleviate the aforementioned problem.
+
+Linux
+-----
+
+Use 'ulimit -n' to raise an allowed number of file descriptors to be
+opened on your host at the same time.
+
+FreeBSD
+-------
+
+Tune the followind sysctl(8) variables:
+ * kern.maxfiles - maximum allowed file descriptors (for entire system)
+ * kern.maxfilesperproc - maximum file descriptors one process is allowed
+ to use
+ * kern.ipc.maxsockets - overall maximum numbers of sockets for entire
+ system
+ * kern.ipc.somaxconn - size of listen queue for incoming TCP connections
+ for entire system
+
+See also:
+ * https://www.freebsd.org/doc/handbook/configtuning-kernel-limits.html
+ * https://wiki.freebsd.org/NetworkPerformanceTuning
+
+Mac OS X
+--------
+
+Since Mac OS X is BSD-based system, most of the above hold for OS X as well.
+However, launchd(8) is known to modify kern.maxfiles and kern.maxfilesperproc
+when it launches tor service (see launchd.plist(5) manpage). Also,
+kern.ipc.maxsockets is determined dynamically by the system and thus is
+read-only on OS X.
+
+OpenBSD
+-------
+
+Because OpenBSD is primarily focused on security and stability, it uses default
+resource limits stricter than those of more popular Unix-like operating systems.
+
+OpenBSD stores a kernel-level file descriptor limit in the sysctl variable
+kern.maxfiles. It defaults to 7,030. To change it to, for example, 16,000 while
+the system is running, use the command 'sudo sysctl kern.maxfiles=16000'.
+kern.maxfiles will reset to the default value upon system reboot unless you also
+add 'kern.maxfiles=16000' to the file /etc/sysctl.conf.
+
+There are stricter resource limits set on user classes, which are stored in
+/etc/login.conf. This config file also allows limit sets for daemons started
+with scripts in the /etc/rc.d directory, which presumably includes Tor.
+
+To increase the file descriptor limit from its default of 1,024, add the
+following to /etc/login.conf:
+
+tor:\
+ :openfiles-max=13500:\
+ :tc=daemon:
+
+Upon restarting Tor, it will be able to open up to 13,500 file descriptors.
+
+This will work *only* if you are starting Tor with the script /etc/rc.d/tor. If
+you're using a custom build instead of the package, you can easily copy the rc.d
+script from the Tor port directory. Alternatively, you can ensure that the Tor's
+daemon user has its own user class and make a /etc/login.conf entry for it.
+
+High-bandwidth relays sometimes give the syslog warning:
+
+/bsd: WARNING: mclpools limit reached; increase kern.maxclusters
+
+In this case, increase kern.maxclusters with the sysctl command and in the file
+/etc/sysctl.conf, as described with kern.maxfiles above. Use 'sysctl
+kern.maxclusters' to query the current value. Increasing by about 15% per day
+until the error no longer appears is a good guideline.
+
+Disclaimer
+----------
+
+Do note that this document is a draft and above information may be
+technically incorrect and/or incomplete. If so, please open a ticket
+on https://trac.torproject.org or post to tor-relays mailing list.
+
+Are you running a busy Tor relay? Let us know how you are solving
+the out-of-sockets problem on your system.
+
diff --git a/doc/building-tor-msvc.txt b/doc/building-tor-msvc.txt
new file mode 100644
index 0000000000..3d3eced8af
--- /dev/null
+++ b/doc/building-tor-msvc.txt
@@ -0,0 +1,122 @@
+Building Tor with MSVC.
+=======================
+
+NOTE: This is not the preferred method for building Tor on windows: we use
+mingw for our packages.
+
+Last updated 9 September 2014.
+
+
+Requirements:
+-------------
+
+ * Visual Studio 2010
+ http://go.microsoft.com/fwlink/?LinkId=323467
+ * CMake 2.8.12.2
+ http://www.cmake.org/download/
+ * Perl 5.16
+ http://www.activestate.com/activeperl/downloads
+ * Latest stable OpenSSL tarball
+ https://www.openssl.org/source/
+ * Latest stable zlib tarball
+ http://zlib.net/
+ * Latest stable libevent Libevent tarball
+ https://github.com/libevent/libevent/releases
+
+Make sure you check signatures for all these packages.
+
+Steps:
+------
+
+Building OpenSSL from source as a shared library:
+
+ cd <openssl source dir>
+ perl Configure VC-WIN32
+ perl util\mkfiles.pl >MINFO
+ perl util\mk1mf.pl no-asm dll VC-WIN32 >32dll.mak
+ perl util\mkdef.pl 32 libeay > ms\libeay32.def
+ perl util\mkdef.pl 32 ssleay > ms\ssleay32.def
+ nmake -f 32dll.mak
+
+Making OpenSSL final package:
+
+ Create <openssl final package dir>, I'd recommend using a name like <openssl
+ source dir>-vc10.
+
+ Copy the following directories and files to their respective locations
+ <openssl source dir>\inc32\openssl => <openssl final package dir>\include\openssl
+ <openssl source dir>\out32dll\libeay32.lib => <openssl final package dir>\lib\libeay32.lib
+ <openssl source dir>\out32dll\ssleay32.lib => <openssl final package dir>\lib\ssleay32.lib
+ <openssl source dir>\out32dll\libeay32.dll => <openssl final package dir>\bin\libeay32.dll
+ <openssl source dir>\out32dll\openssl.exe => <openssl final package dir>\bin\openssl.exe
+ <openssl source dir>\out32dll\ssleay32.dll => <openssl final package dir>\bin\ssleay32.dll
+
+Building Zlib from source:
+
+ cd <zlib source dir>
+ nmake -f win32/Makefile.msc
+
+Building libevent:
+
+ cd <libevent source dir>
+ mkdir build && cd build
+ SET OPENSSL_ROOT_DIR=<openssl final package dir>
+ cmake -G "NMake Makefiles" .. -DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING="/MT /Zi /O2 /Ob1 /D NDEBUG" -DZLIB_LIBRARY:FILEPATH="<zlib source dir>\zdll.lib" -DZLIB_INCLUDE_DIR:PATH="<zlib source dir>"
+ nmake event
+
+Building Tor:
+
+ Create a dir above tor source dir named build-alpha and two subdirs include
+ and lib.
+
+ Your build tree should now be similar to this one:
+ * build-alpha
+ - include
+ - lib
+ * <libevent source dir>
+ - build
+ - cmake
+ - ...
+ * <openssl source dir>
+ - ...
+ - ms
+ - util
+ - ...
+ * <openssl final package dir>
+ - bin
+ - include
+ - lib
+ * <tor source dir>
+ - ...
+ - src
+ - ...
+ * <zlib source dir>
+ - ...
+ - win32
+ - ...
+
+ Copy the following dirs and files to the following locations:
+ <openssl final package dir>\include\openssl => build-alpha\include\openssl
+ <libevent source dir>\include => build-alpha\include
+ <libevent source dir>\WIN32-Code\nmake\event2 => build-alpha\include\event2
+ <zlib source dir>\z*.h => build-alpha\include\z*.h
+
+ Now copy the following files to the following locations and rename them
+ according new names:
+
+ <libevent source dir>\build\lib\event.lib => build-alpha\lib\libevent.lib
+ <openssl final package dir>\lib\libeay32.lib => build-alpha\lib\libcrypto.lib
+ <openssl final package dir>\lib\ssleay32.lib => build-alpha\lib\libssl.lib
+ <zlib source dir>\zdll.lib => build-alpha\lib\libz.lib
+
+ And we are now ready for the build process:
+
+ cd <tor source dir>
+ nmake -f Makefile.nmake
+
+ After the above process is completed there should be a tor.exe in <tor
+ source dir>\src\or
+
+ Copy tor.exe to desired location and also copy zlib1.dll, libeay32.dll and
+ ssleay32.dll from built zlib and openssl packages
+
diff --git a/doc/tor-resolve.1.txt b/doc/tor-resolve.1.txt
index 341d302244..30e16d5daa 100644
--- a/doc/tor-resolve.1.txt
+++ b/doc/tor-resolve.1.txt
@@ -14,7 +14,7 @@ tor-resolve - resolve a hostname to an IP address via tor
SYNOPSIS
--------
-**tor-resolve** [-4|-5] [-v] [-x] __hostname__ [__sockshost__[:__socksport__]]
+**tor-resolve** [-4|-5] [-v] [-x] [-p __socksport__] __hostname__ [__sockshost__[:__socksport__]]
DESCRIPTION
-----------
@@ -40,6 +40,9 @@ OPTIONS
Use the SOCKS4a protocol rather than the default SOCKS5 protocol. Doesn't
support reverse DNS.
+**-p** __socksport__::
+ Override the default SOCKS port without setting the hostname.
+
SEE ALSO
--------
**tor**(1), **torify**(1). +
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 8d51f6e3c2..e136bd0f7e 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -42,7 +42,8 @@ COMMAND-LINE OPTIONS
[[opt-f]] **-f** __FILE__::
Specify a new configuration file to contain further Tor configuration
- options. (Default: @CONFDIR@/torrc, or $HOME/.torrc if that file is not
+ options OR pass *-* to make Tor read its configuration from standard
+ input. (Default: @CONFDIR@/torrc, or $HOME/.torrc if that file is not
found)
[[opt-allow-missing-torrc]] **--allow-missing-torrc**::
@@ -72,7 +73,7 @@ COMMAND-LINE OPTIONS
[[opt-serviceinstall]] **--service install** [**--options** __command-line options__]::
Install an instance of Tor as a Windows service, with the provided
command-line options. Current instructions can be found at
- https://trac.torproject.org/projects/tor/wiki/doc/TorFAQ#HowdoIrunmyTorrelayasanNTservice
+ https://www.torproject.org/docs/faq#NTService
[[opt-service]] **--service** **remove**|**start**|**stop**::
Remove, start, or stop a configured Tor Windows service.
@@ -273,7 +274,7 @@ GENERAL OPTIONS
all sockets will be set to this limit. Must be a value between 2048 and
262144, in 1024 byte increments. Default of 8192 is recommended.
-[[ControlPort]] **ControlPort** __PORT__|**auto**::
+[[ControlPort]] **ControlPort** __PORT__|**unix:**__path__|**auto**::
If set, Tor will accept connections on this port and allow those
connections to control the Tor process using the Tor Control Protocol
(described in control-spec.txt). Note: unless you also specify one or
@@ -294,7 +295,7 @@ GENERAL OPTIONS
[[ControlSocket]] **ControlSocket** __Path__::
Like ControlPort, but listens on a Unix domain socket, rather than a TCP
- socket. (Unix and Unix-like systems only.)
+ socket. '0' disables ControlSocket (Unix and Unix-like systems only.)
[[ControlSocketsGroupWritable]] **ControlSocketsGroupWritable** **0**|**1**::
If this option is set to 0, don't allow the filesystem group to read and
@@ -483,6 +484,11 @@ GENERAL OPTIONS
in accordance to RFC 1929. Both username and password must be between 1 and
255 characters.
+[[SocksSocketsGroupWritable]] **SocksSocketsGroupWritable** **0**|**1**::
+ If this option is set to 0, don't allow the filesystem group to read and
+ write unix sockets (e.g. SocksSocket). If the option is set to 1, make
+ the SocksSocket socket readable and writable by the default GID. (Default: 0)
+
[[KeepalivePeriod]] **KeepalivePeriod** __NUM__::
To keep firewalls from expiring connections, send a padding keepalive cell
every NUM seconds on open connections that are in use. If the connection
@@ -550,7 +556,7 @@ GENERAL OPTIONS
\'info'. (Default: 0)
[[PredictedPortsRelevanceTime]] **PredictedPortsRelevanceTime** __NUM__::
- Set how long, after the client has mad an anonymized connection to a
+ Set how long, after the client has made an anonymized connection to a
given port, we will try to make sure that we build circuits to
exits that support that port. The maximum value for this option is 1
hour. (Default: 1 hour)
@@ -568,6 +574,10 @@ GENERAL OPTIONS
messages to affect times logged by a controller, times attached to
syslog messages, or the mtime fields on log files. (Default: 1 second)
+[[TruncateLogFile]] **TruncateLogFile** **0**|**1**::
+ If 1, Tor will overwrite logs at startup and in response to a HUP signal,
+ instead of appending to them. (Default: 0)
+
[[SafeLogging]] **SafeLogging** **0**|**1**|**relay**::
Tor can scrub potentially sensitive strings from log messages (e.g.
addresses) by replacing them with the string [scrubbed]. This way logs can
@@ -707,10 +717,11 @@ The following options are useful only for clients (that is, if
unless ORPort, ExtORPort, or DirPort are configured.) (Default: 0)
[[ExcludeNodes]] **ExcludeNodes** __node__,__node__,__...__::
- A list of identity fingerprints, nicknames, country codes and address
- patterns of nodes to avoid when building a circuit.
+ A list of identity fingerprints, country codes, and address
+ patterns of nodes to avoid when building a circuit. Country codes must
+ be wrapped in braces; fingerprints may be preceded by a dollar sign.
(Example:
- ExcludeNodes SlowServer, ABCD1234CDEF5678ABCD1234CDEF5678ABCD1234, \{cc}, 255.254.0.0/8) +
+ ExcludeNodes ABCD1234CDEF5678ABCD1234CDEF5678ABCD1234, \{cc}, 255.254.0.0/8) +
+
By default, this option is treated as a preference that Tor is allowed
to override in order to keep working.
@@ -730,11 +741,13 @@ The following options are useful only for clients (that is, if
[[ExcludeExitNodes]] **ExcludeExitNodes** __node__,__node__,__...__::
- A list of identity fingerprints, nicknames, country codes and address
+ A list of identity fingerprints, country codes, and address
patterns of nodes to never use when picking an exit node---that is, a
node that delivers traffic for you outside the Tor network. Note that any
node listed in ExcludeNodes is automatically considered to be part of this
- list too. See also the caveats on the "ExitNodes" option below.
+ list too. See
+ the **ExcludeNodes** option for more information on how to specify
+ nodes. See also the caveats on the "ExitNodes" option below.
[[GeoIPExcludeUnknown]] **GeoIPExcludeUnknown** **0**|**1**|**auto**::
If this option is set to 'auto', then whenever any country code is set in
@@ -745,9 +758,10 @@ The following options are useful only for clients (that is, if
configured or can't be found. (Default: auto)
[[ExitNodes]] **ExitNodes** __node__,__node__,__...__::
- A list of identity fingerprints, nicknames, country codes and address
+ A list of identity fingerprints, country codes, and address
patterns of nodes to use as exit node---that is, a
- node that delivers traffic for you outside the Tor network. +
+ node that delivers traffic for you outside the Tor network. See
+ the **ExcludeNodes** option for more information on how to specify nodes. +
+
Note that if you list too few nodes here, or if you exclude too many exit
nodes with ExcludeExitNodes, you can degrade functionality. For example,
@@ -768,7 +782,7 @@ The following options are useful only for clients (that is, if
this option.
[[EntryNodes]] **EntryNodes** __node__,__node__,__...__::
- A list of identity fingerprints, nicknames, and country codes of nodes
+ A list of identity fingerprints and country codes of nodes
to use for the first hop in your normal circuits.
Normal circuits include all
circuits except for direct connections to directory servers. The Bridge
@@ -776,7 +790,8 @@ The following options are useful only for clients (that is, if
UseBridges is 1, the Bridges are used as your entry nodes. +
+
The ExcludeNodes option overrides this option: any node listed in both
- EntryNodes and ExcludeNodes is treated as excluded.
+ EntryNodes and ExcludeNodes is treated as excluded. See
+ the **ExcludeNodes** option for more information on how to specify nodes.
[[StrictNodes]] **StrictNodes** **0**|**1**::
If StrictNodes is set to 1, Tor will treat the ExcludeNodes option as a
@@ -925,19 +940,21 @@ The following options are useful only for clients (that is, if
but it has not yet been completely constructed. (Default: 32)
[[NodeFamily]] **NodeFamily** __node__,__node__,__...__::
- The Tor servers, defined by their identity fingerprints or nicknames,
+ The Tor servers, defined by their identity fingerprints,
constitute a "family" of similar or co-administered servers, so never use
any two of them in the same circuit. Defining a NodeFamily is only needed
when a server doesn't list the family itself (with MyFamily). This option
- can be used multiple times. In addition to nodes, you can also list
- IP address and ranges and country codes in {curly braces}.
+ can be used multiple times; each instance defines a separate family. In
+ addition to nodes, you can also list IP address and ranges and country
+ codes in {curly braces}. See the **ExcludeNodes** option for more
+ information on how to specify nodes.
[[EnforceDistinctSubnets]] **EnforceDistinctSubnets** **0**|**1**::
If 1, Tor will not put two servers whose IP addresses are "too close" on
the same circuit. Currently, two addresses are "too close" if they lie in
the same /16 range. (Default: 1)
-[[SOCKSPort]] **SOCKSPort** \['address':]__port__|**auto** [_flags_] [_isolation flags_]::
+[[SOCKSPort]] **SOCKSPort** \['address':]__port__|**unix:**__path__|**auto** [_flags_] [_isolation flags_]::
Open this port to listen for connections from SOCKS-speaking
applications. Set this to 0 if you don't want to allow application
connections via SOCKS. Set it to "auto" to have Tor pick a port for
@@ -960,10 +977,10 @@ The following options are useful only for clients (that is, if
(SOCKS 4, SOCKS 5, TransPort connections, NATDPort connections,
and DNSPort requests are all considered to be different protocols.)
**IsolateDestPort**;;
- Don't share circuits with streams targetting a different
+ Don't share circuits with streams targeting a different
destination port.
**IsolateDestAddr**;;
- Don't share circuits with streams targetting a different
+ Don't share circuits with streams targeting a different
destination address.
**SessionGroup=**__INT__;;
If no other isolation rules would prevent it, allow streams
@@ -1014,7 +1031,7 @@ The following options are useful only for clients (that is, if
requests via this connection.
**PreferIPv6Automap**;;
When serving a hostname lookup request on this port that
- should get automapped (according to AutomapHostsOnResove),
+ should get automapped (according to AutomapHostsOnResolve),
if we could return either an IPv4 or an IPv6 answer, prefer
an IPv6 answer. (On by default.)
**PreferSOCKSNoAuth**;;
@@ -1097,6 +1114,17 @@ The following options are useful only for clients (that is, if
download any non-default directory material. It doesn't currently
do anything when we lack a live consensus. (Default: 1)
+[[GuardfractionFile]] **GuardfractionFile** __FILENAME__::
+ V3 authoritative directories only. Configures the location of the
+ guardfraction file which contains information about how long relays
+ have been guards. (Default: unset)
+
+[[UseGuardFraction]] **UseGuardFraction** **0**|**1**|**auto**::
+ This torrc option specifies whether clients should use the
+ guardfraction information found in the consensus during path
+ selection. If it's set to 'auto', clients will do what the
+ UseGuardFraction consensus parameter tells them to do. (Default: auto)
+
[[NumEntryGuards]] **NumEntryGuards** __NUM__::
If UseEntryGuards is set to 1, we will try to pick a total of NUM routers
as long-term entries for our circuits. If NUM is 0, we try to learn
@@ -1318,6 +1346,22 @@ The following options are useful only for clients (that is, if
To enable this option the compile time flag --enable-tor2webmode must be
specified. (Default: 0)
+[[Tor2webRendezvousPoints]] **Tor2webRendezvousPoints** __node__,__node__,__...__::
+ A list of identity fingerprints, nicknames, country codes and
+ address patterns of nodes that are allowed to be used as RPs
+ in HS circuits; any other nodes will not be used as RPs.
+ (Example:
+ Tor2webRendezvousPoints Fastyfasty, ABCD1234CDEF5678ABCD1234CDEF5678ABCD1234, \{cc}, 255.254.0.0/8) +
+ +
+ This feature can only be used if Tor2webMode is also enabled.
+ +
+ ExcludeNodes have higher priority than Tor2webRendezvousPoints,
+ which means that nodes specified in ExcludeNodes will not be
+ picked as RPs.
+ +
+ If no nodes in Tor2webRendezvousPoints are currently available for
+ use, Tor will choose a random node when building HS circuits.
+
[[UseMicrodescriptors]] **UseMicrodescriptors** **0**|**1**|**auto**::
Microdescriptors are a smaller version of the information that Tor needs
in order to build its circuits. Using microdescriptors makes Tor clients
@@ -1415,16 +1459,6 @@ The following options are useful only for clients (that is, if
Tor will use a default value chosen by the directory
authorities. (Default: -1.)
-[[Support022HiddenServices]] **Support022HiddenServices** **0**|**1**|**auto**::
- Tor hidden services running versions before 0.2.3.x required clients to
- send timestamps, which can potentially be used to distinguish clients
- whose view of the current time is skewed. If this option is set to 0, we
- do not send this timestamp, and hidden services on obsolete Tor versions
- will not work. If this option is set to 1, we send the timestamp. If
- this optoin is "auto", we take a recommendation from the latest consensus
- document. (Default: auto)
-
-
SERVER OPTIONS
--------------
@@ -1468,6 +1502,19 @@ is non-zero):
that it's an email address and/or generate a new address for this
purpose.
+[[ExitRelay]] **ExitRelay** **0**|**1**|**auto**::
+ Tells Tor whether to run as an exit relay. If Tor is running as a
+ non-bridge server, and ExitRelay is set to 1, then Tor allows traffic to
+ exit according to the ExitPolicy option (or the default ExitPolicy if
+ none is specified).
+ +
+ If ExitRelay is set to 0, no traffic is allowed to
+ exit, and the ExitPolicy option is ignored. +
+ +
+ If ExitRelay is set to "auto", then Tor behaves as if it were set to 1, but
+ warns the user if this would cause traffic to exit. In a future version,
+ the default value will be 0. (Default: auto)
+
[[ExitPolicy]] **ExitPolicy** __policy__,__policy__,__...__::
Set an exit policy for this server. Each policy is of the form
"**accept**|**reject** __ADDR__[/__MASK__][:__PORT__]". If /__MASK__ is
@@ -1534,7 +1581,7 @@ is non-zero):
[[MyFamily]] **MyFamily** __node__,__node__,__...__::
Declare that this Tor server is controlled or administered by a group or
organization identical or similar to that of the other servers, defined by
- their identity fingerprints or nicknames. When two servers both declare
+ their identity fingerprints. When two servers both declare
that they are in the same \'family', Tor clients will not use them in the
same circuit. (Each server only needs to list the other servers in its
family; it doesn't need to list itself, but it won't hurt.) Do not list
@@ -1631,19 +1678,31 @@ is non-zero):
to 0 will disable the heartbeat. (Default: 6 hours)
[[AccountingMax]] **AccountingMax** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**KBits**|**MBits**|**GBits**|**TBytes**::
- Never send more than the specified number of bytes in a given accounting
- period, or receive more than that number in the period. For example, with
- AccountingMax set to 1 GByte, a server could send 900 MBytes and
- receive 800 MBytes and continue running. It will only hibernate once
- one of the two reaches 1 GByte. When the number of bytes gets low,
- Tor will stop accepting new connections and circuits. When the
- number of bytes is exhausted, Tor will hibernate until some
- time in the next accounting period. To prevent all servers from waking at
- the same time, Tor will also wait until a random point in each period
- before waking up. If you have bandwidth cost issues, enabling hibernation
- is preferable to setting a low bandwidth, since it provides users with a
- collection of fast servers that are up some of the time, which is more
- useful than a set of slow servers that are always "available".
+ Limits the max number of bytes sent and received within a set time period
+ using a given calculation rule (see: AccountingStart, AccountingRule).
+ Useful if you need to stay under a specific bandwidth. By default, the
+ number used for calculation is the max of either the bytes sent or
+ received. For example, with AccountingMax set to 1 GByte, a server
+ could send 900 MBytes and receive 800 MBytes and continue running.
+ It will only hibernate once one of the two reaches 1 GByte. This can
+ be changed to use the sum of the both bytes received and sent by setting
+ the AccountingRule option to "sum" (total bandwidth in/out). When the
+ number of bytes remaining gets low, Tor will stop accepting new connections
+ and circuits. When the number of bytes is exhausted, Tor will hibernate
+ until some time in the next accounting period. To prevent all servers
+ from waking at the same time, Tor will also wait until a random point
+ in each period before waking up. If you have bandwidth cost issues,
+ enabling hibernation is preferable to setting a low bandwidth, since
+ it provides users with a collection of fast servers that are up some
+ of the time, which is more useful than a set of slow servers that are
+ always "available".
+
+[[AccountingRule]] **AccountingRule** **sum**|**max**::
+ How we determine when our AccountingMax has been reached (when we
+ should hibernate) during a time interval. Set to "max" to calculate
+ using the higher of either the sent or received bytes (this is the
+ default functionality). Set to "sum" to calculate using the sent
+ plus received bytes. (Default: max)
[[AccountingStart]] **AccountingStart** **day**|**week**|**month** [__day__] __HH:MM__::
Specify how long accounting periods last. If **month** is given, each
@@ -1751,6 +1810,13 @@ is non-zero):
When this option is enabled, Tor writes statistics on the bidirectional use
of connections to disk every 24 hours. (Default: 0)
+[[HiddenServiceStatistics]] **HiddenServiceStatistics** **0**|**1**::
+ When this option is enabled, a Tor relay writes obfuscated
+ statistics on its role as hidden-service directory, introduction
+ point, or rendezvous point to disk every 24 hours. If
+ ExtraInfoStatistics is also enabled, these statistics are further
+ published to the directory authorities. (Default: 0)
+
[[ExtraInfoStatistics]] **ExtraInfoStatistics** **0**|**1**::
When this option is enabled, Tor includes previously gathered statistics in
its extra-info documents that it uploads to the directory authorities.
@@ -1841,15 +1907,6 @@ on the public Tor network.
authorities provide this service optionally. See **RecommendedVersions**,
**RecommendedClientVersions**, and **RecommendedServerVersions**.
-[[NamingAuthoritativeDirectory]] **NamingAuthoritativeDirectory** **0**|**1**::
- When this option is set to 1, then the server advertises that it has
- opinions about nickname-to-fingerprint bindings. It will include these
- opinions in its published network-status pages, by listing servers with
- the flag "Named" if a correct binding between that nickname and fingerprint
- has been registered with the dirserver. Naming dirservers will refuse to
- accept or publish descriptors that contradict a registered binding. See
- **approved-routers** in the **FILES** section below.
-
[[RecommendedVersions]] **RecommendedVersions** __STRING__::
STRING is a comma-separated list of Tor versions currently believed to be
safe. The list is included in each directory, and nodes which pull down the
@@ -1857,6 +1914,12 @@ on the public Tor network.
multiple times: the values from multiple lines are spliced together. When
this is set then **VersioningAuthoritativeDirectory** should be set too.
+[[RecommendedPackageVersions]] **RecommendedPackageVersions** __PACKAGENAME__ __VERSION__ __URL__ __DIGESTTYPE__**=**__DIGEST__ ::
+ Adds "package" line to the directory authority's vote. This information
+ is used to vote on the correct URL and digest for the released versions
+ of different Tor-related packages, so that the consensus can certify
+ them. This line may appear any number of times.
+
[[RecommendedClientVersions]] **RecommendedClientVersions** __STRING__::
STRING is a comma-separated list of Tor versions currently believed to be
safe for clients to use. This information is included in version 2
@@ -1889,20 +1952,15 @@ on the public Tor network.
elements. Otherwise, if the address is not an IP address or is a private IP
address, it will reject the router descriptor. (Default: 0)
-[[AuthDirBadDir]] **AuthDirBadDir** __AddressPattern...__::
+[[AuthDirBadExit]] **AuthDirBadExit** __AddressPattern...__::
Authoritative directories only. A set of address patterns for servers that
- will be listed as bad directories in any network status document this
- authority publishes, if **AuthDirListBadDirs** is set. +
+ will be listed as bad exits in any network status document this authority
+ publishes, if **AuthDirListBadExits** is set.
+
(The address pattern syntax here and in the options below
is the same as for exit policies, except that you don't need to say
"accept" or "reject", and ports are not needed.)
-[[AuthDirBadExit]] **AuthDirBadExit** __AddressPattern...__::
- Authoritative directories only. A set of address patterns for servers that
- will be listed as bad exits in any network status document this authority
- publishes, if **AuthDirListBadExits** is set.
-
[[AuthDirInvalid]] **AuthDirInvalid** __AddressPattern...__::
Authoritative directories only. A set of address patterns for servers that
will never be listed as "valid" in any network status document that this
@@ -1914,8 +1972,6 @@ on the public Tor network.
authority publishes, or accepted as an OR address in any descriptor
submitted for publication by this authority.
-[[AuthDirBadDirCCs]] **AuthDirBadDirCCs** __CC__,... +
-
[[AuthDirBadExitCCs]] **AuthDirBadExitCCs** __CC__,... +
[[AuthDirInvalidCCs]] **AuthDirInvalidCCs** __CC__,... +
@@ -1923,28 +1979,15 @@ on the public Tor network.
[[AuthDirRejectCCs]] **AuthDirRejectCCs** __CC__,...::
Authoritative directories only. These options contain a comma-separated
list of country codes such that any server in one of those country codes
- will be marked as a bad directory/bad exit/invalid for use, or rejected
+ will be marked as a bad exit/invalid for use, or rejected
entirely.
-[[AuthDirListBadDirs]] **AuthDirListBadDirs** **0**|**1**::
- Authoritative directories only. If set to 1, this directory has some
- opinion about which nodes are unsuitable as directory caches. (Do not set
- this to 1 unless you plan to list non-functioning directories as bad;
- otherwise, you are effectively voting in favor of every declared
- directory.)
-
[[AuthDirListBadExits]] **AuthDirListBadExits** **0**|**1**::
Authoritative directories only. If set to 1, this directory has some
opinion about which nodes are unsuitable as exit nodes. (Do not set this to
1 unless you plan to list non-functioning exits as bad; otherwise, you are
effectively voting in favor of every declared exit as an exit.)
-[[AuthDirRejectUnlisted]] **AuthDirRejectUnlisted** **0**|**1**::
- Authoritative directories only. If set to 1, the directory server rejects
- all uploaded server descriptors that aren't explicitly listed in the
- fingerprints file. This acts as a "panic button" if we get hit with a Sybil
- attack. (Default: 0)
-
[[AuthDirMaxServersPerAddr]] **AuthDirMaxServersPerAddr** __NUM__::
Authoritative directories only. The maximum number of servers that we will
list as acceptable on a single IP address. Set this to "0" for "no limit".
@@ -2041,13 +2084,19 @@ The following options are used to configure a hidden service.
Store data files for a hidden service in DIRECTORY. Every hidden service
must have a separate directory. You may use this option multiple times to
specify multiple services. DIRECTORY must be an existing directory.
+ (Note: in current versions of Tor, if DIRECTORY is a relative path,
+ it will be relative to current
+ working directory of Tor instance, not to its DataDirectory. Do not
+ rely on this behavior; it is not guaranteed to remain the same in future
+ versions.)
[[HiddenServicePort]] **HiddenServicePort** __VIRTPORT__ [__TARGET__]::
Configure a virtual port VIRTPORT for a hidden service. You may use this
option multiple times; each time applies to the service using the most
- recent hiddenservicedir. By default, this option maps the virtual port to
+ recent HiddenServiceDir. By default, this option maps the virtual port to
the same port on 127.0.0.1 over TCP. You may override the target port,
address, or both by specifying a target of addr, port, or addr:port.
+ (You can specify an IPv6 target as [addr]:port.)
You may also have multiple lines with the same VIRTPORT: when a user
connects to that VIRTPORT, one of the TARGETs from those lines will be
chosen at random.
@@ -2074,11 +2123,23 @@ The following options are used to configure a hidden service.
found in the hostname file. Clients need to put this authorization data in
their configuration file using **HidServAuth**.
+[[HiddenServiceAllowUnknownPorts]] **HiddenServiceAllowUnknownPorts** **0**|**1**::
+ If set to 1, then connections to unrecognized ports do not cause the
+ current hidden service to close rendezvous circuits. (Setting this to 0 is
+ not an authorization mechanism; it is instead meant to be a mild
+ inconvenience to port-scanners.) (Default: 0)
+
[[RendPostPeriod]] **RendPostPeriod** __N__ **seconds**|**minutes**|**hours**|**days**|**weeks**::
Every time the specified period elapses, Tor uploads any rendezvous
service descriptors to the directory servers. This information is also
uploaded whenever it changes. (Default: 1 hour)
+[[HiddenServiceDirGroupReadable]] **HiddenServiceDirGroupReadable** **0**|**1**::
+ If this option is set to 1, allow the filesystem group to read the
+ hidden service directory and hostname file. If the option is set to 0,
+ only owner is able to read the hidden service directory. (Default: 0)
+ Has no effect on Windows.
+
TESTING NETWORK OPTIONS
-----------------------
@@ -2210,8 +2271,18 @@ The following options are used for running a testing Tor network.
Try this often to download a v3 authority certificate before giving up.
Changing this requires that **TestingTorNetwork** is set. (Default: 8)
+[[TestingDirAuthVoteExit]] **TestingDirAuthVoteExit** __node__,__node__,__...__::
+ A list of identity fingerprints, country codes, and
+ address patterns of nodes to vote Exit for regardless of their
+ uptime, bandwidth, or exit policy. See the **ExcludeNodes**
+ option for more information on how to specify nodes.
+ +
+ In order for this option to have any effect, **TestingTorNetwork**
+ has to be set. See the **ExcludeNodes** option for more
+ information on how to specify nodes.
+
[[TestingDirAuthVoteGuard]] **TestingDirAuthVoteGuard** __node__,__node__,__...__::
- A list of identity fingerprints, nicknames, country codes and
+ A list of identity fingerprints and country codes and
address patterns of nodes to vote Guard for regardless of their
uptime and bandwidth. See the **ExcludeNodes** option for more
information on how to specify nodes.
@@ -2219,6 +2290,15 @@ The following options are used for running a testing Tor network.
In order for this option to have any effect, **TestingTorNetwork**
has to be set.
+[[TestingDirAuthVoteHSDir]] **TestingDirAuthVoteHSDir** __node__,__node__,__...__::
+ A list of identity fingerprints and country codes and
+ address patterns of nodes to vote HSDir for regardless of their
+ uptime and ORPort connectivity. See the **ExcludeNodes** option for more
+ information on how to specify nodes.
+ +
+ In order for this option to have any effect, **TestingTorNetwork**
+ and **VoteOnHidServDirectoriesV2** both have to be set.
+
[[TestingEnableConnBwEvent]] **TestingEnableConnBwEvent** **0**|**1**::
If this option is set, then Tor controllers may register for CONN_BW
events. Changing this requires that **TestingTorNetwork** is set.
@@ -2352,16 +2432,6 @@ __DataDirectory__**/hashed-fingerprint**::
Only used by bridges. Holds the hashed fingerprint of the bridge's
identity key. (That is, the hash of the hash of the identity key.)
-__DataDirectory__**/approved-routers**::
- Only for naming authoritative directory servers (see
- **NamingAuthoritativeDirectory**). This file lists nickname to identity
- bindings. Each line lists a nickname and a fingerprint separated by
- whitespace. See your **fingerprint** file in the __DataDirectory__ for an
- example line. If the nickname is **!reject** then descriptors from the
- given identity (fingerprint) are rejected by this server. If it is
- **!invalid** then descriptors are accepted but marked in the directory as
- not valid, that is, not recommended.
-
__DataDirectory__**/v3-status-votes**::
Only for authoritative directory servers. This file contains status votes
from all the authoritative directory servers and is used to generate the
@@ -2409,6 +2479,11 @@ __DataDirectory__**/stats/conn-stats**::
Only used by servers. This file is used to collect approximate connection
history (number of active connections over time).
+__DataDirectory__**/networkstatus-bridges**::
+ Only used by authoritative bridge directories. Contains information
+ about bridges that have self-reported themselves to the bridge
+ authority.
+
__HiddenServiceDirectory__**/hostname**::
The <base32-encoded-fingerprint>.onion domain name for this hidden service.
If the hidden service is restricted to authorized clients only, this file
diff --git a/m4/pkg.m4 b/m4/pkg.m4
new file mode 100644
index 0000000000..c5b26b52e6
--- /dev/null
+++ b/m4/pkg.m4
@@ -0,0 +1,214 @@
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+#
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_default([$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes ],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+ ])
+elif test $pkg_failed = untried; then
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+ ])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ $3
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+
+# PKG_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable pkgconfigdir as the location where a module
+# should install pkg-config .pc files. By default the directory is
+# $libdir/pkgconfig, but the default can be changed by passing
+# DIRECTORY. The user can override through the --with-pkgconfigdir
+# parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+ [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+ [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_INSTALLDIR
+
+
+# PKG_NOARCH_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable noarch_pkgconfigdir as the location where a
+# module should install arch-independent pkg-config .pc files. By
+# default the directory is $datadir/pkgconfig, but the default can be
+# changed by passing DIRECTORY. The user can override through the
+# --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+ [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+ [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_NOARCH_INSTALLDIR
+
+
+# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -------------------------------------------
+# Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])# PKG_CHECK_VAR
diff --git a/scripts/README b/scripts/README
index 70c763923c..02faabe06b 100644
--- a/scripts/README
+++ b/scripts/README
@@ -56,3 +56,8 @@ for servers to choose from.
codegen/get_mozilla_ciphers.py -- Generate a list of TLS ciphersuites for
clients to use in order to look like Firefox.
+Code transformation scripts
+---------------------------
+
+coccinelle/calloc.cocci -- Transform code to replace variants of
+malloc(a*b) with calloc(a,b)
diff --git a/scripts/coccinelle/calloc.cocci b/scripts/coccinelle/calloc.cocci
new file mode 100644
index 0000000000..fbda88e538
--- /dev/null
+++ b/scripts/coccinelle/calloc.cocci
@@ -0,0 +1,23 @@
+// Use calloc or realloc as appropriate instead of multiply-and-alloc
+
+@malloc_to_calloc@
+identifier f =~ "(tor_malloc|tor_malloc_zero)";
+expression a;
+constant b;
+@@
+- f(a * b)
++ tor_calloc(a, b)
+
+@calloc_arg_order@
+expression a;
+type t;
+@@
+- tor_calloc(sizeof(t), a)
++ tor_calloc(a, sizeof(t))
+
+@realloc_to_reallocarray@
+expression a, b;
+expression p;
+@@
+- tor_realloc(p, a * b)
++ tor_reallocarray(p, a, b)
diff --git a/scripts/coccinelle/malloc_cast.cocci b/scripts/coccinelle/malloc_cast.cocci
new file mode 100644
index 0000000000..20321d4fd0
--- /dev/null
+++ b/scripts/coccinelle/malloc_cast.cocci
@@ -0,0 +1,38 @@
+@cast_malloc@
+expression e;
+type T;
+@@
+- (T *)tor_malloc(e)
++ tor_malloc(e)
+
+@cast_malloc_zero@
+expression e;
+type T;
+identifier func;
+@@
+- (T *)tor_malloc_zero(e)
++ tor_malloc_zero(e)
+
+@cast_calloc@
+expression a, b;
+type T;
+identifier func;
+@@
+- (T *)tor_calloc(a, b)
++ tor_calloc(a, b)
+
+@cast_realloc@
+expression e;
+expression p;
+type T;
+@@
+- (T *)tor_realloc(p, e)
++ tor_realloc(p, e)
+
+@cast_reallocarray@
+expression a,b;
+expression p;
+type T;
+@@
+- (T *)tor_reallocarray(p, a, b)
++ tor_reallocarray(p, a, b)
diff --git a/scripts/coccinelle/uncalloc.cocci b/scripts/coccinelle/uncalloc.cocci
new file mode 100644
index 0000000000..bf3f74165a
--- /dev/null
+++ b/scripts/coccinelle/uncalloc.cocci
@@ -0,0 +1,13 @@
+
+@@
+expression a;
+@@
+- tor_calloc(1, a)
++ tor_malloc_zero(a)
+
+@@
+expression a;
+@@
+- tor_calloc(a, 1)
++ tor_malloc_zero(a)
+
diff --git a/scripts/codegen/gen_server_ciphers.py b/scripts/codegen/gen_server_ciphers.py
index 97ed9d0469..0dca8a6734 100755
--- a/scripts/codegen/gen_server_ciphers.py
+++ b/scripts/codegen/gen_server_ciphers.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-# Copyright 2014, The Tor Project, Inc
+# Copyright 2014-2015, The Tor Project, Inc
# See LICENSE for licensing information
# This script parses openssl headers to find ciphersuite names, determines
diff --git a/scripts/codegen/get_mozilla_ciphers.py b/scripts/codegen/get_mozilla_ciphers.py
index 0636eb3658..e0a662bea0 100644
--- a/scripts/codegen/get_mozilla_ciphers.py
+++ b/scripts/codegen/get_mozilla_ciphers.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
# coding=utf-8
-# Copyright 2011, The Tor Project, Inc
+# Copyright 2011-2015, The Tor Project, Inc
# original version by Arturo Filastò
# See LICENSE for licensing information
diff --git a/scripts/codegen/makedesc.py b/scripts/codegen/makedesc.py
new file mode 100644
index 0000000000..833951945b
--- /dev/null
+++ b/scripts/codegen/makedesc.py
@@ -0,0 +1,218 @@
+#!/usr/bin/python
+# Copyright 2014-2015, The Tor Project, Inc.
+# See LICENSE for license information
+
+# This is a kludgey python script that uses ctypes and openssl to sign
+# router descriptors and extrainfo documents and put all the keys in
+# the right places. There are examples at the end of the file.
+
+# I've used this to make inputs for unit tests. I wouldn't suggest
+# using it for anything else.
+
+import base64
+import binascii
+import ctypes
+import ctypes.util
+import hashlib
+
+crypt = ctypes.CDLL(ctypes.util.find_library('crypto'))
+BIO_s_mem = crypt.BIO_s_mem
+BIO_s_mem.argtypes = []
+BIO_s_mem.restype = ctypes.c_void_p
+
+BIO_new = crypt.BIO_new
+BIO_new.argtypes = [ctypes.c_void_p]
+BIO_new.restype = ctypes.c_void_p
+
+RSA_generate_key = crypt.RSA_generate_key
+RSA_generate_key.argtypes = [ctypes.c_int, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_void_p]
+RSA_generate_key.restype = ctypes.c_void_p
+
+RSA_private_encrypt = crypt.RSA_private_encrypt
+RSA_private_encrypt.argtypes = [
+ ctypes.c_int, ctypes.c_char_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int ]
+RSA_private_encrypt.restype = ctypes.c_int
+
+i2d_RSAPublicKey = crypt.i2d_RSAPublicKey
+i2d_RSAPublicKey.argtypes = [
+ ctypes.c_void_p, ctypes.POINTER(ctypes.c_char_p)
+]
+i2d_RSAPublicKey.restype = ctypes.c_int
+
+def b64(x):
+ x = base64.b64encode(x)
+ res = []
+ for i in xrange(0, len(x), 64):
+ res.append(x[i:i+64]+"\n")
+ return "".join(res)
+
+def bio_extract(bio):
+ buf = ctypes.c_char_p()
+ length = crypt.BIO_ctrl(bio, 3, 0, ctypes.byref(buf))
+ return ctypes.string_at(buf, length)
+
+def make_key(e=65537):
+ rsa = crypt.RSA_generate_key(1024, e, None, None)
+ bio = BIO_new(BIO_s_mem())
+ crypt.PEM_write_bio_RSAPublicKey(bio, rsa)
+ pem = bio_extract(bio).rstrip()
+ crypt.BIO_free(bio)
+
+ buf = ctypes.create_string_buffer(1024)
+ pBuf = ctypes.c_char_p(ctypes.addressof(buf))
+ n = crypt.i2d_RSAPublicKey(rsa, ctypes.byref(pBuf))
+ s = buf.raw[:n]
+ digest = hashlib.sha1(s).digest()
+
+ return (rsa,pem,digest)
+
+def signdesc(body, args_out=None):
+ rsa, ident_pem, id_digest = make_key()
+ _, onion_pem, _ = make_key()
+
+ hexdigest = binascii.b2a_hex(id_digest).upper()
+ fingerprint = " ".join(hexdigest[i:i+4] for i in range(0,len(hexdigest),4))
+
+ MAGIC = "<<<<<<MAGIC>>>>>>"
+ args = {
+ "RSA-IDENTITY" : ident_pem,
+ "ONION-KEY" : onion_pem,
+ "FINGERPRINT" : fingerprint,
+ "FINGERPRINT-NOSPACE" : hexdigest,
+ "RSA-SIGNATURE" : MAGIC
+ }
+ if args_out:
+ args_out.update(args)
+ body = body.format(**args)
+
+ idx = body.rindex("\nrouter-signature")
+ end_of_sig = body.index("\n", idx+1)
+
+ signed_part = body[:end_of_sig+1]
+
+ digest = hashlib.sha1(signed_part).digest()
+ assert len(digest) == 20
+
+ buf = ctypes.create_string_buffer(1024)
+ n = RSA_private_encrypt(20, digest, buf, rsa, 1)
+ sig = buf.raw[:n]
+
+ sig = """-----BEGIN SIGNATURE-----
+%s
+-----END SIGNATURE-----""" % b64(sig).rstrip()
+ body = body.replace(MAGIC, sig)
+
+ return body.rstrip()
+
+def emit_ri(name, body, args_out=None):
+ print "const char %s[] ="%name
+ body = "\n".join(line.rstrip() for line in body.split("\n"))+"\n"
+ b = signdesc(body, args_out)
+ for line in b.split("\n"):
+ print ' "%s\\n"'%line
+ print " ;"
+
+def emit_ei(name, body):
+ args = { 'NAME' : name }
+ emit_ri(name, body, args)
+ args['key'] = "\n".join(
+ ' "%s\\n"'%line for line in args['RSA-IDENTITY'].split("\n"))
+ print """
+const char {NAME}_fp[] = "{FINGERPRINT-NOSPACE}";
+const char {NAME}_key[] =
+{key};""".format(**args)
+
+if 0:
+ emit_ri("minimal",
+ """\
+router fred 127.0.0.1 9001 0 9002
+signing-key
+{RSA-IDENTITY}
+onion-key
+{ONION-KEY}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+reject *:*
+router-signature
+{RSA-SIGNATURE}
+""")
+
+if 0:
+ emit_ri("maximal",
+ """\
+router fred 127.0.0.1 9001 0 9002
+signing-key
+{RSA-IDENTITY}
+onion-key
+{ONION-KEY}
+published 2014-10-05 12:00:00
+bandwidth 1000 1000 1000
+reject 127.0.0.1:*
+accept *:80
+reject *:*
+ipv6-policy accept 80,100,101
+ntor-onion-key s7rSohmz9SXn8WWh1EefTHIsWePthsEntQi0WL+ScVw
+uptime 1000
+hibernating 0
+unrecognized-keywords are just dandy in this format
+platform Tor 0.2.4.23 on a Banana PC Jr 6000 Series
+contact O.W.Jones
+fingerprint {FINGERPRINT}
+read-history 900 1,2,3,4
+write-history 900 1,2,3,4
+extra-info-digest AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+hidden-service-dir
+allow-single-hop-exits
+family $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
+caches-extra-info
+or-address [::1:2:3:4]:9999
+or-address 127.0.0.99:10000
+opt fred is a fine router
+router-signature
+{RSA-SIGNATURE}
+""")
+
+if 0:
+ emit_ei("maximal",
+"""\
+extra-info bob {FINGERPRINT-NOSPACE}
+published 2014-10-05 20:07:00
+opt foobarbaz
+read-history 900 1,2,3
+write-history 900 1,2,3
+dirreq-v2-ips 1
+dirreq-v3-ips 100
+dirreq-v3-reqs blahblah
+dirreq-v2-share blahblah
+dirreq-v3-share blahblah
+dirreq-v2-resp djfkdj
+dirreq-v3-resp djfkdj
+dirreq-v2-direct-dl djfkdj
+dirreq-v3-direct-dl djfkdj
+dirreq-v2-tunneled-dl djfkdj
+dirreq-v3-tunneled-dl djfkdj
+dirreq-stats-end foobar
+entry-ips jfsdfds
+entry-stats-end ksdflkjfdkf
+cell-stats-end FOO
+cell-processed-cells FOO
+cell-queued-cells FOO
+cell-time-in-queue FOO
+cell-circuits-per-decile FOO
+exit-stats-end FOO
+exit-kibibytes-written FOO
+exit-kibibytes-read FOO
+exit-streams-opened FOO
+router-signature
+{RSA-SIGNATURE}
+""")
+
+if 0:
+ emit_ei("minimal",
+"""\
+extra-info bob {FINGERPRINT-NOSPACE}
+published 2014-10-05 20:07:00
+router-signature
+{RSA-SIGNATURE}
+""")
+
diff --git a/scripts/codegen/run_trunnel.sh b/scripts/codegen/run_trunnel.sh
new file mode 100755
index 0000000000..5f694ce6c9
--- /dev/null
+++ b/scripts/codegen/run_trunnel.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+if test "x$TRUNNEL_PATH" != "x"; then
+ PYTHONPATH="${TRUNNEL_PATH}:${PYTHONPATH}"
+ export PYTHONPATH
+fi
+
+python -m trunnel --require-version=1.2 ./src/trunnel/*.trunnel
+
+python -m trunnel --require-version=1.2 --write-c-files --target-dir=./src/ext/trunnel/
+
diff --git a/scripts/maint/checkSpace.pl b/scripts/maint/checkSpace.pl
index 682dbced00..c785d89567 100755
--- a/scripts/maint/checkSpace.pl
+++ b/scripts/maint/checkSpace.pl
@@ -13,30 +13,45 @@ for $fn (@ARGV) {
$incomment = 0;
while (<F>) {
## Warn about windows-style newlines.
+ # (We insist on lines that end with a single LF character, not
+ # CR LF.)
if (/\r/) {
print " CR:$fn:$.\n";
}
## Warn about tabs.
+ # (We only use spaces)
if (/\t/) {
print " TAB:$fn:$.\n";
}
- ## Warn about markers that don't have a space in front of them
+ ## Warn about labels that don't have a space in front of them
+ # (We indent every label at least one space)
if (/^[a-zA-Z_][a-zA-Z_0-9]*:/) {
print "nosplabel:$fn:$.\n";
}
## Warn about trailing whitespace.
+ # (We don't allow whitespace at the end of the line; make your
+ # editor highlight it for you so you can stop adding it in.)
if (/ +$/) {
print "Space\@EOL:$fn:$.\n";
}
## Warn about control keywords without following space.
+ # (We put a space after every 'if', 'while', 'for', 'switch', etc)
if ($C && /\s(?:if|while|for|switch)\(/) {
print " KW(:$fn:$.\n";
}
## Warn about #else #if instead of #elif.
+ # (We only allow #elif)
if (($lastline =~ /^\# *else/) and ($_ =~ /^\# *if/)) {
print " #else#if:$fn:$.\n";
}
## Warn about some K&R violations
+ # (We use K&R-style C, where open braces go on the same line as
+ # the statement that introduces them. In other words:
+ # if (a) {
+ # stuff;
+ # } else {
+ # other stuff;
+ # }
if (/^\s+\{/ and $lastline =~ /^\s*(if|while|for|else if)/ and
$lastline !~ /\{$/) {
print "non-K&R {:$fn:$.\n";
@@ -46,10 +61,13 @@ for $fn (@ARGV) {
}
$lastline = $_;
## Warn about unnecessary empty lines.
+ # (Don't put an empty line before a line that contains nothing
+ # but a closing brace.)
if ($lastnil && /^\s*}\n/) {
print " UnnecNL:$fn:$.\n";
}
## Warn about multiple empty lines.
+ # (At most one blank line in a row.)
if ($lastnil && /^$/) {
print " DoubleNL:$fn:$.\n";
} elsif (/^$/) {
@@ -59,6 +77,7 @@ for $fn (@ARGV) {
}
## Terminals are still 80 columns wide in my world. I refuse to
## accept double-line lines.
+ # (Don't make lines wider than 80 characters, including newline.)
if (/^.{80}/) {
print " Wide:$fn:$.\n";
}
@@ -83,11 +102,13 @@ for $fn (@ARGV) {
s!"(?:[^\"]+|\\.)*"!"X"!g;
next if /^\#/;
## Warn about C++-style comments.
+ # (Use C style comments only.)
if (m!//!) {
# print " //:$fn:$.\n";
s!//.*!!;
}
## Warn about unquoted braces preceded by non-space.
+ # (No character except a space should come before a {)
if (/([^\s'])\{/) {
print " $1\{:$fn:$.\n";
}
@@ -101,15 +122,21 @@ for $fn (@ARGV) {
# print " {X:$fn:$.\n";
#}
## Warn about function calls with space before parens.
+ # (Don't put a space between the name of a function and its
+ # arguments.)
if (/(\w+)\s\(([A-Z]*)/) {
if ($1 ne "if" and $1 ne "while" and $1 ne "for" and
$1 ne "switch" and $1 ne "return" and $1 ne "int" and
$1 ne "elsif" and $1 ne "WINAPI" and $2 ne "WINAPI" and
- $1 ne "void" and $1 ne "__attribute__" and $1 ne "op") {
+ $1 ne "void" and $1 ne "__attribute__" and $1 ne "op" and
+ $1 ne "size_t" and $1 ne "double") {
print " fn ():$fn:$.\n";
}
}
## Warn about functions not declared at start of line.
+ # (When you're declaring functions, put "static" and "const"
+ # and the return type on one line, and the function name at
+ # the start of a new line.)
if ($in_func_head ||
($fn !~ /\.h$/ && /^[a-zA-Z0-9_]/ &&
! /^(?:const |static )*(?:typedef|struct|union)[^\(]*$/ &&
@@ -130,6 +157,8 @@ for $fn (@ARGV) {
}
}
}
+ ## Warn if the file doesn't end with a blank line.
+ # (End each file with a single blank line.)
if (! $lastnil) {
print " EOL\@EOF:$fn:$.\n";
}
diff --git a/scripts/maint/format_changelog.py b/scripts/maint/format_changelog.py
index f67e89b602..d1b4a3dff3 100755
--- a/scripts/maint/format_changelog.py
+++ b/scripts/maint/format_changelog.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-# Copyright (c) 2014, The Tor Project, Inc.
+# Copyright (c) 2014-2015, The Tor Project, Inc.
# See LICENSE for licensing information
#
# This script reformats a section of the changelog to wrap everything to
@@ -12,6 +12,7 @@
import os
import re
import sys
+import optparse
# ==============================
# Oh, look! It's a cruddy approximation to Knuth's elegant text wrapping
@@ -33,6 +34,9 @@ import sys
NO_HYPHENATE=set("""
pf-divert
+tor-resolve
+tor-gencert
+tor-fw-helper
""".split())
LASTLINE_UNDERFLOW_EXPONENT = 1
@@ -115,7 +119,10 @@ def wrap_graf(words, prefix_len1=0, prefix_len2=0, width=72):
return lines
-def hyphenateable(word):
+def hyphenatable(word):
+ if "--" in word:
+ return False
+
if re.match(r'^[^\d\-]\D*-', word):
stripped = re.sub(r'^\W+','',word)
stripped = re.sub(r'\W+$','',word)
@@ -128,7 +135,7 @@ def split_paragraph(s):
r = []
for word in s.split():
- if hyphenateable(word):
+ if hyphenatable(word):
while "-" in word:
a,word = word.split("-",1)
r.append(a+"\xff")
@@ -156,10 +163,13 @@ TP_SECHEAD = 3
TP_ITEMFIRST = 4
TP_ITEMBODY = 5
TP_END = 6
+TP_PREHEAD = 7
def head_parser(line):
- if re.match(r'^[A-Z]', line):
+ if re.match(r'^Changes in', line):
return TP_MAINHEAD
+ elif re.match(r'^[A-Za-z]', line):
+ return TP_PREHEAD
elif re.match(r'^ o ', line):
return TP_SECHEAD
elif re.match(r'^\s*$', line):
@@ -178,17 +188,67 @@ def body_parser(line):
return TP_BLANK
elif re.match(r'^Changes in', line):
return TP_END
+ elif re.match(r'^\s+\S', line):
+ return TP_HEADTEXT
else:
print "Weird line %r"%line
+def clean_head(head):
+ return head
+
+def head_score(s):
+ m = re.match(r'^ +o (.*)', s)
+ if not m:
+ print >>sys.stderr, "Can't score %r"%s
+ return 99999
+ lw = m.group(1).lower()
+ if lw.startswith("security") and "feature" not in lw:
+ score = -300
+ elif lw.startswith("deprecated version"):
+ score = -200
+ elif (('new' in lw and 'requirement' in lw) or
+ ('new' in lw and 'dependenc' in lw) or
+ ('build' in lw and 'requirement' in lw) or
+ ('removed' in lw and 'platform' in lw)):
+ score = -100
+ elif lw.startswith("major feature"):
+ score = 00
+ elif lw.startswith("major bug"):
+ score = 50
+ elif lw.startswith("major"):
+ score = 70
+ elif lw.startswith("minor feature"):
+ score = 200
+ elif lw.startswith("minor bug"):
+ score = 250
+ elif lw.startswith("minor"):
+ score = 270
+ else:
+ score = 1000
+
+ if 'secur' in lw:
+ score -= 2
+
+ if "(other)" in lw:
+ score += 2
+
+ if '(' not in lw:
+ score -= 1
+
+ return score
+
class ChangeLog(object):
- def __init__(self):
+ def __init__(self, wrapText=True, blogOrder=True, drupalBreak=False):
+ self.prehead = []
self.mainhead = None
self.headtext = []
self.curgraf = None
self.sections = []
self.cursection = None
self.lineno = 0
+ self.wrapText = wrapText
+ self.blogOrder = blogOrder
+ self.drupalBreak = drupalBreak
def addLine(self, tp, line):
self.lineno += 1
@@ -197,6 +257,9 @@ class ChangeLog(object):
assert not self.mainhead
self.mainhead = line
+ elif tp == TP_PREHEAD:
+ self.prehead.append(line)
+
elif tp == TP_HEADTEXT:
if self.curgraf is None:
self.curgraf = []
@@ -240,6 +303,11 @@ class ChangeLog(object):
self.lint_item(item_line, grafs, head_type)
def dumpGraf(self,par,indent1,indent2=-1):
+ if not self.wrapText:
+ for line in par:
+ print line
+ return
+
if indent2 == -1:
indent2 = indent1
text = " ".join(re.sub(r'\s+', ' ', line.strip()) for line in par)
@@ -249,38 +317,210 @@ class ChangeLog(object):
initial_indent=" "*indent1,
subsequent_indent=" "*indent2))
+ def dumpPreheader(self, graf):
+ self.dumpGraf(graf, 0)
+ print
+
+ def dumpMainhead(self, head):
+ print head
+
+ def dumpHeadGraf(self, graf):
+ self.dumpGraf(graf, 2)
+ print
+
+ def dumpSectionHeader(self, header):
+ print header
+
+ def dumpStartOfSections(self):
+ pass
+
+ def dumpEndOfSections(self):
+ pass
+
+ def dumpEndOfSection(self):
+ print
+
+ def dumpEndOfChangelog(self):
+ print
+
+ def dumpDrupalBreak(self):
+ pass
+
+ def dumpItem(self, grafs):
+ self.dumpGraf(grafs[0],4,6)
+ for par in grafs[1:]:
+ print
+ self.dumpGraf(par,6,6)
+
+ def collateAndSortSections(self):
+ heads = []
+ sectionsByHead = { }
+ for _, head, items in self.sections:
+ head = clean_head(head)
+ try:
+ s = sectionsByHead[head]
+ except KeyError:
+ s = sectionsByHead[head] = []
+ heads.append( (head_score(head), head.lower(), head, s) )
+
+ s.extend(items)
+
+ heads.sort()
+ self.sections = [ (0, head, items) for _1,_2,head,items in heads ]
+
def dump(self):
- print self.mainhead
+ if self.prehead:
+ self.dumpPreheader(self.prehead)
+
+ if not self.blogOrder:
+ self.dumpMainhead(self.mainhead)
+
for par in self.headtext:
- self.dumpGraf(par, 2)
- print
+ self.dumpHeadGraf(par)
+
+ if self.blogOrder:
+ self.dumpMainhead(self.mainhead)
+
+ drupalBreakAfter = None
+ if self.drupalBreak and len(self.sections) > 4:
+ drupalBreakAfter = self.sections[1][2]
+
+ self.dumpStartOfSections()
for _,head,items in self.sections:
if not head.endswith(':'):
print >>sys.stderr, "adding : to %r"%head
head = head + ":"
- print head
+ self.dumpSectionHeader(head)
for _,grafs in items:
- self.dumpGraf(grafs[0],4,6)
- for par in grafs[1:]:
- print
- self.dumpGraf(par,6,6)
- print
- print
+ self.dumpItem(grafs)
+ self.dumpEndOfSection()
+ if items is drupalBreakAfter:
+ self.dumpDrupalBreak()
+ self.dumpEndOfSections()
+ self.dumpEndOfChangelog()
+
+class HTMLChangeLog(ChangeLog):
+ def __init__(self, *args, **kwargs):
+ ChangeLog.__init__(self, *args, **kwargs)
+
+ def htmlText(self, graf):
+ for line in graf:
+ line = line.rstrip().replace("&","&amp;")
+ line = line.rstrip().replace("<","&lt;").replace(">","&gt;")
+ sys.stdout.write(line.strip())
+ sys.stdout.write(" ")
+
+ def htmlPar(self, graf):
+ sys.stdout.write("<p>")
+ self.htmlText(graf)
+ sys.stdout.write("</p>\n")
+
+ def dumpPreheader(self, graf):
+ self.htmlPar(graf)
+
+ def dumpMainhead(self, head):
+ sys.stdout.write("<h2>%s</h2>"%head)
+
+ def dumpHeadGraf(self, graf):
+ self.htmlPar(graf)
+
+ def dumpSectionHeader(self, header):
+ header = header.replace(" o ", "", 1).lstrip()
+ sys.stdout.write(" <li>%s\n"%header)
+ sys.stdout.write(" <ul>\n")
+
+ def dumpEndOfSection(self):
+ sys.stdout.write(" </ul>\n\n")
+
+ def dumpEndOfChangelog(self):
+ pass
-CL = ChangeLog()
-parser = head_parser
+ def dumpStartOfSections(self):
+ print "<ul>\n"
+
+ def dumpEndOfSections(self):
+ print "</ul>\n"
-if len(sys.argv) == 1:
+ def dumpDrupalBreak(self):
+ print "\n</ul>\n"
+ print "<p>&nbsp;</p>"
+ print "\n<!--break-->\n\n"
+ print "<ul>"
+
+ def dumpItem(self, grafs):
+ grafs[0][0] = grafs[0][0].replace(" - ", "", 1).lstrip()
+ sys.stdout.write(" <li>")
+ if len(grafs) > 1:
+ for par in grafs:
+ self.htmlPar(par)
+ else:
+ self.htmlText(grafs[0])
+ print
+
+op = optparse.OptionParser(usage="usage: %prog [options] [filename]")
+op.add_option('-W', '--no-wrap', action='store_false',
+ dest='wrapText', default=True,
+ help='Do not re-wrap paragraphs')
+op.add_option('-S', '--no-sort', action='store_false',
+ dest='sort', default=True,
+ help='Do not sort or collate sections')
+op.add_option('-o', '--output', dest='output',
+ default='-', metavar='FILE', help="write output to FILE")
+op.add_option('-H', '--html', action='store_true',
+ dest='html', default=False,
+ help="generate an HTML fragment")
+op.add_option('-1', '--first', action='store_true',
+ dest='firstOnly', default=False,
+ help="write only the first section")
+op.add_option('-b', '--blog-header', action='store_true',
+ dest='blogOrder', default=False,
+ help="Write the header in blog order")
+op.add_option('-B', '--blog', action='store_true',
+ dest='blogFormat', default=False,
+ help="Set all other options as appropriate for a blog post")
+op.add_option('--inplace', action='store_true',
+ dest='inplace', default=False,
+ help="Alter the ChangeLog in place")
+op.add_option('--drupal-break', action='store_true',
+ dest='drupalBreak', default=False,
+ help='Insert a drupal-friendly <!--break--> as needed')
+
+options,args = op.parse_args()
+
+if options.blogFormat:
+ options.blogOrder = True
+ options.html = True
+ options.sort = False
+ options.wrapText = False
+ options.firstOnly = True
+ options.drupalBreak = True
+
+if len(args) > 1:
+ op.error("Too many arguments")
+elif len(args) == 0:
fname = 'ChangeLog'
else:
- fname = sys.argv[1]
+ fname = args[0]
-fname_new = fname+".new"
+if options.inplace:
+ assert options.output == '-'
+ options.output = fname
-sys.stdin = open(fname, 'r')
+if fname != '-':
+ sys.stdin = open(fname, 'r')
nextline = None
+if options.html:
+ ChangeLogClass = HTMLChangeLog
+else:
+ ChangeLogClass = ChangeLog
+
+CL = ChangeLogClass(wrapText=options.wrapText,
+ blogOrder=options.blogOrder,
+ drupalBreak=options.drupalBreak)
+parser = head_parser
+
for line in sys.stdin:
line = line.rstrip()
tp = parser(line)
@@ -295,14 +535,26 @@ for line in sys.stdin:
CL.lint()
-sys.stdout = open(fname_new, 'w')
+if options.output != '-':
+ fname_new = options.output+".new"
+ fname_out = options.output
+ sys.stdout = open(fname_new, 'w')
+else:
+ fname_new = fname_out = None
+
+if options.sort:
+ CL.collateAndSortSections()
CL.dump()
+if options.firstOnly:
+ sys.exit(0)
+
if nextline is not None:
print nextline
for line in sys.stdin:
sys.stdout.write(line)
-os.rename(fname_new, fname)
+if fname_new is not None:
+ os.rename(fname_new, fname_out)
diff --git a/scripts/maint/lintChanges.py b/scripts/maint/lintChanges.py
new file mode 100755
index 0000000000..69963aea28
--- /dev/null
+++ b/scripts/maint/lintChanges.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+
+import sys
+import re
+
+
+
+def lintfile(fname):
+ have_warned = []
+ def warn(s):
+ if not have_warned:
+ have_warned.append(1)
+ print fname,":"
+ print "\t",s
+
+ m = re.search(r'(\d{3,})', fname)
+ if m:
+ bugnum = m.group(1)
+ else:
+ bugnum = None
+
+ with open(fname) as f:
+ contents = f.read()
+
+ if bugnum and bugnum not in contents:
+ warn("bug number %s does not appear"%bugnum)
+
+ lines = contents.split("\n")
+ isBug = ("bug" in lines[0] or "fix" in lines[0])
+
+ if not re.match(r'^ +o (.*)', contents):
+ warn("header not in format expected")
+
+ contents = " ".join(contents.split())
+
+ if re.search(r'\#\d{2,}', contents):
+ warn("don't use a # before ticket numbers")
+
+ if isBug and not re.search(r'(\d+)', contents):
+ warn("bugfix does not mention a number")
+ elif isBug and not re.search(r'Fixes ([a-z ]*)bug (\d+)', contents):
+ warn("bugfix does not say 'Fixes bug XXX'")
+
+ if re.search(r'[bB]ug (\d+)', contents):
+ if not re.search(r'[Bb]ugfix on ', contents):
+ warn("bugfix does not say 'bugfix on X.Y.Z'")
+ elif not re.search('[fF]ixes ([a-z ]*)bug (\d+); bugfix on ', contents):
+ warn("bugfix incant is not semicoloned")
+
+
+if __name__=='__main__':
+ for fname in sys.argv[1:]:
+ if fname.endswith("~"):
+ continue
+ lintfile(fname)
diff --git a/scripts/maint/redox.py b/scripts/maint/redox.py
index fa816a7267..5933d49773 100755
--- a/scripts/maint/redox.py
+++ b/scripts/maint/redox.py
@@ -1,6 +1,6 @@
#!/usr/bin/python
#
-# Copyright (c) 2008-2013, The Tor Project, Inc.
+# Copyright (c) 2008-2015, The Tor Project, Inc.
# See LICENSE for licensing information.
#
# Hi!
diff --git a/scripts/maint/sortChanges.py b/scripts/maint/sortChanges.py
index 726a723f93..ad28c79d9d 100755
--- a/scripts/maint/sortChanges.py
+++ b/scripts/maint/sortChanges.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-# Copyright (c) 2014, The Tor Project, Inc.
+# Copyright (c) 2014-2015, The Tor Project, Inc.
# See LICENSE for licensing information
"""This script sorts a bunch of changes files listed on its command
@@ -18,10 +18,10 @@ def fetch(fn):
s = "%s\n" % s.rstrip()
return s
-def score(s):
+def score(s,fname=None):
m = re.match(r'^ +o (.*)', s)
if not m:
- print >>sys.stderr, "Can't score %r"%s
+ print >>sys.stderr, "Can't score %r from %s"%(s,fname)
lw = m.group(1).lower()
if lw.startswith("major feature"):
score = 0
@@ -41,7 +41,7 @@ def score(s):
return (score, lw, s)
-changes = [ score(fetch(fn)) for fn in sys.argv[1:] if not fn.endswith('~') ]
+changes = [ score(fetch(fn),fn) for fn in sys.argv[1:] if not fn.endswith('~') ]
changes.sort()
diff --git a/scripts/maint/updateCopyright.pl b/scripts/maint/updateCopyright.pl
new file mode 100755
index 0000000000..ec82616a19
--- /dev/null
+++ b/scripts/maint/updateCopyright.pl
@@ -0,0 +1,7 @@
+#!/usr/bin/perl -i -w -p
+
+$NEWYEAR=2015;
+
+s/Copyright(.*) (201[^5]), The Tor Project/Copyright$1 $2-${NEWYEAR}, The Tor Project/;
+
+s/Copyright(.*)-(20..), The Tor Project/Copyright$1-${NEWYEAR}, The Tor Project/;
diff --git a/scripts/test/cov-diff b/scripts/test/cov-diff
index 33a54802b6..48dbec9d54 100755
--- a/scripts/test/cov-diff
+++ b/scripts/test/cov-diff
@@ -9,8 +9,8 @@ DIRB="$2"
for A in $DIRA/*; do
B=$DIRB/`basename $A`
- perl -pe 's/^\s*\d+:/ 1:/; s/^([^:]+:)[\d\s]+:/$1/;' "$A" > "$A.tmp"
- perl -pe 's/^\s*\d+:/ 1:/; s/^([^:]+:)[\d\s]+:/$1/;' "$B" > "$B.tmp"
+ perl -pe 's/^\s*\d+:/ 1:/; s/^([^:]+:)[\d\s]+:/$1/; s/^ *-:(Runs|Programs):.*//;' "$A" > "$A.tmp"
+ perl -pe 's/^\s*\d+:/ 1:/; s/^([^:]+:)[\d\s]+:/$1/; s/^ *-:(Runs|Programs):.*//;' "$B" > "$B.tmp"
diff -u "$A.tmp" "$B.tmp"
rm "$A.tmp" "$B.tmp"
done
diff --git a/src/common/address.c b/src/common/address.c
index 8591f387e6..42a116a91e 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -8,24 +8,26 @@
* \brief Functions to use and manipulate the tor_addr_t structure.
**/
-#include "orconfig.h"
-#include "compat.h"
-#include "util.h"
-#include "address.h"
-#include "torlog.h"
-#include "container.h"
-#include "sandbox.h"
+#define ADDRESS_PRIVATE
#ifdef _WIN32
-#include <process.h>
-#include <windows.h>
-#include <winsock2.h>
/* For access to structs needed by GetAdaptersAddresses */
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
+#include <process.h>
+#include <winsock2.h>
+#include <windows.h>
#include <iphlpapi.h>
#endif
+#include "orconfig.h"
+#include "compat.h"
+#include "util.h"
+#include "address.h"
+#include "torlog.h"
+#include "container.h"
+#include "sandbox.h"
+
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
@@ -89,13 +91,14 @@ tor_addr_to_sockaddr(const tor_addr_t *a,
struct sockaddr *sa_out,
socklen_t len)
{
+ memset(sa_out, 0, len);
+
sa_family_t family = tor_addr_family(a);
if (family == AF_INET) {
struct sockaddr_in *sin;
if (len < (int)sizeof(struct sockaddr_in))
return 0;
sin = (struct sockaddr_in *)sa_out;
- memset(sin, 0, sizeof(struct sockaddr_in));
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
sin->sin_len = sizeof(struct sockaddr_in);
#endif
@@ -108,7 +111,6 @@ tor_addr_to_sockaddr(const tor_addr_t *a,
if (len < (int)sizeof(struct sockaddr_in6))
return 0;
sin6 = (struct sockaddr_in6 *)sa_out;
- memset(sin6, 0, sizeof(struct sockaddr_in6));
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
sin6->sin6_len = sizeof(struct sockaddr_in6);
#endif
@@ -121,14 +123,26 @@ tor_addr_to_sockaddr(const tor_addr_t *a,
}
}
+/** Set address <b>a</b> to zero. This address belongs to
+ * the AF_UNIX family. */
+static void
+tor_addr_make_af_unix(tor_addr_t *a)
+{
+ memset(a, 0, sizeof(*a));
+ a->family = AF_UNIX;
+}
+
/** Set the tor_addr_t in <b>a</b> to contain the socket address contained in
- * <b>sa</b>. */
+ * <b>sa</b>. Return 0 on success and -1 on failure. */
int
tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
uint16_t *port_out)
{
tor_assert(a);
tor_assert(sa);
+
+ memset(a, 0, sizeof(*a));
+
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *) sa;
tor_addr_from_ipv4n(a, sin->sin_addr.s_addr);
@@ -139,6 +153,9 @@ tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
tor_addr_from_in6(a, &sin6->sin6_addr);
if (port_out)
*port_out = ntohs(sin6->sin6_port);
+ } else if (sa->sa_family == AF_UNIX) {
+ tor_addr_make_af_unix(a);
+ return 0;
} else {
tor_addr_make_unspec(a);
return -1;
@@ -323,17 +340,23 @@ tor_addr_is_internal_(const tor_addr_t *addr, int for_listening,
{
uint32_t iph4 = 0;
uint32_t iph6[4];
- sa_family_t v_family;
tor_assert(addr);
- v_family = tor_addr_family(addr);
+ sa_family_t v_family = tor_addr_family(addr);
if (v_family == AF_INET) {
iph4 = tor_addr_to_ipv4h(addr);
} else if (v_family == AF_INET6) {
if (tor_addr_is_v4(addr)) { /* v4-mapped */
+ uint32_t *addr32 = NULL;
v_family = AF_INET;
- iph4 = ntohl(tor_addr_to_in6_addr32(addr)[3]);
+ // Work around an incorrect NULL pointer dereference warning in
+ // "clang --analyze" due to limited analysis depth
+ addr32 = tor_addr_to_in6_addr32(addr);
+ // To improve performance, wrap this assertion in:
+ // #if !defined(__clang_analyzer__) || PARANOIA
+ tor_assert(addr32);
+ iph4 = ntohl(addr32[3]);
}
}
@@ -412,6 +435,10 @@ tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len, int decorate)
ptr = dest;
}
break;
+ case AF_UNIX:
+ tor_snprintf(dest, len, "AF_UNIX");
+ ptr = dest;
+ break;
default:
return NULL;
}
@@ -465,7 +492,6 @@ tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
if (!strcasecmpend(address, ".ip6.arpa")) {
const char *cp;
- int i;
int n0, n1;
struct in6_addr in6;
@@ -473,7 +499,7 @@ tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
return -1;
cp = address;
- for (i = 0; i < 16; ++i) {
+ for (int i = 0; i < 16; ++i) {
n0 = hex_decode_digit(*cp++); /* The low-order nybble appears first. */
if (*cp++ != '.') return -1; /* Then a dot. */
n1 = hex_decode_digit(*cp++); /* The high-order nybble appears first. */
@@ -598,7 +624,7 @@ tor_addr_parse_mask_ports(const char *s,
int any_flag=0, v4map=0;
sa_family_t family;
struct in6_addr in6_tmp;
- struct in_addr in_tmp;
+ struct in_addr in_tmp = { .s_addr = 0 };
tor_assert(s);
tor_assert(addr_out);
@@ -659,7 +685,7 @@ tor_addr_parse_mask_ports(const char *s,
tor_addr_from_ipv4h(addr_out, 0);
any_flag = 1;
} else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) {
- static char nil_bytes[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
family = AF_INET6;
tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
any_flag = 1;
@@ -718,6 +744,11 @@ tor_addr_parse_mask_ports(const char *s,
/* XXXX_IP6 is this really what we want? */
bits = 96 + bits%32; /* map v4-mapped masks onto 96-128 bits */
}
+ if (any_flag) {
+ log_warn(LD_GENERAL,
+ "Found bit prefix with wildcard address; rejecting");
+ goto err;
+ }
} else { /* pick an appropriate mask, as none was given */
if (any_flag)
bits = 0; /* This is okay whether it's V6 or V4 (FIX V4-mapped V6!) */
@@ -803,6 +834,8 @@ tor_addr_is_null(const tor_addr_t *addr)
}
case AF_INET:
return (tor_addr_to_ipv4n(addr) == 0);
+ case AF_UNIX:
+ return 1;
case AF_UNSPEC:
return 1;
default:
@@ -878,7 +911,7 @@ tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src)
memcpy(dest, src, sizeof(tor_addr_t));
}
-/** Copy a tor_addr_t from <b>src</b> to <b>dest</b>, taking extra case to
+/** Copy a tor_addr_t from <b>src</b> to <b>dest</b>, taking extra care to
* copy only the well-defined portions. Used for computing hashes of
* addresses.
*/
@@ -1013,7 +1046,6 @@ tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
} else {
a2 = tor_addr_to_ipv4h(addr2);
}
- if (mbits <= 0) return 0;
if (mbits > 32) mbits = 32;
a1 >>= (32-mbits);
a2 >>= (32-mbits);
@@ -1109,7 +1141,8 @@ fmt_addr32(uint32_t addr)
int
tor_addr_parse(tor_addr_t *addr, const char *src)
{
- char *tmp = NULL; /* Holds substring if we got a dotted quad. */
+ /* Holds substring of IPv6 address after removing square brackets */
+ char *tmp = NULL;
int result;
struct in_addr in_tmp;
struct in6_addr in6_tmp;
@@ -1194,26 +1227,17 @@ typedef ULONG (WINAPI *GetAdaptersAddresses_fn_t)(
ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
#endif
-/** Try to ask our network interfaces what addresses they are bound to.
- * Return a new smartlist of tor_addr_t on success, and NULL on failure.
- * (An empty smartlist indicates that we successfully learned that we have no
- * addresses.) Log failure messages at <b>severity</b>. */
-static smartlist_t *
-get_interface_addresses_raw(int severity)
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+/*
+ * Convert a linked list consisting of <b>ifaddrs</b> structures
+ * into smartlist of <b>tor_addr_t</b> structures.
+ */
+STATIC smartlist_t *
+ifaddrs_to_smartlist(const struct ifaddrs *ifa)
{
-#if defined(HAVE_GETIFADDRS)
- /* Most free Unixy systems provide getifaddrs, which gives us a linked list
- * of struct ifaddrs. */
- struct ifaddrs *ifa = NULL;
+ smartlist_t *result = smartlist_new();
const struct ifaddrs *i;
- smartlist_t *result;
- if (getifaddrs(&ifa) < 0) {
- log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s",
- strerror(errno));
- return NULL;
- }
- result = smartlist_new();
for (i = ifa; i; i = i->ifa_next) {
tor_addr_t tmp;
if ((i->ifa_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
@@ -1228,9 +1252,72 @@ get_interface_addresses_raw(int severity)
smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
}
+ return result;
+}
+
+/** Use getiffaddrs() function to get list of current machine
+ * network interface addresses. Represent the result by smartlist of
+ * <b>tor_addr_t</b> structures.
+ */
+STATIC smartlist_t *
+get_interface_addresses_ifaddrs(int severity)
+{
+
+ /* Most free Unixy systems provide getifaddrs, which gives us a linked list
+ * of struct ifaddrs. */
+ struct ifaddrs *ifa = NULL;
+ smartlist_t *result;
+ if (getifaddrs(&ifa) < 0) {
+ log_fn(severity, LD_NET, "Unable to call getifaddrs(): %s",
+ strerror(errno));
+ return NULL;
+ }
+
+ result = ifaddrs_to_smartlist(ifa);
+
freeifaddrs(ifa);
+
+ return result;
+}
+#endif
+
+#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
+
+/** Convert a Windows-specific <b>addresses</b> linked list into smartlist
+ * of <b>tor_addr_t</b> structures.
+ */
+
+STATIC smartlist_t *
+ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses)
+{
+ smartlist_t *result = smartlist_new();
+ const IP_ADAPTER_ADDRESSES *address;
+
+ for (address = addresses; address; address = address->Next) {
+ const IP_ADAPTER_UNICAST_ADDRESS *a;
+ for (a = address->FirstUnicastAddress; a; a = a->Next) {
+ /* Yes, it's a linked list inside a linked list */
+ const struct sockaddr *sa = a->Address.lpSockaddr;
+ tor_addr_t tmp;
+ if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+ continue;
+ if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
+ continue;
+ smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+ }
+ }
+
return result;
-#elif defined(_WIN32)
+}
+
+/** Windows only: use GetAdaptersInfo() function to retrieve network interface
+ * addresses of current machine and return them to caller as smartlist of
+ * <b>tor_addr_t</b> structures.
+ */
+STATIC smartlist_t *
+get_interface_addresses_win32(int severity)
+{
+
/* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
"GetAdaptersInfo", but that's deprecated; let's just try
GetAdaptersAddresses and fall back to connect+getsockname.
@@ -1239,7 +1326,7 @@ get_interface_addresses_raw(int severity)
smartlist_t *result = NULL;
GetAdaptersAddresses_fn_t fn;
ULONG size, res;
- IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
+ IP_ADAPTER_ADDRESSES *addresses = NULL;
(void) severity;
@@ -1274,67 +1361,130 @@ get_interface_addresses_raw(int severity)
goto done;
}
- result = smartlist_new();
- for (address = addresses; address; address = address->Next) {
- IP_ADAPTER_UNICAST_ADDRESS *a;
- for (a = address->FirstUnicastAddress; a; a = a->Next) {
- /* Yes, it's a linked list inside a linked list */
- struct sockaddr *sa = a->Address.lpSockaddr;
- tor_addr_t tmp;
- if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
- continue;
- if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
- continue;
- smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
- }
- }
+ result = ip_adapter_addresses_to_smartlist(addresses);
done:
if (lib)
FreeLibrary(lib);
tor_free(addresses);
return result;
-#elif defined(SIOCGIFCONF) && defined(HAVE_IOCTL)
+}
+
+#endif
+
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+
+/* Guess how much space we need. There shouldn't be any struct ifreqs
+ * larger than this, even on OS X where the struct's size is dynamic. */
+#define IFREQ_SIZE 4096
+
+/* This is defined on Mac OS X */
+#ifndef _SIZEOF_ADDR_IFREQ
+#define _SIZEOF_ADDR_IFREQ sizeof
+#endif
+
+/** Convert <b>*buf</b>, an ifreq structure array of size <b>buflen</b>,
+ * into smartlist of <b>tor_addr_t</b> structures.
+ */
+STATIC smartlist_t *
+ifreq_to_smartlist(char *buf, size_t buflen)
+{
+ smartlist_t *result = smartlist_new();
+ char *end = buf + buflen;
+
+ /* These acrobatics are due to alignment issues which trigger
+ * undefined behaviour traps on OSX. */
+ struct ifreq *r = tor_malloc(IFREQ_SIZE);
+
+ while (buf < end) {
+ /* Copy up to IFREQ_SIZE bytes into the struct ifreq, but don't overrun
+ * buf. */
+ memcpy(r, buf, end - buf < IFREQ_SIZE ? end - buf : IFREQ_SIZE);
+
+ const struct sockaddr *sa = &r->ifr_addr;
+ tor_addr_t tmp;
+ int valid_sa_family = (sa->sa_family == AF_INET ||
+ sa->sa_family == AF_INET6);
+
+ int conversion_success = (tor_addr_from_sockaddr(&tmp, sa, NULL) == 0);
+
+ if (valid_sa_family && conversion_success)
+ smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
+
+ buf += _SIZEOF_ADDR_IFREQ(*r);
+ }
+
+ tor_free(r);
+ return result;
+}
+
+/** Use ioctl(.,SIOCGIFCONF,.) to get a list of current machine
+ * network interface addresses. Represent the result by smartlist of
+ * <b>tor_addr_t</b> structures.
+ */
+STATIC smartlist_t *
+get_interface_addresses_ioctl(int severity)
+{
/* Some older unixy systems make us use ioctl(SIOCGIFCONF) */
struct ifconf ifc;
- int fd, i, sz, n;
+ int fd;
smartlist_t *result = NULL;
+
/* This interface, AFAICT, only supports AF_INET addresses */
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
tor_log(severity, LD_NET, "socket failed: %s", strerror(errno));
goto done;
}
- /* Guess how much space we need. */
- ifc.ifc_len = sz = 15*1024;
- ifc.ifc_ifcu.ifcu_req = tor_malloc(sz);
- if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
- tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno));
- close(fd);
- goto done;
- }
- close(fd);
- result = smartlist_new();
- if (ifc.ifc_len < sz)
- sz = ifc.ifc_len;
- n = sz / sizeof(struct ifreq);
- for (i = 0; i < n ; ++i) {
- struct ifreq *r = &ifc.ifc_ifcu.ifcu_req[i];
- struct sockaddr *sa = &r->ifr_addr;
- tor_addr_t tmp;
- if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
- continue; /* should be impossible */
- if (tor_addr_from_sockaddr(&tmp, sa, NULL) < 0)
- continue;
- smartlist_add(result, tor_memdup(&tmp, sizeof(tmp)));
- }
+
+ int mult = 1;
+ ifc.ifc_buf = NULL;
+ do {
+ mult *= 2;
+ ifc.ifc_len = mult * IFREQ_SIZE;
+ ifc.ifc_buf = tor_realloc(ifc.ifc_buf, ifc.ifc_len);
+
+ tor_assert(ifc.ifc_buf);
+
+ if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
+ tor_log(severity, LD_NET, "ioctl failed: %s", strerror(errno));
+ goto done;
+ }
+ /* Ensure we have least IFREQ_SIZE bytes unused at the end. Otherwise, we
+ * don't know if we got everything during ioctl. */
+ } while (mult * IFREQ_SIZE - ifc.ifc_len <= IFREQ_SIZE);
+ result = ifreq_to_smartlist(ifc.ifc_buf, ifc.ifc_len);
+
done:
- tor_free(ifc.ifc_ifcu.ifcu_req);
+ if (fd >= 0)
+ close(fd);
+ tor_free(ifc.ifc_buf);
return result;
-#else
+}
+#endif
+
+/** Try to ask our network interfaces what addresses they are bound to.
+ * Return a new smartlist of tor_addr_t on success, and NULL on failure.
+ * (An empty smartlist indicates that we successfully learned that we have no
+ * addresses.) Log failure messages at <b>severity</b>. */
+STATIC smartlist_t *
+get_interface_addresses_raw(int severity)
+{
+ smartlist_t *result = NULL;
+#if defined(HAVE_IFADDRS_TO_SMARTLIST)
+ if ((result = get_interface_addresses_ifaddrs(severity)))
+ return result;
+#endif
+#if defined(HAVE_IP_ADAPTER_TO_SMARTLIST)
+ if ((result = get_interface_addresses_win32(severity)))
+ return result;
+#endif
+#if defined(HAVE_IFCONF_TO_SMARTLIST)
+ if ((result = get_interface_addresses_ioctl(severity)))
+ return result;
+#endif
(void) severity;
return NULL;
-#endif
}
/** Return true iff <b>a</b> is a multicast address. */
@@ -1358,8 +1508,8 @@ tor_addr_is_multicast(const tor_addr_t *a)
* connects to the Internet. This address should only be used in checking
* whether our address has changed. Return 0 on success, -1 on failure.
*/
-int
-get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr)
+MOCK_IMPL(int,
+get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr))
{
/* XXX really, this function should yield a smartlist of addresses. */
smartlist_t *addrs;
@@ -1688,8 +1838,8 @@ tor_dup_ip(uint32_t addr)
* checking whether our address has changed. Return 0 on success, -1 on
* failure.
*/
-int
-get_interface_address(int severity, uint32_t *addr)
+MOCK_IMPL(int,
+get_interface_address,(int severity, uint32_t *addr))
{
tor_addr_t local_addr;
int r;
diff --git a/src/common/address.h b/src/common/address.h
index 8dc63b71c1..df835e917a 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,10 +11,41 @@
#ifndef TOR_ADDRESS_H
#define TOR_ADDRESS_H
+//#include <sys/sockio.h>
#include "orconfig.h"
#include "torint.h"
#include "compat.h"
+#ifdef ADDRESS_PRIVATE
+
+#if defined(HAVE_SYS_IOCTL_H)
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_GETIFADDRS
+#define HAVE_IFADDRS_TO_SMARTLIST
+#endif
+
+#ifdef _WIN32
+#define HAVE_IP_ADAPTER_TO_SMARTLIST
+#endif
+
+#if defined(SIOCGIFCONF) && defined(HAVE_IOCTL)
+#define HAVE_IFCONF_TO_SMARTLIST
+#endif
+
+#if defined(HAVE_NET_IF_H)
+#include <net/if.h> // for struct ifconf
+#endif
+
+#if defined(HAVE_IFADDRS_TO_SMARTLIST)
+#include <ifaddrs.h>
+#endif
+
+// TODO win32 specific includes
+#include "container.h"
+#endif // ADDRESS_PRIVATE
+
/** The number of bits from an address to consider while doing a masked
* comparison. */
typedef uint8_t maskbits_t;
@@ -103,7 +134,18 @@ tor_addr_to_ipv4h(const tor_addr_t *a)
static INLINE uint32_t
tor_addr_to_mapped_ipv4h(const tor_addr_t *a)
{
- return a->family == AF_INET6 ? ntohl(tor_addr_to_in6_addr32(a)[3]) : 0;
+ if (a->family == AF_INET6) {
+ uint32_t *addr32 = NULL;
+ // Work around an incorrect NULL pointer dereference warning in
+ // "clang --analyze" due to limited analysis depth
+ addr32 = tor_addr_to_in6_addr32(a);
+ // To improve performance, wrap this assertion in:
+ // #if !defined(__clang_analyzer__) || PARANOIA
+ tor_assert(addr32);
+ return ntohl(addr32[3]);
+ } else {
+ return 0;
+ }
}
/** Return the address family of <b>a</b>. Possible values are:
* AF_INET6, AF_INET, AF_UNSPEC. */
@@ -148,7 +190,8 @@ char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC;
const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
const char * fmt_addr32(uint32_t addr);
-int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr);
+MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family,
+tor_addr_t *addr));
/** Flag to specify how to do a comparison between addresses. In an "exact"
* comparison, addresses are equivalent only if they are in the same family
@@ -225,9 +268,31 @@ int addr_mask_get_bits(uint32_t mask);
#define INET_NTOA_BUF_LEN 16
int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
-int get_interface_address(int severity, uint32_t *addr);
+MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr));
tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
+#ifdef ADDRESS_PRIVATE
+STATIC smartlist_t *get_interface_addresses_raw(int severity);
+
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+STATIC smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa);
+STATIC smartlist_t *get_interface_addresses_ifaddrs(int severity);
+#endif
+
+#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
+STATIC smartlist_t *ip_adapter_addresses_to_smartlist(
+ const IP_ADAPTER_ADDRESSES *addresses);
+STATIC smartlist_t *get_interface_addresses_win32(int severity);
+#endif
+
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+STATIC smartlist_t *ifreq_to_smartlist(char *ifr,
+ size_t buflen);
+STATIC smartlist_t *get_interface_addresses_ioctl(int severity);
+#endif
+
+#endif // ADDRESS_PRIVATE
+
#endif
diff --git a/src/common/aes.c b/src/common/aes.c
index f454a7f7b2..7651f1d93a 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/aes.h b/src/common/aes.h
index 8ff28a7622..df2f3aa65d 100644
--- a/src/common/aes.h
+++ b/src/common/aes.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Implements a minimal interface to counter-mode AES. */
diff --git a/src/common/backtrace.c b/src/common/backtrace.c
index 3a073a8ff5..a2d5378b20 100644
--- a/src/common/backtrace.c
+++ b/src/common/backtrace.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define __USE_GNU
@@ -80,6 +80,7 @@ clean_backtrace(void **stack, int depth, const ucontext_t *ctx)
#else
(void) depth;
(void) ctx;
+ (void) stack;
#endif
}
diff --git a/src/common/backtrace.h b/src/common/backtrace.h
index 1f4d73339f..a9151d7956 100644
--- a/src/common/backtrace.h
+++ b/src/common/backtrace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_BACKTRACE_H
diff --git a/src/common/compat.c b/src/common/compat.c
index 53d0623c84..6b9f1f71f2 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -27,7 +27,6 @@
#include "compat.h"
#ifdef _WIN32
-#include <process.h>
#include <windows.h>
#include <sys/locking.h>
#endif
@@ -77,6 +76,7 @@
/* Includes for the process attaching prevention */
#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
+/* Only use the linux prctl; the IRIX prctl is totally different */
#include <sys/prctl.h>
#elif defined(__APPLE__)
#include <sys/types.h>
@@ -110,10 +110,6 @@
#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
-#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
-/* Only use the linux prctl; the IRIX prctl is totally different */
-#include <sys/prctl.h>
-#endif
#ifdef TOR_UNIT_TESTS
#if !defined(HAVE_USLEEP) && defined(HAVE_SYS_SELECT_H)
/* as fallback implementation for tor_sleep_msec */
@@ -141,9 +137,10 @@ int
tor_open_cloexec(const char *path, int flags, unsigned mode)
{
int fd;
+ const char *p = path;
#ifdef O_CLOEXEC
- path = sandbox_intern_string(path);
- fd = open(path, flags|O_CLOEXEC, mode);
+ p = sandbox_intern_string(path);
+ fd = open(p, flags|O_CLOEXEC, mode);
if (fd >= 0)
return fd;
/* If we got an error, see if it is EINVAL. EINVAL might indicate that,
@@ -153,8 +150,8 @@ tor_open_cloexec(const char *path, int flags, unsigned mode)
return -1;
#endif
- log_debug(LD_FS, "Opening %s with flags %x", path, flags);
- fd = open(path, flags, mode);
+ log_debug(LD_FS, "Opening %s with flags %x", p, flags);
+ fd = open(p, flags, mode);
#ifdef FD_CLOEXEC
if (fd >= 0) {
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
@@ -825,6 +822,7 @@ replace_file(const char *from, const char *to)
case FN_NOENT:
break;
case FN_FILE:
+ case FN_EMPTY:
if (unlink(to)) return -1;
break;
case FN_ERROR:
@@ -981,14 +979,23 @@ tor_fd_getpos(int fd)
#endif
}
-/** Move <b>fd</b> to the end of the file. Return -1 on error, 0 on success. */
+/** Move <b>fd</b> to the end of the file. Return -1 on error, 0 on success.
+ * If the file is a pipe, do nothing and succeed.
+ **/
int
tor_fd_seekend(int fd)
{
#ifdef _WIN32
return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0;
#else
- return lseek(fd, 0, SEEK_END) < 0 ? -1 : 0;
+ off_t rc = lseek(fd, 0, SEEK_END) < 0 ? -1 : 0;
+#ifdef ESPIPE
+ /* If we get an error and ESPIPE, then it's a pipe or a socket of a fifo:
+ * no need to worry. */
+ if (rc < 0 && errno == ESPIPE)
+ rc = 0;
+#endif
+ return (rc < 0) ? -1 : 0;
#endif
}
@@ -1004,6 +1011,23 @@ tor_fd_setpos(int fd, off_t pos)
#endif
}
+/** Replacement for ftruncate(fd, 0): move to the front of the file and remove
+ * all the rest of the file. Return -1 on error, 0 on success. */
+int
+tor_ftruncate(int fd)
+{
+ /* Rumor has it that some versions of ftruncate do not move the file pointer.
+ */
+ if (tor_fd_setpos(fd, 0) < 0)
+ return -1;
+
+#ifdef _WIN32
+ return _chsize(fd, 0);
+#else
+ return ftruncate(fd, 0);
+#endif
+}
+
#undef DEBUG_SOCKET_COUNTING
#ifdef DEBUG_SOCKET_COUNTING
/** A bitarray of all fds that should be passed to tor_socket_close(). Only
@@ -1409,6 +1433,9 @@ tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2])
socklen_t size;
int saved_errno = -1;
+ memset(&connect_addr, 0, sizeof(connect_addr));
+ memset(&listen_addr, 0, sizeof(listen_addr));
+
if (protocol
#ifdef AF_UNIX
|| family != AF_UNIX
@@ -1670,12 +1697,12 @@ log_credential_status(void)
/* log supplementary groups */
sup_gids_size = 64;
- sup_gids = tor_malloc(sizeof(gid_t) * 64);
+ sup_gids = tor_calloc(64, sizeof(gid_t));
while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 &&
errno == EINVAL &&
sup_gids_size < NGROUPS_MAX) {
sup_gids_size *= 2;
- sup_gids = tor_realloc(sup_gids, sizeof(gid_t) * sup_gids_size);
+ sup_gids = tor_reallocarray(sup_gids, sizeof(gid_t), sup_gids_size);
}
if (ngids < 0) {
@@ -1766,8 +1793,8 @@ tor_getpwnam(const char *username)
if ((pw = getpwnam(username))) {
tor_passwd_free(passwd_cached);
passwd_cached = tor_passwd_dup(pw);
- log_notice(LD_GENERAL, "Caching new entry %s for %s",
- passwd_cached->pw_name, username);
+ log_info(LD_GENERAL, "Caching new entry %s for %s",
+ passwd_cached->pw_name, username);
return pw;
}
@@ -2170,9 +2197,20 @@ get_environment(void)
#endif
}
-/** Set *addr to the IP address (in dotted-quad notation) stored in c.
- * Return 1 on success, 0 if c is badly formatted. (Like inet_aton(c,addr),
- * but works on Windows and Solaris.)
+/** Get name of current host and write it to <b>name</b> array, whose
+ * length is specified by <b>namelen</b> argument. Return 0 upon
+ * successfull completion; otherwise return return -1. (Currently,
+ * this function is merely a mockable wrapper for POSIX gethostname().)
+ */
+MOCK_IMPL(int,
+tor_gethostname,(char *name, size_t namelen))
+{
+ return gethostname(name,namelen);
+}
+
+/** Set *addr to the IP address (in dotted-quad notation) stored in *str.
+ * Return 1 on success, 0 if *str is badly formatted.
+ * (Like inet_aton(str,addr), but works on Windows and Solaris.)
*/
int
tor_inet_aton(const char *str, struct in_addr* addr)
@@ -2396,8 +2434,9 @@ tor_inet_pton(int af, const char *src, void *dst)
* (This function exists because standard windows gethostbyname
* doesn't treat raw IP addresses properly.)
*/
-int
-tor_lookup_hostname(const char *name, uint32_t *addr)
+
+MOCK_IMPL(int,
+tor_lookup_hostname,(const char *name, uint32_t *addr))
{
tor_addr_t myaddr;
int ret;
@@ -2489,14 +2528,12 @@ get_uname(void)
"Unrecognized version of Windows [major=%d,minor=%d]",
(int)info.dwMajorVersion,(int)info.dwMinorVersion);
}
-#if !defined (WINCE)
#ifdef VER_NT_SERVER
if (info.wProductType == VER_NT_SERVER ||
info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
strlcat(uname_result, " [server]", sizeof(uname_result));
}
#endif
-#endif
#else
strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
#endif
@@ -2510,109 +2547,6 @@ get_uname(void)
* Process control
*/
-#if defined(USE_PTHREADS)
-/** Wraps a void (*)(void*) function and its argument so we can
- * invoke them in a way pthreads would expect.
- */
-typedef struct tor_pthread_data_t {
- void (*func)(void *);
- void *data;
-} tor_pthread_data_t;
-/** Given a tor_pthread_data_t <b>_data</b>, call _data-&gt;func(d-&gt;data)
- * and free _data. Used to make sure we can call functions the way pthread
- * expects. */
-static void *
-tor_pthread_helper_fn(void *_data)
-{
- tor_pthread_data_t *data = _data;
- void (*func)(void*);
- void *arg;
- /* mask signals to worker threads to avoid SIGPIPE, etc */
- sigset_t sigs;
- /* We're in a subthread; don't handle any signals here. */
- sigfillset(&sigs);
- pthread_sigmask(SIG_SETMASK, &sigs, NULL);
-
- func = data->func;
- arg = data->data;
- tor_free(_data);
- func(arg);
- return NULL;
-}
-/**
- * A pthread attribute to make threads start detached.
- */
-static pthread_attr_t attr_detached;
-/** True iff we've called tor_threads_init() */
-static int threads_initialized = 0;
-#endif
-
-/** Minimalist interface to run a void function in the background. On
- * Unix calls fork, on win32 calls beginthread. Returns -1 on failure.
- * func should not return, but rather should call spawn_exit.
- *
- * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
- * since in a multithreaded environment, there is no way to be sure that
- * the caller's stack will still be around when the called function is
- * running.
- */
-int
-spawn_func(void (*func)(void *), void *data)
-{
-#if defined(USE_WIN32_THREADS)
- int rv;
- rv = (int)_beginthread(func, 0, data);
- if (rv == (int)-1)
- return -1;
- return 0;
-#elif defined(USE_PTHREADS)
- pthread_t thread;
- tor_pthread_data_t *d;
- if (PREDICT_UNLIKELY(!threads_initialized))
- tor_threads_init();
- d = tor_malloc(sizeof(tor_pthread_data_t));
- d->data = data;
- d->func = func;
- if (pthread_create(&thread,&attr_detached,tor_pthread_helper_fn,d))
- return -1;
- return 0;
-#else
- pid_t pid;
- pid = fork();
- if (pid<0)
- return -1;
- if (pid==0) {
- /* Child */
- func(data);
- tor_assert(0); /* Should never reach here. */
- return 0; /* suppress "control-reaches-end-of-non-void" warning. */
- } else {
- /* Parent */
- return 0;
- }
-#endif
-}
-
-/** End the current thread/process.
- */
-void
-spawn_exit(void)
-{
-#if defined(USE_WIN32_THREADS)
- _endthread();
- //we should never get here. my compiler thinks that _endthread returns, this
- //is an attempt to fool it.
- tor_assert(0);
- _exit(0);
-#elif defined(USE_PTHREADS)
- pthread_exit(NULL);
-#else
- /* http://www.erlenstar.demon.co.uk/unix/faq_2.html says we should
- * call _exit, not exit, from child processes. */
- _exit(0);
-#endif
-}
-
/** Implementation logic for compute_num_cpus(). */
static int
compute_num_cpus_impl(void)
@@ -2701,15 +2635,8 @@ tor_gettimeofday(struct timeval *timeval)
uint64_t ft_64;
FILETIME ft_ft;
} ft;
-#if defined (WINCE)
- /* wince do not have GetSystemTimeAsFileTime */
- SYSTEMTIME stime;
- GetSystemTime(&stime);
- SystemTimeToFileTime(&stime,&ft.ft_ft);
-#else
/* number of 100-nsec units since Jan 1, 1601 */
GetSystemTimeAsFileTime(&ft.ft_ft);
-#endif
if (ft.ft_64 < EPOCH_BIAS) {
log_err(LD_GENERAL,"System time is before 1970; failing.");
exit(1);
@@ -2735,7 +2662,7 @@ tor_gettimeofday(struct timeval *timeval)
return;
}
-#if defined(TOR_IS_MULTITHREADED) && !defined(_WIN32)
+#if !defined(_WIN32)
/** Defined iff we need to add locks when defining fake versions of reentrant
* versions of time-related functions. */
#define TIME_FNS_NEED_LOCKS
@@ -2754,14 +2681,24 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
const char *outcome;
if (PREDICT_LIKELY(r)) {
- if (r->tm_year > 8099) { /* We can't strftime dates after 9999 CE. */
+ /* We can't strftime dates after 9999 CE, and we want to avoid dates
+ * before 1 CE (avoiding the year 0 issue and negative years). */
+ if (r->tm_year > 8099) {
r->tm_year = 8099;
r->tm_mon = 11;
r->tm_mday = 31;
- r->tm_yday = 365;
+ r->tm_yday = 364;
r->tm_hour = 23;
r->tm_min = 59;
r->tm_sec = 59;
+ } else if (r->tm_year < (1-1900)) {
+ r->tm_year = (1-1900);
+ r->tm_mon = 0;
+ r->tm_mday = 1;
+ r->tm_yday = 0;
+ r->tm_hour = 0;
+ r->tm_min = 0;
+ r->tm_sec = 0;
}
return r;
}
@@ -2775,7 +2712,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
r->tm_year = 70; /* 1970 CE */
r->tm_mon = 0;
r->tm_mday = 1;
- r->tm_yday = 1;
+ r->tm_yday = 0;
r->tm_hour = 0;
r->tm_min = 0 ;
r->tm_sec = 0;
@@ -2788,7 +2725,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf,
r->tm_year = 137; /* 2037 CE */
r->tm_mon = 11;
r->tm_mday = 31;
- r->tm_yday = 365;
+ r->tm_yday = 364;
r->tm_hour = 23;
r->tm_min = 59;
r->tm_sec = 59;
@@ -2857,7 +2794,7 @@ tor_localtime_r(const time_t *timep, struct tm *result)
/** @} */
/** @{ */
-/** As gmtimee_r, but defined for platforms that don't have it:
+/** As gmtime_r, but defined for platforms that don't have it:
*
* Convert *<b>timep</b> to a struct tm in UTC, and store the value in
* *<b>result</b>. Return the result on success, or NULL on failure.
@@ -2898,282 +2835,6 @@ tor_gmtime_r(const time_t *timep, struct tm *result)
}
#endif
-#if defined(USE_WIN32_THREADS)
-void
-tor_mutex_init(tor_mutex_t *m)
-{
- InitializeCriticalSection(&m->mutex);
-}
-void
-tor_mutex_uninit(tor_mutex_t *m)
-{
- DeleteCriticalSection(&m->mutex);
-}
-void
-tor_mutex_acquire(tor_mutex_t *m)
-{
- tor_assert(m);
- EnterCriticalSection(&m->mutex);
-}
-void
-tor_mutex_release(tor_mutex_t *m)
-{
- LeaveCriticalSection(&m->mutex);
-}
-unsigned long
-tor_get_thread_id(void)
-{
- return (unsigned long)GetCurrentThreadId();
-}
-#elif defined(USE_PTHREADS)
-/** A mutex attribute that we're going to use to tell pthreads that we want
- * "reentrant" mutexes (i.e., once we can re-lock if we're already holding
- * them.) */
-static pthread_mutexattr_t attr_reentrant;
-/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set
- * up with tor_mutex_init() or tor_mutex_new(); not both. */
-void
-tor_mutex_init(tor_mutex_t *mutex)
-{
- int err;
- if (PREDICT_UNLIKELY(!threads_initialized))
- tor_threads_init();
- err = pthread_mutex_init(&mutex->mutex, &attr_reentrant);
- if (PREDICT_UNLIKELY(err)) {
- log_err(LD_GENERAL, "Error %d creating a mutex.", err);
- tor_fragile_assert();
- }
-}
-/** Wait until <b>m</b> is free, then acquire it. */
-void
-tor_mutex_acquire(tor_mutex_t *m)
-{
- int err;
- tor_assert(m);
- err = pthread_mutex_lock(&m->mutex);
- if (PREDICT_UNLIKELY(err)) {
- log_err(LD_GENERAL, "Error %d locking a mutex.", err);
- tor_fragile_assert();
- }
-}
-/** Release the lock <b>m</b> so another thread can have it. */
-void
-tor_mutex_release(tor_mutex_t *m)
-{
- int err;
- tor_assert(m);
- err = pthread_mutex_unlock(&m->mutex);
- if (PREDICT_UNLIKELY(err)) {
- log_err(LD_GENERAL, "Error %d unlocking a mutex.", err);
- tor_fragile_assert();
- }
-}
-/** Clean up the mutex <b>m</b> so that it no longer uses any system
- * resources. Does not free <b>m</b>. This function must only be called on
- * mutexes from tor_mutex_init(). */
-void
-tor_mutex_uninit(tor_mutex_t *m)
-{
- int err;
- tor_assert(m);
- err = pthread_mutex_destroy(&m->mutex);
- if (PREDICT_UNLIKELY(err)) {
- log_err(LD_GENERAL, "Error %d destroying a mutex.", err);
- tor_fragile_assert();
- }
-}
-/** Return an integer representing this thread. */
-unsigned long
-tor_get_thread_id(void)
-{
- union {
- pthread_t thr;
- unsigned long id;
- } r;
- r.thr = pthread_self();
- return r.id;
-}
-#endif
-
-#ifdef TOR_IS_MULTITHREADED
-/** Return a newly allocated, ready-for-use mutex. */
-tor_mutex_t *
-tor_mutex_new(void)
-{
- tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t));
- tor_mutex_init(m);
- return m;
-}
-/** Release all storage and system resources held by <b>m</b>. */
-void
-tor_mutex_free(tor_mutex_t *m)
-{
- if (!m)
- return;
- tor_mutex_uninit(m);
- tor_free(m);
-}
-#endif
-
-/* Conditions. */
-#ifdef USE_PTHREADS
-#if 0
-/** Cross-platform condition implementation. */
-struct tor_cond_t {
- pthread_cond_t cond;
-};
-/** Return a newly allocated condition, with nobody waiting on it. */
-tor_cond_t *
-tor_cond_new(void)
-{
- tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t));
- if (pthread_cond_init(&cond->cond, NULL)) {
- tor_free(cond);
- return NULL;
- }
- return cond;
-}
-/** Release all resources held by <b>cond</b>. */
-void
-tor_cond_free(tor_cond_t *cond)
-{
- if (!cond)
- return;
- if (pthread_cond_destroy(&cond->cond)) {
- log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno));
- return;
- }
- tor_free(cond);
-}
-/** Wait until one of the tor_cond_signal functions is called on <b>cond</b>.
- * All waiters on the condition must wait holding the same <b>mutex</b>.
- * Returns 0 on success, negative on failure. */
-int
-tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex)
-{
- return pthread_cond_wait(&cond->cond, &mutex->mutex) ? -1 : 0;
-}
-/** Wake up one of the waiters on <b>cond</b>. */
-void
-tor_cond_signal_one(tor_cond_t *cond)
-{
- pthread_cond_signal(&cond->cond);
-}
-/** Wake up all of the waiters on <b>cond</b>. */
-void
-tor_cond_signal_all(tor_cond_t *cond)
-{
- pthread_cond_broadcast(&cond->cond);
-}
-#endif
-/** Set up common structures for use by threading. */
-void
-tor_threads_init(void)
-{
- if (!threads_initialized) {
- pthread_mutexattr_init(&attr_reentrant);
- pthread_mutexattr_settype(&attr_reentrant, PTHREAD_MUTEX_RECURSIVE);
- tor_assert(0==pthread_attr_init(&attr_detached));
- tor_assert(0==pthread_attr_setdetachstate(&attr_detached, 1));
- threads_initialized = 1;
- set_main_thread();
- }
-}
-#elif defined(USE_WIN32_THREADS)
-#if 0
-static DWORD cond_event_tls_index;
-struct tor_cond_t {
- CRITICAL_SECTION mutex;
- smartlist_t *events;
-};
-tor_cond_t *
-tor_cond_new(void)
-{
- tor_cond_t *cond = tor_malloc_zero(sizeof(tor_cond_t));
- InitializeCriticalSection(&cond->mutex);
- cond->events = smartlist_new();
- return cond;
-}
-void
-tor_cond_free(tor_cond_t *cond)
-{
- if (!cond)
- return;
- DeleteCriticalSection(&cond->mutex);
- /* XXXX notify? */
- smartlist_free(cond->events);
- tor_free(cond);
-}
-int
-tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex)
-{
- HANDLE event;
- int r;
- tor_assert(cond);
- tor_assert(mutex);
- event = TlsGetValue(cond_event_tls_index);
- if (!event) {
- event = CreateEvent(0, FALSE, FALSE, NULL);
- TlsSetValue(cond_event_tls_index, event);
- }
- EnterCriticalSection(&cond->mutex);
-
- tor_assert(WaitForSingleObject(event, 0) == WAIT_TIMEOUT);
- tor_assert(!smartlist_contains(cond->events, event));
- smartlist_add(cond->events, event);
-
- LeaveCriticalSection(&cond->mutex);
-
- tor_mutex_release(mutex);
- r = WaitForSingleObject(event, INFINITE);
- tor_mutex_acquire(mutex);
-
- switch (r) {
- case WAIT_OBJECT_0: /* we got the mutex normally. */
- break;
- case WAIT_ABANDONED: /* holding thread exited. */
- case WAIT_TIMEOUT: /* Should never happen. */
- tor_assert(0);
- break;
- case WAIT_FAILED:
- log_warn(LD_GENERAL, "Failed to acquire mutex: %d",(int) GetLastError());
- }
- return 0;
-}
-void
-tor_cond_signal_one(tor_cond_t *cond)
-{
- HANDLE event;
- tor_assert(cond);
-
- EnterCriticalSection(&cond->mutex);
-
- if ((event = smartlist_pop_last(cond->events)))
- SetEvent(event);
-
- LeaveCriticalSection(&cond->mutex);
-}
-void
-tor_cond_signal_all(tor_cond_t *cond)
-{
- tor_assert(cond);
-
- EnterCriticalSection(&cond->mutex);
- SMARTLIST_FOREACH(cond->events, HANDLE, event, SetEvent(event));
- smartlist_clear(cond->events);
- LeaveCriticalSection(&cond->mutex);
-}
-#endif
-void
-tor_threads_init(void)
-{
-#if 0
- cond_event_tls_index = TlsAlloc();
-#endif
- set_main_thread();
-}
-#endif
-
#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK)
/** Attempt to raise the current and max rlimit to infinity for our process.
* This only needs to be done once and can probably only be done when we have
@@ -3257,23 +2918,6 @@ tor_mlockall(void)
#endif
}
-/** Identity of the "main" thread */
-static unsigned long main_thread_id = -1;
-
-/** Start considering the current thread to be the 'main thread'. This has
- * no effect on anything besides in_main_thread(). */
-void
-set_main_thread(void)
-{
- main_thread_id = tor_get_thread_id();
-}
-/** Return true iff called from the main thread. */
-int
-in_main_thread(void)
-{
- return main_thread_id == tor_get_thread_id();
-}
-
/**
* On Windows, WSAEWOULDBLOCK is not always correct: when you see it,
* you need to ask the socket for its actual errno. Also, you need to
@@ -3521,7 +3165,7 @@ get_total_system_memory_impl(void)
size_t len = sizeof(memsize);
int mib[2] = {CTL_HW, HW_USERMEM};
if (sysctl(mib,2,&memsize,&len,NULL,0))
- return -1;
+ return 0;
return memsize;
@@ -3552,12 +3196,12 @@ get_total_system_memory(size_t *mem_out)
return 0;
}
-#if SIZE_T_MAX != UINT64_MAX
- if (m > SIZE_T_MAX) {
+#if SIZE_MAX != UINT64_MAX
+ if (m > SIZE_MAX) {
/* I think this could happen if we're a 32-bit Tor running on a 64-bit
* system: we could have more system memory than would fit in a
* size_t. */
- m = SIZE_T_MAX;
+ m = SIZE_MAX;
}
#endif
diff --git a/src/common/compat.h b/src/common/compat.h
index 531e88f1bd..11b41cded9 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_COMPAT_H
@@ -36,9 +36,6 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
-#if defined(HAVE_PTHREAD_H) && !defined(_WIN32)
-#include <pthread.h>
-#endif
#include <stdarg.h>
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
@@ -56,21 +53,6 @@
#include <stdio.h>
#include <errno.h>
-#if defined (WINCE)
-#include <fcntl.h>
-#include <io.h>
-#include <math.h>
-#include <projects.h>
-/* this is not exported as W .... */
-#define SHGetPathFromIDListW SHGetPathFromIDList
-/* wcecompat has vasprintf */
-#define HAVE_VASPRINTF
-/* no service here */
-#ifdef NT_SERVICE
-#undef NT_SERVICE
-#endif
-#endif // WINCE
-
#ifndef NULL_REP_IS_ZERO_BYTES
#error "It seems your platform does not represent NULL as zero. We can't cope."
#endif
@@ -218,6 +200,15 @@ extern INLINE double U64_TO_DBL(uint64_t x) {
#define STMT_END } while (0)
#endif
+/* Some tools (like coccinelle) don't like to see operators as macro
+ * arguments. */
+#define OP_LT <
+#define OP_GT >
+#define OP_GE >=
+#define OP_LE <=
+#define OP_EQ ==
+#define OP_NE !=
+
/* ===== String compatibility */
#ifdef _WIN32
/* Windows names string functions differently from most other platforms. */
@@ -435,6 +426,7 @@ void tor_lockfile_unlock(tor_lockfile_t *lockfile);
off_t tor_fd_getpos(int fd);
int tor_fd_setpos(int fd, off_t pos);
int tor_fd_seekend(int fd);
+int tor_ftruncate(int fd);
#ifdef _WIN32
#define PATH_SEPARATOR "\\"
@@ -549,10 +541,11 @@ struct sockaddr_in6 {
};
#endif
+MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen));
int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2));
const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len);
int tor_inet_pton(int af, const char *src, void *dst);
-int tor_lookup_hostname(const char *name, uint32_t *addr) ATTR_NONNULL((1,2));
+MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr));
int set_socket_nonblocking(tor_socket_t socket);
int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]);
int network_init(void);
@@ -588,17 +581,18 @@ const char *tor_socket_strerror(int e);
#else
#define SOCK_ERRNO(e) e
#if EAGAIN == EWOULDBLOCK
-#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN)
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
+#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || 0)
#else
#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK)
#endif
-#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS)
-#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS)
+#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0)
+#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0)
#define ERRNO_IS_ACCEPT_EAGAIN(e) \
(ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED)
#define ERRNO_IS_ACCEPT_RESOURCE_LIMIT(e) \
((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM)
-#define ERRNO_IS_EADDRINUSE(e) ((e) == EADDRINUSE)
+#define ERRNO_IS_EADDRINUSE(e) (((e) == EADDRINUSE) || 0)
#define tor_socket_errno(sock) (errno)
#define tor_socket_strerror(e) strerror(e)
#endif
@@ -657,77 +651,10 @@ char **get_environment(void);
int get_total_system_memory(size_t *mem_out);
-int spawn_func(void (*func)(void *), void *data);
-void spawn_exit(void) ATTR_NORETURN;
-
-#if defined(ENABLE_THREADS) && defined(_WIN32)
-#define USE_WIN32_THREADS
-#define TOR_IS_MULTITHREADED 1
-#elif (defined(ENABLE_THREADS) && defined(HAVE_PTHREAD_H) && \
- defined(HAVE_PTHREAD_CREATE))
-#define USE_PTHREADS
-#define TOR_IS_MULTITHREADED 1
-#else
-#undef TOR_IS_MULTITHREADED
-#endif
-
int compute_num_cpus(void);
-/* Because we use threads instead of processes on most platforms (Windows,
- * Linux, etc), we need locking for them. On platforms with poor thread
- * support or broken gethostbyname_r, these functions are no-ops. */
-
-/** A generic lock structure for multithreaded builds. */
-typedef struct tor_mutex_t {
-#if defined(USE_WIN32_THREADS)
- /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */
- CRITICAL_SECTION mutex;
-#elif defined(USE_PTHREADS)
- /** Pthreads-only: with pthreads, we implement locks with
- * pthread_mutex_t. */
- pthread_mutex_t mutex;
-#else
- /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */
- int _unused;
-#endif
-} tor_mutex_t;
-
int tor_mlockall(void);
-#ifdef TOR_IS_MULTITHREADED
-tor_mutex_t *tor_mutex_new(void);
-void tor_mutex_init(tor_mutex_t *m);
-void tor_mutex_acquire(tor_mutex_t *m);
-void tor_mutex_release(tor_mutex_t *m);
-void tor_mutex_free(tor_mutex_t *m);
-void tor_mutex_uninit(tor_mutex_t *m);
-unsigned long tor_get_thread_id(void);
-void tor_threads_init(void);
-#else
-#define tor_mutex_new() ((tor_mutex_t*)tor_malloc(sizeof(int)))
-#define tor_mutex_init(m) STMT_NIL
-#define tor_mutex_acquire(m) STMT_VOID(m)
-#define tor_mutex_release(m) STMT_NIL
-#define tor_mutex_free(m) STMT_BEGIN tor_free(m); STMT_END
-#define tor_mutex_uninit(m) STMT_NIL
-#define tor_get_thread_id() (1UL)
-#define tor_threads_init() STMT_NIL
-#endif
-
-void set_main_thread(void);
-int in_main_thread(void);
-
-#ifdef TOR_IS_MULTITHREADED
-#if 0
-typedef struct tor_cond_t tor_cond_t;
-tor_cond_t *tor_cond_new(void);
-void tor_cond_free(tor_cond_t *cond);
-int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex);
-void tor_cond_signal_one(tor_cond_t *cond);
-void tor_cond_signal_all(tor_cond_t *cond);
-#endif
-#endif
-
/** Macros for MIN/MAX. Never use these when the arguments could have
* side-effects.
* {With GCC extensions we could probably define a safer MIN/MAX. But
@@ -773,5 +700,8 @@ STATIC int tor_ersatz_socketpair(int family, int type, int protocol,
#endif
#endif
+/* This needs some of the declarations above so we include it here. */
+#include "compat_threads.h"
+
#endif
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 74b54bb855..15308dd4cb 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2013, The Tor Project, Inc. */
+/* Copyright (c) 2009-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -146,13 +146,25 @@ tor_evsignal_new(struct event_base * base, int sig,
{
return tor_event_new(base, sig, EV_SIGNAL|EV_PERSIST, cb, arg);
}
-/** Work-alike replacement for event_free() on pre-Libevent-2.0 systems. */
+/** Work-alike replacement for event_free() on pre-Libevent-2.0 systems,
+ * except tolerate tor_event_free(NULL). */
void
tor_event_free(struct event *ev)
{
+ if (ev == NULL)
+ return;
event_del(ev);
tor_free(ev);
}
+#else
+/* Wrapper for event_free() that tolerates tor_event_free(NULL) */
+void
+tor_event_free(struct event *ev)
+{
+ if (ev == NULL)
+ return;
+ event_free(ev);
+}
#endif
/** Global event base for use by the main thread. */
@@ -210,6 +222,9 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
} else {
using_iocp_bufferevents = 0;
}
+#elif defined(__COVERITY__)
+ /* Avoid a 'dead code' warning below. */
+ using_threads = ! torcfg->disable_iocp;
#endif
if (!using_threads) {
@@ -280,8 +295,8 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
}
/** Return the current Libevent event base that we're set up to use. */
-struct event_base *
-tor_libevent_get_base(void)
+MOCK_IMPL(struct event_base *,
+tor_libevent_get_base, (void))
{
return the_event_base;
}
@@ -714,7 +729,7 @@ tor_gettimeofday_cached_monotonic(struct timeval *tv)
struct timeval last_tv = { 0, 0 };
tor_gettimeofday_cached(tv);
- if (timercmp(tv, &last_tv, <)) {
+ if (timercmp(tv, &last_tv, OP_LT)) {
memcpy(tv, &last_tv, sizeof(struct timeval));
} else {
memcpy(&last_tv, tv, sizeof(struct timeval));
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 9ee7b49cfb..6bbfae0056 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -1,10 +1,11 @@
-/* Copyright (c) 2009-2013, The Tor Project, Inc. */
+/* Copyright (c) 2009-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_COMPAT_LIBEVENT_H
#define TOR_COMPAT_LIBEVENT_H
#include "orconfig.h"
+#include "testsupport.h"
struct event;
struct event_base;
@@ -28,11 +29,9 @@ void suppress_libevent_log_msg(const char *msg);
#define tor_event_new event_new
#define tor_evtimer_new evtimer_new
#define tor_evsignal_new evsignal_new
-#define tor_event_free event_free
#define tor_evdns_add_server_port(sock, tcp, cb, data) \
evdns_add_server_port_with_base(tor_libevent_get_base(), \
(sock),(tcp),(cb),(data));
-
#else
struct event *tor_event_new(struct event_base * base, evutil_socket_t sock,
short what, void (*cb)(evutil_socket_t, short, void *), void *arg);
@@ -40,10 +39,11 @@ struct event *tor_evtimer_new(struct event_base * base,
void (*cb)(evutil_socket_t, short, void *), void *arg);
struct event *tor_evsignal_new(struct event_base * base, int sig,
void (*cb)(evutil_socket_t, short, void *), void *arg);
-void tor_event_free(struct event *ev);
#define tor_evdns_add_server_port evdns_add_server_port
#endif
+void tor_event_free(struct event *ev);
+
typedef struct periodic_timer_t periodic_timer_t;
periodic_timer_t *periodic_timer_new(struct event_base *base,
@@ -72,7 +72,7 @@ typedef struct tor_libevent_cfg {
} tor_libevent_cfg;
void tor_libevent_initialize(tor_libevent_cfg *cfg);
-struct event_base *tor_libevent_get_base(void);
+MOCK_DECL(struct event_base *, tor_libevent_get_base, (void));
const char *tor_libevent_get_method(void);
void tor_check_libevent_version(const char *m, int server,
const char **badness_out);
diff --git a/src/common/compat_pthreads.c b/src/common/compat_pthreads.c
new file mode 100644
index 0000000000..246076b276
--- /dev/null
+++ b/src/common/compat_pthreads.c
@@ -0,0 +1,291 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define _GNU_SOURCE
+
+#include "orconfig.h"
+#include <pthread.h>
+#include <signal.h>
+#include <time.h>
+
+#include "compat.h"
+#include "torlog.h"
+#include "util.h"
+
+/** Wraps a void (*)(void*) function and its argument so we can
+ * invoke them in a way pthreads would expect.
+ */
+typedef struct tor_pthread_data_t {
+ void (*func)(void *);
+ void *data;
+} tor_pthread_data_t;
+/** Given a tor_pthread_data_t <b>_data</b>, call _data-&gt;func(d-&gt;data)
+ * and free _data. Used to make sure we can call functions the way pthread
+ * expects. */
+static void *
+tor_pthread_helper_fn(void *_data)
+{
+ tor_pthread_data_t *data = _data;
+ void (*func)(void*);
+ void *arg;
+ /* mask signals to worker threads to avoid SIGPIPE, etc */
+ sigset_t sigs;
+ /* We're in a subthread; don't handle any signals here. */
+ sigfillset(&sigs);
+ pthread_sigmask(SIG_SETMASK, &sigs, NULL);
+
+ func = data->func;
+ arg = data->data;
+ tor_free(_data);
+ func(arg);
+ return NULL;
+}
+/**
+ * A pthread attribute to make threads start detached.
+ */
+static pthread_attr_t attr_detached;
+/** True iff we've called tor_threads_init() */
+static int threads_initialized = 0;
+
+/** Minimalist interface to run a void function in the background. On
+ * Unix calls fork, on win32 calls beginthread. Returns -1 on failure.
+ * func should not return, but rather should call spawn_exit.
+ *
+ * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
+ * since in a multithreaded environment, there is no way to be sure that
+ * the caller's stack will still be around when the called function is
+ * running.
+ */
+int
+spawn_func(void (*func)(void *), void *data)
+{
+ pthread_t thread;
+ tor_pthread_data_t *d;
+ if (PREDICT_UNLIKELY(!threads_initialized))
+ tor_threads_init();
+ d = tor_malloc(sizeof(tor_pthread_data_t));
+ d->data = data;
+ d->func = func;
+ if (pthread_create(&thread,&attr_detached,tor_pthread_helper_fn,d))
+ return -1;
+ return 0;
+}
+
+/** End the current thread/process.
+ */
+void
+spawn_exit(void)
+{
+ pthread_exit(NULL);
+}
+
+/** A mutex attribute that we're going to use to tell pthreads that we want
+ * "recursive" mutexes (i.e., once we can re-lock if we're already holding
+ * them.) */
+static pthread_mutexattr_t attr_recursive;
+
+/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set
+ * up with tor_mutex_init() or tor_mutex_new(); not both. */
+void
+tor_mutex_init(tor_mutex_t *mutex)
+{
+ int err;
+ if (PREDICT_UNLIKELY(!threads_initialized))
+ tor_threads_init();
+ err = pthread_mutex_init(&mutex->mutex, &attr_recursive);
+ if (PREDICT_UNLIKELY(err)) {
+ log_err(LD_GENERAL, "Error %d creating a mutex.", err);
+ tor_fragile_assert();
+ }
+}
+
+/** As tor_mutex_init, but initialize a mutex suitable that may be
+ * non-recursive, if the OS supports that. */
+void
+tor_mutex_init_nonrecursive(tor_mutex_t *mutex)
+{
+ int err;
+ if (PREDICT_UNLIKELY(!threads_initialized))
+ tor_threads_init();
+ err = pthread_mutex_init(&mutex->mutex, NULL);
+ if (PREDICT_UNLIKELY(err)) {
+ log_err(LD_GENERAL, "Error %d creating a mutex.", err);
+ tor_fragile_assert();
+ }
+}
+
+/** Wait until <b>m</b> is free, then acquire it. */
+void
+tor_mutex_acquire(tor_mutex_t *m)
+{
+ int err;
+ tor_assert(m);
+ err = pthread_mutex_lock(&m->mutex);
+ if (PREDICT_UNLIKELY(err)) {
+ log_err(LD_GENERAL, "Error %d locking a mutex.", err);
+ tor_fragile_assert();
+ }
+}
+/** Release the lock <b>m</b> so another thread can have it. */
+void
+tor_mutex_release(tor_mutex_t *m)
+{
+ int err;
+ tor_assert(m);
+ err = pthread_mutex_unlock(&m->mutex);
+ if (PREDICT_UNLIKELY(err)) {
+ log_err(LD_GENERAL, "Error %d unlocking a mutex.", err);
+ tor_fragile_assert();
+ }
+}
+/** Clean up the mutex <b>m</b> so that it no longer uses any system
+ * resources. Does not free <b>m</b>. This function must only be called on
+ * mutexes from tor_mutex_init(). */
+void
+tor_mutex_uninit(tor_mutex_t *m)
+{
+ int err;
+ tor_assert(m);
+ err = pthread_mutex_destroy(&m->mutex);
+ if (PREDICT_UNLIKELY(err)) {
+ log_err(LD_GENERAL, "Error %d destroying a mutex.", err);
+ tor_fragile_assert();
+ }
+}
+/** Return an integer representing this thread. */
+unsigned long
+tor_get_thread_id(void)
+{
+ union {
+ pthread_t thr;
+ unsigned long id;
+ } r;
+ r.thr = pthread_self();
+ return r.id;
+}
+
+/* Conditions. */
+
+/** Initialize an already-allocated condition variable. */
+int
+tor_cond_init(tor_cond_t *cond)
+{
+ pthread_condattr_t condattr;
+
+ memset(cond, 0, sizeof(tor_cond_t));
+ /* Default condition attribute. Might be used if clock monotonic is
+ * available else this won't affect anything. */
+ if (pthread_condattr_init(&condattr)) {
+ return -1;
+ }
+
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ /* Use monotonic time so when we timedwait() on it, any clock adjustment
+ * won't affect the timeout value. */
+ if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) {
+ return -1;
+ }
+#endif
+ if (pthread_cond_init(&cond->cond, &condattr)) {
+ return -1;
+ }
+ return 0;
+}
+
+/** Release all resources held by <b>cond</b>, but do not free <b>cond</b>
+ * itself. */
+void
+tor_cond_uninit(tor_cond_t *cond)
+{
+ if (pthread_cond_destroy(&cond->cond)) {
+ log_warn(LD_GENERAL,"Error freeing condition: %s", strerror(errno));
+ return;
+ }
+}
+/** Wait until one of the tor_cond_signal functions is called on <b>cond</b>.
+ * (If <b>tv</b> is set, and that amount of time passes with no signal to
+ * <b>cond</b>, return anyway. All waiters on the condition must wait holding
+ * the same <b>mutex</b>. All signallers should hold that mutex. The mutex
+ * needs to have been allocated with tor_mutex_init_for_cond().
+ *
+ * Returns 0 on success, -1 on failure, 1 on timeout. */
+int
+tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv)
+{
+ int r;
+ if (tv == NULL) {
+ while (1) {
+ r = pthread_cond_wait(&cond->cond, &mutex->mutex);
+ if (r == EINTR) {
+ /* EINTR should be impossible according to POSIX, but POSIX, like the
+ * Pirate's Code, is apparently treated "more like what you'd call
+ * guidelines than actual rules." */
+ continue;
+ }
+ return r ? -1 : 0;
+ }
+ } else {
+ struct timeval tvnow, tvsum;
+ struct timespec ts;
+ while (1) {
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
+ return -1;
+ }
+ tvnow.tv_sec = ts.tv_sec;
+ tvnow.tv_usec = ts.tv_nsec / 1000;
+ timeradd(tv, &tvnow, &tvsum);
+#else
+ if (gettimeofday(&tvnow, NULL) < 0)
+ return -1;
+ timeradd(tv, &tvnow, &tvsum);
+#endif /* HAVE_CLOCK_GETTIME, CLOCK_MONOTONIC */
+
+ ts.tv_sec = tvsum.tv_sec;
+ ts.tv_nsec = tvsum.tv_usec * 1000;
+
+ r = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &ts);
+ if (r == 0)
+ return 0;
+ else if (r == ETIMEDOUT)
+ return 1;
+ else if (r == EINTR)
+ continue;
+ else
+ return -1;
+ }
+ }
+}
+/** Wake up one of the waiters on <b>cond</b>. */
+void
+tor_cond_signal_one(tor_cond_t *cond)
+{
+ pthread_cond_signal(&cond->cond);
+}
+/** Wake up all of the waiters on <b>cond</b>. */
+void
+tor_cond_signal_all(tor_cond_t *cond)
+{
+ pthread_cond_broadcast(&cond->cond);
+}
+
+/** Set up common structures for use by threading. */
+void
+tor_threads_init(void)
+{
+ if (!threads_initialized) {
+ pthread_mutexattr_init(&attr_recursive);
+ pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE);
+ tor_assert(0==pthread_attr_init(&attr_detached));
+#ifndef PTHREAD_CREATE_DETACHED
+#define PTHREAD_CREATE_DETACHED 1
+#endif
+ tor_assert(0==pthread_attr_setdetachstate(&attr_detached,
+ PTHREAD_CREATE_DETACHED));
+ threads_initialized = 1;
+ set_main_thread();
+ }
+}
+
diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c
new file mode 100644
index 0000000000..15648d2851
--- /dev/null
+++ b/src/common/compat_threads.c
@@ -0,0 +1,306 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define _GNU_SOURCE
+
+#include "orconfig.h"
+#include <stdlib.h>
+#include "compat.h"
+#include "compat_threads.h"
+
+#include "util.h"
+#include "torlog.h"
+
+#ifdef HAVE_SYS_EVENTFD_H
+#include <sys/eventfd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/** Return a newly allocated, ready-for-use mutex. */
+tor_mutex_t *
+tor_mutex_new(void)
+{
+ tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t));
+ tor_mutex_init(m);
+ return m;
+}
+/** Return a newly allocated, ready-for-use mutex. This one might be
+ * non-recursive, if that's faster. */
+tor_mutex_t *
+tor_mutex_new_nonrecursive(void)
+{
+ tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t));
+ tor_mutex_init_nonrecursive(m);
+ return m;
+}
+/** Release all storage and system resources held by <b>m</b>. */
+void
+tor_mutex_free(tor_mutex_t *m)
+{
+ if (!m)
+ return;
+ tor_mutex_uninit(m);
+ tor_free(m);
+}
+
+/** Allocate and return a new condition variable. */
+tor_cond_t *
+tor_cond_new(void)
+{
+ tor_cond_t *cond = tor_malloc(sizeof(tor_cond_t));
+ if (tor_cond_init(cond)<0)
+ tor_free(cond);
+ return cond;
+}
+
+/** Free all storage held in <b>c</b>. */
+void
+tor_cond_free(tor_cond_t *c)
+{
+ if (!c)
+ return;
+ tor_cond_uninit(c);
+ tor_free(c);
+}
+
+/** Identity of the "main" thread */
+static unsigned long main_thread_id = -1;
+
+/** Start considering the current thread to be the 'main thread'. This has
+ * no effect on anything besides in_main_thread(). */
+void
+set_main_thread(void)
+{
+ main_thread_id = tor_get_thread_id();
+}
+/** Return true iff called from the main thread. */
+int
+in_main_thread(void)
+{
+ return main_thread_id == tor_get_thread_id();
+}
+
+#if defined(HAVE_EVENTFD) || defined(HAVE_PIPE)
+/* non-interruptable versions */
+static int
+write_ni(int fd, const void *buf, size_t n)
+{
+ int r;
+ again:
+ r = (int) write(fd, buf, n);
+ if (r < 0 && errno == EINTR)
+ goto again;
+ return r;
+}
+static int
+read_ni(int fd, void *buf, size_t n)
+{
+ int r;
+ again:
+ r = (int) read(fd, buf, n);
+ if (r < 0 && errno == EINTR)
+ goto again;
+ return r;
+}
+#endif
+
+/* non-interruptable versions */
+static int
+send_ni(int fd, const void *buf, size_t n, int flags)
+{
+ int r;
+ again:
+ r = (int) send(fd, buf, n, flags);
+ if (r < 0 && errno == EINTR)
+ goto again;
+ return r;
+}
+
+static int
+recv_ni(int fd, void *buf, size_t n, int flags)
+{
+ int r;
+ again:
+ r = (int) recv(fd, buf, n, flags);
+ if (r < 0 && errno == EINTR)
+ goto again;
+ return r;
+}
+
+#ifdef HAVE_EVENTFD
+static int
+eventfd_alert(int fd)
+{
+ uint64_t u = 1;
+ int r = write_ni(fd, (void*)&u, sizeof(u));
+ if (r < 0 && errno != EAGAIN)
+ return -1;
+ return 0;
+}
+
+static int
+eventfd_drain(int fd)
+{
+ uint64_t u = 0;
+ int r = read_ni(fd, (void*)&u, sizeof(u));
+ if (r < 0 && errno != EAGAIN)
+ return -1;
+ return 0;
+}
+#endif
+
+#ifdef HAVE_PIPE
+static int
+pipe_alert(int fd)
+{
+ ssize_t r = write_ni(fd, "x", 1);
+ if (r < 0 && errno != EAGAIN)
+ return -1;
+ return 0;
+}
+
+static int
+pipe_drain(int fd)
+{
+ char buf[32];
+ ssize_t r;
+ do {
+ r = read_ni(fd, buf, sizeof(buf));
+ } while (r > 0);
+ if (r < 0 && errno != EAGAIN)
+ return -1;
+ /* A value of r = 0 means EOF on the fd so successfully drained. */
+ return 0;
+}
+#endif
+
+static int
+sock_alert(tor_socket_t fd)
+{
+ ssize_t r = send_ni(fd, "x", 1, 0);
+ if (r < 0 && !ERRNO_IS_EAGAIN(tor_socket_errno(fd)))
+ return -1;
+ return 0;
+}
+
+static int
+sock_drain(tor_socket_t fd)
+{
+ char buf[32];
+ ssize_t r;
+ do {
+ r = recv_ni(fd, buf, sizeof(buf), 0);
+ } while (r > 0);
+ if (r < 0 && !ERRNO_IS_EAGAIN(tor_socket_errno(fd)))
+ return -1;
+ /* A value of r = 0 means EOF on the fd so successfully drained. */
+ return 0;
+}
+
+/** Allocate a new set of alert sockets, and set the appropriate function
+ * pointers, in <b>socks_out</b>. */
+int
+alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags)
+{
+ tor_socket_t socks[2] = { TOR_INVALID_SOCKET, TOR_INVALID_SOCKET };
+
+#ifdef HAVE_EVENTFD
+ /* First, we try the Linux eventfd() syscall. This gives a 64-bit counter
+ * associated with a single file descriptor. */
+#if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
+ if (!(flags & ASOCKS_NOEVENTFD2))
+ socks[0] = eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK);
+#endif
+ if (socks[0] < 0 && !(flags & ASOCKS_NOEVENTFD)) {
+ socks[0] = eventfd(0,0);
+ if (socks[0] >= 0) {
+ if (fcntl(socks[0], F_SETFD, FD_CLOEXEC) < 0 ||
+ set_socket_nonblocking(socks[0]) < 0) {
+ close(socks[0]);
+ return -1;
+ }
+ }
+ }
+ if (socks[0] >= 0) {
+ socks_out->read_fd = socks_out->write_fd = socks[0];
+ socks_out->alert_fn = eventfd_alert;
+ socks_out->drain_fn = eventfd_drain;
+ return 0;
+ }
+#endif
+
+#ifdef HAVE_PIPE2
+ /* Now we're going to try pipes. First type the pipe2() syscall, if we
+ * have it, so we can save some calls... */
+ if (!(flags & ASOCKS_NOPIPE2) &&
+ pipe2(socks, O_NONBLOCK|O_CLOEXEC) == 0) {
+ socks_out->read_fd = socks[0];
+ socks_out->write_fd = socks[1];
+ socks_out->alert_fn = pipe_alert;
+ socks_out->drain_fn = pipe_drain;
+ return 0;
+ }
+#endif
+
+#ifdef HAVE_PIPE
+ /* Now try the regular pipe() syscall. Pipes have a bit lower overhead than
+ * socketpairs, fwict. */
+ if (!(flags & ASOCKS_NOPIPE) &&
+ pipe(socks) == 0) {
+ if (fcntl(socks[0], F_SETFD, FD_CLOEXEC) < 0 ||
+ fcntl(socks[1], F_SETFD, FD_CLOEXEC) < 0 ||
+ set_socket_nonblocking(socks[0]) < 0 ||
+ set_socket_nonblocking(socks[1]) < 0) {
+ close(socks[0]);
+ close(socks[1]);
+ return -1;
+ }
+ socks_out->read_fd = socks[0];
+ socks_out->write_fd = socks[1];
+ socks_out->alert_fn = pipe_alert;
+ socks_out->drain_fn = pipe_drain;
+ return 0;
+ }
+#endif
+
+ /* If nothing else worked, fall back on socketpair(). */
+ if (!(flags & ASOCKS_NOSOCKETPAIR) &&
+ tor_socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == 0) {
+ if (set_socket_nonblocking(socks[0]) < 0 ||
+ set_socket_nonblocking(socks[1])) {
+ tor_close_socket(socks[0]);
+ tor_close_socket(socks[1]);
+ return -1;
+ }
+ socks_out->read_fd = socks[0];
+ socks_out->write_fd = socks[1];
+ socks_out->alert_fn = sock_alert;
+ socks_out->drain_fn = sock_drain;
+ return 0;
+ }
+ return -1;
+}
+
+/** Close the sockets in <b>socks</b>. */
+void
+alert_sockets_close(alert_sockets_t *socks)
+{
+ if (socks->alert_fn == sock_alert) {
+ /* they are sockets. */
+ tor_close_socket(socks->read_fd);
+ tor_close_socket(socks->write_fd);
+ } else {
+ close(socks->read_fd);
+ if (socks->write_fd != socks->read_fd)
+ close(socks->write_fd);
+ }
+ socks->read_fd = socks->write_fd = -1;
+}
+
diff --git a/src/common/compat_threads.h b/src/common/compat_threads.h
new file mode 100644
index 0000000000..acf3083f37
--- /dev/null
+++ b/src/common/compat_threads.h
@@ -0,0 +1,115 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_COMPAT_THREADS_H
+#define TOR_COMPAT_THREADS_H
+
+#include "orconfig.h"
+#include "torint.h"
+#include "testsupport.h"
+
+#if defined(HAVE_PTHREAD_H) && !defined(_WIN32)
+#include <pthread.h>
+#endif
+
+#if defined(_WIN32)
+#define USE_WIN32_THREADS
+#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE)
+#define USE_PTHREADS
+#else
+#error "No threading system was found"
+#endif
+
+int spawn_func(void (*func)(void *), void *data);
+void spawn_exit(void) ATTR_NORETURN;
+
+/* Because we use threads instead of processes on most platforms (Windows,
+ * Linux, etc), we need locking for them. On platforms with poor thread
+ * support or broken gethostbyname_r, these functions are no-ops. */
+
+/** A generic lock structure for multithreaded builds. */
+typedef struct tor_mutex_t {
+#if defined(USE_WIN32_THREADS)
+ /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */
+ CRITICAL_SECTION mutex;
+#elif defined(USE_PTHREADS)
+ /** Pthreads-only: with pthreads, we implement locks with
+ * pthread_mutex_t. */
+ pthread_mutex_t mutex;
+#else
+ /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */
+ int _unused;
+#endif
+} tor_mutex_t;
+
+tor_mutex_t *tor_mutex_new(void);
+tor_mutex_t *tor_mutex_new_nonrecursive(void);
+void tor_mutex_init(tor_mutex_t *m);
+void tor_mutex_init_nonrecursive(tor_mutex_t *m);
+void tor_mutex_acquire(tor_mutex_t *m);
+void tor_mutex_release(tor_mutex_t *m);
+void tor_mutex_free(tor_mutex_t *m);
+void tor_mutex_uninit(tor_mutex_t *m);
+unsigned long tor_get_thread_id(void);
+void tor_threads_init(void);
+
+/** Conditions need nonrecursive mutexes with pthreads. */
+#define tor_mutex_init_for_cond(m) tor_mutex_init_nonrecursive(m)
+
+void set_main_thread(void);
+int in_main_thread(void);
+
+typedef struct tor_cond_t {
+#ifdef USE_PTHREADS
+ pthread_cond_t cond;
+#elif defined(USE_WIN32_THREADS)
+ HANDLE event;
+
+ CRITICAL_SECTION lock;
+ int n_waiting;
+ int n_to_wake;
+ int generation;
+#else
+#error no known condition implementation.
+#endif
+} tor_cond_t;
+
+tor_cond_t *tor_cond_new(void);
+void tor_cond_free(tor_cond_t *cond);
+int tor_cond_init(tor_cond_t *cond);
+void tor_cond_uninit(tor_cond_t *cond);
+int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex,
+ const struct timeval *tv);
+void tor_cond_signal_one(tor_cond_t *cond);
+void tor_cond_signal_all(tor_cond_t *cond);
+
+/** Helper type used to manage waking up the main thread while it's in
+ * the libevent main loop. Used by the work queue code. */
+typedef struct alert_sockets_s {
+ /* XXXX This structure needs a better name. */
+ /** Socket that the main thread should listen for EV_READ events on.
+ * Note that this socket may be a regular fd on a non-Windows platform.
+ */
+ tor_socket_t read_fd;
+ /** Socket to use when alerting the main thread. */
+ tor_socket_t write_fd;
+ /** Function to alert the main thread */
+ int (*alert_fn)(tor_socket_t write_fd);
+ /** Function to make the main thread no longer alerted. */
+ int (*drain_fn)(tor_socket_t read_fd);
+} alert_sockets_t;
+
+/* Flags to disable one or more alert_sockets backends. */
+#define ASOCKS_NOEVENTFD2 (1u<<0)
+#define ASOCKS_NOEVENTFD (1u<<1)
+#define ASOCKS_NOPIPE2 (1u<<2)
+#define ASOCKS_NOPIPE (1u<<3)
+#define ASOCKS_NOSOCKETPAIR (1u<<4)
+
+int alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags);
+void alert_sockets_close(alert_sockets_t *socks);
+
+#endif
+
diff --git a/src/common/compat_winthreads.c b/src/common/compat_winthreads.c
new file mode 100644
index 0000000000..71b994c4e4
--- /dev/null
+++ b/src/common/compat_winthreads.c
@@ -0,0 +1,196 @@
+/* Copyright (c) 2003-2004, Roger Dingledine
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "compat.h"
+#include <windows.h>
+#include <process.h>
+#include "util.h"
+#include "container.h"
+#include "torlog.h"
+#include <process.h>
+
+/* This value is more or less total cargo-cult */
+#define SPIN_COUNT 2000
+
+/** Minimalist interface to run a void function in the background. On
+ * Unix calls fork, on win32 calls beginthread. Returns -1 on failure.
+ * func should not return, but rather should call spawn_exit.
+ *
+ * NOTE: if <b>data</b> is used, it should not be allocated on the stack,
+ * since in a multithreaded environment, there is no way to be sure that
+ * the caller's stack will still be around when the called function is
+ * running.
+ */
+int
+spawn_func(void (*func)(void *), void *data)
+{
+ int rv;
+ rv = (int)_beginthread(func, 0, data);
+ if (rv == (int)-1)
+ return -1;
+ return 0;
+}
+
+/** End the current thread/process.
+ */
+void
+spawn_exit(void)
+{
+ _endthread();
+ //we should never get here. my compiler thinks that _endthread returns, this
+ //is an attempt to fool it.
+ tor_assert(0);
+ _exit(0);
+}
+
+void
+tor_mutex_init(tor_mutex_t *m)
+{
+ InitializeCriticalSection(&m->mutex);
+}
+void
+tor_mutex_init_nonrecursive(tor_mutex_t *m)
+{
+ InitializeCriticalSection(&m->mutex);
+}
+
+void
+tor_mutex_uninit(tor_mutex_t *m)
+{
+ DeleteCriticalSection(&m->mutex);
+}
+void
+tor_mutex_acquire(tor_mutex_t *m)
+{
+ tor_assert(m);
+ EnterCriticalSection(&m->mutex);
+}
+void
+tor_mutex_release(tor_mutex_t *m)
+{
+ LeaveCriticalSection(&m->mutex);
+}
+unsigned long
+tor_get_thread_id(void)
+{
+ return (unsigned long)GetCurrentThreadId();
+}
+
+int
+tor_cond_init(tor_cond_t *cond)
+{
+ memset(cond, 0, sizeof(tor_cond_t));
+ if (InitializeCriticalSectionAndSpinCount(&cond->lock, SPIN_COUNT)==0) {
+ return -1;
+ }
+ if ((cond->event = CreateEvent(NULL,TRUE,FALSE,NULL)) == NULL) {
+ DeleteCriticalSection(&cond->lock);
+ return -1;
+ }
+ cond->n_waiting = cond->n_to_wake = cond->generation = 0;
+ return 0;
+}
+void
+tor_cond_uninit(tor_cond_t *cond)
+{
+ DeleteCriticalSection(&cond->lock);
+ CloseHandle(cond->event);
+}
+
+static void
+tor_cond_signal_impl(tor_cond_t *cond, int broadcast)
+{
+ EnterCriticalSection(&cond->lock);
+ if (broadcast)
+ cond->n_to_wake = cond->n_waiting;
+ else
+ ++cond->n_to_wake;
+ cond->generation++;
+ SetEvent(cond->event);
+ LeaveCriticalSection(&cond->lock);
+}
+void
+tor_cond_signal_one(tor_cond_t *cond)
+{
+ tor_cond_signal_impl(cond, 0);
+}
+void
+tor_cond_signal_all(tor_cond_t *cond)
+{
+ tor_cond_signal_impl(cond, 1);
+}
+
+int
+tor_cond_wait(tor_cond_t *cond, tor_mutex_t *lock_, const struct timeval *tv)
+{
+ CRITICAL_SECTION *lock = &lock_->mutex;
+ int generation_at_start;
+ int waiting = 1;
+ int result = -1;
+ DWORD ms = INFINITE, ms_orig = INFINITE, startTime, endTime;
+ if (tv)
+ ms_orig = ms = tv->tv_sec*1000 + (tv->tv_usec+999)/1000;
+
+ EnterCriticalSection(&cond->lock);
+ ++cond->n_waiting;
+ generation_at_start = cond->generation;
+ LeaveCriticalSection(&cond->lock);
+
+ LeaveCriticalSection(lock);
+
+ startTime = GetTickCount();
+ do {
+ DWORD res;
+ res = WaitForSingleObject(cond->event, ms);
+ EnterCriticalSection(&cond->lock);
+ if (cond->n_to_wake &&
+ cond->generation != generation_at_start) {
+ --cond->n_to_wake;
+ --cond->n_waiting;
+ result = 0;
+ waiting = 0;
+ goto out;
+ } else if (res != WAIT_OBJECT_0) {
+ result = (res==WAIT_TIMEOUT) ? 1 : -1;
+ --cond->n_waiting;
+ waiting = 0;
+ goto out;
+ } else if (ms != INFINITE) {
+ endTime = GetTickCount();
+ if (startTime + ms_orig <= endTime) {
+ result = 1; /* Timeout */
+ --cond->n_waiting;
+ waiting = 0;
+ goto out;
+ } else {
+ ms = startTime + ms_orig - endTime;
+ }
+ }
+ /* If we make it here, we are still waiting. */
+ if (cond->n_to_wake == 0) {
+ /* There is nobody else who should wake up; reset
+ * the event. */
+ ResetEvent(cond->event);
+ }
+ out:
+ LeaveCriticalSection(&cond->lock);
+ } while (waiting);
+
+ EnterCriticalSection(lock);
+
+ EnterCriticalSection(&cond->lock);
+ if (!cond->n_waiting)
+ ResetEvent(cond->event);
+ LeaveCriticalSection(&cond->lock);
+
+ return result;
+}
+
+void
+tor_threads_init(void)
+{
+ set_main_thread();
+}
+
diff --git a/src/common/container.c b/src/common/container.c
index c668068e9e..76c129df0b 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,21 +28,21 @@
/** Allocate and return an empty smartlist.
*/
-smartlist_t *
-smartlist_new(void)
+MOCK_IMPL(smartlist_t *,
+smartlist_new,(void))
{
smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
sl->num_used = 0;
sl->capacity = SMARTLIST_DEFAULT_CAPACITY;
- sl->list = tor_malloc(sizeof(void *) * sl->capacity);
+ sl->list = tor_calloc(sizeof(void *), sl->capacity);
return sl;
}
/** Deallocate a smartlist. Does not release storage associated with the
* list's elements.
*/
-void
-smartlist_free(smartlist_t *sl)
+MOCK_IMPL(void,
+smartlist_free,(smartlist_t *sl))
{
if (!sl)
return;
@@ -72,12 +72,12 @@ smartlist_ensure_capacity(smartlist_t *sl, size_t size)
#else
#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*))))
#endif
+
tor_assert(size <= MAX_CAPACITY);
if (size > (size_t) sl->capacity) {
size_t higher = (size_t) sl->capacity;
if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) {
- tor_assert(size <= MAX_CAPACITY);
higher = MAX_CAPACITY;
} else {
while (size > higher)
@@ -85,8 +85,11 @@ smartlist_ensure_capacity(smartlist_t *sl, size_t size)
}
tor_assert(higher <= INT_MAX); /* Redundant */
sl->capacity = (int) higher;
- sl->list = tor_realloc(sl->list, sizeof(void*)*((size_t)sl->capacity));
+ sl->list = tor_reallocarray(sl->list, sizeof(void *),
+ ((size_t)sl->capacity));
}
+#undef ASSERT_CAPACITY
+#undef MAX_CAPACITY
}
/** Append element to the end of the list. */
@@ -518,11 +521,13 @@ smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b))
/** Given a smartlist <b>sl</b> sorted with the function <b>compare</b>,
* return the most frequent member in the list. Break ties in favor of
- * later elements. If the list is empty, return NULL.
+ * later elements. If the list is empty, return NULL. If count_out is
+ * non-null, set it to the most frequent member.
*/
void *
-smartlist_get_most_frequent(const smartlist_t *sl,
- int (*compare)(const void **a, const void **b))
+smartlist_get_most_frequent_(const smartlist_t *sl,
+ int (*compare)(const void **a, const void **b),
+ int *count_out)
{
const void *most_frequent = NULL;
int most_frequent_count = 0;
@@ -530,8 +535,11 @@ smartlist_get_most_frequent(const smartlist_t *sl,
const void *cur = NULL;
int i, count=0;
- if (!sl->num_used)
+ if (!sl->num_used) {
+ if (count_out)
+ *count_out = 0;
return NULL;
+ }
for (i = 0; i < sl->num_used; ++i) {
const void *item = sl->list[i];
if (cur && 0 == compare(&cur, &item)) {
@@ -549,6 +557,8 @@ smartlist_get_most_frequent(const smartlist_t *sl,
most_frequent = cur;
most_frequent_count = count;
}
+ if (count_out)
+ *count_out = most_frequent_count;
return (void*)most_frequent;
}
@@ -728,6 +738,16 @@ smartlist_get_most_frequent_string(smartlist_t *sl)
return smartlist_get_most_frequent(sl, compare_string_ptrs_);
}
+/** Return the most frequent string in the sorted list <b>sl</b>.
+ * If <b>count_out</b> is provided, set <b>count_out</b> to the
+ * number of times that string appears.
+ */
+char *
+smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out)
+{
+ return smartlist_get_most_frequent_(sl, compare_string_ptrs_, count_out);
+}
+
/** Remove duplicate strings from a sorted list, and free them with tor_free().
*/
void
@@ -1021,6 +1041,7 @@ smartlist_uniq_digests256(smartlist_t *sl)
DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_);
DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_);
+DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_);
/** Helper: compare strmap_entry_t objects by key value. */
static INLINE int
@@ -1050,204 +1071,303 @@ digestmap_entry_hash(const digestmap_entry_t *a)
return (unsigned) siphash24g(a->key, DIGEST_LEN);
}
+/** Helper: compare digestmap_entry_t objects by key value. */
+static INLINE int
+digest256map_entries_eq(const digest256map_entry_t *a,
+ const digest256map_entry_t *b)
+{
+ return tor_memeq(a->key, b->key, DIGEST256_LEN);
+}
+
+/** Helper: return a hash value for a digest_map_t. */
+static INLINE unsigned int
+digest256map_entry_hash(const digest256map_entry_t *a)
+{
+ return (unsigned) siphash24g(a->key, DIGEST256_LEN);
+}
+
HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
strmap_entries_eq)
-HT_GENERATE(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
- strmap_entries_eq, 0.6, malloc, realloc, free)
+HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
+ strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
digestmap_entries_eq)
-HT_GENERATE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
- digestmap_entries_eq, 0.6, malloc, realloc, free)
+HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
+ digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
-/** Constructor to create a new empty map from strings to void*'s.
- */
-strmap_t *
-strmap_new(void)
+HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node,
+ digest256map_entry_hash,
+ digest256map_entries_eq)
+HT_GENERATE2(digest256map_impl, digest256map_entry_t, node,
+ digest256map_entry_hash,
+ digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+
+static INLINE void
+strmap_entry_free(strmap_entry_t *ent)
{
- strmap_t *result;
- result = tor_malloc(sizeof(strmap_t));
- HT_INIT(strmap_impl, &result->head);
- return result;
+ tor_free(ent->key);
+ tor_free(ent);
}
-
-/** Constructor to create a new empty map from digests to void*'s.
- */
-digestmap_t *
-digestmap_new(void)
+static INLINE void
+digestmap_entry_free(digestmap_entry_t *ent)
{
- digestmap_t *result;
- result = tor_malloc(sizeof(digestmap_t));
- HT_INIT(digestmap_impl, &result->head);
- return result;
+ tor_free(ent);
}
-
-/** Set the current value for <b>key</b> to <b>val</b>. Returns the previous
- * value for <b>key</b> if one was set, or NULL if one was not.
- *
- * This function makes a copy of <b>key</b> if necessary, but not of
- * <b>val</b>.
- */
-void *
-strmap_set(strmap_t *map, const char *key, void *val)
-{
- strmap_entry_t *resolve;
- strmap_entry_t search;
- void *oldval;
- tor_assert(map);
- tor_assert(key);
- tor_assert(val);
- search.key = (char*)key;
- resolve = HT_FIND(strmap_impl, &map->head, &search);
- if (resolve) {
- oldval = resolve->val;
- resolve->val = val;
- return oldval;
- } else {
- resolve = tor_malloc_zero(sizeof(strmap_entry_t));
- resolve->key = tor_strdup(key);
- resolve->val = val;
- tor_assert(!HT_FIND(strmap_impl, &map->head, resolve));
- HT_INSERT(strmap_impl, &map->head, resolve);
- return NULL;
- }
+static INLINE void
+digest256map_entry_free(digest256map_entry_t *ent)
+{
+ tor_free(ent);
}
-#define OPTIMIZED_DIGESTMAP_SET
-
-/** Like strmap_set() above but for digestmaps. */
-void *
-digestmap_set(digestmap_t *map, const char *key, void *val)
+static INLINE void
+strmap_assign_tmp_key(strmap_entry_t *ent, const char *key)
{
-#ifndef OPTIMIZED_DIGESTMAP_SET
- digestmap_entry_t *resolve;
-#endif
- digestmap_entry_t search;
- void *oldval;
- tor_assert(map);
- tor_assert(key);
- tor_assert(val);
- memcpy(&search.key, key, DIGEST_LEN);
-#ifndef OPTIMIZED_DIGESTMAP_SET
- resolve = HT_FIND(digestmap_impl, &map->head, &search);
- if (resolve) {
- oldval = resolve->val;
- resolve->val = val;
- return oldval;
- } else {
- resolve = tor_malloc_zero(sizeof(digestmap_entry_t));
- memcpy(resolve->key, key, DIGEST_LEN);
- resolve->val = val;
- HT_INSERT(digestmap_impl, &map->head, resolve);
- return NULL;
- }
-#else
- /* We spend up to 5% of our time in this function, so the code below is
- * meant to optimize the check/alloc/set cycle by avoiding the two trips to
- * the hash table that we do in the unoptimized code above. (Each of
- * HT_INSERT and HT_FIND calls HT_SET_HASH and HT_FIND_P.)
- */
- HT_FIND_OR_INSERT_(digestmap_impl, node, digestmap_entry_hash, &(map->head),
- digestmap_entry_t, &search, ptr,
- {
- /* we found an entry. */
- oldval = (*ptr)->val;
- (*ptr)->val = val;
- return oldval;
- },
- {
- /* We didn't find the entry. */
- digestmap_entry_t *newent =
- tor_malloc_zero(sizeof(digestmap_entry_t));
- memcpy(newent->key, key, DIGEST_LEN);
- newent->val = val;
- HT_FOI_INSERT_(node, &(map->head), &search, newent, ptr);
- return NULL;
- });
-#endif
+ ent->key = (char*)key;
}
-
-/** Return the current value associated with <b>key</b>, or NULL if no
- * value is set.
- */
-void *
-strmap_get(const strmap_t *map, const char *key)
-{
- strmap_entry_t *resolve;
- strmap_entry_t search;
- tor_assert(map);
- tor_assert(key);
- search.key = (char*)key;
- resolve = HT_FIND(strmap_impl, &map->head, &search);
- if (resolve) {
- return resolve->val;
- } else {
- return NULL;
- }
+static INLINE void
+digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key)
+{
+ memcpy(ent->key, key, DIGEST_LEN);
}
-
-/** Like strmap_get() above but for digestmaps. */
-void *
-digestmap_get(const digestmap_t *map, const char *key)
-{
- digestmap_entry_t *resolve;
- digestmap_entry_t search;
- tor_assert(map);
- tor_assert(key);
- memcpy(&search.key, key, DIGEST_LEN);
- resolve = HT_FIND(digestmap_impl, &map->head, &search);
- if (resolve) {
- return resolve->val;
- } else {
- return NULL;
- }
+static INLINE void
+digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key)
+{
+ memcpy(ent->key, key, DIGEST256_LEN);
+}
+static INLINE void
+strmap_assign_key(strmap_entry_t *ent, const char *key)
+{
+ ent->key = tor_strdup(key);
+}
+static INLINE void
+digestmap_assign_key(digestmap_entry_t *ent, const char *key)
+{
+ memcpy(ent->key, key, DIGEST_LEN);
+}
+static INLINE void
+digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key)
+{
+ memcpy(ent->key, key, DIGEST256_LEN);
}
-/** Remove the value currently associated with <b>key</b> from the map.
- * Return the value if one was set, or NULL if there was no entry for
- * <b>key</b>.
- *
- * Note: you must free any storage associated with the returned value.
+/**
+ * Macro: implement all the functions for a map that are declared in
+ * container.h by the DECLARE_MAP_FNS() macro. You must additionally define a
+ * prefix_entry_free_() function to free entries (and their keys), a
+ * prefix_assign_tmp_key() function to temporarily set a stack-allocated
+ * entry to hold a key, and a prefix_assign_key() function to set a
+ * heap-allocated entry to hold a key.
*/
-void *
-strmap_remove(strmap_t *map, const char *key)
-{
- strmap_entry_t *resolve;
- strmap_entry_t search;
- void *oldval;
- tor_assert(map);
- tor_assert(key);
- search.key = (char*)key;
- resolve = HT_REMOVE(strmap_impl, &map->head, &search);
- if (resolve) {
- oldval = resolve->val;
- tor_free(resolve->key);
- tor_free(resolve);
- return oldval;
- } else {
- return NULL;
+#define IMPLEMENT_MAP_FNS(maptype, keytype, prefix) \
+ /** Create and return a new empty map. */ \
+ MOCK_IMPL(maptype *, \
+ prefix##_new,(void)) \
+ { \
+ maptype *result; \
+ result = tor_malloc(sizeof(maptype)); \
+ HT_INIT(prefix##_impl, &result->head); \
+ return result; \
+ } \
+ \
+ /** Return the item from <b>map</b> whose key matches <b>key</b>, or \
+ * NULL if no such value exists. */ \
+ void * \
+ prefix##_get(const maptype *map, const keytype key) \
+ { \
+ prefix ##_entry_t *resolve; \
+ prefix ##_entry_t search; \
+ tor_assert(map); \
+ tor_assert(key); \
+ prefix ##_assign_tmp_key(&search, key); \
+ resolve = HT_FIND(prefix ##_impl, &map->head, &search); \
+ if (resolve) { \
+ return resolve->val; \
+ } else { \
+ return NULL; \
+ } \
+ } \
+ \
+ /** Add an entry to <b>map</b> mapping <b>key</b> to <b>val</b>; \
+ * return the previous value, or NULL if no such value existed. */ \
+ void * \
+ prefix##_set(maptype *map, const keytype key, void *val) \
+ { \
+ prefix##_entry_t search; \
+ void *oldval; \
+ tor_assert(map); \
+ tor_assert(key); \
+ tor_assert(val); \
+ prefix##_assign_tmp_key(&search, key); \
+ /* We a lot of our time in this function, so the code below is */ \
+ /* meant to optimize the check/alloc/set cycle by avoiding the two */\
+ /* trips to the hash table that we would do in the unoptimized */ \
+ /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \
+ /* HT_SET_HASH and HT_FIND_P.) */ \
+ HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \
+ &(map->head), \
+ prefix##_entry_t, &search, ptr, \
+ { \
+ /* we found an entry. */ \
+ oldval = (*ptr)->val; \
+ (*ptr)->val = val; \
+ return oldval; \
+ }, \
+ { \
+ /* We didn't find the entry. */ \
+ prefix##_entry_t *newent = \
+ tor_malloc_zero(sizeof(prefix##_entry_t)); \
+ prefix##_assign_key(newent, key); \
+ newent->val = val; \
+ HT_FOI_INSERT_(node, &(map->head), \
+ &search, newent, ptr); \
+ return NULL; \
+ }); \
+ } \
+ \
+ /** Remove the value currently associated with <b>key</b> from the map. \
+ * Return the value if one was set, or NULL if there was no entry for \
+ * <b>key</b>. \
+ * \
+ * Note: you must free any storage associated with the returned value. \
+ */ \
+ void * \
+ prefix##_remove(maptype *map, const keytype key) \
+ { \
+ prefix##_entry_t *resolve; \
+ prefix##_entry_t search; \
+ void *oldval; \
+ tor_assert(map); \
+ tor_assert(key); \
+ prefix##_assign_tmp_key(&search, key); \
+ resolve = HT_REMOVE(prefix##_impl, &map->head, &search); \
+ if (resolve) { \
+ oldval = resolve->val; \
+ prefix##_entry_free(resolve); \
+ return oldval; \
+ } else { \
+ return NULL; \
+ } \
+ } \
+ \
+ /** Return the number of elements in <b>map</b>. */ \
+ int \
+ prefix##_size(const maptype *map) \
+ { \
+ return HT_SIZE(&map->head); \
+ } \
+ \
+ /** Return true iff <b>map</b> has no entries. */ \
+ int \
+ prefix##_isempty(const maptype *map) \
+ { \
+ return HT_EMPTY(&map->head); \
+ } \
+ \
+ /** Assert that <b>map</b> is not corrupt. */ \
+ void \
+ prefix##_assert_ok(const maptype *map) \
+ { \
+ tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head)); \
+ } \
+ \
+ /** Remove all entries from <b>map</b>, and deallocate storage for \
+ * those entries. If free_val is provided, invoked it every value in \
+ * <b>map</b>. */ \
+ MOCK_IMPL(void, \
+ prefix##_free, (maptype *map, void (*free_val)(void*))) \
+ { \
+ prefix##_entry_t **ent, **next, *this; \
+ if (!map) \
+ return; \
+ for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \
+ ent = next) { \
+ this = *ent; \
+ next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \
+ if (free_val) \
+ free_val(this->val); \
+ prefix##_entry_free(this); \
+ } \
+ tor_assert(HT_EMPTY(&map->head)); \
+ HT_CLEAR(prefix##_impl, &map->head); \
+ tor_free(map); \
+ } \
+ \
+ /** return an <b>iterator</b> pointer to the front of a map. \
+ * \
+ * Iterator example: \
+ * \
+ * \code \
+ * // uppercase values in "map", removing empty values. \
+ * \
+ * strmap_iter_t *iter; \
+ * const char *key; \
+ * void *val; \
+ * char *cp; \
+ * \
+ * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) { \
+ * strmap_iter_get(iter, &key, &val); \
+ * cp = (char*)val; \
+ * if (!*cp) { \
+ * iter = strmap_iter_next_rmv(map,iter); \
+ * free(val); \
+ * } else { \
+ * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp); \
+ */ \
+ prefix##_iter_t * \
+ prefix##_iter_init(maptype *map) \
+ { \
+ tor_assert(map); \
+ return HT_START(prefix##_impl, &map->head); \
+ } \
+ \
+ /** Advance <b>iter</b> a single step to the next entry, and return \
+ * its new value. */ \
+ prefix##_iter_t * \
+ prefix##_iter_next(maptype *map, prefix##_iter_t *iter) \
+ { \
+ tor_assert(map); \
+ tor_assert(iter); \
+ return HT_NEXT(prefix##_impl, &map->head, iter); \
+ } \
+ /** Advance <b>iter</b> a single step to the next entry, removing the \
+ * current entry, and return its new value. */ \
+ prefix##_iter_t * \
+ prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter) \
+ { \
+ prefix##_entry_t *rmv; \
+ tor_assert(map); \
+ tor_assert(iter); \
+ tor_assert(*iter); \
+ rmv = *iter; \
+ iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter); \
+ prefix##_entry_free(rmv); \
+ return iter; \
+ } \
+ /** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed \
+ * to by iter. */ \
+ void \
+ prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp, \
+ void **valp) \
+ { \
+ tor_assert(iter); \
+ tor_assert(*iter); \
+ tor_assert(keyp); \
+ tor_assert(valp); \
+ *keyp = (*iter)->key; \
+ *valp = (*iter)->val; \
+ } \
+ /** Return true iff <b>iter</b> has advanced past the last entry of \
+ * <b>map</b>. */ \
+ int \
+ prefix##_iter_done(prefix##_iter_t *iter) \
+ { \
+ return iter == NULL; \
}
-}
-/** Like strmap_remove() above but for digestmaps. */
-void *
-digestmap_remove(digestmap_t *map, const char *key)
-{
- digestmap_entry_t *resolve;
- digestmap_entry_t search;
- void *oldval;
- tor_assert(map);
- tor_assert(key);
- memcpy(&search.key, key, DIGEST_LEN);
- resolve = HT_REMOVE(digestmap_impl, &map->head, &search);
- if (resolve) {
- oldval = resolve->val;
- tor_free(resolve);
- return oldval;
- } else {
- return NULL;
- }
-}
+IMPLEMENT_MAP_FNS(strmap_t, char *, strmap)
+IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap)
+IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map)
/** Same as strmap_set, but first converts <b>key</b> to lowercase. */
void *
@@ -1287,231 +1407,6 @@ strmap_remove_lc(strmap_t *map, const char *key)
return v;
}
-/** return an <b>iterator</b> pointer to the front of a map.
- *
- * Iterator example:
- *
- * \code
- * // uppercase values in "map", removing empty values.
- *
- * strmap_iter_t *iter;
- * const char *key;
- * void *val;
- * char *cp;
- *
- * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) {
- * strmap_iter_get(iter, &key, &val);
- * cp = (char*)val;
- * if (!*cp) {
- * iter = strmap_iter_next_rmv(map,iter);
- * free(val);
- * } else {
- * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp);
- * iter = strmap_iter_next(map,iter);
- * }
- * }
- * \endcode
- *
- */
-strmap_iter_t *
-strmap_iter_init(strmap_t *map)
-{
- tor_assert(map);
- return HT_START(strmap_impl, &map->head);
-}
-
-/** Start iterating through <b>map</b>. See strmap_iter_init() for example. */
-digestmap_iter_t *
-digestmap_iter_init(digestmap_t *map)
-{
- tor_assert(map);
- return HT_START(digestmap_impl, &map->head);
-}
-
-/** Advance the iterator <b>iter</b> for <b>map</b> a single step to the next
- * entry, and return its new value. */
-strmap_iter_t *
-strmap_iter_next(strmap_t *map, strmap_iter_t *iter)
-{
- tor_assert(map);
- tor_assert(iter);
- return HT_NEXT(strmap_impl, &map->head, iter);
-}
-
-/** Advance the iterator <b>iter</b> for map a single step to the next entry,
- * and return its new value. */
-digestmap_iter_t *
-digestmap_iter_next(digestmap_t *map, digestmap_iter_t *iter)
-{
- tor_assert(map);
- tor_assert(iter);
- return HT_NEXT(digestmap_impl, &map->head, iter);
-}
-
-/** Advance the iterator <b>iter</b> a single step to the next entry, removing
- * the current entry, and return its new value.
- */
-strmap_iter_t *
-strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter)
-{
- strmap_entry_t *rmv;
- tor_assert(map);
- tor_assert(iter);
- tor_assert(*iter);
- rmv = *iter;
- iter = HT_NEXT_RMV(strmap_impl, &map->head, iter);
- tor_free(rmv->key);
- tor_free(rmv);
- return iter;
-}
-
-/** Advance the iterator <b>iter</b> a single step to the next entry, removing
- * the current entry, and return its new value.
- */
-digestmap_iter_t *
-digestmap_iter_next_rmv(digestmap_t *map, digestmap_iter_t *iter)
-{
- digestmap_entry_t *rmv;
- tor_assert(map);
- tor_assert(iter);
- tor_assert(*iter);
- rmv = *iter;
- iter = HT_NEXT_RMV(digestmap_impl, &map->head, iter);
- tor_free(rmv);
- return iter;
-}
-
-/** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed to by
- * iter. */
-void
-strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp)
-{
- tor_assert(iter);
- tor_assert(*iter);
- tor_assert(keyp);
- tor_assert(valp);
- *keyp = (*iter)->key;
- *valp = (*iter)->val;
-}
-
-/** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed to by
- * iter. */
-void
-digestmap_iter_get(digestmap_iter_t *iter, const char **keyp, void **valp)
-{
- tor_assert(iter);
- tor_assert(*iter);
- tor_assert(keyp);
- tor_assert(valp);
- *keyp = (*iter)->key;
- *valp = (*iter)->val;
-}
-
-/** Return true iff <b>iter</b> has advanced past the last entry of
- * <b>map</b>. */
-int
-strmap_iter_done(strmap_iter_t *iter)
-{
- return iter == NULL;
-}
-
-/** Return true iff <b>iter</b> has advanced past the last entry of
- * <b>map</b>. */
-int
-digestmap_iter_done(digestmap_iter_t *iter)
-{
- return iter == NULL;
-}
-
-/** Remove all entries from <b>map</b>, and deallocate storage for those
- * entries. If free_val is provided, it is invoked on every value in
- * <b>map</b>.
- */
-void
-strmap_free(strmap_t *map, void (*free_val)(void*))
-{
- strmap_entry_t **ent, **next, *this;
- if (!map)
- return;
-
- for (ent = HT_START(strmap_impl, &map->head); ent != NULL; ent = next) {
- this = *ent;
- next = HT_NEXT_RMV(strmap_impl, &map->head, ent);
- tor_free(this->key);
- if (free_val)
- free_val(this->val);
- tor_free(this);
- }
- tor_assert(HT_EMPTY(&map->head));
- HT_CLEAR(strmap_impl, &map->head);
- tor_free(map);
-}
-
-/** Remove all entries from <b>map</b>, and deallocate storage for those
- * entries. If free_val is provided, it is invoked on every value in
- * <b>map</b>.
- */
-void
-digestmap_free(digestmap_t *map, void (*free_val)(void*))
-{
- digestmap_entry_t **ent, **next, *this;
- if (!map)
- return;
- for (ent = HT_START(digestmap_impl, &map->head); ent != NULL; ent = next) {
- this = *ent;
- next = HT_NEXT_RMV(digestmap_impl, &map->head, ent);
- if (free_val)
- free_val(this->val);
- tor_free(this);
- }
- tor_assert(HT_EMPTY(&map->head));
- HT_CLEAR(digestmap_impl, &map->head);
- tor_free(map);
-}
-
-/** Fail with an assertion error if anything has gone wrong with the internal
- * representation of <b>map</b>. */
-void
-strmap_assert_ok(const strmap_t *map)
-{
- tor_assert(!strmap_impl_HT_REP_IS_BAD_(&map->head));
-}
-/** Fail with an assertion error if anything has gone wrong with the internal
- * representation of <b>map</b>. */
-void
-digestmap_assert_ok(const digestmap_t *map)
-{
- tor_assert(!digestmap_impl_HT_REP_IS_BAD_(&map->head));
-}
-
-/** Return true iff <b>map</b> has no entries. */
-int
-strmap_isempty(const strmap_t *map)
-{
- return HT_EMPTY(&map->head);
-}
-
-/** Return true iff <b>map</b> has no entries. */
-int
-digestmap_isempty(const digestmap_t *map)
-{
- return HT_EMPTY(&map->head);
-}
-
-/** Return the number of items in <b>map</b>. */
-int
-strmap_size(const strmap_t *map)
-{
- return HT_SIZE(&map->head);
-}
-
-/** Return the number of items in <b>map</b>. */
-int
-digestmap_size(const digestmap_t *map)
-{
- return HT_SIZE(&map->head);
-}
-
/** Declare a function called <b>funcname</b> that acts as a find_nth_FOO
* function for an array of type <b>elt_t</b>*.
*
diff --git a/src/common/container.h b/src/common/container.h
index 0d31f2093b..457b5e4ea0 100644
--- a/src/common/container.h
+++ b/src/common/container.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_CONTAINER_H
@@ -27,8 +27,8 @@ typedef struct smartlist_t {
/** @} */
} smartlist_t;
-smartlist_t *smartlist_new(void);
-void smartlist_free(smartlist_t *sl);
+MOCK_DECL(smartlist_t *, smartlist_new, (void));
+MOCK_DECL(void, smartlist_free, (smartlist_t *sl));
void smartlist_clear(smartlist_t *sl);
void smartlist_add(smartlist_t *sl, void *element);
void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
@@ -94,8 +94,11 @@ void smartlist_del_keeporder(smartlist_t *sl, int idx);
void smartlist_insert(smartlist_t *sl, int idx, void *val);
void smartlist_sort(smartlist_t *sl,
int (*compare)(const void **a, const void **b));
-void *smartlist_get_most_frequent(const smartlist_t *sl,
- int (*compare)(const void **a, const void **b));
+void *smartlist_get_most_frequent_(const smartlist_t *sl,
+ int (*compare)(const void **a, const void **b),
+ int *count_out);
+#define smartlist_get_most_frequent(sl, compare) \
+ smartlist_get_most_frequent_((sl), (compare), NULL)
void smartlist_uniq(smartlist_t *sl,
int (*compare)(const void **a, const void **b),
void (*free_fn)(void *elt));
@@ -106,6 +109,7 @@ void smartlist_sort_digests256(smartlist_t *sl);
void smartlist_sort_pointers(smartlist_t *sl);
char *smartlist_get_most_frequent_string(smartlist_t *sl);
+char *smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out);
char *smartlist_get_most_frequent_digest256(smartlist_t *sl);
void smartlist_uniq_strings(smartlist_t *sl);
@@ -243,6 +247,16 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
STMT_END
/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed
+ * with the variable <b>var</b>, remove the current element in a way that
+ * won't confuse the loop. */
+#define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \
+ STMT_BEGIN \
+ smartlist_del_keeporder(sl, var ## _sl_idx); \
+ --var ## _sl_idx; \
+ --var ## _sl_len; \
+ STMT_END
+
+/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed
* with the variable <b>var</b>, replace the current element with <b>val</b>.
* Does not deallocate the current value of <b>var</b>.
*/
@@ -328,11 +342,11 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
#define DECLARE_MAP_FNS(maptype, keytype, prefix) \
typedef struct maptype maptype; \
typedef struct prefix##entry_t *prefix##iter_t; \
- maptype* prefix##new(void); \
+ MOCK_DECL(maptype*, prefix##new, (void)); \
void* prefix##set(maptype *map, keytype key, void *val); \
void* prefix##get(const maptype *map, keytype key); \
void* prefix##remove(maptype *map, keytype key); \
- void prefix##free(maptype *map, void (*free_val)(void*)); \
+ MOCK_DECL(void, prefix##free, (maptype *map, void (*free_val)(void*))); \
int prefix##isempty(const maptype *map); \
int prefix##size(const maptype *map); \
prefix##iter_t *prefix##iter_init(maptype *map); \
@@ -346,6 +360,9 @@ char *smartlist_join_strings2(smartlist_t *sl, const char *join,
DECLARE_MAP_FNS(strmap_t, const char *, strmap_);
/* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */
DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_);
+/* Map from const uint8_t[DIGEST_LEN] to void *. Implemented with a hash
+ * table. */
+DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_);
#undef DECLARE_MAP_FNS
@@ -461,6 +478,13 @@ DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_);
/** Used to end a DIGESTMAP_FOREACH() block. */
#define DIGESTMAP_FOREACH_END MAP_FOREACH_END
+#define DIGEST256MAP_FOREACH(map, keyvar, valtype, valvar) \
+ MAP_FOREACH(digest256map_, map, const uint8_t *, keyvar, valtype, valvar)
+#define DIGEST256MAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \
+ MAP_FOREACH_MODIFY(digest256map_, map, const uint8_t *, \
+ keyvar, valtype, valvar)
+#define DIGEST256MAP_FOREACH_END MAP_FOREACH_END
+
#define STRMAP_FOREACH(map, keyvar, valtype, valvar) \
MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar)
#define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \
@@ -473,7 +497,7 @@ void* strmap_remove_lc(strmap_t *map, const char *key);
#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \
typedef struct maptype maptype; \
- typedef struct prefix##iter_t prefix##iter_t; \
+ typedef struct prefix##iter_t *prefix##iter_t; \
ATTR_UNUSED static INLINE maptype* \
prefix##new(void) \
{ \
@@ -563,7 +587,7 @@ bitarray_init_zero(unsigned int n_bits)
{
/* round up to the next int. */
size_t sz = (n_bits+BITARRAY_MASK) >> BITARRAY_SHIFT;
- return tor_malloc_zero(sz*sizeof(unsigned int));
+ return tor_calloc(sz, sizeof(unsigned int));
}
/** Expand <b>ba</b> from holding <b>n_bits_old</b> to <b>n_bits_new</b>,
* clearing all new bits. Returns a possibly changed pointer to the
@@ -577,7 +601,7 @@ bitarray_expand(bitarray_t *ba,
char *ptr;
if (sz_new <= sz_old)
return ba;
- ptr = tor_realloc(ba, sz_new*sizeof(unsigned int));
+ ptr = tor_reallocarray(ba, sz_new, sizeof(unsigned int));
/* This memset does nothing to the older excess bytes. But they were
* already set to 0 by bitarry_init_zero. */
memset(ptr+sz_old*sizeof(unsigned int), 0,
@@ -689,5 +713,11 @@ median_int32(int32_t *array, int n_elements)
return find_nth_int32(array, n_elements, (n_elements-1)/2);
}
+static INLINE uint32_t
+third_quartile_uint32(uint32_t *array, int n_elements)
+{
+ return find_nth_uint32(array, n_elements, (n_elements*3)/4);
+}
+
#endif
diff --git a/src/common/crypto.c b/src/common/crypto.c
index f7362765d2..8db9681539 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -75,12 +75,10 @@
/** Macro: is k a valid RSA private key? */
#define PRIVATE_KEY_OK(k) ((k) && (k)->key && (k)->key->p)
-#ifdef TOR_IS_MULTITHREADED
/** A number of preallocated mutexes for use by OpenSSL. */
static tor_mutex_t **openssl_mutexes_ = NULL;
/** How many mutexes have we allocated for use by OpenSSL? */
static int n_openssl_mutexes_ = 0;
-#endif
/** A public key, or a public/private key-pair. */
struct crypto_pk_t
@@ -1016,7 +1014,7 @@ crypto_pk_public_checksig(crypto_pk_t *env, char *to,
env->key, RSA_PKCS1_PADDING);
if (r<0) {
- crypto_log_errors(LOG_WARN, "checking RSA signature");
+ crypto_log_errors(LOG_INFO, "checking RSA signature");
return -1;
}
return r;
@@ -1297,7 +1295,7 @@ crypto_pk_asn1_decode(const char *str, size_t len)
* Return 0 on success, -1 on failure.
*/
int
-crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out)
+crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
{
unsigned char *buf = NULL;
int len;
@@ -1688,7 +1686,7 @@ crypto_digest_get_digest(crypto_digest_t *digest,
log_warn(LD_BUG, "Called with unknown algorithm %d", digest->algorithm);
/* If fragile_assert is not enabled, then we should at least not
* leak anything. */
- memset(r, 0xff, sizeof(r));
+ memwipe(r, 0xff, sizeof(r));
tor_fragile_assert();
break;
}
@@ -1784,9 +1782,13 @@ crypto_generate_dynamic_dh_modulus(void)
dynamic_dh_modulus = BN_new();
tor_assert(dynamic_dh_modulus);
- dh_parameters = DH_generate_parameters(DH_BYTES*8, DH_GENERATOR, NULL, NULL);
+ dh_parameters = DH_new();
tor_assert(dh_parameters);
+ r = DH_generate_parameters_ex(dh_parameters,
+ DH_BYTES*8, DH_GENERATOR, NULL);
+ tor_assert(r == 0);
+
r = DH_check(dh_parameters, &dh_codes);
tor_assert(r && !dh_codes);
@@ -1842,7 +1844,7 @@ crypto_store_dynamic_dh_modulus(const char *fname)
goto done;
}
- base64_encoded_dh = tor_malloc_zero(len * 2); /* should be enough */
+ base64_encoded_dh = tor_calloc(len, 2); /* should be enough */
new_len = base64_encode(base64_encoded_dh, len * 2,
(char *)dh_string_repr, len);
if (new_len < 0) {
@@ -2458,10 +2460,8 @@ crypto_strongest_rand(uint8_t *out, size_t out_len)
if (!provider_set) {
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
- if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) {
- log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]");
- return -1;
- }
+ log_warn(LD_CRYPTO, "Can't get CryptoAPI provider [1]");
+ return -1;
}
provider_set = 1;
}
@@ -3011,50 +3011,6 @@ base32_decode(char *dest, size_t destlen, const char *src, size_t srclen)
return 0;
}
-/** Implement RFC2440-style iterated-salted S2K conversion: convert the
- * <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte
- * <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier
- * are a salt; the 9th byte describes how much iteration to do.
- * Does not support <b>key_out_len</b> &gt; DIGEST_LEN.
- */
-void
-secret_to_key(char *key_out, size_t key_out_len, const char *secret,
- size_t secret_len, const char *s2k_specifier)
-{
- crypto_digest_t *d;
- uint8_t c;
- size_t count, tmplen;
- char *tmp;
- tor_assert(key_out_len < SIZE_T_CEILING);
-
-#define EXPBIAS 6
- c = s2k_specifier[8];
- count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
-#undef EXPBIAS
-
- tor_assert(key_out_len <= DIGEST_LEN);
-
- d = crypto_digest_new();
- tmplen = 8+secret_len;
- tmp = tor_malloc(tmplen);
- memcpy(tmp,s2k_specifier,8);
- memcpy(tmp+8,secret,secret_len);
- secret_len += 8;
- while (count) {
- if (count >= secret_len) {
- crypto_digest_add_bytes(d, tmp, secret_len);
- count -= secret_len;
- } else {
- crypto_digest_add_bytes(d, tmp, count);
- count = 0;
- }
- }
- crypto_digest_get_digest(d, key_out, key_out_len);
- memwipe(tmp, 0, tmplen);
- tor_free(tmp);
- crypto_digest_free(d);
-}
-
/**
* Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to
* the value <b>byte</b>.
@@ -3108,8 +3064,6 @@ memwipe(void *mem, uint8_t byte, size_t sz)
memset(mem, byte, sz);
}
-#ifdef TOR_IS_MULTITHREADED
-
#ifndef OPENSSL_THREADS
#error OpenSSL has been built without thread support. Tor requires an \
OpenSSL library with thread support enabled.
@@ -3177,6 +3131,14 @@ openssl_dynlock_destroy_cb_(struct CRYPTO_dynlock_value *v,
tor_free(v);
}
+#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
+static void
+tor_set_openssl_thread_id(CRYPTO_THREADID *threadid)
+{
+ CRYPTO_THREADID_set_numeric(threadid, tor_get_thread_id());
+}
+#endif
+
/** @{ */
/** Helper: Construct mutexes, and set callbacks to help OpenSSL handle being
* multithreaded. */
@@ -3186,23 +3148,20 @@ setup_openssl_threading(void)
int i;
int n = CRYPTO_num_locks();
n_openssl_mutexes_ = n;
- openssl_mutexes_ = tor_malloc(n*sizeof(tor_mutex_t *));
+ openssl_mutexes_ = tor_calloc(n, sizeof(tor_mutex_t *));
for (i=0; i < n; ++i)
openssl_mutexes_[i] = tor_mutex_new();
CRYPTO_set_locking_callback(openssl_locking_cb_);
+#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0)
CRYPTO_set_id_callback(tor_get_thread_id);
+#else
+ CRYPTO_THREADID_set_callback(tor_set_openssl_thread_id);
+#endif
CRYPTO_set_dynlock_create_callback(openssl_dynlock_create_cb_);
CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock_cb_);
CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy_cb_);
return 0;
}
-#else
-static int
-setup_openssl_threading(void)
-{
- return 0;
-}
-#endif
/** Uninitialize the crypto library. Return 0 on success, -1 on failure.
*/
@@ -3226,7 +3185,7 @@ crypto_global_cleanup(void)
CONF_modules_unload(1);
CRYPTO_cleanup_all_ex_data();
-#ifdef TOR_IS_MULTITHREADED
+
if (n_openssl_mutexes_) {
int n = n_openssl_mutexes_;
tor_mutex_t **ms = openssl_mutexes_;
@@ -3238,7 +3197,7 @@ crypto_global_cleanup(void)
}
tor_free(ms);
}
-#endif
+
tor_free(crypto_openssl_version_str);
tor_free(crypto_openssl_header_version_str);
return 0;
diff --git a/src/common/crypto.h b/src/common/crypto.h
index aa4271aa33..d305bc17a0 100644
--- a/src/common/crypto.h
+++ b/src/common/crypto.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -180,7 +180,7 @@ int crypto_pk_private_hybrid_decrypt(crypto_pk_t *env, char *to,
int crypto_pk_asn1_encode(crypto_pk_t *pk, char *dest, size_t dest_len);
crypto_pk_t *crypto_pk_asn1_decode(const char *str, size_t len);
-int crypto_pk_get_digest(crypto_pk_t *pk, char *digest_out);
+int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out);
int crypto_pk_get_all_digests(crypto_pk_t *pk, digests_t *digests_out);
int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out,int add_space);
int crypto_pk_get_hashed_fingerprint(crypto_pk_t *pk, char *fp_out);
@@ -280,12 +280,6 @@ int digest_from_base64(char *digest, const char *d64);
int digest256_to_base64(char *d64, const char *digest);
int digest256_from_base64(char *digest, const char *d64);
-/** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the
- * 9th describes how much iteration to do. */
-#define S2K_SPECIFIER_LEN 9
-void secret_to_key(char *key_out, size_t key_out_len, const char *secret,
- size_t secret_len, const char *s2k_specifier);
-
/** OpenSSL-based utility functions. */
void memwipe(void *mem, uint8_t byte, size_t sz);
diff --git a/src/common/crypto_curve25519.c b/src/common/crypto_curve25519.c
index 9e83440e16..5bb14b0d95 100644
--- a/src/common/crypto_curve25519.c
+++ b/src/common/crypto_curve25519.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Wrapper code for a curve25519 implementation. */
@@ -8,6 +8,7 @@
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
+#include "container.h"
#include "crypto.h"
#include "crypto_curve25519.h"
#include "util.h"
@@ -63,26 +64,44 @@ curve25519_public_key_is_ok(const curve25519_public_key_t *key)
return !safe_mem_is_zero(key->public_key, CURVE25519_PUBKEY_LEN);
}
-/** Generate a new keypair and return the secret key. If <b>extra_strong</b>
- * is true, this key is possibly going to get used more than once, so
- * use a better-than-usual RNG. Return 0 on success, -1 on failure. */
+/**
+ * Generate CURVE25519_SECKEY_LEN random bytes in <b>out</b>. If
+ * <b>extra_strong</b> is true, this key is possibly going to get used more
+ * than once, so use a better-than-usual RNG. Return 0 on success, -1 on
+ * failure.
+ *
+ * This function does not adjust the output of the RNG at all; the will caller
+ * will need to clear or set the appropriate bits to make curve25519 work.
+ */
int
-curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
- int extra_strong)
+curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong)
{
uint8_t k_tmp[CURVE25519_SECKEY_LEN];
- if (crypto_rand((char*)key_out->secret_key, CURVE25519_SECKEY_LEN) < 0)
+ if (crypto_rand((char*)out, CURVE25519_SECKEY_LEN) < 0)
return -1;
if (extra_strong && !crypto_strongest_rand(k_tmp, CURVE25519_SECKEY_LEN)) {
/* If they asked for extra-strong entropy and we have some, use it as an
* HMAC key to improve not-so-good entropy rather than using it directly,
* just in case the extra-strong entropy is less amazing than we hoped. */
- crypto_hmac_sha256((char *)key_out->secret_key,
- (const char *)k_tmp, sizeof(k_tmp),
- (const char *)key_out->secret_key, CURVE25519_SECKEY_LEN);
+ crypto_hmac_sha256((char*) out,
+ (const char *)k_tmp, sizeof(k_tmp),
+ (const char *)out, CURVE25519_SECKEY_LEN);
}
memwipe(k_tmp, 0, sizeof(k_tmp));
+ return 0;
+}
+
+/** Generate a new keypair and return the secret key. If <b>extra_strong</b>
+ * is true, this key is possibly going to get used more than once, so
+ * use a better-than-usual RNG. Return 0 on success, -1 on failure. */
+int
+curve25519_secret_key_generate(curve25519_secret_key_t *key_out,
+ int extra_strong)
+{
+ if (curve25519_rand_seckey_bytes(key_out->secret_key, extra_strong) < 0)
+ return -1;
+
key_out->secret_key[0] &= 248;
key_out->secret_key[31] &= 127;
key_out->secret_key[31] |= 64;
@@ -109,69 +128,144 @@ curve25519_keypair_generate(curve25519_keypair_t *keypair_out,
return 0;
}
+/** Write the <b>datalen</b> bytes from <b>data</b> to the file named
+ * <b>fname</b> in the tagged-data format. This format contains a
+ * 32-byte header, followed by the data itself. The header is the
+ * NUL-padded string "== <b>typestring</b>: <b>tag</b> ==". The length
+ * of <b>typestring</b> and <b>tag</b> must therefore be no more than
+ * 24.
+ **/
int
-curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
- const char *fname,
- const char *tag)
+crypto_write_tagged_contents_to_file(const char *fname,
+ const char *typestring,
+ const char *tag,
+ const uint8_t *data,
+ size_t datalen)
{
- char contents[32 + CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN];
- int r;
+ char header[32];
+ smartlist_t *chunks = smartlist_new();
+ sized_chunk_t ch0, ch1;
+ int r = -1;
- memset(contents, 0, sizeof(contents));
- tor_snprintf(contents, sizeof(contents), "== c25519v1: %s ==", tag);
- tor_assert(strlen(contents) <= 32);
- memcpy(contents+32, keypair->seckey.secret_key, CURVE25519_SECKEY_LEN);
- memcpy(contents+32+CURVE25519_SECKEY_LEN,
- keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+ memset(header, 0, sizeof(header));
+ if (tor_snprintf(header, sizeof(header),
+ "== %s: %s ==", typestring, tag) < 0)
+ goto end;
+ ch0.bytes = header;
+ ch0.len = 32;
+ ch1.bytes = (const char*) data;
+ ch1.len = datalen;
+ smartlist_add(chunks, &ch0);
+ smartlist_add(chunks, &ch1);
- r = write_bytes_to_file(fname, contents, sizeof(contents), 1);
+ r = write_chunks_to_file(fname, chunks, 1, 0);
- memwipe(contents, 0, sizeof(contents));
+ end:
+ smartlist_free(chunks);
return r;
}
-int
-curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
- char **tag_out,
- const char *fname)
+/** Read a tagged-data file from <b>fname</b> into the
+ * <b>data_out_len</b>-byte buffer in <b>data_out</b>. Check that the
+ * typestring matches <b>typestring</b>; store the tag into a newly allocated
+ * string in <b>tag_out</b>. Return -1 on failure, and the number of bytes of
+ * data on success. */
+ssize_t
+crypto_read_tagged_contents_from_file(const char *fname,
+ const char *typestring,
+ char **tag_out,
+ uint8_t *data_out,
+ ssize_t data_out_len)
{
char prefix[33];
- char *content;
+ char *content = NULL;
struct stat st;
- int r = -1;
+ ssize_t r = -1;
+ size_t st_size = 0;
*tag_out = NULL;
-
st.st_size = 0;
content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
if (! content)
goto end;
- if (st.st_size != 32 + CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN)
+ if (st.st_size < 32 || st.st_size > 32 + data_out_len)
goto end;
+ st_size = (size_t)st.st_size;
memcpy(prefix, content, 32);
- prefix[32] = '\0';
- if (strcmpstart(prefix, "== c25519v1: ") ||
- strcmpend(prefix, " =="))
+ prefix[32] = 0;
+ /* Check type, extract tag. */
+ if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") ||
+ ! tor_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix)))
+ goto end;
+
+ if (strcmpstart(prefix+3, typestring) ||
+ 3+strlen(typestring) >= 32 ||
+ strcmpstart(prefix+3+strlen(typestring), ": "))
goto end;
- *tag_out = tor_strndup(prefix+strlen("== c25519v1: "),
- strlen(prefix) - strlen("== c25519v1: =="));
+ *tag_out = tor_strndup(prefix+5+strlen(typestring),
+ strlen(prefix)-8-strlen(typestring));
+
+ memcpy(data_out, content+32, st_size-32);
+ r = st_size - 32;
+
+ end:
+ if (content)
+ memwipe(content, 0, st_size);
+ tor_free(content);
+ return r;
+}
+
+/** DOCDOC */
+int
+curve25519_keypair_write_to_file(const curve25519_keypair_t *keypair,
+ const char *fname,
+ const char *tag)
+{
+ uint8_t contents[CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN];
+ int r;
+
+ memcpy(contents, keypair->seckey.secret_key, CURVE25519_SECKEY_LEN);
+ memcpy(contents+CURVE25519_SECKEY_LEN,
+ keypair->pubkey.public_key, CURVE25519_PUBKEY_LEN);
+
+ r = crypto_write_tagged_contents_to_file(fname,
+ "c25519v1",
+ tag,
+ contents,
+ sizeof(contents));
+
+ memwipe(contents, 0, sizeof(contents));
+ return r;
+}
+
+/** DOCDOC */
+int
+curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
+ char **tag_out,
+ const char *fname)
+{
+ uint8_t content[CURVE25519_SECKEY_LEN + CURVE25519_PUBKEY_LEN];
+ ssize_t len;
+ int r = -1;
+
+ len = crypto_read_tagged_contents_from_file(fname, "c25519v1", tag_out,
+ content, sizeof(content));
+ if (len != sizeof(content))
+ goto end;
- memcpy(keypair_out->seckey.secret_key, content+32, CURVE25519_SECKEY_LEN);
+ memcpy(keypair_out->seckey.secret_key, content, CURVE25519_SECKEY_LEN);
curve25519_public_key_generate(&keypair_out->pubkey, &keypair_out->seckey);
if (tor_memneq(keypair_out->pubkey.public_key,
- content + 32 + CURVE25519_SECKEY_LEN,
+ content + CURVE25519_SECKEY_LEN,
CURVE25519_PUBKEY_LEN))
goto end;
r = 0;
end:
- if (content) {
- memwipe(content, 0, (size_t) st.st_size);
- tor_free(content);
- }
+ memwipe(content, 0, sizeof(content));
if (r != 0) {
memset(keypair_out, 0, sizeof(*keypair_out));
tor_free(*tag_out);
diff --git a/src/common/crypto_curve25519.h b/src/common/crypto_curve25519.h
index 57018ac2f5..48e8a6d962 100644
--- a/src/common/crypto_curve25519.h
+++ b/src/common/crypto_curve25519.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_CRYPTO_CURVE25519_H
@@ -30,7 +30,6 @@ typedef struct curve25519_keypair_t {
curve25519_secret_key_t seckey;
} curve25519_keypair_t;
-#ifdef CURVE25519_ENABLED
/* These functions require that we actually know how to use curve25519 keys.
* The other data structures and functions in this header let us parse them,
* store them, and move them around.
@@ -57,11 +56,12 @@ int curve25519_keypair_read_from_file(curve25519_keypair_t *keypair_out,
char **tag_out,
const char *fname);
+int curve25519_rand_seckey_bytes(uint8_t *out, int extra_strong);
+
#ifdef CRYPTO_CURVE25519_PRIVATE
STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret,
const uint8_t *basepoint);
#endif
-#endif
#define CURVE25519_BASE64_PADDED_LEN 44
@@ -70,5 +70,17 @@ int curve25519_public_from_base64(curve25519_public_key_t *pkey,
int curve25519_public_to_base64(char *output,
const curve25519_public_key_t *pkey);
+int crypto_write_tagged_contents_to_file(const char *fname,
+ const char *typestring,
+ const char *tag,
+ const uint8_t *data,
+ size_t datalen);
+
+ssize_t crypto_read_tagged_contents_from_file(const char *fname,
+ const char *typestring,
+ char **tag_out,
+ uint8_t *data_out,
+ ssize_t data_out_len);
+
#endif
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c
new file mode 100644
index 0000000000..f2e6945ac8
--- /dev/null
+++ b/src/common/crypto_ed25519.c
@@ -0,0 +1,353 @@
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Wrapper code for an ed25519 implementation. */
+
+#include "orconfig.h"
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include "crypto.h"
+
+#include "crypto_curve25519.h"
+#include "crypto_ed25519.h"
+#include "torlog.h"
+#include "util.h"
+
+#include "ed25519/ref10/ed25519_ref10.h"
+
+#include <openssl/sha.h>
+
+/**
+ * Initialize a new ed25519 secret key in <b>seckey_out</b>. If
+ * <b>extra_strong</b>, take the RNG inputs directly from the operating
+ * system. Return 0 on success, -1 on failure.
+ */
+int
+ed25519_secret_key_generate(ed25519_secret_key_t *seckey_out,
+ int extra_strong)
+{
+ int r;
+ uint8_t seed[32];
+ if (! extra_strong || crypto_strongest_rand(seed, sizeof(seed)) < 0)
+ crypto_rand((char*)seed, sizeof(seed));
+
+ r = ed25519_ref10_seckey_expand(seckey_out->seckey, seed);
+ memwipe(seed, 0, sizeof(seed));
+
+ return r < 0 ? -1 : 0;
+}
+
+/**
+ * Given a 32-byte random seed in <b>seed</b>, expand it into an ed25519
+ * secret key in <b>seckey_out</b>. Return 0 on success, -1 on failure.
+ */
+int
+ed25519_secret_key_from_seed(ed25519_secret_key_t *seckey_out,
+ const uint8_t *seed)
+{
+ if (ed25519_ref10_seckey_expand(seckey_out->seckey, seed) < 0)
+ return -1;
+ return 0;
+}
+
+/**
+ * Given a secret key in <b>seckey</b>, expand it into an
+ * ed25519 public key. Return 0 on success, -1 on failure.
+ */
+int
+ed25519_public_key_generate(ed25519_public_key_t *pubkey_out,
+ const ed25519_secret_key_t *seckey)
+{
+ if (ed25519_ref10_pubkey(pubkey_out->pubkey, seckey->seckey) < 0)
+ return -1;
+ return 0;
+}
+
+/** Generate a new ed25519 keypair in <b>keypair_out</b>. If
+ * <b>extra_strong</b> is set, try to mix some system entropy into the key
+ * generation process. Return 0 on success, -1 on failure. */
+int
+ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong)
+{
+ if (ed25519_secret_key_generate(&keypair_out->seckey, extra_strong) < 0)
+ return -1;
+ if (ed25519_public_key_generate(&keypair_out->pubkey,
+ &keypair_out->seckey)<0)
+ return -1;
+ return 0;
+}
+
+/**
+ * Set <b>signature_out</b> to a signature of the <b>len</b>-byte message
+ * <b>msg</b>, using the secret and public key in <b>keypair</b>.
+ */
+int
+ed25519_sign(ed25519_signature_t *signature_out,
+ const uint8_t *msg, size_t len,
+ const ed25519_keypair_t *keypair)
+{
+
+ if (ed25519_ref10_sign(signature_out->sig, msg, len,
+ keypair->seckey.seckey,
+ keypair->pubkey.pubkey) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Check whether if <b>signature</b> is a valid signature for the
+ * <b>len</b>-byte message in <b>msg</b> made with the key <b>pubkey</b>.
+ *
+ * Return 0 if the signature is valid; -1 if it isn't.
+ */
+int
+ed25519_checksig(const ed25519_signature_t *signature,
+ const uint8_t *msg, size_t len,
+ const ed25519_public_key_t *pubkey)
+{
+ return
+ ed25519_ref10_open(signature->sig, msg, len, pubkey->pubkey) < 0 ? -1 : 0;
+}
+
+/** Validate every signature among those in <b>checkable</b>, which contains
+ * exactly <b>n_checkable</b> elements. If <b>okay_out</b> is non-NULL, set
+ * the i'th element of <b>okay_out</b> to 1 if the i'th element of
+ * <b>checkable</b> is valid, and to 0 otherwise. Return 0 if every signature
+ * was valid. Otherwise return -N, where N is the number of invalid
+ * signatures.
+ */
+int
+ed25519_checksig_batch(int *okay_out,
+ const ed25519_checkable_t *checkable,
+ int n_checkable)
+{
+ int res, i;
+
+ res = 0;
+ for (i = 0; i < n_checkable; ++i) {
+ const ed25519_checkable_t *ch = &checkable[i];
+ int r = ed25519_checksig(&ch->signature, ch->msg, ch->len, ch->pubkey);
+ if (r < 0)
+ --res;
+ if (okay_out)
+ okay_out[i] = (r == 0);
+ }
+
+#if 0
+ /* This is how we'd do it if we were using ed25519_donna. I'll keep this
+ * code around here in case we ever do that. */
+ const uint8_t **ms;
+ size_t *lens;
+ const uint8_t **pks;
+ const uint8_t **sigs;
+ int *oks;
+
+ ms = tor_malloc(sizeof(uint8_t*)*n_checkable);
+ lens = tor_malloc(sizeof(size_t)*n_checkable);
+ pks = tor_malloc(sizeof(uint8_t*)*n_checkable);
+ sigs = tor_malloc(sizeof(uint8_t*)*n_checkable);
+ oks = okay_out ? okay_out : tor_malloc(sizeof(int)*n_checkable);
+
+ for (i = 0; i < n_checkable; ++i) {
+ ms[i] = checkable[i].msg;
+ lens[i] = checkable[i].len;
+ pks[i] = checkable[i].pubkey->pubkey;
+ sigs[i] = checkable[i].signature.sig;
+ oks[i] = 0;
+ }
+
+ ed25519_sign_open_batch_donna_fb(ms, lens, pks, sigs, n_checkable, oks);
+
+ res = 0;
+ for (i = 0; i < n_checkable; ++i) {
+ if (!oks[i])
+ --res;
+ }
+
+ tor_free(ms);
+ tor_free(lens);
+ tor_free(pks);
+ if (! okay_out)
+ tor_free(oks);
+#endif
+
+ return res;
+}
+
+/**
+ * Given a curve25519 keypair in <b>inp</b>, generate a corresponding
+ * ed25519 keypair in <b>out</b>, and set <b>signbit_out</b> to the
+ * sign bit of the X coordinate of the ed25519 key.
+ *
+ * NOTE THAT IT IS PROBABLY NOT SAFE TO USE THE GENERATED KEY FOR ANYTHING
+ * OUTSIDE OF WHAT'S PRESENTED IN PROPOSAL 228. In particular, it's probably
+ * not a great idea to use it to sign attacker-supplied anything.
+ */
+int
+ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out,
+ int *signbit_out,
+ const curve25519_keypair_t *inp)
+{
+ const char string[] = "Derive high part of ed25519 key from curve25519 key";
+ ed25519_public_key_t pubkey_check;
+ SHA512_CTX ctx;
+ uint8_t sha512_output[64];
+
+ memcpy(out->seckey.seckey, inp->seckey.secret_key, 32);
+ SHA512_Init(&ctx);
+ SHA512_Update(&ctx, out->seckey.seckey, 32);
+ SHA512_Update(&ctx, string, sizeof(string));
+ SHA512_Final(sha512_output, &ctx);
+ memcpy(out->seckey.seckey + 32, sha512_output, 32);
+
+ ed25519_public_key_generate(&out->pubkey, &out->seckey);
+
+ *signbit_out = out->pubkey.pubkey[31] >> 7;
+
+ ed25519_public_key_from_curve25519_public_key(&pubkey_check, &inp->pubkey,
+ *signbit_out);
+
+ tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32));
+
+ memwipe(&pubkey_check, 0, sizeof(pubkey_check));
+ memwipe(&ctx, 0, sizeof(ctx));
+ memwipe(sha512_output, 0, sizeof(sha512_output));
+
+ return 0;
+}
+
+/**
+ * Given a curve25519 public key and sign bit of X coordinate of the ed25519
+ * public key, generate the corresponding ed25519 public key.
+ */
+int
+ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey,
+ const curve25519_public_key_t *pubkey_in,
+ int signbit)
+{
+ return ed25519_ref10_pubkey_from_curve25519_pubkey(pubkey->pubkey,
+ pubkey_in->public_key,
+ signbit);
+}
+
+/**
+ * Given an ed25519 keypair in <b>inp</b>, generate a corresponding
+ * ed25519 keypair in <b>out</b>, blinded by the corresponding 32-byte input
+ * in 'param'.
+ *
+ * Tor uses key blinding for the "next-generation" hidden services design:
+ * service descriptors are encrypted with a key derived from the service's
+ * long-term public key, and then signed with (and stored at a position
+ * indexed by) a short-term key derived by blinding the long-term keys.
+ */
+int
+ed25519_keypair_blind(ed25519_keypair_t *out,
+ const ed25519_keypair_t *inp,
+ const uint8_t *param)
+{
+ ed25519_public_key_t pubkey_check;
+
+ ed25519_ref10_blind_secret_key(out->seckey.seckey,
+ inp->seckey.seckey, param);
+
+ ed25519_public_blind(&pubkey_check, &inp->pubkey, param);
+ ed25519_public_key_generate(&out->pubkey, &out->seckey);
+
+ tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32));
+
+ memwipe(&pubkey_check, 0, sizeof(pubkey_check));
+
+ return 0;
+}
+
+/**
+ * Given an ed25519 public key in <b>inp</b>, generate a corresponding blinded
+ * public key in <b>out</b>, blinded with the 32-byte parameter in
+ * <b>param</b>. Return 0 on sucess, -1 on railure.
+ */
+int
+ed25519_public_blind(ed25519_public_key_t *out,
+ const ed25519_public_key_t *inp,
+ const uint8_t *param)
+{
+ ed25519_ref10_blind_public_key(out->pubkey, inp->pubkey, param);
+ return 0;
+}
+
+/**
+ * Store seckey unencrypted to <b>filename</b>, marking it with <b>tag</b>.
+ * Return 0 on success, -1 on failure.
+ */
+int
+ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey,
+ const char *filename,
+ const char *tag)
+{
+ return crypto_write_tagged_contents_to_file(filename,
+ "ed25519v1-secret",
+ tag,
+ seckey->seckey,
+ sizeof(seckey->seckey));
+}
+
+/**
+ * Read seckey unencrypted from <b>filename</b>, storing it into
+ * <b>seckey_out</b>. Set *<b>tag_out</> to the tag it was marked with.
+ * Return 0 on success, -1 on failure.
+ */
+int
+ed25519_seckey_read_from_file(ed25519_secret_key_t *seckey_out,
+ char **tag_out,
+ const char *filename)
+{
+ ssize_t len;
+
+ len = crypto_read_tagged_contents_from_file(filename, "ed25519v1-secret",
+ tag_out, seckey_out->seckey,
+ sizeof(seckey_out->seckey));
+ if (len != sizeof(seckey_out->seckey))
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Store pubkey unencrypted to <b>filename</b>, marking it with <b>tag</b>.
+ * Return 0 on success, -1 on failure.
+ */
+int
+ed25519_pubkey_write_to_file(const ed25519_public_key_t *pubkey,
+ const char *filename,
+ const char *tag)
+{
+ return crypto_write_tagged_contents_to_file(filename,
+ "ed25519v1-public",
+ tag,
+ pubkey->pubkey,
+ sizeof(pubkey->pubkey));
+}
+
+/**
+ * Store pubkey unencrypted to <b>filename</b>, marking it with <b>tag</b>.
+ * Return 0 on success, -1 on failure.
+ */
+int
+ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
+ char **tag_out,
+ const char *filename)
+{
+ ssize_t len;
+
+ len = crypto_read_tagged_contents_from_file(filename, "ed25519v1-public",
+ tag_out, pubkey_out->pubkey,
+ sizeof(pubkey_out->pubkey));
+ if (len != sizeof(pubkey_out->pubkey))
+ return -1;
+
+ return 0;
+}
+
diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h
new file mode 100644
index 0000000000..7efa74bff5
--- /dev/null
+++ b/src/common/crypto_ed25519.h
@@ -0,0 +1,113 @@
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_CRYPTO_ED25519_H
+#define TOR_CRYPTO_ED25519_H
+
+#include "testsupport.h"
+#include "torint.h"
+
+#define ED25519_PUBKEY_LEN 32
+#define ED25519_SECKEY_LEN 64
+#define ED25519_SECKEY_SEED_LEN 32
+#define ED25519_SIG_LEN 64
+
+/** An Ed25519 signature. */
+typedef struct {
+ uint8_t sig[ED25519_SIG_LEN];
+} ed25519_signature_t;
+
+/** An Ed25519 public key */
+typedef struct {
+ uint8_t pubkey[ED25519_PUBKEY_LEN];
+} ed25519_public_key_t;
+
+/** An Ed25519 secret key */
+typedef struct {
+ /** Note that we store secret keys in an expanded format that doesn't match
+ * the format from standard ed25519. Ed25519 stores a 32-byte value k and
+ * expands it into a 64-byte H(k), using the first 32 bytes for a multiplier
+ * of the base point, and second 32 bytes as an input to a hash function
+ * for deriving r. But because we implement key blinding, we need to store
+ * keys in the 64-byte expanded form. */
+ uint8_t seckey[ED25519_SECKEY_LEN];
+} ed25519_secret_key_t;
+
+/** An Ed25519 keypair. */
+typedef struct {
+ ed25519_public_key_t pubkey;
+ ed25519_secret_key_t seckey;
+} ed25519_keypair_t;
+
+int ed25519_secret_key_generate(ed25519_secret_key_t *seckey_out,
+ int extra_strong);
+int ed25519_secret_key_from_seed(ed25519_secret_key_t *seckey_out,
+ const uint8_t *seed);
+
+int ed25519_public_key_generate(ed25519_public_key_t *pubkey_out,
+ const ed25519_secret_key_t *seckey);
+int ed25519_keypair_generate(ed25519_keypair_t *keypair_out, int extra_strong);
+int ed25519_sign(ed25519_signature_t *signature_out,
+ const uint8_t *msg, size_t len,
+ const ed25519_keypair_t *key);
+int ed25519_checksig(const ed25519_signature_t *signature,
+ const uint8_t *msg, size_t len,
+ const ed25519_public_key_t *pubkey);
+
+/**
+ * A collection of information necessary to check an Ed25519 signature. Used
+ * for batch verification.
+ */
+typedef struct {
+ /** The public key that supposedly generated the signature. */
+ ed25519_public_key_t *pubkey;
+ /** The signature to check. */
+ ed25519_signature_t signature;
+ /** The message that the signature is supposed to have been applied to. */
+ const uint8_t *msg;
+ /** The length of the message. */
+ size_t len;
+} ed25519_checkable_t;
+
+int ed25519_checksig_batch(int *okay_out,
+ const ed25519_checkable_t *checkable,
+ int n_checkable);
+
+int ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out,
+ int *signbit_out,
+ const curve25519_keypair_t *inp);
+
+int ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey,
+ const curve25519_public_key_t *pubkey_in,
+ int signbit);
+int ed25519_keypair_blind(ed25519_keypair_t *out,
+ const ed25519_keypair_t *inp,
+ const uint8_t *param);
+int ed25519_public_blind(ed25519_public_key_t *out,
+ const ed25519_public_key_t *inp,
+ const uint8_t *param);
+
+#define ED25519_BASE64_LEN 43
+
+int ed25519_public_from_base64(ed25519_public_key_t *pkey,
+ const char *input);
+int ed25519_public_to_base64(char *output,
+ const ed25519_public_key_t *pkey);
+
+/* XXXX read encrypted, write encrypted. */
+
+int ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey,
+ const char *filename,
+ const char *tag);
+int ed25519_seckey_read_from_file(ed25519_secret_key_t *seckey_out,
+ char **tag_out,
+ const char *filename);
+int ed25519_pubkey_write_to_file(const ed25519_public_key_t *pubkey,
+ const char *filename,
+ const char *tag);
+int ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out,
+ char **tag_out,
+ const char *filename);
+
+#endif
+
diff --git a/src/common/crypto_format.c b/src/common/crypto_format.c
index be669c8d2b..00e0e9ea85 100644
--- a/src/common/crypto_format.c
+++ b/src/common/crypto_format.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Formatting and parsing code for crypto-related data structures. */
@@ -9,6 +9,7 @@
#endif
#include "crypto.h"
#include "crypto_curve25519.h"
+#include "crypto_ed25519.h"
#include "util.h"
#include "torlog.h"
@@ -43,3 +44,24 @@ curve25519_public_from_base64(curve25519_public_key_t *pkey,
}
}
+/** Try to decode the string <b>input</b> into an ed25519 public key. On
+ * success, store the value in <b>pkey</b> and return 0. Otherwise return
+ * -1. */
+int
+ed25519_public_from_base64(ed25519_public_key_t *pkey,
+ const char *input)
+{
+ return digest256_from_base64((char*)pkey->pubkey, input);
+}
+
+/** Encode the public key <b>pkey</b> into the buffer at <b>output</b>,
+ * which must have space for ED25519_BASE64_LEN bytes of encoded key,
+ * plus one byte for a terminating NUL. Return 0 on success, -1 on failure.
+ */
+int
+ed25519_public_to_base64(char *output,
+ const ed25519_public_key_t *pkey)
+{
+ return digest256_to_base64(output, (const char *)pkey->pubkey);
+}
+
diff --git a/src/common/crypto_pwbox.c b/src/common/crypto_pwbox.c
new file mode 100644
index 0000000000..b866c7ef39
--- /dev/null
+++ b/src/common/crypto_pwbox.c
@@ -0,0 +1,187 @@
+
+#include "crypto.h"
+#include "crypto_s2k.h"
+#include "crypto_pwbox.h"
+#include "di_ops.h"
+#include "util.h"
+#include "pwbox.h"
+
+/* 8 bytes "TORBOX00"
+ 1 byte: header len (H)
+ H bytes: header, denoting secret key algorithm.
+ 16 bytes: IV
+ Round up to multiple of 128 bytes, then encrypt:
+ 4 bytes: data len
+ data
+ zeros
+ 32 bytes: HMAC-SHA256 of all previous bytes.
+*/
+
+#define MAX_OVERHEAD (S2K_MAXLEN + 8 + 1 + 32 + CIPHER_IV_LEN)
+
+/**
+ * Make an authenticated passphrase-encrypted blob to encode the
+ * <b>input_len</b> bytes in <b>input</b> using the passphrase
+ * <b>secret</b> of <b>secret_len</b> bytes. Allocate a new chunk of memory
+ * to hold the encrypted data, and store a pointer to that memory in
+ * *<b>out</b>, and its size in <b>outlen_out</b>. Use <b>s2k_flags</b> as an
+ * argument to the passphrase-hashing function.
+ */
+int
+crypto_pwbox(uint8_t **out, size_t *outlen_out,
+ const uint8_t *input, size_t input_len,
+ const char *secret, size_t secret_len,
+ unsigned s2k_flags)
+{
+ uint8_t *result = NULL, *encrypted_portion;
+ size_t encrypted_len = 128 * CEIL_DIV(input_len+4, 128);
+ ssize_t result_len;
+ int spec_len;
+ uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
+ pwbox_encoded_t *enc = NULL;
+ ssize_t enc_len;
+
+ crypto_cipher_t *cipher;
+ int rv;
+
+ enc = pwbox_encoded_new();
+
+ pwbox_encoded_setlen_skey_header(enc, S2K_MAXLEN);
+
+ spec_len = secret_to_key_make_specifier(
+ pwbox_encoded_getarray_skey_header(enc),
+ S2K_MAXLEN,
+ s2k_flags);
+ if (spec_len < 0 || spec_len > S2K_MAXLEN)
+ goto err;
+ pwbox_encoded_setlen_skey_header(enc, spec_len);
+ enc->header_len = spec_len;
+
+ crypto_rand((char*)enc->iv, sizeof(enc->iv));
+
+ pwbox_encoded_setlen_data(enc, encrypted_len);
+ encrypted_portion = pwbox_encoded_getarray_data(enc);
+
+ set_uint32(encrypted_portion, htonl((uint32_t)input_len));
+ memcpy(encrypted_portion+4, input, input_len);
+
+ /* Now that all the data is in position, derive some keys, encrypt, and
+ * digest */
+ if (secret_to_key_derivekey(keys, sizeof(keys),
+ pwbox_encoded_getarray_skey_header(enc),
+ spec_len,
+ secret, secret_len) < 0)
+ goto err;
+
+ cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
+ crypto_cipher_crypt_inplace(cipher, (char*)encrypted_portion, encrypted_len);
+ crypto_cipher_free(cipher);
+
+ result_len = pwbox_encoded_encoded_len(enc);
+ if (result_len < 0)
+ goto err;
+ result = tor_malloc(result_len);
+ enc_len = pwbox_encoded_encode(result, result_len, enc);
+ if (enc_len < 0)
+ goto err;
+ tor_assert(enc_len == result_len);
+
+ crypto_hmac_sha256((char*) result + result_len - 32,
+ (const char*)keys + CIPHER_KEY_LEN,
+ DIGEST256_LEN,
+ (const char*)result,
+ result_len - 32);
+
+ *out = result;
+ *outlen_out = result_len;
+ rv = 0;
+ goto out;
+
+ err:
+ tor_free(result);
+ rv = -1;
+
+ out:
+ pwbox_encoded_free(enc);
+ memwipe(keys, 0, sizeof(keys));
+ return rv;
+}
+
+/**
+ * Try to decrypt the passphrase-encrypted blob of <b>input_len</b> bytes in
+ * <b>input</b> using the passphrase <b>secret</b> of <b>secret_len</b> bytes.
+ * On success, return 0 and allocate a new chunk of memory to hold the
+ * decrypted data, and store a pointer to that memory in *<b>out</b>, and its
+ * size in <b>outlen_out</b>. On failure, return UNPWBOX_BAD_SECRET if
+ * the passphrase might have been wrong, and UNPWBOX_CORRUPT if the object is
+ * definitely corrupt.
+ */
+int
+crypto_unpwbox(uint8_t **out, size_t *outlen_out,
+ const uint8_t *inp, size_t input_len,
+ const char *secret, size_t secret_len)
+{
+ uint8_t *result = NULL;
+ const uint8_t *encrypted;
+ uint8_t keys[CIPHER_KEY_LEN + DIGEST256_LEN];
+ uint8_t hmac[DIGEST256_LEN];
+ uint32_t result_len;
+ size_t encrypted_len;
+ crypto_cipher_t *cipher = NULL;
+ int rv = UNPWBOX_CORRUPTED;
+ ssize_t got_len;
+
+ pwbox_encoded_t *enc = NULL;
+
+ got_len = pwbox_encoded_parse(&enc, inp, input_len);
+ if (got_len < 0 || (size_t)got_len != input_len)
+ goto err;
+
+ /* Now derive the keys and check the hmac. */
+ if (secret_to_key_derivekey(keys, sizeof(keys),
+ pwbox_encoded_getarray_skey_header(enc),
+ pwbox_encoded_getlen_skey_header(enc),
+ secret, secret_len) < 0)
+ goto err;
+
+ crypto_hmac_sha256((char *)hmac,
+ (const char*)keys + CIPHER_KEY_LEN, DIGEST256_LEN,
+ (const char*)inp, input_len - DIGEST256_LEN);
+
+ if (tor_memneq(hmac, enc->hmac, DIGEST256_LEN)) {
+ rv = UNPWBOX_BAD_SECRET;
+ goto err;
+ }
+
+ /* How long is the plaintext? */
+ encrypted = pwbox_encoded_getarray_data(enc);
+ encrypted_len = pwbox_encoded_getlen_data(enc);
+ if (encrypted_len < 4)
+ goto err;
+
+ cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv);
+ crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4);
+ result_len = ntohl(result_len);
+ if (encrypted_len < result_len + 4)
+ goto err;
+
+ /* Allocate a buffer and decrypt */
+ result = tor_malloc_zero(result_len);
+ crypto_cipher_decrypt(cipher, (char*)result, (char*)encrypted+4, result_len);
+
+ *out = result;
+ *outlen_out = result_len;
+
+ rv = UNPWBOX_OKAY;
+ goto out;
+
+ err:
+ tor_free(result);
+
+ out:
+ crypto_cipher_free(cipher);
+ pwbox_encoded_free(enc);
+ memwipe(keys, 0, sizeof(keys));
+ return rv;
+}
+
diff --git a/src/common/crypto_pwbox.h b/src/common/crypto_pwbox.h
new file mode 100644
index 0000000000..aadd477078
--- /dev/null
+++ b/src/common/crypto_pwbox.h
@@ -0,0 +1,20 @@
+#ifndef CRYPTO_PWBOX_H_INCLUDED_
+#define CRYPTO_PWBOX_H_INCLUDED_
+
+#include "torint.h"
+
+#define UNPWBOX_OKAY 0
+#define UNPWBOX_BAD_SECRET -1
+#define UNPWBOX_CORRUPTED -2
+
+int crypto_pwbox(uint8_t **out, size_t *outlen_out,
+ const uint8_t *inp, size_t input_len,
+ const char *secret, size_t secret_len,
+ unsigned s2k_flags);
+
+int crypto_unpwbox(uint8_t **out, size_t *outlen_out,
+ const uint8_t *inp, size_t input_len,
+ const char *secret, size_t secret_len);
+
+#endif
+
diff --git a/src/common/crypto_s2k.c b/src/common/crypto_s2k.c
new file mode 100644
index 0000000000..99f3b2ebbc
--- /dev/null
+++ b/src/common/crypto_s2k.c
@@ -0,0 +1,460 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define CRYPTO_S2K_PRIVATE
+
+#include "crypto.h"
+#include "util.h"
+#include "compat.h"
+#include "crypto_s2k.h"
+
+#include <openssl/evp.h>
+
+#ifdef HAVE_LIBSCRYPT_H
+#define HAVE_SCRYPT
+#include <libscrypt.h>
+#endif
+
+/* Encoded secrets take the form:
+
+ u8 type;
+ u8 salt_and_parameters[depends on type];
+ u8 key[depends on type];
+
+ As a special case, if the encoded secret is exactly 29 bytes long,
+ type 0 is understood.
+
+ Recognized types are:
+ 00 -- RFC2440. salt_and_parameters is 9 bytes. key is 20 bytes.
+ salt_and_parameters is 8 bytes random salt,
+ 1 byte iteration info.
+ 01 -- PKBDF2_SHA1. salt_and_parameters is 17 bytes. key is 20 bytes.
+ salt_and_parameters is 16 bytes random salt,
+ 1 byte iteration info.
+ 02 -- SCRYPT_SALSA208_SHA256. salt_and_parameters is 18 bytes. key is
+ 32 bytes.
+ salt_and_parameters is 18 bytes random salt, 2 bytes iteration
+ info.
+*/
+
+#define S2K_TYPE_RFC2440 0
+#define S2K_TYPE_PBKDF2 1
+#define S2K_TYPE_SCRYPT 2
+
+#define PBKDF2_SPEC_LEN 17
+#define PBKDF2_KEY_LEN 20
+
+#define SCRYPT_SPEC_LEN 18
+#define SCRYPT_KEY_LEN 32
+
+/** Given an algorithm ID (one of S2K_TYPE_*), return the length of the
+ * specifier part of it, without the prefix type byte. */
+static int
+secret_to_key_spec_len(uint8_t type)
+{
+ switch (type) {
+ case S2K_TYPE_RFC2440:
+ return S2K_RFC2440_SPECIFIER_LEN;
+ case S2K_TYPE_PBKDF2:
+ return PBKDF2_SPEC_LEN;
+ case S2K_TYPE_SCRYPT:
+ return SCRYPT_SPEC_LEN;
+ default:
+ return -1;
+ }
+}
+
+/** Given an algorithm ID (one of S2K_TYPE_*), return the length of the
+ * its preferred output. */
+static int
+secret_to_key_key_len(uint8_t type)
+{
+ switch (type) {
+ case S2K_TYPE_RFC2440:
+ return DIGEST_LEN;
+ case S2K_TYPE_PBKDF2:
+ return DIGEST_LEN;
+ case S2K_TYPE_SCRYPT:
+ return DIGEST256_LEN;
+ default:
+ return -1;
+ }
+}
+
+/** Given a specifier in <b>spec_and_key</b> of length
+ * <b>spec_and_key_len</b>, along with its prefix algorithm ID byte, and along
+ * with a key if <b>key_included</b> is true, check whether the whole
+ * specifier-and-key is of valid length, and return the algorithm type if it
+ * is. Set *<b>legacy_out</b> to 1 iff this is a legacy password hash or
+ * legacy specifier. Return an error code on failure.
+ */
+static int
+secret_to_key_get_type(const uint8_t *spec_and_key, size_t spec_and_key_len,
+ int key_included, int *legacy_out)
+{
+ size_t legacy_len = S2K_RFC2440_SPECIFIER_LEN;
+ uint8_t type;
+ int total_len;
+
+ if (key_included)
+ legacy_len += DIGEST_LEN;
+
+ if (spec_and_key_len == legacy_len) {
+ *legacy_out = 1;
+ return S2K_TYPE_RFC2440;
+ }
+
+ *legacy_out = 0;
+ if (spec_and_key_len == 0)
+ return S2K_BAD_LEN;
+
+ type = spec_and_key[0];
+ total_len = secret_to_key_spec_len(type);
+ if (total_len < 0)
+ return S2K_BAD_ALGORITHM;
+ if (key_included) {
+ int keylen = secret_to_key_key_len(type);
+ if (keylen < 0)
+ return S2K_BAD_ALGORITHM;
+ total_len += keylen;
+ }
+
+ if ((size_t)total_len + 1 == spec_and_key_len)
+ return type;
+ else
+ return S2K_BAD_LEN;
+}
+
+/**
+ * Write a new random s2k specifier of type <b>type</b>, without prefixing
+ * type byte, to <b>spec_out</b>, which must have enough room. May adjust
+ * parameter choice based on <b>flags</b>.
+ */
+static int
+make_specifier(uint8_t *spec_out, uint8_t type, unsigned flags)
+{
+ int speclen = secret_to_key_spec_len(type);
+ if (speclen < 0)
+ return S2K_BAD_ALGORITHM;
+
+ crypto_rand((char*)spec_out, speclen);
+ switch (type) {
+ case S2K_TYPE_RFC2440:
+ /* Hash 64 k of data. */
+ spec_out[S2K_RFC2440_SPECIFIER_LEN-1] = 96;
+ break;
+ case S2K_TYPE_PBKDF2:
+ /* 131 K iterations */
+ spec_out[PBKDF2_SPEC_LEN-1] = 17;
+ break;
+ case S2K_TYPE_SCRYPT:
+ if (flags & S2K_FLAG_LOW_MEM) {
+ /* N = 1<<12 */
+ spec_out[SCRYPT_SPEC_LEN-2] = 12;
+ } else {
+ /* N = 1<<15 */
+ spec_out[SCRYPT_SPEC_LEN-2] = 15;
+ }
+ /* r = 8; p = 2. */
+ spec_out[SCRYPT_SPEC_LEN-1] = (3u << 4) | (1u << 0);
+ break;
+ default:
+ tor_fragile_assert();
+ return S2K_BAD_ALGORITHM;
+ }
+
+ return speclen;
+}
+
+/** Implement RFC2440-style iterated-salted S2K conversion: convert the
+ * <b>secret_len</b>-byte <b>secret</b> into a <b>key_out_len</b> byte
+ * <b>key_out</b>. As in RFC2440, the first 8 bytes of s2k_specifier
+ * are a salt; the 9th byte describes how much iteration to do.
+ * If <b>key_out_len</b> &gt; DIGEST_LEN, use HDKF to expand the result.
+ */
+void
+secret_to_key_rfc2440(char *key_out, size_t key_out_len, const char *secret,
+ size_t secret_len, const char *s2k_specifier)
+{
+ crypto_digest_t *d;
+ uint8_t c;
+ size_t count, tmplen;
+ char *tmp;
+ uint8_t buf[DIGEST_LEN];
+ tor_assert(key_out_len < SIZE_T_CEILING);
+
+#define EXPBIAS 6
+ c = s2k_specifier[8];
+ count = ((uint32_t)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
+#undef EXPBIAS
+
+ d = crypto_digest_new();
+ tmplen = 8+secret_len;
+ tmp = tor_malloc(tmplen);
+ memcpy(tmp,s2k_specifier,8);
+ memcpy(tmp+8,secret,secret_len);
+ secret_len += 8;
+ while (count) {
+ if (count >= secret_len) {
+ crypto_digest_add_bytes(d, tmp, secret_len);
+ count -= secret_len;
+ } else {
+ crypto_digest_add_bytes(d, tmp, count);
+ count = 0;
+ }
+ }
+ crypto_digest_get_digest(d, (char*)buf, sizeof(buf));
+
+ if (key_out_len <= sizeof(buf)) {
+ memcpy(key_out, buf, key_out_len);
+ } else {
+ crypto_expand_key_material_rfc5869_sha256(buf, DIGEST_LEN,
+ (const uint8_t*)s2k_specifier, 8,
+ (const uint8_t*)"EXPAND", 6,
+ (uint8_t*)key_out, key_out_len);
+ }
+ memwipe(tmp, 0, tmplen);
+ memwipe(buf, 0, sizeof(buf));
+ tor_free(tmp);
+ crypto_digest_free(d);
+}
+
+/**
+ * Helper: given a valid specifier without prefix type byte in <b>spec</b>,
+ * whose length must be correct, and given a secret passphrase <b>secret</b>
+ * of length <b>secret_len</b>, compute the key and store it into
+ * <b>key_out</b>, which must have enough room for secret_to_key_key_len(type)
+ * bytes. Return the number of bytes written on success and an error code
+ * on failure.
+ */
+STATIC int
+secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
+ const uint8_t *spec, size_t spec_len,
+ const char *secret, size_t secret_len,
+ int type)
+{
+ int rv;
+ if (key_out_len > INT_MAX)
+ return S2K_BAD_LEN;
+
+ switch (type) {
+ case S2K_TYPE_RFC2440:
+ secret_to_key_rfc2440((char*)key_out, key_out_len, secret, secret_len,
+ (const char*)spec);
+ return (int)key_out_len;
+
+ case S2K_TYPE_PBKDF2: {
+ uint8_t log_iters;
+ if (spec_len < 1 || secret_len > INT_MAX || spec_len > INT_MAX)
+ return S2K_BAD_LEN;
+ log_iters = spec[spec_len-1];
+ if (log_iters > 31)
+ return S2K_BAD_PARAMS;
+ rv = PKCS5_PBKDF2_HMAC_SHA1(secret, (int)secret_len,
+ spec, (int)spec_len-1,
+ (1<<log_iters),
+ (int)key_out_len, key_out);
+ if (rv < 0)
+ return S2K_FAILED;
+ return (int)key_out_len;
+ }
+
+ case S2K_TYPE_SCRYPT: {
+#ifdef HAVE_SCRYPT
+ uint8_t log_N, log_r, log_p;
+ uint64_t N;
+ uint32_t r, p;
+ if (spec_len < 2)
+ return S2K_BAD_LEN;
+ log_N = spec[spec_len-2];
+ log_r = (spec[spec_len-1]) >> 4;
+ log_p = (spec[spec_len-1]) & 15;
+ if (log_N > 63)
+ return S2K_BAD_PARAMS;
+ N = ((uint64_t)1) << log_N;
+ r = 1u << log_r;
+ p = 1u << log_p;
+ rv = libscrypt_scrypt((const uint8_t*)secret, secret_len,
+ spec, spec_len-2, N, r, p, key_out, key_out_len);
+ if (rv != 0)
+ return S2K_FAILED;
+ return (int)key_out_len;
+#else
+ return S2K_NO_SCRYPT_SUPPORT;
+#endif
+ }
+ default:
+ return S2K_BAD_ALGORITHM;
+ }
+}
+
+/**
+ * Given a specifier previously constructed with secret_to_key_make_specifier
+ * in <b>spec</b> of length <b>spec_len</b>, and a secret password in
+ * <b>secret</b> of length <b>secret_len</b>, generate <b>key_out_len</b>
+ * bytes of cryptographic material in <b>key_out</b>. The native output of
+ * the secret-to-key function will be truncated if key_out_len is short, and
+ * expanded with HKDF if key_out_len is long. Returns S2K_OKAY on success,
+ * and an error code on failure.
+ */
+int
+secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len,
+ const uint8_t *spec, size_t spec_len,
+ const char *secret, size_t secret_len)
+{
+ int legacy_format = 0;
+ int type = secret_to_key_get_type(spec, spec_len, 0, &legacy_format);
+ int r;
+
+ if (type < 0)
+ return type;
+#ifndef HAVE_SCRYPT
+ if (type == S2K_TYPE_SCRYPT)
+ return S2K_NO_SCRYPT_SUPPORT;
+ #endif
+
+ if (! legacy_format) {
+ ++spec;
+ --spec_len;
+ }
+
+ r = secret_to_key_compute_key(key_out, key_out_len, spec, spec_len,
+ secret, secret_len, type);
+ if (r < 0)
+ return r;
+ else
+ return S2K_OKAY;
+}
+
+/**
+ * Construct a new s2k algorithm specifier and salt in <b>buf</b>, according
+ * to the bitwise-or of some S2K_FLAG_* options in <b>flags</b>. Up to
+ * <b>buf_len</b> bytes of storage may be used in <b>buf</b>. Return the
+ * number of bytes used on success and an error code on failure.
+ */
+int
+secret_to_key_make_specifier(uint8_t *buf, size_t buf_len, unsigned flags)
+{
+ int rv;
+ int spec_len;
+#ifdef HAVE_SCRYPT
+ uint8_t type = S2K_TYPE_SCRYPT;
+#else
+ uint8_t type = S2K_TYPE_RFC2440;
+#endif
+
+ if (flags & S2K_FLAG_NO_SCRYPT)
+ type = S2K_TYPE_RFC2440;
+ if (flags & S2K_FLAG_USE_PBKDF2)
+ type = S2K_TYPE_PBKDF2;
+
+ spec_len = secret_to_key_spec_len(type);
+
+ if ((int)buf_len < spec_len + 1)
+ return S2K_TRUNCATED;
+
+ buf[0] = type;
+ rv = make_specifier(buf+1, type, flags);
+ if (rv < 0)
+ return rv;
+ else
+ return rv + 1;
+}
+
+/**
+ * Hash a passphrase from <b>secret</b> of length <b>secret_len</b>, according
+ * to the bitwise-or of some S2K_FLAG_* options in <b>flags</b>, and store the
+ * hash along with salt and hashing parameters into <b>buf</b>. Up to
+ * <b>buf_len</b> bytes of storage may be used in <b>buf</b>. Set
+ * *<b>len_out</b> to the number of bytes used and return S2K_OKAY on success;
+ * and return an error code on failure.
+ */
+int
+secret_to_key_new(uint8_t *buf,
+ size_t buf_len,
+ size_t *len_out,
+ const char *secret, size_t secret_len,
+ unsigned flags)
+{
+ int key_len;
+ int spec_len;
+ int type;
+ int rv;
+
+ spec_len = secret_to_key_make_specifier(buf, buf_len, flags);
+
+ if (spec_len < 0)
+ return spec_len;
+
+ type = buf[0];
+ key_len = secret_to_key_key_len(type);
+
+ if (key_len < 0)
+ return key_len;
+
+ if ((int)buf_len < key_len + spec_len)
+ return S2K_TRUNCATED;
+
+ rv = secret_to_key_compute_key(buf + spec_len, key_len,
+ buf + 1, spec_len-1,
+ secret, secret_len, type);
+ if (rv < 0)
+ return rv;
+
+ *len_out = spec_len + key_len;
+
+ return S2K_OKAY;
+}
+
+/**
+ * Given a hashed passphrase in <b>spec_and_key</b> of length
+ * <b>spec_and_key_len</b> as generated by secret_to_key_new(), verify whether
+ * it is a hash of the passphrase <b>secret</b> of length <b>secret_len</b>.
+ * Return S2K_OKAY on a match, S2K_BAD_SECRET on a well-formed hash that
+ * doesn't match this secret, and another error code on other errors.
+ */
+int
+secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len,
+ const char *secret, size_t secret_len)
+{
+ int is_legacy = 0;
+ int type = secret_to_key_get_type(spec_and_key, spec_and_key_len,
+ 1, &is_legacy);
+ uint8_t buf[32];
+ int spec_len;
+ int key_len;
+ int rv;
+
+ if (type < 0)
+ return type;
+
+ if (! is_legacy) {
+ spec_and_key++;
+ spec_and_key_len--;
+ }
+
+ spec_len = secret_to_key_spec_len(type);
+ key_len = secret_to_key_key_len(type);
+ tor_assert(spec_len > 0);
+ tor_assert(key_len > 0);
+ tor_assert(key_len <= (int) sizeof(buf));
+ tor_assert((int)spec_and_key_len == spec_len + key_len);
+ rv = secret_to_key_compute_key(buf, key_len,
+ spec_and_key, spec_len,
+ secret, secret_len, type);
+ if (rv < 0)
+ goto done;
+
+ if (tor_memeq(buf, spec_and_key + spec_len, key_len))
+ rv = S2K_OKAY;
+ else
+ rv = S2K_BAD_SECRET;
+
+ done:
+ memwipe(buf, 0, sizeof(buf));
+ return rv;
+}
+
diff --git a/src/common/crypto_s2k.h b/src/common/crypto_s2k.h
new file mode 100644
index 0000000000..66df24c3c4
--- /dev/null
+++ b/src/common/crypto_s2k.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_CRYPTO_S2K_H_INCLUDED
+#define TOR_CRYPTO_S2K_H_INCLUDED
+
+#include <stdio.h>
+#include "torint.h"
+
+/** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the
+ * 9th describes how much iteration to do. */
+#define S2K_RFC2440_SPECIFIER_LEN 9
+void secret_to_key_rfc2440(
+ char *key_out, size_t key_out_len, const char *secret,
+ size_t secret_len, const char *s2k_specifier);
+
+/** Flag for secret-to-key function: do not use scrypt. */
+#define S2K_FLAG_NO_SCRYPT (1u<<0)
+/** Flag for secret-to-key functions: if using a memory-tuned s2k function,
+ * assume that we have limited memory. */
+#define S2K_FLAG_LOW_MEM (1u<<1)
+/** Flag for secret-to-key functions: force use of pbkdf2. Without this, we
+ * default to scrypt, then RFC2440. */
+#define S2K_FLAG_USE_PBKDF2 (1u<<2)
+
+/** Maximum possible output length from secret_to_key_new. */
+#define S2K_MAXLEN 64
+
+/** Error code from secret-to-key functions: all is well */
+#define S2K_OKAY 0
+/** Error code from secret-to-key functions: generic failure */
+#define S2K_FAILED -1
+/** Error code from secret-to-key functions: provided secret didn't match */
+#define S2K_BAD_SECRET -2
+/** Error code from secret-to-key functions: didn't recognize the algorithm */
+#define S2K_BAD_ALGORITHM -3
+/** Error code from secret-to-key functions: specifier wasn't valid */
+#define S2K_BAD_PARAMS -4
+/** Error code from secret-to-key functions: compiled without scrypt */
+#define S2K_NO_SCRYPT_SUPPORT -5
+/** Error code from secret-to-key functions: not enough space to write output.
+ */
+#define S2K_TRUNCATED -6
+/** Error code from secret-to-key functions: Wrong length for specifier. */
+#define S2K_BAD_LEN -7
+
+int secret_to_key_new(uint8_t *buf,
+ size_t buf_len,
+ size_t *len_out,
+ const char *secret, size_t secret_len,
+ unsigned flags);
+
+int secret_to_key_make_specifier(uint8_t *buf, size_t buf_len, unsigned flags);
+
+int secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len,
+ const char *secret, size_t secret_len);
+
+int secret_to_key_derivekey(uint8_t *key_out, size_t key_out_len,
+ const uint8_t *spec, size_t spec_len,
+ const char *secret, size_t secret_len);
+
+#ifdef CRYPTO_S2K_PRIVATE
+STATIC int secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len,
+ const uint8_t *spec, size_t spec_len,
+ const char *secret, size_t secret_len,
+ int type);
+#endif
+
+#endif
+
diff --git a/src/common/di_ops.c b/src/common/di_ops.c
index 14a1443400..c9d1350880 100644
--- a/src/common/di_ops.c
+++ b/src/common/di_ops.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Tor Project, Inc. */
+/* Copyright (c) 2011-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -130,6 +130,7 @@ tor_memeq(const void *a, const void *b, size_t sz)
* 1 & ((any_difference - 1) >> 8) == 0
*/
+ /*coverity[overflow]*/
return 1 & ((any_difference - 1) >> 8);
}
@@ -217,6 +218,7 @@ safe_mem_is_zero(const void *mem, size_t sz)
total |= *ptr++;
}
+ /*coverity[overflow]*/
return 1 & ((total - 1) >> 8);
}
diff --git a/src/common/di_ops.h b/src/common/di_ops.h
index d93534b69b..bbb1caa00c 100644
--- a/src/common/di_ops.h
+++ b/src/common/di_ops.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/include.am b/src/common/include.am
index 68e0110c26..5b63392541 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -16,7 +16,7 @@ EXTRA_DIST+= \
src/common/Makefile.nmake
#CFLAGS = -Wall -Wpointer-arith -O2
-AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common
+AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel
if USE_OPENBSD_MALLOC
libor_extra_source=src/ext/OpenBSD_malloc_Linux.c
@@ -24,14 +24,6 @@ else
libor_extra_source=
endif
-if USE_MEMPOOLS
-libor_mempool_source=src/common/mempool.c
-libor_mempool_header=src/common/mempool.h
-else
-libor_mempool_source=
-libor_mempool_header=
-endif
-
src_common_libcurve25519_donna_a_CFLAGS=
if BUILD_CURVE25519_DONNA
@@ -52,14 +44,20 @@ LIBDONNA=
endif
endif
-if CURVE25519_ENABLED
-libcrypto_extra_source=src/common/crypto_curve25519.c
+LIBDONNA += $(LIBED25519_REF10)
+
+if THREADS_PTHREADS
+threads_impl_source=src/common/compat_pthreads.c
+endif
+if THREADS_WIN32
+threads_impl_source=src/common/compat_winthreads.c
endif
LIBOR_A_SOURCES = \
src/common/address.c \
src/common/backtrace.c \
src/common/compat.c \
+ src/common/compat_threads.c \
src/common/container.c \
src/common/di_ops.c \
src/common/log.c \
@@ -68,17 +66,23 @@ LIBOR_A_SOURCES = \
src/common/util_codedigest.c \
src/common/util_process.c \
src/common/sandbox.c \
+ src/common/workqueue.c \
src/ext/csiphash.c \
+ src/ext/trunnel/trunnel.c \
$(libor_extra_source) \
- $(libor_mempool_source)
+ $(threads_impl_source)
LIBOR_CRYPTO_A_SOURCES = \
src/common/aes.c \
src/common/crypto.c \
+ src/common/crypto_pwbox.c \
+ src/common/crypto_s2k.c \
src/common/crypto_format.c \
src/common/torgzip.c \
src/common/tortls.c \
- $(libcrypto_extra_source)
+ src/trunnel/pwbox.c \
+ src/common/crypto_curve25519.c \
+ src/common/crypto_ed25519.c
LIBOR_EVENT_A_SOURCES = \
src/common/compat_libevent.c \
@@ -99,7 +103,6 @@ src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_common_libor_crypto_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
-
COMMONHEADERS = \
src/common/address.h \
src/common/backtrace.h \
@@ -107,9 +110,13 @@ COMMONHEADERS = \
src/common/ciphers.inc \
src/common/compat.h \
src/common/compat_libevent.h \
+ src/common/compat_threads.h \
src/common/container.h \
src/common/crypto.h \
src/common/crypto_curve25519.h \
+ src/common/crypto_ed25519.h \
+ src/common/crypto_pwbox.h \
+ src/common/crypto_s2k.h \
src/common/di_ops.h \
src/common/memarea.h \
src/common/linux_syscalls.inc \
@@ -122,7 +129,7 @@ COMMONHEADERS = \
src/common/tortls.h \
src/common/util.h \
src/common/util_process.h \
- $(libor_mempool_header)
+ src/common/workqueue.h
noinst_HEADERS+= $(COMMONHEADERS)
diff --git a/src/common/log.c b/src/common/log.c
index 517fa4faaa..e8cc30c312 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -117,15 +117,33 @@ static int syslog_count = 0;
/** Represents a log message that we are going to send to callback-driven
* loggers once we can do so in a non-reentrant way. */
-typedef struct pending_cb_message_t {
+typedef struct pending_log_message_t {
int severity; /**< The severity of the message */
log_domain_mask_t domain; /**< The domain of the message */
+ char *fullmsg; /**< The message, with all decorations */
char *msg; /**< The content of the message */
-} pending_cb_message_t;
+} pending_log_message_t;
/** Log messages waiting to be replayed onto callback-based logs */
static smartlist_t *pending_cb_messages = NULL;
+/** Log messages waiting to be replayed once the logging system is initialized.
+ */
+static smartlist_t *pending_startup_messages = NULL;
+
+/** Number of bytes of messages queued in pending_startup_messages. (This is
+ * the length of the messages, not the number of bytes used to store
+ * them.) */
+static size_t pending_startup_messages_len;
+
+/** True iff we should store messages while waiting for the logs to get
+ * configured. */
+static int queue_startup_messages = 1;
+
+/** Don't store more than this many bytes of messages while waiting for the
+ * logs to get configured. */
+#define MAX_STARTUP_MSG_LEN (1<<16)
+
/** Lock the log_mutex to prevent others from changing the logfile_t list */
#define LOCK_LOGS() STMT_BEGIN \
tor_mutex_acquire(&log_mutex); \
@@ -329,6 +347,102 @@ format_msg(char *buf, size_t buf_len,
return end_of_prefix;
}
+/* Create a new pending_log_message_t with appropriate values */
+static pending_log_message_t *
+pending_log_message_new(int severity, log_domain_mask_t domain,
+ const char *fullmsg, const char *shortmsg)
+{
+ pending_log_message_t *m = tor_malloc(sizeof(pending_log_message_t));
+ m->severity = severity;
+ m->domain = domain;
+ m->fullmsg = fullmsg ? tor_strdup(fullmsg) : NULL;
+ m->msg = tor_strdup(shortmsg);
+ return m;
+}
+
+/** Release all storage held by <b>msg</b>. */
+static void
+pending_log_message_free(pending_log_message_t *msg)
+{
+ if (!msg)
+ return;
+ tor_free(msg->msg);
+ tor_free(msg->fullmsg);
+ tor_free(msg);
+}
+
+/** Return true iff <b>lf</b> would like to receive a message with the
+ * specified <b>severity</b> in the specified <b>domain</b>.
+ */
+static INLINE int
+logfile_wants_message(const logfile_t *lf, int severity,
+ log_domain_mask_t domain)
+{
+ if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
+ return 0;
+ }
+ if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) {
+ return 0;
+ }
+ if (lf->seems_dead) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/** Send a message to <b>lf</b>. The full message, with time prefix and
+ * severity, is in <b>buf</b>. The message itself is in
+ * <b>msg_after_prefix</b>. If <b>callbacks_deferred</b> points to true, then
+ * we already deferred this message for pending callbacks and don't need to do
+ * it again. Otherwise, if we need to do it, do it, and set
+ * <b>callbacks_deferred</b> to 1. */
+static INLINE void
+logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len,
+ const char *msg_after_prefix, log_domain_mask_t domain,
+ int severity, int *callbacks_deferred)
+{
+
+ if (lf->is_syslog) {
+#ifdef HAVE_SYSLOG_H
+#ifdef MAXLINE
+ /* Some syslog implementations have limits on the length of what you can
+ * pass them, and some very old ones do not detect overflow so well.
+ * Regrettably, they call their maximum line length MAXLINE. */
+#if MAXLINE < 64
+#warn "MAXLINE is a very low number; it might not be from syslog.h after all"
+#endif
+ char *m = msg_after_prefix;
+ if (msg_len >= MAXLINE)
+ m = tor_strndup(msg_after_prefix, MAXLINE-1);
+ syslog(severity, "%s", m);
+ if (m != msg_after_prefix) {
+ tor_free(m);
+ }
+#else
+ /* We have syslog but not MAXLINE. That's promising! */
+ syslog(severity, "%s", msg_after_prefix);
+#endif
+#endif
+ } else if (lf->callback) {
+ if (domain & LD_NOCB) {
+ if (!*callbacks_deferred && pending_cb_messages) {
+ smartlist_add(pending_cb_messages,
+ pending_log_message_new(severity,domain,NULL,msg_after_prefix));
+ *callbacks_deferred = 1;
+ }
+ } else {
+ lf->callback(severity, domain, msg_after_prefix);
+ }
+ } else {
+ if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */
+ /* don't log the error! mark this log entry to be blown away, and
+ * continue. */
+ lf->seems_dead = 1;
+ }
+ }
+}
+
/** Helper: sends a message to the appropriate logfiles, at loglevel
* <b>severity</b>. If provided, <b>funcname</b> is prepended to the
* message. The actual message is derived as from tor_snprintf(format,ap).
@@ -337,7 +451,7 @@ MOCK_IMPL(STATIC void,
logv,(int severity, log_domain_mask_t domain, const char *funcname,
const char *suffix, const char *format, va_list ap))
{
- char buf[10024];
+ char buf[10240];
size_t msg_len = 0;
int formatted = 0;
logfile_t *lf;
@@ -354,20 +468,21 @@ logv,(int severity, log_domain_mask_t domain, const char *funcname,
if ((! (domain & LD_NOCB)) && smartlist_len(pending_cb_messages))
flush_pending_log_callbacks();
- lf = logfiles;
- while (lf) {
- if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) {
- lf = lf->next;
- continue;
- }
- if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) {
- lf = lf->next;
- continue;
- }
- if (lf->seems_dead) {
- lf = lf->next;
+ if (queue_startup_messages &&
+ pending_startup_messages_len < MAX_STARTUP_MSG_LEN) {
+ end_of_prefix =
+ format_msg(buf, sizeof(buf), domain, severity, funcname, suffix,
+ format, ap, &msg_len);
+ formatted = 1;
+
+ smartlist_add(pending_startup_messages,
+ pending_log_message_new(severity,domain,buf,end_of_prefix));
+ pending_startup_messages_len += msg_len;
+ }
+
+ for (lf = logfiles; lf; lf = lf->next) {
+ if (! logfile_wants_message(lf, severity, domain))
continue;
- }
if (!formatted) {
end_of_prefix =
@@ -376,51 +491,8 @@ logv,(int severity, log_domain_mask_t domain, const char *funcname,
formatted = 1;
}
- if (lf->is_syslog) {
-#ifdef HAVE_SYSLOG_H
- char *m = end_of_prefix;
-#ifdef MAXLINE
- /* Some syslog implementations have limits on the length of what you can
- * pass them, and some very old ones do not detect overflow so well.
- * Regrettably, they call their maximum line length MAXLINE. */
-#if MAXLINE < 64
-#warn "MAXLINE is a very low number; it might not be from syslog.h after all"
-#endif
- if (msg_len >= MAXLINE)
- m = tor_strndup(end_of_prefix, MAXLINE-1);
-#endif
- syslog(severity, "%s", m);
-#ifdef MAXLINE
- if (m != end_of_prefix) {
- tor_free(m);
- }
-#endif
-#endif
- lf = lf->next;
- continue;
- } else if (lf->callback) {
- if (domain & LD_NOCB) {
- if (!callbacks_deferred && pending_cb_messages) {
- pending_cb_message_t *msg = tor_malloc(sizeof(pending_cb_message_t));
- msg->severity = severity;
- msg->domain = domain;
- msg->msg = tor_strdup(end_of_prefix);
- smartlist_add(pending_cb_messages, msg);
-
- callbacks_deferred = 1;
- }
- } else {
- lf->callback(severity, domain, end_of_prefix);
- }
- lf = lf->next;
- continue;
- }
- if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */
- /* don't log the error! mark this log entry to be blown away, and
- * continue. */
- lf->seems_dead = 1;
- }
- lf = lf->next;
+ logfile_deliver(lf, buf, msg_len, end_of_prefix, domain, severity,
+ &callbacks_deferred);
}
UNLOCK_LOGS();
}
@@ -724,12 +796,14 @@ void
logs_free_all(void)
{
logfile_t *victim, *next;
- smartlist_t *messages;
+ smartlist_t *messages, *messages2;
LOCK_LOGS();
next = logfiles;
logfiles = NULL;
messages = pending_cb_messages;
pending_cb_messages = NULL;
+ messages2 = pending_startup_messages;
+ pending_startup_messages = NULL;
UNLOCK_LOGS();
while (next) {
victim = next;
@@ -739,12 +813,18 @@ logs_free_all(void)
}
tor_free(appname);
- SMARTLIST_FOREACH(messages, pending_cb_message_t *, msg, {
- tor_free(msg->msg);
- tor_free(msg);
+ SMARTLIST_FOREACH(messages, pending_log_message_t *, msg, {
+ pending_log_message_free(msg);
});
smartlist_free(messages);
+ if (messages2) {
+ SMARTLIST_FOREACH(messages2, pending_log_message_t *, msg, {
+ pending_log_message_free(msg);
+ });
+ smartlist_free(messages2);
+ }
+
/* We _could_ destroy the log mutex here, but that would screw up any logs
* that happened between here and the end of execution. */
}
@@ -839,7 +919,7 @@ add_stream_log(const log_severity_list_t *severity, const char *name, int fd)
/** Initialize the global logging facility */
void
-init_logging(void)
+init_logging(int disable_startup_queue)
{
if (!log_mutex_initialized) {
tor_mutex_init(&log_mutex);
@@ -847,6 +927,11 @@ init_logging(void)
}
if (pending_cb_messages == NULL)
pending_cb_messages = smartlist_new();
+ if (disable_startup_queue)
+ queue_startup_messages = 0;
+ if (pending_startup_messages == NULL && queue_startup_messages) {
+ pending_startup_messages = smartlist_new();
+ }
}
/** Set whether we report logging domains as a part of our log messages.
@@ -932,7 +1017,7 @@ flush_pending_log_callbacks(void)
messages = pending_cb_messages;
pending_cb_messages = smartlist_new();
do {
- SMARTLIST_FOREACH_BEGIN(messages, pending_cb_message_t *, msg) {
+ SMARTLIST_FOREACH_BEGIN(messages, pending_log_message_t *, msg) {
const int severity = msg->severity;
const int domain = msg->domain;
for (lf = logfiles; lf; lf = lf->next) {
@@ -942,8 +1027,7 @@ flush_pending_log_callbacks(void)
}
lf->callback(severity, domain, msg->msg);
}
- tor_free(msg->msg);
- tor_free(msg);
+ pending_log_message_free(msg);
} SMARTLIST_FOREACH_END(msg);
smartlist_clear(messages);
@@ -957,6 +1041,45 @@ flush_pending_log_callbacks(void)
UNLOCK_LOGS();
}
+/** Flush all the messages we stored from startup while waiting for log
+ * initialization.
+ */
+void
+flush_log_messages_from_startup(void)
+{
+ logfile_t *lf;
+
+ LOCK_LOGS();
+ queue_startup_messages = 0;
+ pending_startup_messages_len = 0;
+ if (! pending_startup_messages)
+ goto out;
+
+ SMARTLIST_FOREACH_BEGIN(pending_startup_messages, pending_log_message_t *,
+ msg) {
+ int callbacks_deferred = 0;
+ for (lf = logfiles; lf; lf = lf->next) {
+ if (! logfile_wants_message(lf, msg->severity, msg->domain))
+ continue;
+
+ /* We configure a temporary startup log that goes to stdout, so we
+ * shouldn't replay to stdout/stderr*/
+ if (lf->fd == STDOUT_FILENO || lf->fd == STDERR_FILENO) {
+ continue;
+ }
+
+ logfile_deliver(lf, msg->fullmsg, strlen(msg->fullmsg), msg->msg,
+ msg->domain, msg->severity, &callbacks_deferred);
+ }
+ pending_log_message_free(msg);
+ } SMARTLIST_FOREACH_END(msg);
+ smartlist_free(pending_startup_messages);
+ pending_startup_messages = NULL;
+
+ out:
+ UNLOCK_LOGS();
+}
+
/** Close any log handlers added by add_temp_log() or marked by
* mark_logs_temp(). */
void
@@ -1010,12 +1133,16 @@ mark_logs_temp(void)
* logfile fails, -1 is returned and errno is set appropriately (by open(2)).
*/
int
-add_file_log(const log_severity_list_t *severity, const char *filename)
+add_file_log(const log_severity_list_t *severity, const char *filename,
+ const int truncate)
{
int fd;
logfile_t *lf;
- fd = tor_open_cloexec(filename, O_WRONLY|O_CREAT|O_APPEND, 0644);
+ int open_flags = O_WRONLY|O_CREAT;
+ open_flags |= truncate ? O_TRUNC : O_APPEND;
+
+ fd = tor_open_cloexec(filename, open_flags, 0644);
if (fd<0)
return -1;
if (tor_fd_seekend(fd)<0) {
@@ -1094,7 +1221,8 @@ log_level_to_string(int level)
static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
- "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL", NULL
+ "OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL",
+ "SCHED", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
@@ -1124,7 +1252,8 @@ domain_to_string(log_domain_mask_t domain, char *buf, size_t buflen)
const char *d;
int bit = tor_log2(domain);
size_t n;
- if (bit >= N_LOGGING_DOMAINS) {
+ if ((unsigned)bit >= ARRAY_LENGTH(domain_list)-1 ||
+ bit >= N_LOGGING_DOMAINS) {
tor_snprintf(buf, buflen, "<BUG:Unknown domain %lx>", (long)domain);
return buf+strlen(buf);
}
@@ -1297,3 +1426,15 @@ switch_logs_debug(void)
UNLOCK_LOGS();
}
+/** Truncate all the log files. */
+void
+truncate_logs(void)
+{
+ logfile_t *lf;
+ for (lf = logfiles; lf; lf = lf->next) {
+ if (lf->fd >= 0) {
+ tor_ftruncate(lf->fd);
+ }
+ }
+}
+
diff --git a/src/common/memarea.c b/src/common/memarea.c
index bcaea0949e..6841ba54e7 100644
--- a/src/common/memarea.c
+++ b/src/common/memarea.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Tor Project, Inc. */
+/* Copyright (c) 2008-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** \file memarea.c
diff --git a/src/common/memarea.h b/src/common/memarea.h
index 8b88585d35..d14f3a2bae 100644
--- a/src/common/memarea.h
+++ b/src/common/memarea.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Tor Project, Inc. */
+/* Copyright (c) 2008-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Tor dependencies */
diff --git a/src/common/mempool.c b/src/common/mempool.c
deleted file mode 100644
index 4389888760..0000000000
--- a/src/common/mempool.c
+++ /dev/null
@@ -1,628 +0,0 @@
-/* Copyright (c) 2007-2013, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-#if 1
-/* Tor dependencies */
-#include "orconfig.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include "torint.h"
-#include "crypto.h"
-#define MEMPOOL_PRIVATE
-#include "mempool.h"
-
-/* OVERVIEW:
- *
- * This is an implementation of memory pools for Tor cells. It may be
- * useful for you too.
- *
- * Generally, a memory pool is an allocation strategy optimized for large
- * numbers of identically-sized objects. Rather than the elaborate arena
- * and coalescing strategies you need to get good performance for a
- * general-purpose malloc(), pools use a series of large memory "chunks",
- * each of which is carved into a bunch of smaller "items" or
- * "allocations".
- *
- * To get decent performance, you need to:
- * - Minimize the number of times you hit the underlying allocator.
- * - Try to keep accesses as local in memory as possible.
- * - Try to keep the common case fast.
- *
- * Our implementation uses three lists of chunks per pool. Each chunk can
- * be either "full" (no more room for items); "empty" (no items); or
- * "used" (not full, not empty). There are independent doubly-linked
- * lists for each state.
- *
- * CREDIT:
- *
- * I wrote this after looking at 3 or 4 other pooling allocators, but
- * without copying. The strategy this most resembles (which is funny,
- * since that's the one I looked at longest ago) is the pool allocator
- * underlying Python's obmalloc code. Major differences from obmalloc's
- * pools are:
- * - We don't even try to be threadsafe.
- * - We only handle objects of one size.
- * - Our list of empty chunks is doubly-linked, not singly-linked.
- * (This could change pretty easily; it's only doubly-linked for
- * consistency.)
- * - We keep a list of full chunks (so we can have a "nuke everything"
- * function). Obmalloc's pools leave full chunks to float unanchored.
- *
- * LIMITATIONS:
- * - Not even slightly threadsafe.
- * - Likes to have lots of items per chunks.
- * - One pointer overhead per allocated thing. (The alternative is
- * something like glib's use of an RB-tree to keep track of what
- * chunk any given piece of memory is in.)
- * - Only aligns allocated things to void* level: redefine ALIGNMENT_TYPE
- * if you need doubles.
- * - Could probably be optimized a bit; the representation contains
- * a bit more info than it really needs to have.
- */
-
-#if 1
-/* Tor dependencies */
-#include "util.h"
-#include "compat.h"
-#include "torlog.h"
-#define ALLOC(x) tor_malloc(x)
-#define FREE(x) tor_free(x)
-#define ASSERT(x) tor_assert(x)
-#undef ALLOC_CAN_RETURN_NULL
-#define TOR
-/* End Tor dependencies */
-#else
-/* If you're not building this as part of Tor, you'll want to define the
- * following macros. For now, these should do as defaults.
- */
-#include <assert.h>
-#define PREDICT_UNLIKELY(x) (x)
-#define PREDICT_LIKELY(x) (x)
-#define ALLOC(x) malloc(x)
-#define FREE(x) free(x)
-#define STRUCT_OFFSET(tp, member) \
- ((off_t) (((char*)&((tp*)0)->member)-(char*)0))
-#define ASSERT(x) assert(x)
-#define ALLOC_CAN_RETURN_NULL
-#endif
-
-/* Tuning parameters */
-/** Largest type that we need to ensure returned memory items are aligned to.
- * Change this to "double" if we need to be safe for structs with doubles. */
-#define ALIGNMENT_TYPE void *
-/** Increment that we need to align allocated. */
-#define ALIGNMENT sizeof(ALIGNMENT_TYPE)
-/** Largest memory chunk that we should allocate. */
-#define MAX_CHUNK (8*(1L<<20))
-/** Smallest memory chunk size that we should allocate. */
-#define MIN_CHUNK 4096
-
-typedef struct mp_allocated_t mp_allocated_t;
-typedef struct mp_chunk_t mp_chunk_t;
-
-/** Holds a single allocated item, allocated as part of a chunk. */
-struct mp_allocated_t {
- /** The chunk that this item is allocated in. This adds overhead to each
- * allocated item, thus making this implementation inappropriate for
- * very small items. */
- mp_chunk_t *in_chunk;
- union {
- /** If this item is free, the next item on the free list. */
- mp_allocated_t *next_free;
- /** If this item is not free, the actual memory contents of this item.
- * (Not actual size.) */
- char mem[1];
- /** An extra element to the union to insure correct alignment. */
- ALIGNMENT_TYPE dummy_;
- } u;
-};
-
-/** 'Magic' value used to detect memory corruption. */
-#define MP_CHUNK_MAGIC 0x09870123
-
-/** A chunk of memory. Chunks come from malloc; we use them */
-struct mp_chunk_t {
- unsigned long magic; /**< Must be MP_CHUNK_MAGIC if this chunk is valid. */
- mp_chunk_t *next; /**< The next free, used, or full chunk in sequence. */
- mp_chunk_t *prev; /**< The previous free, used, or full chunk in sequence. */
- mp_pool_t *pool; /**< The pool that this chunk is part of. */
- /** First free item in the freelist for this chunk. Note that this may be
- * NULL even if this chunk is not at capacity: if so, the free memory at
- * next_mem has not yet been carved into items.
- */
- mp_allocated_t *first_free;
- int n_allocated; /**< Number of currently allocated items in this chunk. */
- int capacity; /**< Number of items that can be fit into this chunk. */
- size_t mem_size; /**< Number of usable bytes in mem. */
- char *next_mem; /**< Pointer into part of <b>mem</b> not yet carved up. */
- char mem[FLEXIBLE_ARRAY_MEMBER]; /**< Storage for this chunk. */
-};
-
-/** Number of extra bytes needed beyond mem_size to allocate a chunk. */
-#define CHUNK_OVERHEAD STRUCT_OFFSET(mp_chunk_t, mem[0])
-
-/** Given a pointer to a mp_allocated_t, return a pointer to the memory
- * item it holds. */
-#define A2M(a) (&(a)->u.mem)
-/** Given a pointer to a memory_item_t, return a pointer to its enclosing
- * mp_allocated_t. */
-#define M2A(p) ( ((char*)p) - STRUCT_OFFSET(mp_allocated_t, u.mem) )
-
-#ifdef ALLOC_CAN_RETURN_NULL
-/** If our ALLOC() macro can return NULL, check whether <b>x</b> is NULL,
- * and if so, return NULL. */
-#define CHECK_ALLOC(x) \
- if (PREDICT_UNLIKELY(!x)) { return NULL; }
-#else
-/** If our ALLOC() macro can't return NULL, do nothing. */
-#define CHECK_ALLOC(x)
-#endif
-
-/** Helper: Allocate and return a new memory chunk for <b>pool</b>. Does not
- * link the chunk into any list. */
-static mp_chunk_t *
-mp_chunk_new(mp_pool_t *pool)
-{
- size_t sz = pool->new_chunk_capacity * pool->item_alloc_size;
- mp_chunk_t *chunk = ALLOC(CHUNK_OVERHEAD + sz);
-
-#ifdef MEMPOOL_STATS
- ++pool->total_chunks_allocated;
-#endif
- CHECK_ALLOC(chunk);
- memset(chunk, 0, sizeof(mp_chunk_t)); /* Doesn't clear the whole thing. */
- chunk->magic = MP_CHUNK_MAGIC;
- chunk->capacity = pool->new_chunk_capacity;
- chunk->mem_size = sz;
- chunk->next_mem = chunk->mem;
- chunk->pool = pool;
- return chunk;
-}
-
-/** Take a <b>chunk</b> that has just been allocated or removed from
- * <b>pool</b>'s empty chunk list, and add it to the head of the used chunk
- * list. */
-static INLINE void
-add_newly_used_chunk_to_used_list(mp_pool_t *pool, mp_chunk_t *chunk)
-{
- chunk->next = pool->used_chunks;
- if (chunk->next)
- chunk->next->prev = chunk;
- pool->used_chunks = chunk;
- ASSERT(!chunk->prev);
-}
-
-/** Return a newly allocated item from <b>pool</b>. */
-void *
-mp_pool_get(mp_pool_t *pool)
-{
- mp_chunk_t *chunk;
- mp_allocated_t *allocated;
-
- if (PREDICT_LIKELY(pool->used_chunks != NULL)) {
- /* Common case: there is some chunk that is neither full nor empty. Use
- * that one. (We can't use the full ones, obviously, and we should fill
- * up the used ones before we start on any empty ones. */
- chunk = pool->used_chunks;
-
- } else if (pool->empty_chunks) {
- /* We have no used chunks, but we have an empty chunk that we haven't
- * freed yet: use that. (We pull from the front of the list, which should
- * get us the most recently emptied chunk.) */
- chunk = pool->empty_chunks;
-
- /* Remove the chunk from the empty list. */
- pool->empty_chunks = chunk->next;
- if (chunk->next)
- chunk->next->prev = NULL;
-
- /* Put the chunk on the 'used' list*/
- add_newly_used_chunk_to_used_list(pool, chunk);
-
- ASSERT(!chunk->prev);
- --pool->n_empty_chunks;
- if (pool->n_empty_chunks < pool->min_empty_chunks)
- pool->min_empty_chunks = pool->n_empty_chunks;
- } else {
- /* We have no used or empty chunks: allocate a new chunk. */
- chunk = mp_chunk_new(pool);
- CHECK_ALLOC(chunk);
-
- /* Add the new chunk to the used list. */
- add_newly_used_chunk_to_used_list(pool, chunk);
- }
-
- ASSERT(chunk->n_allocated < chunk->capacity);
-
- if (chunk->first_free) {
- /* If there's anything on the chunk's freelist, unlink it and use it. */
- allocated = chunk->first_free;
- chunk->first_free = allocated->u.next_free;
- allocated->u.next_free = NULL; /* For debugging; not really needed. */
- ASSERT(allocated->in_chunk == chunk);
- } else {
- /* Otherwise, the chunk had better have some free space left on it. */
- ASSERT(chunk->next_mem + pool->item_alloc_size <=
- chunk->mem + chunk->mem_size);
-
- /* Good, it did. Let's carve off a bit of that free space, and use
- * that. */
- allocated = (void*)chunk->next_mem;
- chunk->next_mem += pool->item_alloc_size;
- allocated->in_chunk = chunk;
- allocated->u.next_free = NULL; /* For debugging; not really needed. */
- }
-
- ++chunk->n_allocated;
-#ifdef MEMPOOL_STATS
- ++pool->total_items_allocated;
-#endif
-
- if (PREDICT_UNLIKELY(chunk->n_allocated == chunk->capacity)) {
- /* This chunk just became full. */
- ASSERT(chunk == pool->used_chunks);
- ASSERT(chunk->prev == NULL);
-
- /* Take it off the used list. */
- pool->used_chunks = chunk->next;
- if (chunk->next)
- chunk->next->prev = NULL;
-
- /* Put it on the full list. */
- chunk->next = pool->full_chunks;
- if (chunk->next)
- chunk->next->prev = chunk;
- pool->full_chunks = chunk;
- }
- /* And return the memory portion of the mp_allocated_t. */
- return A2M(allocated);
-}
-
-/** Return an allocated memory item to its memory pool. */
-void
-mp_pool_release(void *item)
-{
- mp_allocated_t *allocated = (void*) M2A(item);
- mp_chunk_t *chunk = allocated->in_chunk;
-
- ASSERT(chunk);
- ASSERT(chunk->magic == MP_CHUNK_MAGIC);
- ASSERT(chunk->n_allocated > 0);
-
- allocated->u.next_free = chunk->first_free;
- chunk->first_free = allocated;
-
- if (PREDICT_UNLIKELY(chunk->n_allocated == chunk->capacity)) {
- /* This chunk was full and is about to be used. */
- mp_pool_t *pool = chunk->pool;
- /* unlink from the full list */
- if (chunk->prev)
- chunk->prev->next = chunk->next;
- if (chunk->next)
- chunk->next->prev = chunk->prev;
- if (chunk == pool->full_chunks)
- pool->full_chunks = chunk->next;
-
- /* link to the used list. */
- chunk->next = pool->used_chunks;
- chunk->prev = NULL;
- if (chunk->next)
- chunk->next->prev = chunk;
- pool->used_chunks = chunk;
- } else if (PREDICT_UNLIKELY(chunk->n_allocated == 1)) {
- /* This was used and is about to be empty. */
- mp_pool_t *pool = chunk->pool;
-
- /* Unlink from the used list */
- if (chunk->prev)
- chunk->prev->next = chunk->next;
- if (chunk->next)
- chunk->next->prev = chunk->prev;
- if (chunk == pool->used_chunks)
- pool->used_chunks = chunk->next;
-
- /* Link to the empty list */
- chunk->next = pool->empty_chunks;
- chunk->prev = NULL;
- if (chunk->next)
- chunk->next->prev = chunk;
- pool->empty_chunks = chunk;
-
- /* Reset the guts of this chunk to defragment it, in case it gets
- * used again. */
- chunk->first_free = NULL;
- chunk->next_mem = chunk->mem;
-
- ++pool->n_empty_chunks;
- }
- --chunk->n_allocated;
-}
-
-/** Allocate a new memory pool to hold items of size <b>item_size</b>. We'll
- * try to fit about <b>chunk_capacity</b> bytes in each chunk. */
-mp_pool_t *
-mp_pool_new(size_t item_size, size_t chunk_capacity)
-{
- mp_pool_t *pool;
- size_t alloc_size, new_chunk_cap;
-
- tor_assert(item_size < SIZE_T_CEILING);
- tor_assert(chunk_capacity < SIZE_T_CEILING);
- tor_assert(SIZE_T_CEILING / item_size > chunk_capacity);
-
- pool = ALLOC(sizeof(mp_pool_t));
- CHECK_ALLOC(pool);
- memset(pool, 0, sizeof(mp_pool_t));
-
- /* First, we figure out how much space to allow per item. We'll want to
- * use make sure we have enough for the overhead plus the item size. */
- alloc_size = (size_t)(STRUCT_OFFSET(mp_allocated_t, u.mem) + item_size);
- /* If the item_size is less than sizeof(next_free), we need to make
- * the allocation bigger. */
- if (alloc_size < sizeof(mp_allocated_t))
- alloc_size = sizeof(mp_allocated_t);
-
- /* If we're not an even multiple of ALIGNMENT, round up. */
- if (alloc_size % ALIGNMENT) {
- alloc_size = alloc_size + ALIGNMENT - (alloc_size % ALIGNMENT);
- }
- if (alloc_size < ALIGNMENT)
- alloc_size = ALIGNMENT;
- ASSERT((alloc_size % ALIGNMENT) == 0);
-
- /* Now we figure out how many items fit in each chunk. We need to fit at
- * least 2 items per chunk. No chunk can be more than MAX_CHUNK bytes long,
- * or less than MIN_CHUNK. */
- if (chunk_capacity > MAX_CHUNK)
- chunk_capacity = MAX_CHUNK;
- /* Try to be around a power of 2 in size, since that's what allocators like
- * handing out. 512K-1 byte is a lot better than 512K+1 byte. */
- chunk_capacity = (size_t) round_to_power_of_2(chunk_capacity);
- while (chunk_capacity < alloc_size * 2 + CHUNK_OVERHEAD)
- chunk_capacity *= 2;
- if (chunk_capacity < MIN_CHUNK)
- chunk_capacity = MIN_CHUNK;
-
- new_chunk_cap = (chunk_capacity-CHUNK_OVERHEAD) / alloc_size;
- tor_assert(new_chunk_cap < INT_MAX);
- pool->new_chunk_capacity = (int)new_chunk_cap;
-
- pool->item_alloc_size = alloc_size;
-
- log_debug(LD_MM, "Capacity is %lu, item size is %lu, alloc size is %lu",
- (unsigned long)pool->new_chunk_capacity,
- (unsigned long)pool->item_alloc_size,
- (unsigned long)(pool->new_chunk_capacity*pool->item_alloc_size));
-
- return pool;
-}
-
-/** Helper function for qsort: used to sort pointers to mp_chunk_t into
- * descending order of fullness. */
-static int
-mp_pool_sort_used_chunks_helper(const void *_a, const void *_b)
-{
- mp_chunk_t *a = *(mp_chunk_t**)_a;
- mp_chunk_t *b = *(mp_chunk_t**)_b;
- return b->n_allocated - a->n_allocated;
-}
-
-/** Sort the used chunks in <b>pool</b> into descending order of fullness,
- * so that we preferentially fill up mostly full chunks before we make
- * nearly empty chunks less nearly empty. */
-static void
-mp_pool_sort_used_chunks(mp_pool_t *pool)
-{
- int i, n=0, inverted=0;
- mp_chunk_t **chunks, *chunk;
- for (chunk = pool->used_chunks; chunk; chunk = chunk->next) {
- ++n;
- if (chunk->next && chunk->next->n_allocated > chunk->n_allocated)
- ++inverted;
- }
- if (!inverted)
- return;
- //printf("Sort %d/%d\n",inverted,n);
- chunks = ALLOC(sizeof(mp_chunk_t *)*n);
-#ifdef ALLOC_CAN_RETURN_NULL
- if (PREDICT_UNLIKELY(!chunks)) return;
-#endif
- for (i=0,chunk = pool->used_chunks; chunk; chunk = chunk->next)
- chunks[i++] = chunk;
- qsort(chunks, n, sizeof(mp_chunk_t *), mp_pool_sort_used_chunks_helper);
- pool->used_chunks = chunks[0];
- chunks[0]->prev = NULL;
- for (i=1;i<n;++i) {
- chunks[i-1]->next = chunks[i];
- chunks[i]->prev = chunks[i-1];
- }
- chunks[n-1]->next = NULL;
- FREE(chunks);
- mp_pool_assert_ok(pool);
-}
-
-/** If there are more than <b>n</b> empty chunks in <b>pool</b>, free the
- * excess ones that have been empty for the longest. If
- * <b>keep_recently_used</b> is true, do not free chunks unless they have been
- * empty since the last call to this function.
- **/
-void
-mp_pool_clean(mp_pool_t *pool, int n_to_keep, int keep_recently_used)
-{
- mp_chunk_t *chunk, **first_to_free;
-
- mp_pool_sort_used_chunks(pool);
- ASSERT(n_to_keep >= 0);
-
- if (keep_recently_used) {
- int n_recently_used = pool->n_empty_chunks - pool->min_empty_chunks;
- if (n_to_keep < n_recently_used)
- n_to_keep = n_recently_used;
- }
-
- ASSERT(n_to_keep >= 0);
-
- first_to_free = &pool->empty_chunks;
- while (*first_to_free && n_to_keep > 0) {
- first_to_free = &(*first_to_free)->next;
- --n_to_keep;
- }
- if (!*first_to_free) {
- pool->min_empty_chunks = pool->n_empty_chunks;
- return;
- }
-
- chunk = *first_to_free;
- while (chunk) {
- mp_chunk_t *next = chunk->next;
- chunk->magic = 0xdeadbeef;
- FREE(chunk);
-#ifdef MEMPOOL_STATS
- ++pool->total_chunks_freed;
-#endif
- --pool->n_empty_chunks;
- chunk = next;
- }
-
- pool->min_empty_chunks = pool->n_empty_chunks;
- *first_to_free = NULL;
-}
-
-/** Helper: Given a list of chunks, free all the chunks in the list. */
-static void
-destroy_chunks(mp_chunk_t *chunk)
-{
- mp_chunk_t *next;
- while (chunk) {
- chunk->magic = 0xd3adb33f;
- next = chunk->next;
- FREE(chunk);
- chunk = next;
- }
-}
-
-/** Free all space held in <b>pool</b> This makes all pointers returned from
- * mp_pool_get(<b>pool</b>) invalid. */
-void
-mp_pool_destroy(mp_pool_t *pool)
-{
- destroy_chunks(pool->empty_chunks);
- destroy_chunks(pool->used_chunks);
- destroy_chunks(pool->full_chunks);
- memwipe(pool, 0xe0, sizeof(mp_pool_t));
- FREE(pool);
-}
-
-/** Helper: make sure that a given chunk list is not corrupt. */
-static int
-assert_chunks_ok(mp_pool_t *pool, mp_chunk_t *chunk, int empty, int full)
-{
- mp_allocated_t *allocated;
- int n = 0;
- if (chunk)
- ASSERT(chunk->prev == NULL);
-
- while (chunk) {
- n++;
- ASSERT(chunk->magic == MP_CHUNK_MAGIC);
- ASSERT(chunk->pool == pool);
- for (allocated = chunk->first_free; allocated;
- allocated = allocated->u.next_free) {
- ASSERT(allocated->in_chunk == chunk);
- }
- if (empty)
- ASSERT(chunk->n_allocated == 0);
- else if (full)
- ASSERT(chunk->n_allocated == chunk->capacity);
- else
- ASSERT(chunk->n_allocated > 0 && chunk->n_allocated < chunk->capacity);
-
- ASSERT(chunk->capacity == pool->new_chunk_capacity);
-
- ASSERT(chunk->mem_size ==
- pool->new_chunk_capacity * pool->item_alloc_size);
-
- ASSERT(chunk->next_mem >= chunk->mem &&
- chunk->next_mem <= chunk->mem + chunk->mem_size);
-
- if (chunk->next)
- ASSERT(chunk->next->prev == chunk);
-
- chunk = chunk->next;
- }
- return n;
-}
-
-/** Fail with an assertion if <b>pool</b> is not internally consistent. */
-void
-mp_pool_assert_ok(mp_pool_t *pool)
-{
- int n_empty;
-
- n_empty = assert_chunks_ok(pool, pool->empty_chunks, 1, 0);
- assert_chunks_ok(pool, pool->full_chunks, 0, 1);
- assert_chunks_ok(pool, pool->used_chunks, 0, 0);
-
- ASSERT(pool->n_empty_chunks == n_empty);
-}
-
-#ifdef TOR
-/** Dump information about <b>pool</b>'s memory usage to the Tor log at level
- * <b>severity</b>. */
-/*FFFF uses Tor logging functions. */
-void
-mp_pool_log_status(mp_pool_t *pool, int severity)
-{
- uint64_t bytes_used = 0;
- uint64_t bytes_allocated = 0;
- uint64_t bu = 0, ba = 0;
- mp_chunk_t *chunk;
- int n_full = 0, n_used = 0;
-
- ASSERT(pool);
-
- for (chunk = pool->empty_chunks; chunk; chunk = chunk->next) {
- bytes_allocated += chunk->mem_size;
- }
- log_fn(severity, LD_MM, U64_FORMAT" bytes in %d empty chunks",
- U64_PRINTF_ARG(bytes_allocated), pool->n_empty_chunks);
- for (chunk = pool->used_chunks; chunk; chunk = chunk->next) {
- ++n_used;
- bu += chunk->n_allocated * pool->item_alloc_size;
- ba += chunk->mem_size;
- log_fn(severity, LD_MM, " used chunk: %d items allocated",
- chunk->n_allocated);
- }
- log_fn(severity, LD_MM, U64_FORMAT"/"U64_FORMAT
- " bytes in %d partially full chunks",
- U64_PRINTF_ARG(bu), U64_PRINTF_ARG(ba), n_used);
- bytes_used += bu;
- bytes_allocated += ba;
- bu = ba = 0;
- for (chunk = pool->full_chunks; chunk; chunk = chunk->next) {
- ++n_full;
- bu += chunk->n_allocated * pool->item_alloc_size;
- ba += chunk->mem_size;
- }
- log_fn(severity, LD_MM, U64_FORMAT"/"U64_FORMAT
- " bytes in %d full chunks",
- U64_PRINTF_ARG(bu), U64_PRINTF_ARG(ba), n_full);
- bytes_used += bu;
- bytes_allocated += ba;
-
- log_fn(severity, LD_MM, "Total: "U64_FORMAT"/"U64_FORMAT" bytes allocated "
- "for cell pools are full.",
- U64_PRINTF_ARG(bytes_used), U64_PRINTF_ARG(bytes_allocated));
-
-#ifdef MEMPOOL_STATS
- log_fn(severity, LD_MM, U64_FORMAT" cell allocations ever; "
- U64_FORMAT" chunk allocations ever; "
- U64_FORMAT" chunk frees ever.",
- U64_PRINTF_ARG(pool->total_items_allocated),
- U64_PRINTF_ARG(pool->total_chunks_allocated),
- U64_PRINTF_ARG(pool->total_chunks_freed));
-#endif
-}
-#endif
-
diff --git a/src/common/mempool.h b/src/common/mempool.h
deleted file mode 100644
index 0fc1e4c676..0000000000
--- a/src/common/mempool.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* Copyright (c) 2007-2013, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file mempool.h
- * \brief Headers for mempool.c
- **/
-
-#ifndef TOR_MEMPOOL_H
-#define TOR_MEMPOOL_H
-
-/** A memory pool is a context in which a large number of fixed-sized
-* objects can be allocated efficiently. See mempool.c for implementation
-* details. */
-typedef struct mp_pool_t mp_pool_t;
-
-void *mp_pool_get(mp_pool_t *pool);
-void mp_pool_release(void *item);
-mp_pool_t *mp_pool_new(size_t item_size, size_t chunk_capacity);
-void mp_pool_clean(mp_pool_t *pool, int n_to_keep, int keep_recently_used);
-void mp_pool_destroy(mp_pool_t *pool);
-void mp_pool_assert_ok(mp_pool_t *pool);
-void mp_pool_log_status(mp_pool_t *pool, int severity);
-
-#define MP_POOL_ITEM_OVERHEAD (sizeof(void*))
-
-#define MEMPOOL_STATS
-
-#ifdef MEMPOOL_PRIVATE
-/* These declarations are only used by mempool.c and test.c */
-
-struct mp_pool_t {
- /** Doubly-linked list of chunks in which no items have been allocated.
- * The front of the list is the most recently emptied chunk. */
- struct mp_chunk_t *empty_chunks;
- /** Doubly-linked list of chunks in which some items have been allocated,
- * but which are not yet full. The front of the list is the chunk that has
- * most recently been modified. */
- struct mp_chunk_t *used_chunks;
- /** Doubly-linked list of chunks in which no more items can be allocated.
- * The front of the list is the chunk that has most recently become full. */
- struct mp_chunk_t *full_chunks;
- /** Length of <b>empty_chunks</b>. */
- int n_empty_chunks;
- /** Lowest value of <b>empty_chunks</b> since last call to
- * mp_pool_clean(-1). */
- int min_empty_chunks;
- /** Size of each chunk (in items). */
- int new_chunk_capacity;
- /** Size to allocate for each item, including overhead and alignment
- * padding. */
- size_t item_alloc_size;
-#ifdef MEMPOOL_STATS
- /** Total number of items allocated ever. */
- uint64_t total_items_allocated;
- /** Total number of chunks allocated ever. */
- uint64_t total_chunks_allocated;
- /** Total number of chunks freed ever. */
- uint64_t total_chunks_freed;
-#endif
-};
-#endif
-
-#endif
-
diff --git a/src/common/procmon.c b/src/common/procmon.c
index 7c9b7c3c88..2d0f021724 100644
--- a/src/common/procmon.c
+++ b/src/common/procmon.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Tor Project, Inc. */
+/* Copyright (c) 2011-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/procmon.h b/src/common/procmon.h
index b9388e2e90..ccee6bfac6 100644
--- a/src/common/procmon.h
+++ b/src/common/procmon.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Tor Project, Inc. */
+/* Copyright (c) 2011-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/sandbox.c b/src/common/sandbox.c
index e43b64b913..161eab7aad 100644
--- a/src/common/sandbox.c
+++ b/src/common/sandbox.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,6 +58,16 @@
#include <time.h>
#include <poll.h>
+#ifdef HAVE_LINUX_NETFILTER_IPV4_H
+#include <linux/netfilter_ipv4.h>
+#endif
+#ifdef HAVE_LINUX_IF_H
+#include <linux/if.h>
+#endif
+#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#endif
+
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
#define USE_BACKTRACE
@@ -98,6 +108,8 @@ static sandbox_cfg_t *filter_dynamic = NULL;
#undef SCMP_CMP
#define SCMP_CMP(a,b,c) ((struct scmp_arg_cmp){(a),(b),(c),0})
+#define SCMP_CMP_STR(a,b,c) \
+ ((struct scmp_arg_cmp) {(a),(b),(intptr_t)(void*)(c),0})
#define SCMP_CMP4(a,b,c,d) ((struct scmp_arg_cmp){(a),(b),(c),(d)})
/* We use a wrapper here because these masked comparisons seem to be pretty
* verbose. Also, it's important to cast to scmp_datum_t before negating the
@@ -117,11 +129,21 @@ static int filter_nopar_gen[] = {
SCMP_SYS(clone),
SCMP_SYS(epoll_create),
SCMP_SYS(epoll_wait),
+#ifdef HAVE_EVENTFD
+ SCMP_SYS(eventfd2),
+#endif
+#ifdef HAVE_PIPE2
+ SCMP_SYS(pipe2),
+#endif
+#ifdef HAVE_PIPE
+ SCMP_SYS(pipe),
+#endif
SCMP_SYS(fcntl),
SCMP_SYS(fstat),
#ifdef __NR_fstat64
SCMP_SYS(fstat64),
#endif
+ SCMP_SYS(futex),
SCMP_SYS(getdents64),
SCMP_SYS(getegid),
#ifdef __NR_getegid32
@@ -158,6 +180,7 @@ static int filter_nopar_gen[] = {
SCMP_SYS(read),
SCMP_SYS(rt_sigreturn),
SCMP_SYS(sched_getaffinity),
+ SCMP_SYS(sendmsg),
SCMP_SYS(set_robust_list),
#ifdef __NR_sigreturn
SCMP_SYS(sigreturn),
@@ -253,7 +276,7 @@ sb_execve(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
if (param != NULL && param->prot == 1 && param->syscall
== SCMP_SYS(execve)) {
rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(execve),
- SCMP_CMP(0, SCMP_CMP_EQ, param->value));
+ SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
if (rc != 0) {
log_err(LD_BUG,"(Sandbox) failed to add execve syscall, received "
"libseccomp error %d", rc);
@@ -390,7 +413,7 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
if (param != NULL && param->prot == 1 && param->syscall
== SCMP_SYS(open)) {
rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open),
- SCMP_CMP(0, SCMP_CMP_EQ, param->value));
+ SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
if (rc != 0) {
log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
"libseccomp error %d", rc);
@@ -445,8 +468,8 @@ sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
param->syscall == SCMP_SYS(rename)) {
rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rename),
- SCMP_CMP(0, SCMP_CMP_EQ, param->value),
- SCMP_CMP(1, SCMP_CMP_EQ, param->value2));
+ SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value),
+ SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value2));
if (rc != 0) {
log_err(LD_BUG,"(Sandbox) failed to add rename syscall, received "
"libseccomp error %d", rc);
@@ -476,7 +499,7 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
== SCMP_SYS(openat)) {
rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
SCMP_CMP(0, SCMP_CMP_EQ, AT_FDCWD),
- SCMP_CMP(1, SCMP_CMP_EQ, param->value),
+ SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value),
SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|
O_CLOEXEC));
if (rc != 0) {
@@ -532,6 +555,20 @@ sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
}
rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
+ SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX),
+ SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM),
+ SCMP_CMP(2, SCMP_CMP_EQ, 0));
+ if (rc)
+ return rc;
+
+ rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
+ SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX),
+ SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_DGRAM),
+ SCMP_CMP(2, SCMP_CMP_EQ, 0));
+ if (rc)
+ return rc;
+
+ rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
SCMP_CMP(0, SCMP_CMP_EQ, PF_NETLINK),
SCMP_CMP(1, SCMP_CMP_EQ, SOCK_RAW),
SCMP_CMP(2, SCMP_CMP_EQ, 0));
@@ -633,6 +670,22 @@ sb_getsockopt(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
if (rc)
return rc;
+#ifdef HAVE_LINUX_NETFILTER_IPV4_H
+ rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
+ SCMP_CMP(1, SCMP_CMP_EQ, SOL_IP),
+ SCMP_CMP(2, SCMP_CMP_EQ, SO_ORIGINAL_DST));
+ if (rc)
+ return rc;
+#endif
+
+#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
+ rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt),
+ SCMP_CMP(1, SCMP_CMP_EQ, SOL_IPV6),
+ SCMP_CMP(2, SCMP_CMP_EQ, IP6T_SO_ORIGINAL_DST));
+ if (rc)
+ return rc;
+#endif
+
return 0;
}
@@ -885,7 +938,7 @@ sb_stat64(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
if (param != NULL && param->prot == 1 && (param->syscall == SCMP_SYS(open)
|| param->syscall == SCMP_SYS(stat64))) {
rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat64),
- SCMP_CMP(0, SCMP_CMP_EQ, param->value));
+ SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
if (rc != 0) {
log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
"libseccomp error %d", rc);
@@ -968,7 +1021,7 @@ static int
prot_strings_helper(strmap_t *locations,
char **pr_mem_next_p,
size_t *pr_mem_left_p,
- intptr_t *value_p)
+ char **value_p)
{
char *param_val;
size_t param_size;
@@ -984,7 +1037,7 @@ prot_strings_helper(strmap_t *locations,
if (location) {
// We already interned this string.
tor_free(param_val);
- *value_p = (intptr_t) location;
+ *value_p = location;
return 0;
} else if (*pr_mem_left_p >= param_size) {
// copy to protected
@@ -993,7 +1046,7 @@ prot_strings_helper(strmap_t *locations,
// re-point el parameter to protected
tor_free(param_val);
- *value_p = (intptr_t) location;
+ *value_p = location;
strmap_set(locations, location, location); /* good real estate advice */
@@ -1075,7 +1128,7 @@ prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base));
if (ret) {
log_err(LD_BUG,"(Sandbox) mremap protected memory filter fail!");
- return ret;
+ goto out;
}
// no munmap of the protected base address
@@ -1083,7 +1136,7 @@ prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base));
if (ret) {
log_err(LD_BUG,"(Sandbox) munmap protected memory filter fail!");
- return ret;
+ goto out;
}
/*
@@ -1102,7 +1155,7 @@ prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE));
if (ret) {
log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (LT)!");
- return ret;
+ goto out;
}
ret = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect),
@@ -1112,7 +1165,7 @@ prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE));
if (ret) {
log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (GT)!");
- return ret;
+ goto out;
}
out:
@@ -1127,7 +1180,7 @@ prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
* point.
*/
static sandbox_cfg_t*
-new_element2(int syscall, intptr_t value, intptr_t value2)
+new_element2(int syscall, char *value, char *value2)
{
smp_param_t *param = NULL;
@@ -1143,9 +1196,9 @@ new_element2(int syscall, intptr_t value, intptr_t value2)
}
static sandbox_cfg_t*
-new_element(int syscall, intptr_t value)
+new_element(int syscall, char *value)
{
- return new_element2(syscall, value, 0);
+ return new_element2(syscall, value, NULL);
}
#ifdef __NR_stat64
@@ -1159,7 +1212,7 @@ sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file)
{
sandbox_cfg_t *elem = NULL;
- elem = new_element(SCMP_stat, (intptr_t)(void*) file);
+ elem = new_element(SCMP_stat, file);
if (!elem) {
log_err(LD_BUG,"(Sandbox) failed to register parameter!");
return -1;
@@ -1172,33 +1225,11 @@ sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file)
}
int
-sandbox_cfg_allow_stat_filename_array(sandbox_cfg_t **cfg, ...)
-{
- int rc = 0;
- char *fn = NULL;
-
- va_list ap;
- va_start(ap, cfg);
-
- while ((fn = va_arg(ap, char*)) != NULL) {
- rc = sandbox_cfg_allow_stat_filename(cfg, fn);
- if (rc) {
- log_err(LD_BUG,"(Sandbox) sandbox_cfg_allow_stat_filename_array fail");
- goto end;
- }
- }
-
- end:
- va_end(ap);
- return 0;
-}
-
-int
sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file)
{
sandbox_cfg_t *elem = NULL;
- elem = new_element(SCMP_SYS(open), (intptr_t)(void *) file);
+ elem = new_element(SCMP_SYS(open), file);
if (!elem) {
log_err(LD_BUG,"(Sandbox) failed to register parameter!");
return -1;
@@ -1215,9 +1246,7 @@ sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2)
{
sandbox_cfg_t *elem = NULL;
- elem = new_element2(SCMP_SYS(rename),
- (intptr_t)(void *) file1,
- (intptr_t)(void *) file2);
+ elem = new_element2(SCMP_SYS(rename), file1, file2);
if (!elem) {
log_err(LD_BUG,"(Sandbox) failed to register parameter!");
@@ -1231,33 +1260,11 @@ sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2)
}
int
-sandbox_cfg_allow_open_filename_array(sandbox_cfg_t **cfg, ...)
-{
- int rc = 0;
- char *fn = NULL;
-
- va_list ap;
- va_start(ap, cfg);
-
- while ((fn = va_arg(ap, char*)) != NULL) {
- rc = sandbox_cfg_allow_open_filename(cfg, fn);
- if (rc) {
- log_err(LD_BUG,"(Sandbox) sandbox_cfg_allow_open_filename_array fail");
- goto end;
- }
- }
-
- end:
- va_end(ap);
- return 0;
-}
-
-int
sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
{
sandbox_cfg_t *elem = NULL;
- elem = new_element(SCMP_SYS(openat), (intptr_t)(void *) file);
+ elem = new_element(SCMP_SYS(openat), file);
if (!elem) {
log_err(LD_BUG,"(Sandbox) failed to register parameter!");
return -1;
@@ -1269,35 +1276,13 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
return 0;
}
-int
-sandbox_cfg_allow_openat_filename_array(sandbox_cfg_t **cfg, ...)
-{
- int rc = 0;
- char *fn = NULL;
-
- va_list ap;
- va_start(ap, cfg);
-
- while ((fn = va_arg(ap, char*)) != NULL) {
- rc = sandbox_cfg_allow_openat_filename(cfg, fn);
- if (rc) {
- log_err(LD_BUG,"(Sandbox) sandbox_cfg_allow_openat_filename_array fail");
- goto end;
- }
- }
-
- end:
- va_end(ap);
- return 0;
-}
-
#if 0
int
sandbox_cfg_allow_execve(sandbox_cfg_t **cfg, const char *com)
{
sandbox_cfg_t *elem = NULL;
- elem = new_element(SCMP_SYS(execve), (intptr_t)(void *) com);
+ elem = new_element(SCMP_SYS(execve), com);
if (!elem) {
log_err(LD_BUG,"(Sandbox) failed to register parameter!");
return -1;
@@ -1309,28 +1294,6 @@ sandbox_cfg_allow_execve(sandbox_cfg_t **cfg, const char *com)
return 0;
}
-int
-sandbox_cfg_allow_execve_array(sandbox_cfg_t **cfg, ...)
-{
- int rc = 0;
- char *fn = NULL;
-
- va_list ap;
- va_start(ap, cfg);
-
- while ((fn = va_arg(ap, char*)) != NULL) {
-
- rc = sandbox_cfg_allow_execve(cfg, fn);
- if (rc) {
- log_err(LD_BUG,"(Sandbox) sandbox_cfg_allow_execve_array failed");
- goto end;
- }
- }
-
- end:
- va_end(ap);
- return 0;
-}
#endif
/** Cache entry for getaddrinfo results; used when sandboxing is implemented
@@ -1381,10 +1344,10 @@ static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t)
HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
cached_getaddrinfo_item_hash,
cached_getaddrinfo_items_eq);
-HT_GENERATE(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
- cached_getaddrinfo_item_hash,
- cached_getaddrinfo_items_eq,
- 0.6, tor_malloc_, tor_realloc_, tor_free_);
+HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node,
+ cached_getaddrinfo_item_hash,
+ cached_getaddrinfo_items_eq,
+ 0.6, tor_reallocarray_, tor_free_)
/** If true, don't try to cache getaddrinfo results. */
static int sandbox_getaddrinfo_cache_disabled = 0;
@@ -1398,6 +1361,13 @@ sandbox_disable_getaddrinfo_cache(void)
sandbox_getaddrinfo_cache_disabled = 1;
}
+void
+sandbox_freeaddrinfo(struct addrinfo *ai)
+{
+ if (sandbox_getaddrinfo_cache_disabled)
+ freeaddrinfo(ai);
+}
+
int
sandbox_getaddrinfo(const char *name, const char *servname,
const struct addrinfo *hints,
@@ -1732,6 +1702,9 @@ register_cfg(sandbox_cfg_t* cfg)
static int
initialise_libseccomp_sandbox(sandbox_cfg_t* cfg)
{
+ /* Prevent glibc from trying to open /dev/tty on fatal error */
+ setenv("LIBC_FATAL_STDERR_", "1", 1);
+
if (install_sigsys_debugging())
return -1;
@@ -1789,26 +1762,12 @@ sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file)
}
int
-sandbox_cfg_allow_open_filename_array(sandbox_cfg_t **cfg, ...)
-{
- (void)cfg;
- return 0;
-}
-
-int
sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file)
{
(void)cfg; (void)file;
return 0;
}
-int
-sandbox_cfg_allow_openat_filename_array(sandbox_cfg_t **cfg, ...)
-{
- (void)cfg;
- return 0;
-}
-
#if 0
int
sandbox_cfg_allow_execve(sandbox_cfg_t **cfg, const char *com)
@@ -1816,13 +1775,6 @@ sandbox_cfg_allow_execve(sandbox_cfg_t **cfg, const char *com)
(void)cfg; (void)com;
return 0;
}
-
-int
-sandbox_cfg_allow_execve_array(sandbox_cfg_t **cfg, ...)
-{
- (void)cfg;
- return 0;
-}
#endif
int
@@ -1833,13 +1785,6 @@ sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file)
}
int
-sandbox_cfg_allow_stat_filename_array(sandbox_cfg_t **cfg, ...)
-{
- (void)cfg;
- return 0;
-}
-
-int
sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2)
{
(void)cfg; (void)file1; (void)file2;
diff --git a/src/common/sandbox.h b/src/common/sandbox.h
index 35d87772fd..36d25d6516 100644
--- a/src/common/sandbox.h
+++ b/src/common/sandbox.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -66,9 +66,9 @@ typedef struct smp_param {
int syscall;
/** parameter value. */
- intptr_t value;
+ char *value;
/** parameter value, second argument. */
- intptr_t value2;
+ char *value2;
/** parameter flag (0 = not protected, 1 = protected). */
int prot;
@@ -115,7 +115,7 @@ struct addrinfo;
int sandbox_getaddrinfo(const char *name, const char *servname,
const struct addrinfo *hints,
struct addrinfo **res);
-#define sandbox_freeaddrinfo(addrinfo) ((void)0)
+void sandbox_freeaddrinfo(struct addrinfo *addrinfo);
void sandbox_free_getaddrinfo_cache(void);
#else
#define sandbox_getaddrinfo(name, servname, hints, res) \
@@ -149,14 +149,6 @@ int sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file);
/**DOCDOC*/
int sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2);
-/** Function used to add a series of open allowed filenames to a supplied
- * configuration.
- * @param cfg sandbox configuration.
- * @param ... a list of stealable pointers to permitted files. The last
- * one must be NULL.
-*/
-int sandbox_cfg_allow_open_filename_array(sandbox_cfg_t **cfg, ...);
-
/**
* Function used to add a openat allowed filename to a supplied configuration.
* The (char*) specifies the path to the allowed file; we steal the pointer to
@@ -164,28 +156,12 @@ int sandbox_cfg_allow_open_filename_array(sandbox_cfg_t **cfg, ...);
*/
int sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file);
-/** Function used to add a series of openat allowed filenames to a supplied
- * configuration.
- * @param cfg sandbox configuration.
- * @param ... a list of stealable pointers to permitted files. The last
- * one must be NULL.
- */
-int sandbox_cfg_allow_openat_filename_array(sandbox_cfg_t **cfg, ...);
-
#if 0
/**
* Function used to add a execve allowed filename to a supplied configuration.
* The (char*) specifies the path to the allowed file; that pointer is stolen.
*/
int sandbox_cfg_allow_execve(sandbox_cfg_t **cfg, const char *com);
-
-/** Function used to add a series of execve allowed filenames to a supplied
- * configuration.
- * @param cfg sandbox configuration.
- * @param ... an array of stealable pointers to permitted files. The last
- * one must be NULL.
- */
-int sandbox_cfg_allow_execve_array(sandbox_cfg_t **cfg, ...);
#endif
/**
@@ -194,14 +170,6 @@ int sandbox_cfg_allow_execve_array(sandbox_cfg_t **cfg, ...);
*/
int sandbox_cfg_allow_stat_filename(sandbox_cfg_t **cfg, char *file);
-/** Function used to add a series of stat64 allowed filenames to a supplied
- * configuration.
- * @param cfg sandbox configuration.
- * @param ... an array of stealable pointers to permitted files. The last
- * one must be NULL.
- */
-int sandbox_cfg_allow_stat_filename_array(sandbox_cfg_t **cfg, ...);
-
/** Function used to initialise a sandbox configuration.*/
int sandbox_init(sandbox_cfg_t* cfg);
diff --git a/src/common/testsupport.h b/src/common/testsupport.h
index 4a4f50b69b..db7700aeb0 100644
--- a/src/common/testsupport.h
+++ b/src/common/testsupport.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TESTSUPPORT_H
@@ -20,8 +20,8 @@
*
* and implement it as:
*
- * MOCK_IMPL(void
- * writebuf,(size_t n, char *buf)
+ * MOCK_IMPL(void,
+ * writebuf,(size_t n, char *buf))
* {
* ...
* }
diff --git a/src/common/torgzip.c b/src/common/torgzip.c
index 15451ee30d..4f23407e23 100644
--- a/src/common/torgzip.c
+++ b/src/common/torgzip.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -46,6 +46,12 @@
#include <zlib.h>
+static size_t tor_zlib_state_size_precalc(int inflate,
+ int windowbits, int memlevel);
+
+/** Total number of bytes allocated for zlib state */
+static size_t total_zlib_allocation = 0;
+
/** Set to 1 if zlib is a version that supports gzip; set to 0 if it doesn't;
* set to -1 if we haven't checked yet. */
static int gzip_is_supported = -1;
@@ -86,10 +92,27 @@ tor_zlib_get_header_version_str(void)
/** Return the 'bits' value to tell zlib to use <b>method</b>.*/
static INLINE int
-method_bits(compress_method_t method)
+method_bits(compress_method_t method, zlib_compression_level_t level)
{
/* Bits+16 means "use gzip" in zlib >= 1.2 */
- return method == GZIP_METHOD ? 15+16 : 15;
+ const int flag = method == GZIP_METHOD ? 16 : 0;
+ switch (level) {
+ default:
+ case HIGH_COMPRESSION: return flag + 15;
+ case MEDIUM_COMPRESSION: return flag + 13;
+ case LOW_COMPRESSION: return flag + 11;
+ }
+}
+
+static INLINE int
+get_memlevel(zlib_compression_level_t level)
+{
+ switch (level) {
+ default:
+ case HIGH_COMPRESSION: return 8;
+ case MEDIUM_COMPRESSION: return 7;
+ case LOW_COMPRESSION: return 6;
+ }
}
/** @{ */
@@ -156,8 +179,9 @@ tor_gzip_compress(char **out, size_t *out_len,
stream->avail_in = (unsigned int)in_len;
if (deflateInit2(stream, Z_BEST_COMPRESSION, Z_DEFLATED,
- method_bits(method),
- 8, Z_DEFAULT_STRATEGY) != Z_OK) {
+ method_bits(method, HIGH_COMPRESSION),
+ get_memlevel(HIGH_COMPRESSION),
+ Z_DEFAULT_STRATEGY) != Z_OK) {
log_warn(LD_GENERAL, "Error from deflateInit2: %s",
stream->msg?stream->msg:"<no message>");
goto err;
@@ -283,7 +307,7 @@ tor_gzip_uncompress(char **out, size_t *out_len,
stream->avail_in = (unsigned int)in_len;
if (inflateInit2(stream,
- method_bits(method)) != Z_OK) {
+ method_bits(method, HIGH_COMPRESSION)) != Z_OK) {
log_warn(LD_GENERAL, "Error from inflateInit2: %s",
stream->msg?stream->msg:"<no message>");
goto err;
@@ -309,7 +333,8 @@ tor_gzip_uncompress(char **out, size_t *out_len,
log_warn(LD_BUG, "Error freeing gzip structures");
goto err;
}
- if (inflateInit2(stream, method_bits(method)) != Z_OK) {
+ if (inflateInit2(stream,
+ method_bits(method,HIGH_COMPRESSION)) != Z_OK) {
log_warn(LD_GENERAL, "Error from second inflateInit2: %s",
stream->msg?stream->msg:"<no message>");
goto err;
@@ -411,15 +436,20 @@ struct tor_zlib_state_t {
size_t input_so_far;
/** Number of bytes written so far. Used to detect zlib bombs. */
size_t output_so_far;
+
+ /** Approximate number of bytes allocated for this object. */
+ size_t allocation;
};
/** Construct and return a tor_zlib_state_t object using <b>method</b>. If
* <b>compress</b>, it's for compression; otherwise it's for
* decompression. */
tor_zlib_state_t *
-tor_zlib_new(int compress, compress_method_t method)
+tor_zlib_new(int compress, compress_method_t method,
+ zlib_compression_level_t compression_level)
{
tor_zlib_state_t *out;
+ int bits, memlevel;
if (method == GZIP_METHOD && !is_gzip_supported()) {
/* Old zlib version don't support gzip in inflateInit2 */
@@ -427,19 +457,32 @@ tor_zlib_new(int compress, compress_method_t method)
return NULL;
}
+ if (! compress) {
+ /* use this setting for decompression, since we might have the
+ * max number of window bits */
+ compression_level = HIGH_COMPRESSION;
+ }
+
out = tor_malloc_zero(sizeof(tor_zlib_state_t));
out->stream.zalloc = Z_NULL;
out->stream.zfree = Z_NULL;
out->stream.opaque = NULL;
out->compress = compress;
+ bits = method_bits(method, compression_level);
+ memlevel = get_memlevel(compression_level);
if (compress) {
if (deflateInit2(&out->stream, Z_BEST_COMPRESSION, Z_DEFLATED,
- method_bits(method), 8, Z_DEFAULT_STRATEGY) != Z_OK)
+ bits, memlevel,
+ Z_DEFAULT_STRATEGY) != Z_OK)
goto err;
} else {
- if (inflateInit2(&out->stream, method_bits(method)) != Z_OK)
+ if (inflateInit2(&out->stream, bits) != Z_OK)
goto err;
}
+ out->allocation = tor_zlib_state_size_precalc(!compress, bits, memlevel);
+
+ total_zlib_allocation += out->allocation;
+
return out;
err:
@@ -472,7 +515,7 @@ tor_zlib_process(tor_zlib_state_t *state,
state->stream.avail_out = (unsigned int)*out_len;
if (state->compress) {
- err = deflate(&state->stream, finish ? Z_FINISH : Z_SYNC_FLUSH);
+ err = deflate(&state->stream, finish ? Z_FINISH : Z_NO_FLUSH);
} else {
err = inflate(&state->stream, finish ? Z_FINISH : Z_SYNC_FLUSH);
}
@@ -496,7 +539,7 @@ tor_zlib_process(tor_zlib_state_t *state,
case Z_STREAM_END:
return TOR_ZLIB_DONE;
case Z_BUF_ERROR:
- if (state->stream.avail_in == 0)
+ if (state->stream.avail_in == 0 && !finish)
return TOR_ZLIB_OK;
return TOR_ZLIB_BUF_FULL;
case Z_OK:
@@ -517,6 +560,8 @@ tor_zlib_free(tor_zlib_state_t *state)
if (!state)
return;
+ total_zlib_allocation -= state->allocation;
+
if (state->compress)
deflateEnd(&state->stream);
else
@@ -525,3 +570,48 @@ tor_zlib_free(tor_zlib_state_t *state)
tor_free(state);
}
+/** Return an approximate number of bytes used in RAM to hold a state with
+ * window bits <b>windowBits</b> and compression level 'memlevel' */
+static size_t
+tor_zlib_state_size_precalc(int inflate, int windowbits, int memlevel)
+{
+ windowbits &= 15;
+
+#define A_FEW_KILOBYTES 2048
+
+ if (inflate) {
+ /* From zconf.h:
+
+ "The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects."
+ */
+ return sizeof(tor_zlib_state_t) + sizeof(struct z_stream_s) +
+ (1 << 15) + A_FEW_KILOBYTES;
+ } else {
+ /* Also from zconf.h:
+
+ "The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ ... plus a few kilobytes for small objects."
+ */
+ return sizeof(tor_zlib_state_t) + sizeof(struct z_stream_s) +
+ (1 << (windowbits + 2)) + (1 << (memlevel + 9)) + A_FEW_KILOBYTES;
+ }
+#undef A_FEW_KILOBYTES
+}
+
+/** Return the approximate number of bytes allocated for <b>state</b>. */
+size_t
+tor_zlib_state_size(const tor_zlib_state_t *state)
+{
+ return state->allocation;
+}
+
+/** Return the approximate number of bytes allocated for all zlib states. */
+size_t
+tor_zlib_get_total_allocation(void)
+{
+ return total_zlib_allocation;
+}
+
diff --git a/src/common/torgzip.h b/src/common/torgzip.h
index 5db03fe6e0..0fc2deb6c4 100644
--- a/src/common/torgzip.h
+++ b/src/common/torgzip.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -19,6 +19,15 @@ typedef enum {
NO_METHOD=0, GZIP_METHOD=1, ZLIB_METHOD=2, UNKNOWN_METHOD=3
} compress_method_t;
+/**
+ * Enumeration to define tradeoffs between memory usage and compression level.
+ * HIGH_COMPRESSION saves the most bandwidth; LOW_COMPRESSION saves the most
+ * memory.
+ **/
+typedef enum {
+ HIGH_COMPRESSION, MEDIUM_COMPRESSION, LOW_COMPRESSION
+} zlib_compression_level_t;
+
int
tor_gzip_compress(char **out, size_t *out_len,
const char *in, size_t in_len,
@@ -47,7 +56,8 @@ typedef enum {
} tor_zlib_output_t;
/** Internal state for an incremental zlib compression/decompression. */
typedef struct tor_zlib_state_t tor_zlib_state_t;
-tor_zlib_state_t *tor_zlib_new(int compress, compress_method_t method);
+tor_zlib_state_t *tor_zlib_new(int compress, compress_method_t method,
+ zlib_compression_level_t level);
tor_zlib_output_t tor_zlib_process(tor_zlib_state_t *state,
char **out, size_t *out_len,
@@ -55,5 +65,8 @@ tor_zlib_output_t tor_zlib_process(tor_zlib_state_t *state,
int finish);
void tor_zlib_free(tor_zlib_state_t *state);
+size_t tor_zlib_state_size(const tor_zlib_state_t *state);
+size_t tor_zlib_get_total_allocation(void);
+
#endif
diff --git a/src/common/torint.h b/src/common/torint.h
index a993d7649a..6171700898 100644
--- a/src/common/torint.h
+++ b/src/common/torint.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -191,6 +191,10 @@ typedef unsigned __int64 uint64_t;
#endif
#endif
+#ifndef INT64_MIN
+#define INT64_MIN ((- INT64_MAX) - 1)
+#endif
+
#ifndef SIZE_MAX
#if SIZEOF_SIZE_T == 8
#define SIZE_MAX UINT64_MAX
@@ -332,30 +336,30 @@ typedef uint32_t uintptr_t;
#endif /* time_t_is_signed */
#endif /* ifndef(TIME_MAX) */
-#ifndef SIZE_T_MAX
+#ifndef SIZE_MAX
#if (SIZEOF_SIZE_T == 4)
-#define SIZE_T_MAX UINT32_MAX
+#define SIZE_MAX UINT32_MAX
#elif (SIZEOF_SIZE_T == 8)
-#define SIZE_T_MAX UINT64_MAX
+#define SIZE_MAX UINT64_MAX
#else
-#error "Can't define SIZE_T_MAX"
+#error "Can't define SIZE_MAX"
#endif
#endif
-#ifndef SSIZE_T_MAX
+#ifndef SSIZE_MAX
#if (SIZEOF_SIZE_T == 4)
-#define SSIZE_T_MAX INT32_MAX
+#define SSIZE_MAX INT32_MAX
#elif (SIZEOF_SIZE_T == 8)
-#define SSIZE_T_MAX INT64_MAX
+#define SSIZE_MAX INT64_MAX
#else
-#error "Can't define SSIZE_T_MAX"
+#error "Can't define SSIZE_MAX"
#endif
#endif
/** Any ssize_t larger than this amount is likely to be an underflow. */
-#define SSIZE_T_CEILING ((ssize_t)(SSIZE_T_MAX-16))
+#define SSIZE_T_CEILING ((ssize_t)(SSIZE_MAX-16))
/** Any size_t larger than this amount is likely to be an underflow. */
-#define SIZE_T_CEILING ((size_t)(SSIZE_T_MAX-16))
+#define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16))
#endif /* __TORINT_H */
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 34f70f3c00..8923a9e213 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001, Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -97,8 +97,10 @@
#define LD_HEARTBEAT (1u<<20)
/** Abstract channel_t code */
#define LD_CHANNEL (1u<<21)
+/** Scheduler */
+#define LD_SCHED (1u<<22)
/** Number of logging domains in the code. */
-#define N_LOGGING_DOMAINS 22
+#define N_LOGGING_DOMAINS 23
/** This log message is not safe to send to a callback-based logger
* immediately. Used as a flag, not a log domain. */
@@ -121,7 +123,7 @@ typedef struct log_severity_list_t {
/** Callback type used for add_callback_log. */
typedef void (*log_callback)(int severity, uint32_t domain, const char *msg);
-void init_logging(void);
+void init_logging(int disable_startup_queue);
int parse_log_level(const char *level);
const char *log_level_to_string(int level);
int parse_log_severity_config(const char **cfg,
@@ -130,7 +132,8 @@ void set_log_severity_config(int minSeverity, int maxSeverity,
log_severity_list_t *severity_out);
void add_stream_log(const log_severity_list_t *severity, const char *name,
int fd);
-int add_file_log(const log_severity_list_t *severity, const char *filename);
+int add_file_log(const log_severity_list_t *severity, const char *filename,
+ const int truncate);
#ifdef HAVE_SYSLOG_H
int add_syslog_log(const log_severity_list_t *severity);
#endif
@@ -146,8 +149,10 @@ void mark_logs_temp(void);
void change_callback_log_severity(int loglevelMin, int loglevelMax,
log_callback cb);
void flush_pending_log_callbacks(void);
+void flush_log_messages_from_startup(void);
void log_set_application_name(const char *name);
void set_log_time_granularity(int granularity_msec);
+void truncate_logs(void);
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
CHECK_PRINTF(3,4);
diff --git a/src/common/tortls.c b/src/common/tortls.c
index 221b47e009..379f7347db 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,10 +16,6 @@
#include "orconfig.h"
-#if defined (WINCE)
-#include <WinSock2.h>
-#endif
-
#include <assert.h>
#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
#ifndef _WIN32_WINNT
@@ -54,6 +50,8 @@
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/opensslv.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
#if __GNUC__ && GCC_VERSION >= 402
#if GCC_VERSION >= 406
@@ -478,6 +476,8 @@ tor_tls_get_error(tor_tls_t *tls, int r, int extra,
static void
tor_tls_init(void)
{
+ check_no_tls_errors();
+
if (!tls_library_is_initialized) {
long version;
SSL_library_init();
@@ -576,6 +576,8 @@ tor_tls_init(void)
void
tor_tls_free_all(void)
{
+ check_no_tls_errors();
+
if (server_tls_context) {
tor_tls_context_t *ctx = server_tls_context;
server_tls_context = NULL;
@@ -808,8 +810,7 @@ static const cipher_info_t CLIENT_CIPHER_INFO_LIST[] = {
};
/** The length of CLIENT_CIPHER_INFO_LIST and CLIENT_CIPHER_DUMMIES. */
-static const int N_CLIENT_CIPHERS =
- sizeof(CLIENT_CIPHER_INFO_LIST)/sizeof(CLIENT_CIPHER_INFO_LIST[0]);
+static const int N_CLIENT_CIPHERS = ARRAY_LENGTH(CLIENT_CIPHER_INFO_LIST);
#endif
#ifndef V2_HANDSHAKE_CLIENT
@@ -888,29 +889,33 @@ tor_cert_decode(const uint8_t *certificate, size_t certificate_len)
const unsigned char *cp = (const unsigned char *)certificate;
tor_cert_t *newcert;
tor_assert(certificate);
+ check_no_tls_errors();
if (certificate_len > INT_MAX)
- return NULL;
+ goto err;
x509 = d2i_X509(NULL, &cp, (int)certificate_len);
if (!x509)
- return NULL; /* Couldn't decode */
+ goto err; /* Couldn't decode */
if (cp - certificate != (int)certificate_len) {
X509_free(x509);
- return NULL; /* Didn't use all the bytes */
+ goto err; /* Didn't use all the bytes */
}
newcert = tor_cert_new(x509);
if (!newcert) {
- return NULL;
+ goto err;
}
if (newcert->encoded_len != certificate_len ||
fast_memneq(newcert->encoded, certificate, certificate_len)) {
/* Cert wasn't in DER */
tor_cert_free(newcert);
- return NULL;
+ goto err;
}
return newcert;
+ err:
+ tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "decoding a certificate");
+ return NULL;
}
/** Set *<b>encoded_out</b> and *<b>size_out</b> to <b>cert</b>'s encoded DER
@@ -1052,21 +1057,24 @@ tor_tls_cert_is_valid(int severity,
const tor_cert_t *signing_cert,
int check_rsa_1024)
{
+ check_no_tls_errors();
+
EVP_PKEY *cert_key;
EVP_PKEY *signing_key = X509_get_pubkey(signing_cert->cert);
int r, key_ok = 0;
+
if (!signing_key)
- return 0;
+ goto bad;
r = X509_verify(cert->cert, signing_key);
EVP_PKEY_free(signing_key);
if (r <= 0)
- return 0;
+ goto bad;
/* okay, the signature checked out right. Now let's check the check the
* lifetime. */
if (check_cert_lifetime_internal(severity, cert->cert,
48*60*60, 30*24*60*60) < 0)
- return 0;
+ goto bad;
cert_key = X509_get_pubkey(cert->cert);
if (check_rsa_1024 && cert_key) {
@@ -1086,11 +1094,14 @@ tor_tls_cert_is_valid(int severity,
}
EVP_PKEY_free(cert_key);
if (!key_ok)
- return 0;
+ goto bad;
/* XXXX compare DNs or anything? */
return 1;
+ bad:
+ tls_log_errors(NULL, LOG_INFO, LD_CRYPTO, "checking a certificate");
+ return 0;
}
/** Increase the reference count of <b>ctx</b>. */
@@ -1117,6 +1128,7 @@ tor_tls_context_init(unsigned flags,
int rv1 = 0;
int rv2 = 0;
const int is_public_server = flags & TOR_TLS_CTX_IS_PUBLIC_SERVER;
+ check_no_tls_errors();
if (is_public_server) {
tor_tls_context_t *new_ctx;
@@ -1161,6 +1173,7 @@ tor_tls_context_init(unsigned flags,
1);
}
+ tls_log_errors(NULL, LOG_WARN, LD_CRYPTO, "constructing a TLS context");
return MIN(rv1, rv2);
}
@@ -1197,6 +1210,9 @@ tor_tls_context_init_one(tor_tls_context_t **ppcontext,
return ((new_ctx != NULL) ? 0 : -1);
}
+/** The group we should use for ecdhe when none was selected. */
+#define NID_tor_default_ecdhe_group NID_X9_62_prime256v1
+
/** Create a new TLS context for use with Tor TLS handshakes.
* <b>identity</b> should be set to the identity key used to sign the
* certificate.
@@ -1392,7 +1408,7 @@ tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime,
else if (flags & TOR_TLS_CTX_USE_ECDHE_P256)
nid = NID_X9_62_prime256v1;
else
- nid = NID_X9_62_prime256v1;
+ nid = NID_tor_default_ecdhe_group;
/* Use P-256 for ECDHE. */
ec_key = EC_KEY_new_by_curve_name(nid);
if (ec_key != NULL) /*XXXX Handle errors? */
@@ -1881,11 +1897,12 @@ tor_tls_new(int sock, int isServer)
client_tls_context;
result->magic = TOR_TLS_MAGIC;
+ check_no_tls_errors();
tor_assert(context); /* make sure somebody made it first */
if (!(result->ssl = SSL_new(context->ctx))) {
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating SSL object");
tor_free(result);
- return NULL;
+ goto err;
}
#ifdef SSL_set_tlsext_host_name
@@ -1905,7 +1922,7 @@ tor_tls_new(int sock, int isServer)
#endif
SSL_free(result->ssl);
tor_free(result);
- return NULL;
+ goto err;
}
if (!isServer)
rectify_client_ciphers(&result->ssl->cipher_list);
@@ -1918,7 +1935,7 @@ tor_tls_new(int sock, int isServer)
#endif
SSL_free(result->ssl);
tor_free(result);
- return NULL;
+ goto err;
}
{
int set_worked =
@@ -1952,6 +1969,10 @@ tor_tls_new(int sock, int isServer)
if (isServer)
tor_tls_setup_session_secret_cb(result);
+ goto done;
+ err:
+ result = NULL;
+ done:
/* Not expected to get called. */
tls_log_errors(NULL, LOG_WARN, LD_NET, "creating tor_tls_t object");
return result;
@@ -2199,6 +2220,7 @@ int
tor_tls_finish_handshake(tor_tls_t *tls)
{
int r = TOR_TLS_DONE;
+ check_no_tls_errors();
if (tls->isServer) {
SSL_set_info_callback(tls->ssl, NULL);
SSL_set_verify(tls->ssl, SSL_VERIFY_PEER, always_accept_verify_cb);
@@ -2244,6 +2266,7 @@ tor_tls_finish_handshake(tor_tls_t *tls)
r = TOR_TLS_ERROR_MISC;
}
}
+ tls_log_errors(NULL, LOG_WARN, LD_NET, "finishing the handshake");
return r;
}
@@ -2274,6 +2297,8 @@ tor_tls_renegotiate(tor_tls_t *tls)
/* We could do server-initiated renegotiation too, but that would be tricky.
* Instead of "SSL_renegotiate, then SSL_do_handshake until done" */
tor_assert(!tls->isServer);
+
+ check_no_tls_errors();
if (tls->state != TOR_TLS_ST_RENEGOTIATE) {
int r = SSL_renegotiate(tls->ssl);
if (r <= 0) {
@@ -2302,6 +2327,7 @@ tor_tls_shutdown(tor_tls_t *tls)
char buf[128];
tor_assert(tls);
tor_assert(tls->ssl);
+ check_no_tls_errors();
while (1) {
if (tls->state == TOR_TLS_ST_SENTCLOSE) {
@@ -2489,6 +2515,7 @@ tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity_key)
RSA *rsa;
int r = -1;
+ check_no_tls_errors();
*identity_key = NULL;
try_to_extract_certs_from_tls(severity, tls, &cert, &id_cert);
@@ -2667,16 +2694,20 @@ check_no_tls_errors_(const char *fname, int line)
int
tor_tls_used_v1_handshake(tor_tls_t *tls)
{
+#if defined(V2_HANDSHAKE_SERVER) && defined(V2_HANDSHAKE_CLIENT)
+ return ! tls->wasV2Handshake;
+#else
if (tls->isServer) {
-#ifdef V2_HANDSHAKE_SERVER
+# ifdef V2_HANDSHAKE_SERVER
return ! tls->wasV2Handshake;
-#endif
+# endif
} else {
-#ifdef V2_HANDSHAKE_CLIENT
+# ifdef V2_HANDSHAKE_CLIENT
return ! tls->wasV2Handshake;
-#endif
+# endif
}
return 1;
+#endif
}
/** Return true iff <b>name</b> is a DN of a kind that could only
@@ -2729,6 +2760,8 @@ dn_indicates_v3_cert(X509_NAME *name)
int
tor_tls_received_v3_certificate(tor_tls_t *tls)
{
+ check_no_tls_errors();
+
X509 *cert = SSL_get_peer_certificate(tls->ssl);
EVP_PKEY *key = NULL;
X509_NAME *issuer_name, *subject_name;
@@ -2761,6 +2794,8 @@ tor_tls_received_v3_certificate(tor_tls_t *tls)
}
done:
+ tls_log_errors(tls, LOG_WARN, LD_NET, "checking for a v3 cert");
+
if (key)
EVP_PKEY_free(key);
if (cert)
diff --git a/src/common/tortls.h b/src/common/tortls.h
index a76ba3bc7a..f8c6d5913b 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TORTLS_H
diff --git a/src/common/util.c b/src/common/util.c
index 04cc6b12c6..442d57a2cf 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -96,6 +96,10 @@
#include <sys/wait.h>
#endif
+#ifdef __clang_analyzer__
+#undef MALLOC_ZERO_WORKS
+#endif
+
/* =====
* Assertion helper.
* ===== */
@@ -191,33 +195,40 @@ tor_malloc_zero_(size_t size DMALLOC_PARAMS)
return result;
}
+/* The square root of SIZE_MAX + 1. If a is less than this, and b is less
+ * than this, then a*b is less than SIZE_MAX. (For example, if size_t is
+ * 32 bits, then SIZE_MAX is 0xffffffff and this value is 0x10000. If a and
+ * b are less than this, then their product is at most (65535*65535) ==
+ * 0xfffe0001. */
+#define SQRT_SIZE_MAX_P1 (((size_t)1) << (sizeof(size_t)*4))
+
+/** Return non-zero if and only if the product of the arguments is exact. */
+static INLINE int
+size_mul_check(const size_t x, const size_t y)
+{
+ /* This first check is equivalent to
+ (x < SQRT_SIZE_MAX_P1 && y < SQRT_SIZE_MAX_P1)
+
+ Rationale: if either one of x or y is >= SQRT_SIZE_MAX_P1, then it
+ will have some bit set in its most significant half.
+ */
+ return ((x|y) < SQRT_SIZE_MAX_P1 ||
+ y == 0 ||
+ x <= SIZE_MAX / y);
+}
+
/** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill
* the memory with zero bytes, and return a pointer to the result.
* Log and terminate the process on error. (Same as
* calloc(<b>nmemb</b>,<b>size</b>), but never returns NULL.)
- *
- * XXXX This implementation probably asserts in cases where it could
- * work, because it only tries dividing SIZE_MAX by size (according to
- * the calloc(3) man page, the size of an element of the nmemb-element
- * array to be allocated), not by nmemb (which could in theory be
- * smaller than size). Don't do that then.
+ * The second argument (<b>size</b>) should preferably be non-zero
+ * and a compile-time constant.
*/
void *
tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS)
{
- /* You may ask yourself, "wouldn't it be smart to use calloc instead of
- * malloc+memset? Perhaps libc's calloc knows some nifty optimization trick
- * we don't!" Indeed it does, but its optimizations are only a big win when
- * we're allocating something very big (it knows if it just got the memory
- * from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero
- * for big stuff, so we don't bother with calloc. */
- void *result;
- size_t max_nmemb = (size == 0) ? SIZE_MAX : SIZE_MAX/size;
-
- tor_assert(nmemb < max_nmemb);
-
- result = tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS);
- return result;
+ tor_assert(size_mul_check(nmemb, size));
+ return tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS);
}
/** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b>
@@ -231,6 +242,13 @@ tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS)
tor_assert(size < SIZE_T_CEILING);
+#ifndef MALLOC_ZERO_WORKS
+ /* Some libc mallocs don't work when size==0. Override them. */
+ if (size==0) {
+ size=1;
+ }
+#endif
+
#ifdef USE_DMALLOC
result = dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0);
#else
@@ -244,6 +262,20 @@ tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS)
return result;
}
+/**
+ * Try to realloc <b>ptr</b> so that it takes up sz1 * sz2 bytes. Check for
+ * overflow. Unlike other allocation functions, return NULL on overflow.
+ */
+void *
+tor_reallocarray_(void *ptr, size_t sz1, size_t sz2 DMALLOC_PARAMS)
+{
+ /* XXXX we can make this return 0, but we would need to check all the
+ * reallocarray users. */
+ tor_assert(size_mul_check(sz1, sz2));
+
+ return tor_realloc(ptr, (sz1 * sz2) DMALLOC_FN_ARGS);
+}
+
/** Return a newly allocated copy of the NUL-terminated string s. On
* error, log and terminate. (Like strdup(s), but never returns
* NULL.)
@@ -481,6 +513,61 @@ round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor)
return number;
}
+/** Return the lowest x in [INT64_MIN, INT64_MAX] such that x is at least
+ * <b>number</b>, and x modulo <b>divisor</b> == 0. */
+int64_t
+round_int64_to_next_multiple_of(int64_t number, int64_t divisor)
+{
+ tor_assert(divisor > 0);
+ if (number >= 0 && INT64_MAX - divisor + 1 >= number)
+ number += divisor - 1;
+ number -= number % divisor;
+ return number;
+}
+
+/** Transform a random value <b>p</b> from the uniform distribution in
+ * [0.0, 1.0[ into a Laplace distributed value with location parameter
+ * <b>mu</b> and scale parameter <b>b</b>. Truncate the final result
+ * to be an integer in [INT64_MIN, INT64_MAX]. */
+int64_t
+sample_laplace_distribution(double mu, double b, double p)
+{
+ double result;
+
+ tor_assert(p >= 0.0 && p < 1.0);
+ /* This is the "inverse cumulative distribution function" from:
+ * http://en.wikipedia.org/wiki/Laplace_distribution */
+ result = mu - b * (p > 0.5 ? 1.0 : -1.0)
+ * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5));
+
+ if (result >= INT64_MAX)
+ return INT64_MAX;
+ else if (result <= INT64_MIN)
+ return INT64_MIN;
+ else
+ return (int64_t) result;
+}
+
+/** Add random noise between INT64_MIN and INT64_MAX coming from a
+ * Laplace distribution with mu = 0 and b = <b>delta_f</b>/<b>epsilon</b>
+ * to <b>signal</b> based on the provided <b>random</b> value in
+ * [0.0, 1.0[. */
+int64_t
+add_laplace_noise(int64_t signal, double random, double delta_f,
+ double epsilon)
+{
+ int64_t noise = sample_laplace_distribution(
+ 0.0, /* just add noise, no further signal */
+ delta_f / epsilon, random);
+
+ if (noise > 0 && INT64_MAX - noise < signal)
+ return INT64_MAX;
+ else if (noise < 0 && INT64_MIN - noise > signal)
+ return INT64_MIN;
+ else
+ return signal + noise;
+}
+
/** Return the number of bits set in <b>v</b>. */
int
n_bits_set_u8(uint8_t v)
@@ -932,6 +1019,68 @@ string_is_key_value(int severity, const char *string)
return 1;
}
+/** Return true if <b>string</b> represents a valid IPv4 adddress in
+ * 'a.b.c.d' form.
+ */
+int
+string_is_valid_ipv4_address(const char *string)
+{
+ struct in_addr addr;
+
+ return (tor_inet_pton(AF_INET,string,&addr) == 1);
+}
+
+/** Return true if <b>string</b> represents a valid IPv6 address in
+ * a form that inet_pton() can parse.
+ */
+int
+string_is_valid_ipv6_address(const char *string)
+{
+ struct in6_addr addr;
+
+ return (tor_inet_pton(AF_INET6,string,&addr) == 1);
+}
+
+/** Return true iff <b>string</b> matches a pattern of DNS names
+ * that we allow Tor clients to connect to.
+ */
+int
+string_is_valid_hostname(const char *string)
+{
+ int result = 1;
+ smartlist_t *components;
+
+ components = smartlist_new();
+
+ smartlist_split_string(components,string,".",0,0);
+
+ SMARTLIST_FOREACH_BEGIN(components, char *, c) {
+ if (c[0] == '-') {
+ result = 0;
+ break;
+ }
+
+ do {
+ if ((*c >= 'a' && *c <= 'z') ||
+ (*c >= 'A' && *c <= 'Z') ||
+ (*c >= '0' && *c <= '9') ||
+ (*c == '-'))
+ c++;
+ else
+ result = 0;
+ } while (result && *c);
+
+ } SMARTLIST_FOREACH_END(c);
+
+ SMARTLIST_FOREACH_BEGIN(components, char *, c) {
+ tor_free(c);
+ } SMARTLIST_FOREACH_END(c);
+
+ smartlist_free(components);
+
+ return result;
+}
+
/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */
int
tor_digest256_is_zero(const char *digest)
@@ -1186,9 +1335,14 @@ esc_for_log(const char *s)
}
}
+ tor_assert(len <= SSIZE_MAX);
+
result = outp = tor_malloc(len);
*outp++ = '\"';
for (cp = s; *cp; ++cp) {
+ /* This assertion should always succeed, since we will write at least
+ * one char here, and two chars for closing quote and nul later */
+ tor_assert((outp-result) < (ssize_t)len-2);
switch (*cp) {
case '\\':
case '\"':
@@ -1212,6 +1366,7 @@ esc_for_log(const char *s)
if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) {
*outp++ = *cp;
} else {
+ tor_assert((outp-result) < (ssize_t)len-4);
tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp);
outp += 4;
}
@@ -1219,12 +1374,27 @@ esc_for_log(const char *s)
}
}
+ tor_assert((outp-result) <= (ssize_t)len-2);
*outp++ = '\"';
*outp++ = 0;
return result;
}
+/** Similar to esc_for_log. Allocate and return a new string representing
+ * the first n characters in <b>chars</b>, surround by quotes and using
+ * standard C escapes. If a NUL character is encountered in <b>chars</b>,
+ * the resulting string will be terminated there.
+ */
+char *
+esc_for_log_len(const char *chars, size_t n)
+{
+ char *string = tor_strndup(chars, n);
+ char *string_escaped = esc_for_log(string);
+ tor_free(string);
+ return string_escaped;
+}
+
/** Allocate and return a new string representing the contents of <b>s</b>,
* surrounded by quotes and using standard C escapes.
*
@@ -1347,7 +1517,8 @@ n_leapdays(int y1, int y2)
--y2;
return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400);
}
-/** Number of days per month in non-leap year; used by tor_timegm. */
+/** Number of days per month in non-leap year; used by tor_timegm and
+ * parse_rfc1123_time. */
static const int days_per_month[] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
@@ -1361,10 +1532,32 @@ tor_timegm(const struct tm *tm, time_t *time_out)
* It's way more brute-force than fiddling with tzset().
*/
time_t year, days, hours, minutes, seconds;
- int i;
- year = tm->tm_year + 1900;
- if (year < 1970 || tm->tm_mon < 0 || tm->tm_mon > 11 ||
- tm->tm_year >= INT32_MAX-1900) {
+ int i, invalid_year, dpm;
+ /* avoid int overflow on addition */
+ if (tm->tm_year < INT32_MAX-1900) {
+ year = tm->tm_year + 1900;
+ } else {
+ /* clamp year */
+ year = INT32_MAX;
+ }
+ invalid_year = (year < 1970 || tm->tm_year >= INT32_MAX-1900);
+
+ if (tm->tm_mon >= 0 && tm->tm_mon <= 11) {
+ dpm = days_per_month[tm->tm_mon];
+ if (tm->tm_mon == 1 && !invalid_year && IS_LEAPYEAR(tm->tm_year)) {
+ dpm = 29;
+ }
+ } else {
+ /* invalid month - default to 0 days per month */
+ dpm = 0;
+ }
+
+ if (invalid_year ||
+ tm->tm_mon < 0 || tm->tm_mon > 11 ||
+ tm->tm_mday < 1 || tm->tm_mday > dpm ||
+ tm->tm_hour < 0 || tm->tm_hour > 23 ||
+ tm->tm_min < 0 || tm->tm_min > 59 ||
+ tm->tm_sec < 0 || tm->tm_sec > 60) {
log_warn(LD_BUG, "Out-of-range argument to tor_timegm");
return -1;
}
@@ -1428,8 +1621,9 @@ parse_rfc1123_time(const char *buf, time_t *t)
struct tm tm;
char month[4];
char weekday[4];
- int i, m;
+ int i, m, invalid_year;
unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec;
+ unsigned dpm;
if (strlen(buf) != RFC1123_TIME_LEN)
return -1;
@@ -1442,18 +1636,6 @@ parse_rfc1123_time(const char *buf, time_t *t)
tor_free(esc);
return -1;
}
- if (tm_mday < 1 || tm_mday > 31 || tm_hour > 23 || tm_min > 59 ||
- tm_sec > 60 || tm_year >= INT32_MAX || tm_year < 1970) {
- char *esc = esc_for_log(buf);
- log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc);
- tor_free(esc);
- return -1;
- }
- tm.tm_mday = (int)tm_mday;
- tm.tm_year = (int)tm_year;
- tm.tm_hour = (int)tm_hour;
- tm.tm_min = (int)tm_min;
- tm.tm_sec = (int)tm_sec;
m = -1;
for (i = 0; i < 12; ++i) {
@@ -1470,6 +1652,26 @@ parse_rfc1123_time(const char *buf, time_t *t)
}
tm.tm_mon = m;
+ invalid_year = (tm_year >= INT32_MAX || tm_year < 1970);
+ tor_assert(m >= 0 && m <= 11);
+ dpm = days_per_month[m];
+ if (m == 1 && !invalid_year && IS_LEAPYEAR(tm_year)) {
+ dpm = 29;
+ }
+
+ if (invalid_year || tm_mday < 1 || tm_mday > dpm ||
+ tm_hour > 23 || tm_min > 59 || tm_sec > 60) {
+ char *esc = esc_for_log(buf);
+ log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc);
+ tor_free(esc);
+ return -1;
+ }
+ tm.tm_mday = (int)tm_mday;
+ tm.tm_year = (int)tm_year;
+ tm.tm_hour = (int)tm_hour;
+ tm.tm_min = (int)tm_min;
+ tm.tm_sec = (int)tm_sec;
+
if (tm.tm_year < 1970) {
char *esc = esc_for_log(buf);
log_warn(LD_GENERAL,
@@ -1526,15 +1728,18 @@ format_iso_time_nospace_usec(char *buf, const struct timeval *tv)
/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>,
* parse it and store its value in *<b>t</b>. Return 0 on success, -1 on
- * failure. Ignore extraneous stuff in <b>cp</b> separated by whitespace from
- * the end of the time string. */
+ * failure. Ignore extraneous stuff in <b>cp</b> after the end of the time
+ * string, unless <b>strict</b> is set. */
int
-parse_iso_time(const char *cp, time_t *t)
+parse_iso_time_(const char *cp, time_t *t, int strict)
{
struct tm st_tm;
unsigned int year=0, month=0, day=0, hour=0, minute=0, second=0;
- if (tor_sscanf(cp, "%u-%2u-%2u %2u:%2u:%2u", &year, &month,
- &day, &hour, &minute, &second) < 6) {
+ int n_fields;
+ char extra_char;
+ n_fields = tor_sscanf(cp, "%u-%2u-%2u %2u:%2u:%2u%c", &year, &month,
+ &day, &hour, &minute, &second, &extra_char);
+ if (strict ? (n_fields != 6) : (n_fields < 6)) {
char *esc = esc_for_log(cp);
log_warn(LD_GENERAL, "ISO time %s was unparseable", esc);
tor_free(esc);
@@ -1563,6 +1768,16 @@ parse_iso_time(const char *cp, time_t *t)
return tor_timegm(&st_tm, t);
}
+/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>,
+ * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on
+ * failure. Reject the string if any characters are present after the time.
+ */
+int
+parse_iso_time(const char *cp, time_t *t)
+{
+ return parse_iso_time_(cp, t, 1);
+}
+
/** Given a <b>date</b> in one of the three formats allowed by HTTP (ugh),
* parse it into <b>tm</b>. Return 0 on success, negative on failure. */
int
@@ -1641,7 +1856,11 @@ format_time_interval(char *out, size_t out_len, long interval)
{
/* We only report seconds if there's no hours. */
long sec = 0, min = 0, hour = 0, day = 0;
- if (interval < 0)
+
+ /* -LONG_MIN is LONG_MAX + 1, which causes signed overflow */
+ if (interval < -LONG_MAX)
+ interval = LONG_MAX;
+ else if (interval < 0)
interval = -interval;
if (interval >= 86400) {
@@ -1757,7 +1976,7 @@ write_all(tor_socket_t fd, const char *buf, size_t count, int isSocket)
{
size_t written = 0;
ssize_t result;
- tor_assert(count < SSIZE_T_MAX);
+ tor_assert(count < SSIZE_MAX);
while (written != count) {
if (isSocket)
@@ -1782,7 +2001,7 @@ read_all(tor_socket_t fd, char *buf, size_t count, int isSocket)
size_t numread = 0;
ssize_t result;
- if (count > SIZE_T_CEILING || count > SSIZE_T_MAX)
+ if (count > SIZE_T_CEILING || count > SSIZE_MAX)
return -1;
while (numread != count) {
@@ -1823,15 +2042,24 @@ clean_name_for_stat(char *name)
#endif
}
-/** Return FN_ERROR if filename can't be read, FN_NOENT if it doesn't
- * exist, FN_FILE if it is a regular file, or FN_DIR if it's a
- * directory. On FN_ERROR, sets errno. */
+/** Return:
+ * FN_ERROR if filename can't be read, is NULL, or is zero-length,
+ * FN_NOENT if it doesn't exist,
+ * FN_FILE if it is a non-empty regular file, or a FIFO on unix-like systems,
+ * FN_EMPTY for zero-byte regular files,
+ * FN_DIR if it's a directory, and
+ * FN_ERROR for any other file type.
+ * On FN_ERROR and FN_NOENT, sets errno. (errno is not set when FN_ERROR
+ * is returned due to an unhandled file type.) */
file_status_t
file_status(const char *fname)
{
struct stat st;
char *f;
int r;
+ if (!fname || strlen(fname) == 0) {
+ return FN_ERROR;
+ }
f = tor_strdup(fname);
clean_name_for_stat(f);
log_debug(LD_FS, "stat()ing %s", f);
@@ -1843,16 +2071,23 @@ file_status(const char *fname)
}
return FN_ERROR;
}
- if (st.st_mode & S_IFDIR)
+ if (st.st_mode & S_IFDIR) {
return FN_DIR;
- else if (st.st_mode & S_IFREG)
- return FN_FILE;
+ } else if (st.st_mode & S_IFREG) {
+ if (st.st_size > 0) {
+ return FN_FILE;
+ } else if (st.st_size == 0) {
+ return FN_EMPTY;
+ } else {
+ return FN_ERROR;
+ }
#ifndef _WIN32
- else if (st.st_mode & S_IFIFO)
+ } else if (st.st_mode & S_IFIFO) {
return FN_FILE;
#endif
- else
+ } else {
return FN_ERROR;
+ }
}
/** Check whether <b>dirname</b> exists and is private. If yes return 0. If
@@ -1861,8 +2096,12 @@ file_status(const char *fname)
* <b>check</b>&CPD_CHECK, and we think we can create it, return 0. Else
* return -1. If CPD_GROUP_OK is set, then it's okay if the directory
* is group-readable, but in all cases we create the directory mode 0700.
- * If CPD_CHECK_MODE_ONLY is set, then we don't alter the directory permissions
- * if they are too permissive: we just return -1.
+ * If CPD_GROUP_READ is set, existing directory behaves as CPD_GROUP_OK and
+ * if the directory is created it will use mode 0750 with group read
+ * permission. Group read privileges also assume execute permission
+ * as norm for directories. If CPD_CHECK_MODE_ONLY is set, then we don't
+ * alter the directory permissions if they are too permissive:
+ * we just return -1.
* When effective_user is not NULL, check permissions against the given user
* and its primary group.
*/
@@ -1874,7 +2113,7 @@ check_private_dir(const char *dirname, cpd_check_t check,
struct stat st;
char *f;
#ifndef _WIN32
- int mask;
+ unsigned unwanted_bits = 0;
const struct passwd *pw = NULL;
uid_t running_uid;
gid_t running_gid;
@@ -1896,10 +2135,14 @@ check_private_dir(const char *dirname, cpd_check_t check,
}
if (check & CPD_CREATE) {
log_info(LD_GENERAL, "Creating directory %s", dirname);
-#if defined (_WIN32) && !defined (WINCE)
+#if defined (_WIN32)
r = mkdir(dirname);
#else
- r = mkdir(dirname, 0700);
+ if (check & CPD_GROUP_READ) {
+ r = mkdir(dirname, 0750);
+ } else {
+ r = mkdir(dirname, 0700);
+ }
#endif
if (r) {
log_warn(LD_FS, "Error creating directory %s: %s", dirname,
@@ -1952,7 +2195,8 @@ check_private_dir(const char *dirname, cpd_check_t check,
tor_free(process_ownername);
return -1;
}
- if ((check & CPD_GROUP_OK) && st.st_gid != running_gid) {
+ if ( (check & (CPD_GROUP_OK|CPD_GROUP_READ))
+ && (st.st_gid != running_gid) ) {
struct group *gr;
char *process_groupname = NULL;
gr = getgrgid(running_gid);
@@ -1967,12 +2211,12 @@ check_private_dir(const char *dirname, cpd_check_t check,
tor_free(process_groupname);
return -1;
}
- if (check & CPD_GROUP_OK) {
- mask = 0027;
+ if (check & (CPD_GROUP_OK|CPD_GROUP_READ)) {
+ unwanted_bits = 0027;
} else {
- mask = 0077;
+ unwanted_bits = 0077;
}
- if (st.st_mode & mask) {
+ if ((st.st_mode & unwanted_bits) != 0) {
unsigned new_mode;
if (check & CPD_CHECK_MODE_ONLY) {
log_warn(LD_FS, "Permissions on directory %s are too permissive.",
@@ -1982,10 +2226,13 @@ check_private_dir(const char *dirname, cpd_check_t check,
log_warn(LD_FS, "Fixing permissions on directory %s", dirname);
new_mode = st.st_mode;
new_mode |= 0700; /* Owner should have rwx */
- new_mode &= ~mask; /* Clear the other bits that we didn't want set...*/
+ if (check & CPD_GROUP_READ) {
+ new_mode |= 0050; /* Group should have rx */
+ }
+ new_mode &= ~unwanted_bits; /* Clear the bits that we didn't want set...*/
if (chmod(dirname, new_mode)) {
log_warn(LD_FS, "Could not chmod directory %s: %s", dirname,
- strerror(errno));
+ strerror(errno));
return -1;
} else {
return 0;
@@ -2335,6 +2582,7 @@ read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out)
pos += r;
} while (r > 0 && pos < max_bytes_to_read);
+ tor_assert(pos < string_max);
*sz_out = pos;
string[pos] = '\0';
return string;
@@ -2758,7 +3006,7 @@ expand_filename(const char *filename)
tor_free(username);
rest = slash ? (slash+1) : "";
#else
- log_warn(LD_CONFIG, "Couldn't expend homedir on system without pwd.h");
+ log_warn(LD_CONFIG, "Couldn't expand homedir on system without pwd.h");
return tor_strdup(filename);
#endif
}
@@ -2807,10 +3055,14 @@ scan_unsigned(const char **bufp, unsigned long *out, int width, int base)
while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
&& scanned_so_far < width) {
int digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
- unsigned long new_result = result * base + digit;
- if (new_result < result)
- return -1; /* over/underflow. */
- result = new_result;
+ // Check for overflow beforehand, without actually causing any overflow
+ // This preserves functionality on compilers that don't wrap overflow
+ // (i.e. that trap or optimise away overflow)
+ // result * base + digit > ULONG_MAX
+ // result * base > ULONG_MAX - digit
+ if (result > (ULONG_MAX - digit)/base)
+ return -1; /* Processing this digit would overflow */
+ result = result * base + digit;
++scanned_so_far;
}
@@ -2845,10 +3097,17 @@ scan_signed(const char **bufp, long *out, int width)
if (scan_unsigned(bufp, &result, width, 10) < 0)
return -1;
- if (neg) {
+ if (neg && result > 0) {
if (result > ((unsigned long)LONG_MAX) + 1)
return -1; /* Underflow */
- *out = -(long)result;
+ // Avoid overflow on the cast to signed long when result is LONG_MIN
+ // by subtracting 1 from the unsigned long positive value,
+ // then, after it has been cast to signed and negated,
+ // subtracting the original 1 (the double-subtraction is intentional).
+ // Otherwise, the cast to signed could cause a temporary long
+ // to equal LONG_MAX + 1, which is undefined.
+ // We avoid underflow on the subtraction by treating -0 as positive.
+ *out = (-(long)(result - 1)) - 1;
} else {
if (result > LONG_MAX)
return -1; /* Overflow */
@@ -3381,8 +3640,9 @@ format_win_cmdline_argument(const char *arg)
smartlist_add(arg_chars, (void*)&backslash);
/* Allocate space for argument, quotes (if needed), and terminator */
- formatted_arg = tor_malloc(sizeof(char) *
- (smartlist_len(arg_chars) + (need_quotes?2:0) + 1));
+ const size_t formatted_arg_len = smartlist_len(arg_chars) +
+ (need_quotes ? 2 : 0) + 1;
+ formatted_arg = tor_malloc_zero(formatted_arg_len);
/* Add leading quote */
i=0;
@@ -3547,7 +3807,13 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
/* Convert errno to be unsigned for hex conversion */
if (saved_errno < 0) {
- unsigned_errno = (unsigned int) -saved_errno;
+ // Avoid overflow on the cast to unsigned int when result is INT_MIN
+ // by adding 1 to the signed int negative value,
+ // then, after it has been negated and cast to unsigned,
+ // adding the original 1 back (the double-addition is intentional).
+ // Otherwise, the cast to signed could cause a temporary int
+ // to equal INT_MAX + 1, which is undefined.
+ unsigned_errno = ((unsigned int) -(saved_errno + 1)) + 1;
} else {
unsigned_errno = (unsigned int) saved_errno;
}
@@ -4041,8 +4307,11 @@ tor_spawn_background(const char *const filename, const char **argv,
status = process_handle->status = PROCESS_STATUS_RUNNING;
/* Set stdout/stderr pipes to be non-blocking */
- fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK);
- fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK);
+ if (fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK) < 0 ||
+ fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0) {
+ log_warn(LD_GENERAL, "Failed to set stderror/stdout pipes nonblocking "
+ "in parent process: %s", strerror(errno));
+ }
/* Open the buffered IO streams */
process_handle->stdout_handle = fdopen(process_handle->stdout_pipe, "r");
process_handle->stderr_handle = fdopen(process_handle->stderr_pipe, "r");
@@ -4376,7 +4645,7 @@ tor_read_all_handle(HANDLE h, char *buf, size_t count,
DWORD byte_count;
BOOL process_exited = FALSE;
- if (count > SIZE_T_CEILING || count > SSIZE_T_MAX)
+ if (count > SIZE_T_CEILING || count > SSIZE_MAX)
return -1;
while (numread != count) {
@@ -4442,7 +4711,7 @@ tor_read_all_handle(FILE *h, char *buf, size_t count,
if (eof)
*eof = 0;
- if (count > SIZE_T_CEILING || count > SSIZE_T_MAX)
+ if (count > SIZE_T_CEILING || count > SSIZE_MAX)
return -1;
while (numread != count) {
@@ -5011,7 +5280,7 @@ tor_check_port_forwarding(const char *filename,
for each smartlist element (one for "-p" and one for the
ports), and one for the final NULL. */
args_n = 1 + 2*smartlist_len(ports_to_forward) + 1;
- argv = tor_malloc_zero(sizeof(char*)*args_n);
+ argv = tor_calloc(args_n, sizeof(char *));
argv[argv_index++] = filename;
SMARTLIST_FOREACH_BEGIN(ports_to_forward, const char *, port) {
diff --git a/src/common/util.h b/src/common/util.h
index 97367a9a7b..ea774bd9bd 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -79,6 +79,7 @@ void *tor_malloc_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *tor_malloc_zero_(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS);
+void *tor_reallocarray_(void *ptr, size_t size1, size_t size2 DMALLOC_PARAMS);
char *tor_strdup_(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1));
char *tor_strndup_(const char *s, size_t n DMALLOC_PARAMS)
ATTR_MALLOC ATTR_NONNULL((1));
@@ -116,6 +117,8 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
#define tor_malloc_zero(size) tor_malloc_zero_(size DMALLOC_ARGS)
#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size DMALLOC_ARGS)
#define tor_realloc(ptr, size) tor_realloc_(ptr, size DMALLOC_ARGS)
+#define tor_reallocarray(ptr, sz1, sz2) \
+ tor_reallocarray_((ptr), (sz1), (sz2) DMALLOC_ARGS)
#define tor_strdup(s) tor_strdup_(s DMALLOC_ARGS)
#define tor_strndup(s, n) tor_strndup_(s, n DMALLOC_ARGS)
#define tor_memdup(s, n) tor_memdup_(s, n DMALLOC_ARGS)
@@ -169,6 +172,10 @@ uint64_t round_to_power_of_2(uint64_t u64);
unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor);
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
+int64_t round_int64_to_next_multiple_of(int64_t number, int64_t divisor);
+int64_t sample_laplace_distribution(double mu, double b, double p);
+int64_t add_laplace_noise(int64_t signal, double random, double delta_f,
+ double epsilon);
int n_bits_set_u8(uint8_t v);
/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b>
@@ -224,11 +231,15 @@ const char *find_str_at_start_of_line(const char *haystack,
const char *needle);
int string_is_C_identifier(const char *string);
int string_is_key_value(int severity, const char *string);
+int string_is_valid_hostname(const char *string);
+int string_is_valid_ipv4_address(const char *string);
+int string_is_valid_ipv6_address(const char *string);
int tor_mem_is_zero(const char *mem, size_t len);
int tor_digest_is_zero(const char *digest);
int tor_digest256_is_zero(const char *digest);
char *esc_for_log(const char *string) ATTR_MALLOC;
+char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC;
const char *escaped(const char *string);
char *tor_escape_str_for_pt_args(const char *string,
@@ -264,6 +275,7 @@ void format_local_iso_time(char *buf, time_t t);
void format_iso_time(char *buf, time_t t);
void format_iso_time_nospace(char *buf, time_t t);
void format_iso_time_nospace_usec(char *buf, const struct timeval *tv);
+int parse_iso_time_(const char *cp, time_t *t, int strict);
int parse_iso_time(const char *buf, time_t *t);
int parse_http_time(const char *buf, struct tm *tm);
int format_time_interval(char *out, size_t out_len, long interval);
@@ -331,7 +343,7 @@ enum stream_status get_string_from_pipe(FILE *stream, char *buf, size_t count);
/** Return values from file_status(); see that function's documentation
* for details. */
-typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR } file_status_t;
+typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t;
file_status_t file_status(const char *filename);
/** Possible behaviors for check_private_dir() on encountering a nonexistent
@@ -341,9 +353,11 @@ typedef unsigned int cpd_check_t;
#define CPD_CREATE 1
#define CPD_CHECK 2
#define CPD_GROUP_OK 4
-#define CPD_CHECK_MODE_ONLY 8
+#define CPD_GROUP_READ 8
+#define CPD_CHECK_MODE_ONLY 16
int check_private_dir(const char *dirname, cpd_check_t check,
const char *effective_user);
+
#define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC)
#define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND)
#define OPEN_FLAGS_DONT_REPLACE (O_CREAT|O_EXCL|O_APPEND|O_WRONLY)
@@ -551,7 +565,7 @@ STATIC int format_helper_exit_status(unsigned char child_state,
const char *libor_get_digests(void);
-#define ARRAY_LENGTH(x) (sizeof(x)) / sizeof(x[0])
+#define ARRAY_LENGTH(x) ((sizeof(x)) / sizeof(x[0]))
#endif
diff --git a/src/common/util_process.c b/src/common/util_process.c
index d6ef590162..849a5c0b63 100644
--- a/src/common/util_process.c
+++ b/src/common/util_process.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -62,8 +62,8 @@ static HT_HEAD(process_map, waitpid_callback_t) process_map = HT_INITIALIZER();
HT_PROTOTYPE(process_map, waitpid_callback_t, node, process_map_entry_hash_,
process_map_entries_eq_);
-HT_GENERATE(process_map, waitpid_callback_t, node, process_map_entry_hash_,
- process_map_entries_eq_, 0.6, malloc, realloc, free);
+HT_GENERATE2(process_map, waitpid_callback_t, node, process_map_entry_hash_,
+ process_map_entries_eq_, 0.6, tor_reallocarray_, tor_free_);
/**
* Begin monitoring the child pid <b>pid</b> to see if we get a SIGCHLD for
diff --git a/src/common/util_process.h b/src/common/util_process.h
index 0b268b85d3..c55cd8c5fa 100644
--- a/src/common/util_process.h
+++ b/src/common/util_process.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Tor Project, Inc. */
+/* Copyright (c) 2011-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/common/workqueue.c b/src/common/workqueue.c
new file mode 100644
index 0000000000..c1bd6d4e8b
--- /dev/null
+++ b/src/common/workqueue.c
@@ -0,0 +1,495 @@
+/* copyright (c) 2013-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "compat.h"
+#include "compat_threads.h"
+#include "util.h"
+#include "workqueue.h"
+#include "tor_queue.h"
+#include "torlog.h"
+
+struct threadpool_s {
+ /** An array of pointers to workerthread_t: one for each running worker
+ * thread. */
+ struct workerthread_s **threads;
+
+ /** Condition variable that we wait on when we have no work, and which
+ * gets signaled when our queue becomes nonempty. */
+ tor_cond_t condition;
+ /** Queue of pending work that we have to do. */
+ TOR_TAILQ_HEAD(, workqueue_entry_s) work;
+
+ /** The current 'update generation' of the threadpool. Any thread that is
+ * at an earlier generation needs to run the update function. */
+ unsigned generation;
+
+ /** Function that should be run for updates on each thread. */
+ int (*update_fn)(void *, void *);
+ /** Function to free update arguments if they can't be run. */
+ void (*free_update_arg_fn)(void *);
+ /** Array of n_threads update arguments. */
+ void **update_args;
+
+ /** Number of elements in threads. */
+ int n_threads;
+ /** Mutex to protect all the above fields. */
+ tor_mutex_t lock;
+
+ /** A reply queue to use when constructing new threads. */
+ replyqueue_t *reply_queue;
+
+ /** Functions used to allocate and free thread state. */
+ void *(*new_thread_state_fn)(void*);
+ void (*free_thread_state_fn)(void*);
+ void *new_thread_state_arg;
+};
+
+struct workqueue_entry_s {
+ /** The next workqueue_entry_t that's pending on the same thread or
+ * reply queue. */
+ TOR_TAILQ_ENTRY(workqueue_entry_s) next_work;
+ /** The threadpool to which this workqueue_entry_t was assigned. This field
+ * is set when the workqueue_entry_t is created, and won't be cleared until
+ * after it's handled in the main thread. */
+ struct threadpool_s *on_pool;
+ /** True iff this entry is waiting for a worker to start processing it. */
+ uint8_t pending;
+ /** Function to run in the worker thread. */
+ int (*fn)(void *state, void *arg);
+ /** Function to run while processing the reply queue. */
+ void (*reply_fn)(void *arg);
+ /** Argument for the above functions. */
+ void *arg;
+};
+
+struct replyqueue_s {
+ /** Mutex to protect the answers field */
+ tor_mutex_t lock;
+ /** Doubly-linked list of answers that the reply queue needs to handle. */
+ TOR_TAILQ_HEAD(, workqueue_entry_s) answers;
+
+ /** Mechanism to wake up the main thread when it is receiving answers. */
+ alert_sockets_t alert;
+};
+
+/** A worker thread represents a single thread in a thread pool. To avoid
+ * contention, each gets its own queue. This breaks the guarantee that that
+ * queued work will get executed strictly in order. */
+typedef struct workerthread_s {
+ /** Which thread it this? In range 0..in_pool->n_threads-1 */
+ int index;
+ /** The pool this thread is a part of. */
+ struct threadpool_s *in_pool;
+ /** User-supplied state field that we pass to the worker functions of each
+ * work item. */
+ void *state;
+ /** Reply queue to which we pass our results. */
+ replyqueue_t *reply_queue;
+ /** The current update generation of this thread */
+ unsigned generation;
+} workerthread_t;
+
+static void queue_reply(replyqueue_t *queue, workqueue_entry_t *work);
+
+/** Allocate and return a new workqueue_entry_t, set up to run the function
+ * <b>fn</b> in the worker thread, and <b>reply_fn</b> in the main
+ * thread. See threadpool_queue_work() for full documentation. */
+static workqueue_entry_t *
+workqueue_entry_new(int (*fn)(void*, void*),
+ void (*reply_fn)(void*),
+ void *arg)
+{
+ workqueue_entry_t *ent = tor_malloc_zero(sizeof(workqueue_entry_t));
+ ent->fn = fn;
+ ent->reply_fn = reply_fn;
+ ent->arg = arg;
+ return ent;
+}
+
+/**
+ * Release all storage held in <b>ent</b>. Call only when <b>ent</b> is not on
+ * any queue.
+ */
+static void
+workqueue_entry_free(workqueue_entry_t *ent)
+{
+ if (!ent)
+ return;
+ memset(ent, 0xf0, sizeof(*ent));
+ tor_free(ent);
+}
+
+/**
+ * Cancel a workqueue_entry_t that has been returned from
+ * threadpool_queue_work.
+ *
+ * You must not call this function on any work whose reply function has been
+ * executed in the main thread; that will cause undefined behavior (probably,
+ * a crash).
+ *
+ * If the work is cancelled, this function return the argument passed to the
+ * work function. It is the caller's responsibility to free this storage.
+ *
+ * This function will have no effect if the worker thread has already executed
+ * or begun to execute the work item. In that case, it will return NULL.
+ */
+void *
+workqueue_entry_cancel(workqueue_entry_t *ent)
+{
+ int cancelled = 0;
+ void *result = NULL;
+ tor_mutex_acquire(&ent->on_pool->lock);
+ if (ent->pending) {
+ TOR_TAILQ_REMOVE(&ent->on_pool->work, ent, next_work);
+ cancelled = 1;
+ result = ent->arg;
+ }
+ tor_mutex_release(&ent->on_pool->lock);
+
+ if (cancelled) {
+ workqueue_entry_free(ent);
+ }
+ return result;
+}
+
+/**DOCDOC
+
+ must hold lock */
+static int
+worker_thread_has_work(workerthread_t *thread)
+{
+ return !TOR_TAILQ_EMPTY(&thread->in_pool->work) ||
+ thread->generation != thread->in_pool->generation;
+}
+
+/**
+ * Main function for the worker thread.
+ */
+static void
+worker_thread_main(void *thread_)
+{
+ workerthread_t *thread = thread_;
+ threadpool_t *pool = thread->in_pool;
+ workqueue_entry_t *work;
+ int result;
+
+ tor_mutex_acquire(&pool->lock);
+ while (1) {
+ /* lock must be held at this point. */
+ while (worker_thread_has_work(thread)) {
+ /* lock must be held at this point. */
+ if (thread->in_pool->generation != thread->generation) {
+ void *arg = thread->in_pool->update_args[thread->index];
+ thread->in_pool->update_args[thread->index] = NULL;
+ int (*update_fn)(void*,void*) = thread->in_pool->update_fn;
+ thread->generation = thread->in_pool->generation;
+ tor_mutex_release(&pool->lock);
+
+ int r = update_fn(thread->state, arg);
+
+ if (r < 0) {
+ return;
+ }
+
+ tor_mutex_acquire(&pool->lock);
+ continue;
+ }
+ work = TOR_TAILQ_FIRST(&pool->work);
+ TOR_TAILQ_REMOVE(&pool->work, work, next_work);
+ work->pending = 0;
+ tor_mutex_release(&pool->lock);
+
+ /* We run the work function without holding the thread lock. This
+ * is the main thread's first opportunity to give us more work. */
+ result = work->fn(thread->state, work->arg);
+
+ /* Queue the reply for the main thread. */
+ queue_reply(thread->reply_queue, work);
+
+ /* We may need to exit the thread. */
+ if (result >= WQ_RPL_ERROR) {
+ return;
+ }
+ tor_mutex_acquire(&pool->lock);
+ }
+ /* At this point the lock is held, and there is no work in this thread's
+ * queue. */
+
+ /* TODO: support an idle-function */
+
+ /* Okay. Now, wait till somebody has work for us. */
+ if (tor_cond_wait(&pool->condition, &pool->lock, NULL) < 0) {
+ log_warn(LD_GENERAL, "Fail tor_cond_wait.");
+ }
+ }
+}
+
+/** Put a reply on the reply queue. The reply must not currently be on
+ * any thread's work queue. */
+static void
+queue_reply(replyqueue_t *queue, workqueue_entry_t *work)
+{
+ int was_empty;
+ tor_mutex_acquire(&queue->lock);
+ was_empty = TOR_TAILQ_EMPTY(&queue->answers);
+ TOR_TAILQ_INSERT_TAIL(&queue->answers, work, next_work);
+ tor_mutex_release(&queue->lock);
+
+ if (was_empty) {
+ if (queue->alert.alert_fn(queue->alert.write_fd) < 0) {
+ /* XXXX complain! */
+ }
+ }
+}
+
+/** Allocate and start a new worker thread to use state object <b>state</b>,
+ * and send responses to <b>replyqueue</b>. */
+static workerthread_t *
+workerthread_new(void *state, threadpool_t *pool, replyqueue_t *replyqueue)
+{
+ workerthread_t *thr = tor_malloc_zero(sizeof(workerthread_t));
+ thr->state = state;
+ thr->reply_queue = replyqueue;
+ thr->in_pool = pool;
+
+ if (spawn_func(worker_thread_main, thr) < 0) {
+ log_err(LD_GENERAL, "Can't launch worker thread.");
+ return NULL;
+ }
+
+ return thr;
+}
+
+/**
+ * Queue an item of work for a thread in a thread pool. The function
+ * <b>fn</b> will be run in a worker thread, and will receive as arguments the
+ * thread's state object, and the provided object <b>arg</b>. It must return
+ * one of WQ_RPL_REPLY, WQ_RPL_ERROR, or WQ_RPL_SHUTDOWN.
+ *
+ * Regardless of its return value, the function <b>reply_fn</b> will later be
+ * run in the main thread when it invokes replyqueue_process(), and will
+ * receive as its argument the same <b>arg</b> object. It's the reply
+ * function's responsibility to free the work object.
+ *
+ * On success, return a workqueue_entry_t object that can be passed to
+ * workqueue_entry_cancel(). On failure, return NULL.
+ *
+ * Note that because each thread has its own work queue, work items may not
+ * be executed strictly in order.
+ */
+workqueue_entry_t *
+threadpool_queue_work(threadpool_t *pool,
+ int (*fn)(void *, void *),
+ void (*reply_fn)(void *),
+ void *arg)
+{
+ workqueue_entry_t *ent = workqueue_entry_new(fn, reply_fn, arg);
+ ent->on_pool = pool;
+ ent->pending = 1;
+
+ tor_mutex_acquire(&pool->lock);
+
+ TOR_TAILQ_INSERT_TAIL(&pool->work, ent, next_work);
+
+ tor_mutex_release(&pool->lock);
+
+ tor_cond_signal_one(&pool->condition);
+
+ return ent;
+}
+
+/**
+ * Queue a copy of a work item for every thread in a pool. This can be used,
+ * for example, to tell the threads to update some parameter in their states.
+ *
+ * Arguments are as for <b>threadpool_queue_work</b>, except that the
+ * <b>arg</b> value is passed to <b>dup_fn</b> once per each thread to
+ * make a copy of it.
+ *
+ * UPDATE FUNCTIONS MUST BE IDEMPOTENT. We do not guarantee that every update
+ * will be run. If a new update is scheduled before the old update finishes
+ * running, then the new will replace the old in any threads that haven't run
+ * it yet.
+ *
+ * Return 0 on success, -1 on failure.
+ */
+int
+threadpool_queue_update(threadpool_t *pool,
+ void *(*dup_fn)(void *),
+ int (*fn)(void *, void *),
+ void (*free_fn)(void *),
+ void *arg)
+{
+ int i, n_threads;
+ void (*old_args_free_fn)(void *arg);
+ void **old_args;
+ void **new_args;
+
+ tor_mutex_acquire(&pool->lock);
+ n_threads = pool->n_threads;
+ old_args = pool->update_args;
+ old_args_free_fn = pool->free_update_arg_fn;
+
+ new_args = tor_calloc(n_threads, sizeof(void*));
+ for (i = 0; i < n_threads; ++i) {
+ if (dup_fn)
+ new_args[i] = dup_fn(arg);
+ else
+ new_args[i] = arg;
+ }
+
+ pool->update_args = new_args;
+ pool->free_update_arg_fn = free_fn;
+ pool->update_fn = fn;
+ ++pool->generation;
+
+ tor_mutex_release(&pool->lock);
+
+ tor_cond_signal_all(&pool->condition);
+
+ if (old_args) {
+ for (i = 0; i < n_threads; ++i) {
+ if (old_args[i] && old_args_free_fn)
+ old_args_free_fn(old_args[i]);
+ }
+ tor_free(old_args);
+ }
+
+ return 0;
+}
+
+/** Launch threads until we have <b>n</b>. */
+static int
+threadpool_start_threads(threadpool_t *pool, int n)
+{
+ if (n < 0)
+ return -1;
+
+ tor_mutex_acquire(&pool->lock);
+
+ if (pool->n_threads < n)
+ pool->threads = tor_reallocarray(pool->threads,
+ sizeof(workerthread_t*), n);
+
+ while (pool->n_threads < n) {
+ void *state = pool->new_thread_state_fn(pool->new_thread_state_arg);
+ workerthread_t *thr = workerthread_new(state, pool, pool->reply_queue);
+
+ if (!thr) {
+ tor_mutex_release(&pool->lock);
+ return -1;
+ }
+ thr->index = pool->n_threads;
+ pool->threads[pool->n_threads++] = thr;
+ }
+ tor_mutex_release(&pool->lock);
+
+ return 0;
+}
+
+/**
+ * Construct a new thread pool with <b>n</b> worker threads, configured to
+ * send their output to <b>replyqueue</b>. The threads' states will be
+ * constructed with the <b>new_thread_state_fn</b> call, receiving <b>arg</b>
+ * as its argument. When the threads close, they will call
+ * <b>free_thread_state_fn</b> on their states.
+ */
+threadpool_t *
+threadpool_new(int n_threads,
+ replyqueue_t *replyqueue,
+ void *(*new_thread_state_fn)(void*),
+ void (*free_thread_state_fn)(void*),
+ void *arg)
+{
+ threadpool_t *pool;
+ pool = tor_malloc_zero(sizeof(threadpool_t));
+ tor_mutex_init_nonrecursive(&pool->lock);
+ tor_cond_init(&pool->condition);
+ TOR_TAILQ_INIT(&pool->work);
+
+ pool->new_thread_state_fn = new_thread_state_fn;
+ pool->new_thread_state_arg = arg;
+ pool->free_thread_state_fn = free_thread_state_fn;
+ pool->reply_queue = replyqueue;
+
+ if (threadpool_start_threads(pool, n_threads) < 0) {
+ tor_cond_uninit(&pool->condition);
+ tor_mutex_uninit(&pool->lock);
+ tor_free(pool);
+ return NULL;
+ }
+
+ return pool;
+}
+
+/** Return the reply queue associated with a given thread pool. */
+replyqueue_t *
+threadpool_get_replyqueue(threadpool_t *tp)
+{
+ return tp->reply_queue;
+}
+
+/** Allocate a new reply queue. Reply queues are used to pass results from
+ * worker threads to the main thread. Since the main thread is running an
+ * IO-centric event loop, it needs to get woken up with means other than a
+ * condition variable. */
+replyqueue_t *
+replyqueue_new(uint32_t alertsocks_flags)
+{
+ replyqueue_t *rq;
+
+ rq = tor_malloc_zero(sizeof(replyqueue_t));
+ if (alert_sockets_create(&rq->alert, alertsocks_flags) < 0) {
+ tor_free(rq);
+ return NULL;
+ }
+
+ tor_mutex_init(&rq->lock);
+ TOR_TAILQ_INIT(&rq->answers);
+
+ return rq;
+}
+
+/**
+ * Return the "read socket" for a given reply queue. The main thread should
+ * listen for read events on this socket, and call replyqueue_process() every
+ * time it triggers.
+ */
+tor_socket_t
+replyqueue_get_socket(replyqueue_t *rq)
+{
+ return rq->alert.read_fd;
+}
+
+/**
+ * Process all pending replies on a reply queue. The main thread should call
+ * this function every time the socket returned by replyqueue_get_socket() is
+ * readable.
+ */
+void
+replyqueue_process(replyqueue_t *queue)
+{
+ if (queue->alert.drain_fn(queue->alert.read_fd) < 0) {
+ static ratelim_t warn_limit = RATELIM_INIT(7200);
+ log_fn_ratelim(&warn_limit, LOG_WARN, LD_GENERAL,
+ "Failure from drain_fd");
+ }
+
+ tor_mutex_acquire(&queue->lock);
+ while (!TOR_TAILQ_EMPTY(&queue->answers)) {
+ /* lock must be held at this point.*/
+ workqueue_entry_t *work = TOR_TAILQ_FIRST(&queue->answers);
+ TOR_TAILQ_REMOVE(&queue->answers, work, next_work);
+ tor_mutex_release(&queue->lock);
+ work->on_pool = NULL;
+
+ work->reply_fn(work->arg);
+ workqueue_entry_free(work);
+
+ tor_mutex_acquire(&queue->lock);
+ }
+
+ tor_mutex_release(&queue->lock);
+}
+
diff --git a/src/common/workqueue.h b/src/common/workqueue.h
new file mode 100644
index 0000000000..92e82b8a48
--- /dev/null
+++ b/src/common/workqueue.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_WORKQUEUE_H
+#define TOR_WORKQUEUE_H
+
+#include "compat.h"
+
+/** A replyqueue is used to tell the main thread about the outcome of
+ * work that we queued for the the workers. */
+typedef struct replyqueue_s replyqueue_t;
+/** A thread-pool manages starting threads and passing work to them. */
+typedef struct threadpool_s threadpool_t;
+/** A workqueue entry represents a request that has been passed to a thread
+ * pool. */
+typedef struct workqueue_entry_s workqueue_entry_t;
+
+/** Possible return value from a work function: indicates success. */
+#define WQ_RPL_REPLY 0
+/** Possible return value from a work function: indicates fatal error */
+#define WQ_RPL_ERROR 1
+/** Possible return value from a work function: indicates thread is shutting
+ * down. */
+#define WQ_RPL_SHUTDOWN 2
+
+workqueue_entry_t *threadpool_queue_work(threadpool_t *pool,
+ int (*fn)(void *, void *),
+ void (*reply_fn)(void *),
+ void *arg);
+int threadpool_queue_update(threadpool_t *pool,
+ void *(*dup_fn)(void *),
+ int (*fn)(void *, void *),
+ void (*free_fn)(void *),
+ void *arg);
+void *workqueue_entry_cancel(workqueue_entry_t *pending_work);
+threadpool_t *threadpool_new(int n_threads,
+ replyqueue_t *replyqueue,
+ void *(*new_thread_state_fn)(void*),
+ void (*free_thread_state_fn)(void*),
+ void *arg);
+replyqueue_t *threadpool_get_replyqueue(threadpool_t *tp);
+
+replyqueue_t *replyqueue_new(uint32_t alertsocks_flags);
+tor_socket_t replyqueue_get_socket(replyqueue_t *rq);
+void replyqueue_process(replyqueue_t *queue);
+
+#endif
+
diff --git a/src/config/include.am b/src/config/include.am
index 35961b829a..c283628513 100644
--- a/src/config/include.am
+++ b/src/config/include.am
@@ -2,7 +2,7 @@ confdir = $(sysconfdir)/tor
tordatadir = $(datadir)/tor
-EXTRA_DIST+= src/config/geoip src/config/geoip6
+EXTRA_DIST+= src/config/geoip src/config/geoip6 src/config/torrc.minimal.in
# fallback-consensus
conf_DATA = src/config/torrc.sample
diff --git a/src/config/torrc.minimal.in b/src/config/torrc.minimal.in
new file mode 100644
index 0000000000..d842fbcaf5
--- /dev/null
+++ b/src/config/torrc.minimal.in
@@ -0,0 +1,192 @@
+## Configuration file for a typical Tor user
+## Last updated 9 October 2013 for Tor 0.2.5.2-alpha.
+## (may or may not work for much older or much newer versions of Tor.)
+##
+## Lines that begin with "## " try to explain what's going on. Lines
+## that begin with just "#" are disabled commands: you can enable them
+## by removing the "#" symbol.
+##
+## See 'man tor', or https://www.torproject.org/docs/tor-manual.html,
+## for more options you can use in this file.
+##
+## Tor will look for this file in various places based on your platform:
+## https://www.torproject.org/docs/faq#torrc
+
+## Tor opens a socks proxy on port 9050 by default -- even if you don't
+## configure one below. Set "SocksPort 0" if you plan to run Tor only
+## as a relay, and not make any local application connections yourself.
+#SocksPort 9050 # Default: Bind to localhost:9050 for local connections.
+#SocksPort 192.168.0.1:9100 # Bind to this address:port too.
+
+## Entry policies to allow/deny SOCKS requests based on IP address.
+## First entry that matches wins. If no SocksPolicy is set, we accept
+## all (and only) requests that reach a SocksPort. Untrusted users who
+## can access your SocksPort may be able to learn about the connections
+## you make.
+#SocksPolicy accept 192.168.0.0/16
+#SocksPolicy reject *
+
+## Logs go to stdout at level "notice" unless redirected by something
+## else, like one of the below lines. You can have as many Log lines as
+## you want.
+##
+## We advise using "notice" in most cases, since anything more verbose
+## may provide sensitive information to an attacker who obtains the logs.
+##
+## Send all messages of level 'notice' or higher to @LOCALSTATEDIR@/log/tor/notices.log
+#Log notice file @LOCALSTATEDIR@/log/tor/notices.log
+## Send every possible message to @LOCALSTATEDIR@/log/tor/debug.log
+#Log debug file @LOCALSTATEDIR@/log/tor/debug.log
+## Use the system log instead of Tor's logfiles
+#Log notice syslog
+## To send all messages to stderr:
+#Log debug stderr
+
+## Uncomment this to start the process in the background... or use
+## --runasdaemon 1 on the command line. This is ignored on Windows;
+## see the FAQ entry if you want Tor to run as an NT service.
+#RunAsDaemon 1
+
+## The directory for keeping all the keys/etc. By default, we store
+## things in $HOME/.tor on Unix, and in Application Data\tor on Windows.
+#DataDirectory @LOCALSTATEDIR@/lib/tor
+
+## The port on which Tor will listen for local connections from Tor
+## controller applications, as documented in control-spec.txt.
+#ControlPort 9051
+## If you enable the controlport, be sure to enable one of these
+## authentication methods, to prevent attackers from accessing it.
+#HashedControlPassword 16:872860B76453A77D60CA2BB8C1A7042072093276A3D701AD684053EC4C
+#CookieAuthentication 1
+
+############### This section is just for location-hidden services ###
+
+## Once you have configured a hidden service, you can look at the
+## contents of the file ".../hidden_service/hostname" for the address
+## to tell people.
+##
+## HiddenServicePort x y:z says to redirect requests on port x to the
+## address y:z.
+
+#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/hidden_service/
+#HiddenServicePort 80 127.0.0.1:80
+
+#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/other_hidden_service/
+#HiddenServicePort 80 127.0.0.1:80
+#HiddenServicePort 22 127.0.0.1:22
+
+################ This section is just for relays #####################
+#
+## See https://www.torproject.org/docs/tor-doc-relay for details.
+
+## Required: what port to advertise for incoming Tor connections.
+#ORPort 9001
+## If you want to listen on a port other than the one advertised in
+## ORPort (e.g. to advertise 443 but bind to 9090), you can do it as
+## follows. You'll need to do ipchains or other port forwarding
+## yourself to make this work.
+#ORPort 443 NoListen
+#ORPort 127.0.0.1:9090 NoAdvertise
+
+## The IP address or full DNS name for incoming connections to your
+## relay. Leave commented out and Tor will guess.
+#Address noname.example.com
+
+## If you have multiple network interfaces, you can specify one for
+## outgoing traffic to use.
+# OutboundBindAddress 10.0.0.5
+
+## A handle for your relay, so people don't have to refer to it by key.
+#Nickname ididnteditheconfig
+
+## Define these to limit how much relayed traffic you will allow. Your
+## own traffic is still unthrottled. Note that RelayBandwidthRate must
+## be at least 20 KB.
+## Note that units for these config options are bytes per second, not bits
+## per second, and that prefixes are binary prefixes, i.e. 2^10, 2^20, etc.
+#RelayBandwidthRate 100 KB # Throttle traffic to 100KB/s (800Kbps)
+#RelayBandwidthBurst 200 KB # But allow bursts up to 200KB/s (1600Kbps)
+
+## Use these to restrict the maximum traffic per day, week, or month.
+## Note that this threshold applies separately to sent and received bytes,
+## not to their sum: setting "4 GB" may allow up to 8 GB total before
+## hibernating.
+##
+## Set a maximum of 4 gigabytes each way per period.
+#AccountingMax 4 GB
+## Each period starts daily at midnight (AccountingMax is per day)
+#AccountingStart day 00:00
+## Each period starts on the 3rd of the month at 15:00 (AccountingMax
+## is per month)
+#AccountingStart month 3 15:00
+
+## Administrative contact information for this relay or bridge. This line
+## can be used to contact you if your relay or bridge is misconfigured or
+## something else goes wrong. Note that we archive and publish all
+## descriptors containing these lines and that Google indexes them, so
+## spammers might also collect them. You may want to obscure the fact that
+## it's an email address and/or generate a new address for this purpose.
+#ContactInfo Random Person <nobody AT example dot com>
+## You might also include your PGP or GPG fingerprint if you have one:
+#ContactInfo 0xFFFFFFFF Random Person <nobody AT example dot com>
+
+## Uncomment this to mirror directory information for others. Please do
+## if you have enough bandwidth.
+#DirPort 9030 # what port to advertise for directory connections
+## If you want to listen on a port other than the one advertised in
+## DirPort (e.g. to advertise 80 but bind to 9091), you can do it as
+## follows. below too. You'll need to do ipchains or other port
+## forwarding yourself to make this work.
+#DirPort 80 NoListen
+#DirPort 127.0.0.1:9091 NoAdvertise
+## Uncomment to return an arbitrary blob of html on your DirPort. Now you
+## can explain what Tor is if anybody wonders why your IP address is
+## contacting them. See contrib/tor-exit-notice.html in Tor's source
+## distribution for a sample.
+#DirPortFrontPage @CONFDIR@/tor-exit-notice.html
+
+## Uncomment this if you run more than one Tor relay, and add the identity
+## key fingerprint of each Tor relay you control, even if they're on
+## different networks. You declare it here so Tor clients can avoid
+## using more than one of your relays in a single circuit. See
+## https://www.torproject.org/docs/faq#MultipleRelays
+## However, you should never include a bridge's fingerprint here, as it would
+## break its concealability and potentionally reveal its IP/TCP address.
+#MyFamily $keyid,$keyid,...
+
+## A comma-separated list of exit policies. They're considered first
+## to last, and the first match wins. If you want to _replace_
+## the default exit policy, end this with either a reject *:* or an
+## accept *:*. Otherwise, you're _augmenting_ (prepending to) the
+## default exit policy. Leave commented to just use the default, which is
+## described in the man page or at
+## https://www.torproject.org/documentation.html
+##
+## Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses
+## for issues you might encounter if you use the default exit policy.
+##
+## If certain IPs and ports are blocked externally, e.g. by your firewall,
+## you should update your exit policy to reflect this -- otherwise Tor
+## users will be told that those destinations are down.
+##
+## For security, by default Tor rejects connections to private (local)
+## networks, including to your public IP address. See the man page entry
+## for ExitPolicyRejectPrivate if you want to allow "exit enclaving".
+##
+#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports but no more
+#ExitPolicy accept *:119 # accept nntp as well as default exit policy
+#ExitPolicy reject *:* # no exits allowed
+
+## Bridge relays (or "bridges") are Tor relays that aren't listed in the
+## main directory. Since there is no complete public list of them, even an
+## ISP that filters connections to all the known Tor relays probably
+## won't be able to block all the bridges. Also, websites won't treat you
+## differently because they won't know you're running Tor. If you can
+## be a real relay, please do; but if not, be a bridge!
+#BridgeRelay 1
+## By default, Tor will advertise your bridge to users through various
+## mechanisms like https://bridges.torproject.org/. If you want to run
+## a private bridge, for example because you'll give out your bridge
+## address manually to your friends, uncomment this line:
+#PublishServerDescriptor 0
+
diff --git a/src/config/torrc.minimal.in-staging b/src/config/torrc.minimal.in-staging
new file mode 100644
index 0000000000..bde800fd23
--- /dev/null
+++ b/src/config/torrc.minimal.in-staging
@@ -0,0 +1,193 @@
+## Configuration file for a typical Tor user
+## Last updated 2 September 2014 for Tor 0.2.6.1-alpha.
+## (may or may not work for much older or much newer versions of Tor.)
+##
+## Lines that begin with "## " try to explain what's going on. Lines
+## that begin with just "#" are disabled commands: you can enable them
+## by removing the "#" symbol.
+##
+## See 'man tor', or https://www.torproject.org/docs/tor-manual.html,
+## for more options you can use in this file.
+##
+## Tor will look for this file in various places based on your platform:
+## https://www.torproject.org/docs/faq#torrc
+
+## Tor opens a socks proxy on port 9050 by default -- even if you don't
+## configure one below. Set "SocksPort 0" if you plan to run Tor only
+## as a relay, and not make any local application connections yourself.
+#SocksPort 9050 # Default: Bind to localhost:9050 for local connections.
+#SocksPort 192.168.0.1:9100 # Bind to this address:port too.
+
+## Entry policies to allow/deny SOCKS requests based on IP address.
+## First entry that matches wins. If no SocksPolicy is set, we accept
+## all (and only) requests that reach a SocksPort. Untrusted users who
+## can access your SocksPort may be able to learn about the connections
+## you make.
+#SocksPolicy accept 192.168.0.0/16
+#SocksPolicy reject *
+
+## Logs go to stdout at level "notice" unless redirected by something
+## else, like one of the below lines. You can have as many Log lines as
+## you want.
+##
+## We advise using "notice" in most cases, since anything more verbose
+## may provide sensitive information to an attacker who obtains the logs.
+##
+## Send all messages of level 'notice' or higher to @LOCALSTATEDIR@/log/tor/notices.log
+#Log notice file @LOCALSTATEDIR@/log/tor/notices.log
+## Send every possible message to @LOCALSTATEDIR@/log/tor/debug.log
+#Log debug file @LOCALSTATEDIR@/log/tor/debug.log
+## Use the system log instead of Tor's logfiles
+#Log notice syslog
+## To send all messages to stderr:
+#Log debug stderr
+
+## Uncomment this to start the process in the background... or use
+## --runasdaemon 1 on the command line. This is ignored on Windows;
+## see the FAQ entry if you want Tor to run as an NT service.
+#RunAsDaemon 1
+
+## The directory for keeping all the keys/etc. By default, we store
+## things in $HOME/.tor on Unix, and in Application Data\tor on Windows.
+#DataDirectory @LOCALSTATEDIR@/lib/tor
+
+## The port on which Tor will listen for local connections from Tor
+## controller applications, as documented in control-spec.txt.
+#ControlPort 9051
+## If you enable the controlport, be sure to enable one of these
+## authentication methods, to prevent attackers from accessing it.
+#HashedControlPassword 16:872860B76453A77D60CA2BB8C1A7042072093276A3D701AD684053EC4C
+#CookieAuthentication 1
+
+############### This section is just for location-hidden services ###
+
+## Once you have configured a hidden service, you can look at the
+## contents of the file ".../hidden_service/hostname" for the address
+## to tell people.
+##
+## HiddenServicePort x y:z says to redirect requests on port x to the
+## address y:z.
+
+#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/hidden_service/
+#HiddenServicePort 80 127.0.0.1:80
+
+#HiddenServiceDir @LOCALSTATEDIR@/lib/tor/other_hidden_service/
+#HiddenServicePort 80 127.0.0.1:80
+#HiddenServicePort 22 127.0.0.1:22
+
+################ This section is just for relays #####################
+#
+## See https://www.torproject.org/docs/tor-doc-relay for details.
+
+## Required: what port to advertise for incoming Tor connections.
+#ORPort 9001
+## If you want to listen on a port other than the one advertised in
+## ORPort (e.g. to advertise 443 but bind to 9090), you can do it as
+## follows. You'll need to do ipchains or other port forwarding
+## yourself to make this work.
+#ORPort 443 NoListen
+#ORPort 127.0.0.1:9090 NoAdvertise
+
+## The IP address or full DNS name for incoming connections to your
+## relay. Leave commented out and Tor will guess.
+#Address noname.example.com
+
+## If you have multiple network interfaces, you can specify one for
+## outgoing traffic to use.
+# OutboundBindAddress 10.0.0.5
+
+## A handle for your relay, so people don't have to refer to it by key.
+#Nickname ididnteditheconfig
+
+## Define these to limit how much relayed traffic you will allow. Your
+## own traffic is still unthrottled. Note that RelayBandwidthRate must
+## be at least 20 kilobytes per second.
+## Note that units for these config options are bytes (per second), not
+## bits (per second), and that prefixes are binary prefixes, i.e. 2^10,
+## 2^20, etc.
+#RelayBandwidthRate 100 KBytes # Throttle traffic to 100KB/s (800Kbps)
+#RelayBandwidthBurst 200 KBytes # But allow bursts up to 200KB (1600Kb)
+
+## Use these to restrict the maximum traffic per day, week, or month.
+## Note that this threshold applies separately to sent and received bytes,
+## not to their sum: setting "4 GB" may allow up to 8 GB total before
+## hibernating.
+##
+## Set a maximum of 4 gigabytes each way per period.
+#AccountingMax 4 GBytes
+## Each period starts daily at midnight (AccountingMax is per day)
+#AccountingStart day 00:00
+## Each period starts on the 3rd of the month at 15:00 (AccountingMax
+## is per month)
+#AccountingStart month 3 15:00
+
+## Administrative contact information for this relay or bridge. This line
+## can be used to contact you if your relay or bridge is misconfigured or
+## something else goes wrong. Note that we archive and publish all
+## descriptors containing these lines and that Google indexes them, so
+## spammers might also collect them. You may want to obscure the fact that
+## it's an email address and/or generate a new address for this purpose.
+#ContactInfo Random Person <nobody AT example dot com>
+## You might also include your PGP or GPG fingerprint if you have one:
+#ContactInfo 0xFFFFFFFF Random Person <nobody AT example dot com>
+
+## Uncomment this to mirror directory information for others. Please do
+## if you have enough bandwidth.
+#DirPort 9030 # what port to advertise for directory connections
+## If you want to listen on a port other than the one advertised in
+## DirPort (e.g. to advertise 80 but bind to 9091), you can do it as
+## follows. below too. You'll need to do ipchains or other port
+## forwarding yourself to make this work.
+#DirPort 80 NoListen
+#DirPort 127.0.0.1:9091 NoAdvertise
+## Uncomment to return an arbitrary blob of html on your DirPort. Now you
+## can explain what Tor is if anybody wonders why your IP address is
+## contacting them. See contrib/tor-exit-notice.html in Tor's source
+## distribution for a sample.
+#DirPortFrontPage @CONFDIR@/tor-exit-notice.html
+
+## Uncomment this if you run more than one Tor relay, and add the identity
+## key fingerprint of each Tor relay you control, even if they're on
+## different networks. You declare it here so Tor clients can avoid
+## using more than one of your relays in a single circuit. See
+## https://www.torproject.org/docs/faq#MultipleRelays
+## However, you should never include a bridge's fingerprint here, as it would
+## break its concealability and potentially reveal its IP/TCP address.
+#MyFamily $keyid,$keyid,...
+
+## A comma-separated list of exit policies. They're considered first
+## to last, and the first match wins. If you want to _replace_
+## the default exit policy, end this with either a reject *:* or an
+## accept *:*. Otherwise, you're _augmenting_ (prepending to) the
+## default exit policy. Leave commented to just use the default, which is
+## described in the man page or at
+## https://www.torproject.org/documentation.html
+##
+## Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses
+## for issues you might encounter if you use the default exit policy.
+##
+## If certain IPs and ports are blocked externally, e.g. by your firewall,
+## you should update your exit policy to reflect this -- otherwise Tor
+## users will be told that those destinations are down.
+##
+## For security, by default Tor rejects connections to private (local)
+## networks, including to your public IP address. See the man page entry
+## for ExitPolicyRejectPrivate if you want to allow "exit enclaving".
+##
+#ExitPolicy accept *:6660-6667,reject *:* # allow irc ports but no more
+#ExitPolicy accept *:119 # accept nntp as well as default exit policy
+#ExitPolicy reject *:* # no exits allowed
+
+## Bridge relays (or "bridges") are Tor relays that aren't listed in the
+## main directory. Since there is no complete public list of them, even an
+## ISP that filters connections to all the known Tor relays probably
+## won't be able to block all the bridges. Also, websites won't treat you
+## differently because they won't know you're running Tor. If you can
+## be a real relay, please do; but if not, be a bridge!
+#BridgeRelay 1
+## By default, Tor will advertise your bridge to users through various
+## mechanisms like https://bridges.torproject.org/. If you want to run
+## a private bridge, for example because you'll give out your bridge
+## address manually to your friends, uncomment this line:
+#PublishServerDescriptor 0
+
diff --git a/src/config/torrc.sample.in b/src/config/torrc.sample.in
index d842fbcaf5..bde800fd23 100644
--- a/src/config/torrc.sample.in
+++ b/src/config/torrc.sample.in
@@ -1,5 +1,5 @@
## Configuration file for a typical Tor user
-## Last updated 9 October 2013 for Tor 0.2.5.2-alpha.
+## Last updated 2 September 2014 for Tor 0.2.6.1-alpha.
## (may or may not work for much older or much newer versions of Tor.)
##
## Lines that begin with "## " try to explain what's going on. Lines
@@ -101,11 +101,12 @@
## Define these to limit how much relayed traffic you will allow. Your
## own traffic is still unthrottled. Note that RelayBandwidthRate must
-## be at least 20 KB.
-## Note that units for these config options are bytes per second, not bits
-## per second, and that prefixes are binary prefixes, i.e. 2^10, 2^20, etc.
-#RelayBandwidthRate 100 KB # Throttle traffic to 100KB/s (800Kbps)
-#RelayBandwidthBurst 200 KB # But allow bursts up to 200KB/s (1600Kbps)
+## be at least 20 kilobytes per second.
+## Note that units for these config options are bytes (per second), not
+## bits (per second), and that prefixes are binary prefixes, i.e. 2^10,
+## 2^20, etc.
+#RelayBandwidthRate 100 KBytes # Throttle traffic to 100KB/s (800Kbps)
+#RelayBandwidthBurst 200 KBytes # But allow bursts up to 200KB (1600Kb)
## Use these to restrict the maximum traffic per day, week, or month.
## Note that this threshold applies separately to sent and received bytes,
@@ -113,7 +114,7 @@
## hibernating.
##
## Set a maximum of 4 gigabytes each way per period.
-#AccountingMax 4 GB
+#AccountingMax 4 GBytes
## Each period starts daily at midnight (AccountingMax is per day)
#AccountingStart day 00:00
## Each period starts on the 3rd of the month at 15:00 (AccountingMax
@@ -151,7 +152,7 @@
## using more than one of your relays in a single circuit. See
## https://www.torproject.org/docs/faq#MultipleRelays
## However, you should never include a bridge's fingerprint here, as it would
-## break its concealability and potentionally reveal its IP/TCP address.
+## break its concealability and potentially reveal its IP/TCP address.
#MyFamily $keyid,$keyid,...
## A comma-separated list of exit policies. They're considered first
diff --git a/src/ext/OpenBSD_malloc_Linux.c b/src/ext/OpenBSD_malloc_Linux.c
index da82729811..855c912310 100644
--- a/src/ext/OpenBSD_malloc_Linux.c
+++ b/src/ext/OpenBSD_malloc_Linux.c
@@ -58,7 +58,7 @@
#include <limits.h>
#include <errno.h>
#include <err.h>
-/* For SIZE_T_MAX */
+/* For SIZE_MAX */
#include "torint.h"
//#include "thread_private.h"
@@ -1961,16 +1961,6 @@ realloc(void *ptr, size_t size)
return (r);
}
-#ifndef SIZE_MAX
-//#if defined(__i386__)||defined(__arm__)||defined(__powerpc__)
-//#define SIZE_MAX 0xffffffff
-//#endif
-//#if defined(__x86_64__)
-//#define SIZE_MAX 0xffffffffffffffff
-//#endif
-#define SIZE_MAX SIZE_T_MAX
-#endif
-
void *
calloc(size_t num, size_t size)
{
diff --git a/src/ext/README b/src/ext/README
index 5d5a6e1518..616716e099 100644
--- a/src/ext/README
+++ b/src/ext/README
@@ -49,3 +49,15 @@ siphash.h
Marek Majkowski's implementation of siphash 2-4, a secure keyed
hash algorithm to avoid collision-based DoS attacks against hash
tables.
+
+trunnel/*.[ch]
+
+ Headers and runtime code for Trunnel, a system for generating
+ code to encode and decode binary formats.
+
+ed25519/ref10/*
+
+ Daniel Bernsten's portable ref10 implementation of ed25519.
+ Public domain.
+
+
diff --git a/src/ext/csiphash.c b/src/ext/csiphash.c
index c247886038..27c5358ebe 100644
--- a/src/ext/csiphash.c
+++ b/src/ext/csiphash.c
@@ -1,5 +1,5 @@
/* <MIT License>
- Copyright (c) 2013 Marek Majkowski <marek@popcount.org>
+ Copyright (c) 2013-2014 Marek Majkowski <marek@popcount.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -100,10 +100,18 @@ uint64_t siphash24(const void *src, unsigned long src_sz, const struct sipkey *k
uint64_t k0 = key->k0;
uint64_t k1 = key->k1;
uint64_t b = (uint64_t)src_sz << 56;
+#ifdef UNALIGNED_OK
const uint64_t *in = (uint64_t*)src;
+#else
+ /* On platforms where alignment matters, if 'in' is a pointer to a
+ * datatype that must be aligned, the compiler is allowed to
+ * generate code that assumes that it is aligned as such.
+ */
+ const uint8_t *in = (uint8_t *)src;
+#endif
- uint64_t t;
- uint8_t *pt, *m;
+ uint64_t t;
+ uint8_t *pt, *m;
uint64_t v0 = k0 ^ 0x736f6d6570736575ULL;
uint64_t v1 = k1 ^ 0x646f72616e646f6dULL;
@@ -113,12 +121,14 @@ uint64_t siphash24(const void *src, unsigned long src_sz, const struct sipkey *k
while (src_sz >= 8) {
#ifdef UNALIGNED_OK
uint64_t mi = _le64toh(*in);
+ in += 1;
#else
uint64_t mi;
memcpy(&mi, in, 8);
mi = _le64toh(mi);
+ in += 8;
#endif
- in += 1; src_sz -= 8;
+ src_sz -= 8;
v3 ^= mi;
DOUBLE_ROUND(v0,v1,v2,v3);
v0 ^= mi;
diff --git a/src/ext/ed25519/ref10/Makefile b/src/ext/ed25519/ref10/Makefile
new file mode 100644
index 0000000000..9b0ba7ad45
--- /dev/null
+++ b/src/ext/ed25519/ref10/Makefile
@@ -0,0 +1,41 @@
+all: d.h d2.h sqrtm1.h base.h base2.h \
+ge_add.h ge_sub.h \
+ge_madd.h ge_msub.h \
+ge_p2_dbl.h \
+pow225521.h pow22523.h
+
+d.h: d.py
+ python d.py > d.h
+
+d2.h: d2.py
+ python d2.py > d2.h
+
+sqrtm1.h: sqrtm1.py
+ python sqrtm1.py > sqrtm1.h
+
+base.h: base.py
+ python base.py > base.h
+
+base2.h: base2.py
+ python base2.py > base2.h
+
+ge_add.h: ge_add.q q2h.sh
+ ./q2h.sh < ge_add.q > ge_add.h
+
+ge_sub.h: ge_sub.q q2h.sh
+ ./q2h.sh < ge_sub.q > ge_sub.h
+
+ge_madd.h: ge_madd.q q2h.sh
+ ./q2h.sh < ge_madd.q > ge_madd.h
+
+ge_msub.h: ge_msub.q q2h.sh
+ ./q2h.sh < ge_msub.q > ge_msub.h
+
+ge_p2_dbl.h: ge_p2_dbl.q q2h.sh
+ ./q2h.sh < ge_p2_dbl.q > ge_p2_dbl.h
+
+pow22523.h: pow22523.q q2h.sh
+ ./q2h.sh < pow22523.q > pow22523.h
+
+pow225521.h: pow225521.q q2h.sh
+ ./q2h.sh < pow225521.q > pow225521.h
diff --git a/src/ext/ed25519/ref10/README.tor b/src/ext/ed25519/ref10/README.tor
new file mode 100644
index 0000000000..38ed97ba05
--- /dev/null
+++ b/src/ext/ed25519/ref10/README.tor
@@ -0,0 +1,23 @@
+
+We've made the following changes to the stock ed25519_ref10 from
+supercop-20140622:
+
+ * We added the necessary glue to provide integers of fixed bit
+ sizes, SHA512, and to compile without warnings everywhere we need
+ to build.
+
+ * Secret keys are stored in expanded format. There are functions
+ to expand them from the 32-byte seed.
+
+ * Signatures are made and processed detached from the messages that
+ they sign. (In other words, we support "make signature" and
+ "check signature", not "create signed message" and "check and
+ unpack signed message".)
+
+ * There's an implementation of 'convert a curve25519 key to an
+ ed25519 key' so we can do cross-certification with curve25519 keys.
+ (keyconv.c)
+
+ * There's an implementation of multiplicative key blinding so we
+ can use it for next-gen hidden srevice descriptors. (blinding.c)
+
diff --git a/src/ext/ed25519/ref10/api.h b/src/ext/ed25519/ref10/api.h
new file mode 100644
index 0000000000..d88dae0c32
--- /dev/null
+++ b/src/ext/ed25519/ref10/api.h
@@ -0,0 +1,4 @@
+#define CRYPTO_SECRETKEYBYTES 64
+#define CRYPTO_PUBLICKEYBYTES 32
+#define CRYPTO_BYTES 64
+#define CRYPTO_DETERMINISTIC 1
diff --git a/src/ext/ed25519/ref10/base.h b/src/ext/ed25519/ref10/base.h
new file mode 100644
index 0000000000..573bd8a05c
--- /dev/null
+++ b/src/ext/ed25519/ref10/base.h
@@ -0,0 +1,1344 @@
+{
+ {
+ { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+ { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+ { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+ { -12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303 },
+ { -21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081 },
+ { 26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697 },
+ },
+ {
+ { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+ { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+ { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+ { -17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540 },
+ { 23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397 },
+ { 7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325 },
+ },
+ {
+ { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+ { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+ { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+ { -15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777 },
+ { -8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737 },
+ { -18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652 },
+ },
+ {
+ { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+ { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+ { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+ { 14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726 },
+ { -7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955 },
+ { 27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425 },
+ },
+},
+{
+ {
+ { -13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171 },
+ { 27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510 },
+ { 17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660 },
+ },
+ {
+ { -10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639 },
+ { 29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963 },
+ { 5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950 },
+ },
+ {
+ { -27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568 },
+ { 12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335 },
+ { 25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628 },
+ },
+ {
+ { -26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007 },
+ { -2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772 },
+ { -22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653 },
+ },
+ {
+ { 2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567 },
+ { 13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686 },
+ { 21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372 },
+ },
+ {
+ { -13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887 },
+ { -23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954 },
+ { -29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953 },
+ },
+ {
+ { 24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833 },
+ { -16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532 },
+ { -22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876 },
+ },
+ {
+ { 2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268 },
+ { 33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214 },
+ { 1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038 },
+ },
+},
+{
+ {
+ { 6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800 },
+ { 4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645 },
+ { -4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664 },
+ },
+ {
+ { 1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933 },
+ { -25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182 },
+ { -17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222 },
+ },
+ {
+ { -18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991 },
+ { 20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880 },
+ { 9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092 },
+ },
+ {
+ { -16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295 },
+ { 19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788 },
+ { 8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553 },
+ },
+ {
+ { -15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026 },
+ { 11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347 },
+ { -18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033 },
+ },
+ {
+ { -23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395 },
+ { -27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278 },
+ { 1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890 },
+ },
+ {
+ { 32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995 },
+ { -30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596 },
+ { -11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891 },
+ },
+ {
+ { 31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060 },
+ { 11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608 },
+ { -20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606 },
+ },
+},
+{
+ {
+ { 7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389 },
+ { -19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016 },
+ { -11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341 },
+ },
+ {
+ { -22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505 },
+ { 14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553 },
+ { -28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655 },
+ },
+ {
+ { 15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220 },
+ { 12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631 },
+ { -4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099 },
+ },
+ {
+ { 26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556 },
+ { 14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749 },
+ { 236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930 },
+ },
+ {
+ { 1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391 },
+ { 5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253 },
+ { 20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066 },
+ },
+ {
+ { 24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958 },
+ { -11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082 },
+ { -28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383 },
+ },
+ {
+ { -30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521 },
+ { -11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807 },
+ { 23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948 },
+ },
+ {
+ { 9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134 },
+ { -32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455 },
+ { 27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629 },
+ },
+},
+{
+ {
+ { -8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069 },
+ { -32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746 },
+ { 24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919 },
+ },
+ {
+ { 11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837 },
+ { 8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906 },
+ { -28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771 },
+ },
+ {
+ { -25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817 },
+ { 10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098 },
+ { 10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409 },
+ },
+ {
+ { -12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504 },
+ { -26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727 },
+ { 28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420 },
+ },
+ {
+ { -32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003 },
+ { -1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605 },
+ { -30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384 },
+ },
+ {
+ { -26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701 },
+ { -23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683 },
+ { 29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708 },
+ },
+ {
+ { -3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563 },
+ { -19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260 },
+ { -5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387 },
+ },
+ {
+ { -19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672 },
+ { 23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686 },
+ { -24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665 },
+ },
+},
+{
+ {
+ { 11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182 },
+ { -31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277 },
+ { 14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628 },
+ },
+ {
+ { -4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474 },
+ { -26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539 },
+ { -25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822 },
+ },
+ {
+ { -10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970 },
+ { 19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756 },
+ { -24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508 },
+ },
+ {
+ { -26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683 },
+ { -10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655 },
+ { -20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158 },
+ },
+ {
+ { -4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125 },
+ { -15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839 },
+ { -20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664 },
+ },
+ {
+ { 27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294 },
+ { -18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899 },
+ { -11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070 },
+ },
+ {
+ { 3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294 },
+ { -15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949 },
+ { -21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083 },
+ },
+ {
+ { 31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420 },
+ { -5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940 },
+ { 29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396 },
+ },
+},
+{
+ {
+ { -12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567 },
+ { 20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127 },
+ { -16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294 },
+ },
+ {
+ { -12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887 },
+ { 22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964 },
+ { 16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195 },
+ },
+ {
+ { 9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244 },
+ { 24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999 },
+ { -1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762 },
+ },
+ {
+ { -18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274 },
+ { -33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236 },
+ { -16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605 },
+ },
+ {
+ { -13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761 },
+ { -22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884 },
+ { -6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482 },
+ },
+ {
+ { -24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638 },
+ { -11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490 },
+ { -32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170 },
+ },
+ {
+ { 5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736 },
+ { 10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124 },
+ { -17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392 },
+ },
+ {
+ { 8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029 },
+ { 6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048 },
+ { 28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958 },
+ },
+},
+{
+ {
+ { 24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593 },
+ { 26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071 },
+ { -11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692 },
+ },
+ {
+ { 11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687 },
+ { -160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441 },
+ { -20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001 },
+ },
+ {
+ { -938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460 },
+ { -19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007 },
+ { -21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762 },
+ },
+ {
+ { 15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005 },
+ { -9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674 },
+ { 4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035 },
+ },
+ {
+ { 7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590 },
+ { -2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957 },
+ { -30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812 },
+ },
+ {
+ { 33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740 },
+ { -18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122 },
+ { -27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158 },
+ },
+ {
+ { 8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885 },
+ { 26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140 },
+ { 19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857 },
+ },
+ {
+ { 801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155 },
+ { 19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260 },
+ { 19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483 },
+ },
+},
+{
+ {
+ { -3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677 },
+ { 32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815 },
+ { 22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751 },
+ },
+ {
+ { -16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203 },
+ { -11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208 },
+ { 1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230 },
+ },
+ {
+ { 16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850 },
+ { -21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389 },
+ { -9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968 },
+ },
+ {
+ { -11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689 },
+ { 14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880 },
+ { 5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304 },
+ },
+ {
+ { 30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632 },
+ { -3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412 },
+ { 20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566 },
+ },
+ {
+ { -20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038 },
+ { -26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232 },
+ { -1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943 },
+ },
+ {
+ { 17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856 },
+ { 23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738 },
+ { 15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971 },
+ },
+ {
+ { -27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718 },
+ { -13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697 },
+ { -11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883 },
+ },
+},
+{
+ {
+ { 5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912 },
+ { -26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358 },
+ { 3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849 },
+ },
+ {
+ { 29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307 },
+ { -14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977 },
+ { -6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335 },
+ },
+ {
+ { -29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644 },
+ { -22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616 },
+ { -27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735 },
+ },
+ {
+ { -21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099 },
+ { 29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341 },
+ { -936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336 },
+ },
+ {
+ { -23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646 },
+ { 31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425 },
+ { -17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388 },
+ },
+ {
+ { -31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743 },
+ { -16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822 },
+ { -8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462 },
+ },
+ {
+ { 18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985 },
+ { 9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702 },
+ { -22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797 },
+ },
+ {
+ { 21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293 },
+ { 27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100 },
+ { 19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688 },
+ },
+},
+{
+ {
+ { 12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186 },
+ { 2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610 },
+ { -2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707 },
+ },
+ {
+ { 7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220 },
+ { 915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025 },
+ { 32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044 },
+ },
+ {
+ { 32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992 },
+ { -4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027 },
+ { 21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197 },
+ },
+ {
+ { 8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901 },
+ { 31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952 },
+ { 19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878 },
+ },
+ {
+ { -28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390 },
+ { 32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730 },
+ { 2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730 },
+ },
+ {
+ { -19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180 },
+ { -30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272 },
+ { -15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715 },
+ },
+ {
+ { -22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970 },
+ { -31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772 },
+ { -17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865 },
+ },
+ {
+ { 15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750 },
+ { 20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373 },
+ { 32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348 },
+ },
+},
+{
+ {
+ { 9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144 },
+ { -22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195 },
+ { 5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086 },
+ },
+ {
+ { -13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684 },
+ { -8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518 },
+ { -2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233 },
+ },
+ {
+ { -5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793 },
+ { -2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794 },
+ { 580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435 },
+ },
+ {
+ { 23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921 },
+ { 13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518 },
+ { 2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563 },
+ },
+ {
+ { 14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278 },
+ { -27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024 },
+ { 4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030 },
+ },
+ {
+ { 10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783 },
+ { 27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717 },
+ { 6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844 },
+ },
+ {
+ { 14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333 },
+ { 16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048 },
+ { 22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760 },
+ },
+ {
+ { -4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760 },
+ { -15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757 },
+ { -2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112 },
+ },
+},
+{
+ {
+ { -19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468 },
+ { 3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184 },
+ { 10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289 },
+ },
+ {
+ { 15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066 },
+ { 24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882 },
+ { 13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226 },
+ },
+ {
+ { 16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101 },
+ { 29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279 },
+ { -6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811 },
+ },
+ {
+ { 27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709 },
+ { 20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714 },
+ { -2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121 },
+ },
+ {
+ { 9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464 },
+ { 12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847 },
+ { 13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400 },
+ },
+ {
+ { 4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414 },
+ { -15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158 },
+ { 17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045 },
+ },
+ {
+ { -461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415 },
+ { -5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459 },
+ { -31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079 },
+ },
+ {
+ { 21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412 },
+ { -20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743 },
+ { -14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836 },
+ },
+},
+{
+ {
+ { 12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022 },
+ { 18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429 },
+ { -6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065 },
+ },
+ {
+ { 30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861 },
+ { 10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000 },
+ { -33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101 },
+ },
+ {
+ { 32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815 },
+ { 29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642 },
+ { 10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966 },
+ },
+ {
+ { 25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574 },
+ { -21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742 },
+ { -18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689 },
+ },
+ {
+ { 12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020 },
+ { -10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772 },
+ { 3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982 },
+ },
+ {
+ { -14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953 },
+ { -16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218 },
+ { -17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265 },
+ },
+ {
+ { 29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073 },
+ { -3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325 },
+ { -11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798 },
+ },
+ {
+ { -4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870 },
+ { -7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863 },
+ { -13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927 },
+ },
+},
+{
+ {
+ { -2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267 },
+ { -9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663 },
+ { 22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862 },
+ },
+ {
+ { -25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673 },
+ { 15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943 },
+ { 15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020 },
+ },
+ {
+ { -4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238 },
+ { 11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064 },
+ { 14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795 },
+ },
+ {
+ { 15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052 },
+ { -10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904 },
+ { 29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531 },
+ },
+ {
+ { -13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979 },
+ { -5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841 },
+ { 10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431 },
+ },
+ {
+ { 10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324 },
+ { -31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940 },
+ { 10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320 },
+ },
+ {
+ { -15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184 },
+ { 14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114 },
+ { 30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878 },
+ },
+ {
+ { 12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784 },
+ { -2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091 },
+ { -16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585 },
+ },
+},
+{
+ {
+ { -8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208 },
+ { 10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864 },
+ { 17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661 },
+ },
+ {
+ { 7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233 },
+ { 26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212 },
+ { -12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525 },
+ },
+ {
+ { -24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068 },
+ { 9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397 },
+ { -8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988 },
+ },
+ {
+ { 5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889 },
+ { 32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038 },
+ { 14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697 },
+ },
+ {
+ { 20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875 },
+ { -25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905 },
+ { -25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656 },
+ },
+ {
+ { 11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818 },
+ { 27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714 },
+ { 10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203 },
+ },
+ {
+ { 20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931 },
+ { -30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024 },
+ { -23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084 },
+ },
+ {
+ { -1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204 },
+ { 20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817 },
+ { 27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667 },
+ },
+},
+{
+ {
+ { 11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504 },
+ { -12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768 },
+ { -19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255 },
+ },
+ {
+ { 6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790 },
+ { 1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438 },
+ { -22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333 },
+ },
+ {
+ { 17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971 },
+ { 31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905 },
+ { 29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409 },
+ },
+ {
+ { 12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409 },
+ { 6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499 },
+ { -8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363 },
+ },
+ {
+ { 28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664 },
+ { -11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324 },
+ { -21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940 },
+ },
+ {
+ { 13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990 },
+ { -17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914 },
+ { -25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290 },
+ },
+ {
+ { 24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257 },
+ { -6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433 },
+ { -16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236 },
+ },
+ {
+ { -12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045 },
+ { 11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093 },
+ { -1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347 },
+ },
+},
+{
+ {
+ { -28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191 },
+ { -15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507 },
+ { -12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906 },
+ },
+ {
+ { 3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018 },
+ { -16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109 },
+ { -23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926 },
+ },
+ {
+ { -24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528 },
+ { 8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625 },
+ { -32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286 },
+ },
+ {
+ { 2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033 },
+ { 27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866 },
+ { 21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896 },
+ },
+ {
+ { 30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075 },
+ { 26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347 },
+ { -22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437 },
+ },
+ {
+ { -5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165 },
+ { -18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588 },
+ { -32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193 },
+ },
+ {
+ { -19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017 },
+ { -28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883 },
+ { 21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961 },
+ },
+ {
+ { 8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043 },
+ { 29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663 },
+ { -20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362 },
+ },
+},
+{
+ {
+ { -33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860 },
+ { 2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466 },
+ { -24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063 },
+ },
+ {
+ { -26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997 },
+ { -1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295 },
+ { -13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369 },
+ },
+ {
+ { 9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385 },
+ { 18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109 },
+ { 2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906 },
+ },
+ {
+ { 4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424 },
+ { -19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185 },
+ { 7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962 },
+ },
+ {
+ { -7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325 },
+ { 10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593 },
+ { 696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404 },
+ },
+ {
+ { -11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644 },
+ { 17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801 },
+ { 26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804 },
+ },
+ {
+ { -31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884 },
+ { -586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577 },
+ { -9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849 },
+ },
+ {
+ { 32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473 },
+ { -8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644 },
+ { -2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319 },
+ },
+},
+{
+ {
+ { -11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599 },
+ { -9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768 },
+ { -27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084 },
+ },
+ {
+ { -27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328 },
+ { -15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369 },
+ { 20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920 },
+ },
+ {
+ { 12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815 },
+ { -32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025 },
+ { -21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397 },
+ },
+ {
+ { -20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448 },
+ { 6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981 },
+ { 30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165 },
+ },
+ {
+ { 32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501 },
+ { 17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073 },
+ { -1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861 },
+ },
+ {
+ { 14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845 },
+ { -1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211 },
+ { 18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870 },
+ },
+ {
+ { 10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096 },
+ { 33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803 },
+ { -32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168 },
+ },
+ {
+ { 30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965 },
+ { -14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505 },
+ { 18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598 },
+ },
+},
+{
+ {
+ { 5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782 },
+ { 5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900 },
+ { -31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479 },
+ },
+ {
+ { -12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208 },
+ { 8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232 },
+ { 17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719 },
+ },
+ {
+ { 16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271 },
+ { -4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326 },
+ { -8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132 },
+ },
+ {
+ { 14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300 },
+ { 8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570 },
+ { 15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670 },
+ },
+ {
+ { -2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994 },
+ { -12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913 },
+ { 31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317 },
+ },
+ {
+ { -25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730 },
+ { 842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096 },
+ { -4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078 },
+ },
+ {
+ { -15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411 },
+ { -19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905 },
+ { -9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654 },
+ },
+ {
+ { -28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870 },
+ { -23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498 },
+ { 12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579 },
+ },
+},
+{
+ {
+ { 14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677 },
+ { 10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647 },
+ { -2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743 },
+ },
+ {
+ { -25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468 },
+ { 21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375 },
+ { -25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155 },
+ },
+ {
+ { 6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725 },
+ { -12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612 },
+ { -10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943 },
+ },
+ {
+ { -30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944 },
+ { 30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928 },
+ { 9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406 },
+ },
+ {
+ { 22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139 },
+ { -8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963 },
+ { -31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693 },
+ },
+ {
+ { 1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734 },
+ { -448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680 },
+ { -24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410 },
+ },
+ {
+ { -9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931 },
+ { -16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654 },
+ { 22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710 },
+ },
+ {
+ { 29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180 },
+ { -26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684 },
+ { -10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895 },
+ },
+},
+{
+ {
+ { 22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501 },
+ { -11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413 },
+ { 6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880 },
+ },
+ {
+ { -8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874 },
+ { 22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962 },
+ { -7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899 },
+ },
+ {
+ { 21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152 },
+ { 9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063 },
+ { 7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080 },
+ },
+ {
+ { -9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146 },
+ { -17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183 },
+ { -19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133 },
+ },
+ {
+ { -32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421 },
+ { -3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622 },
+ { -4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197 },
+ },
+ {
+ { 2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663 },
+ { 31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753 },
+ { 4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755 },
+ },
+ {
+ { -9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862 },
+ { -26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118 },
+ { 26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171 },
+ },
+ {
+ { 15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380 },
+ { 16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824 },
+ { 28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270 },
+ },
+},
+{
+ {
+ { -817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438 },
+ { -31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584 },
+ { -594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562 },
+ },
+ {
+ { 30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471 },
+ { 18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610 },
+ { 19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269 },
+ },
+ {
+ { -30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650 },
+ { 14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369 },
+ { 19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461 },
+ },
+ {
+ { 30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462 },
+ { -5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793 },
+ { -2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218 },
+ },
+ {
+ { -24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226 },
+ { 18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019 },
+ { -15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037 },
+ },
+ {
+ { 31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171 },
+ { -17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132 },
+ { -28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841 },
+ },
+ {
+ { 21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181 },
+ { -33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210 },
+ { -1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040 },
+ },
+ {
+ { 3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935 },
+ { 24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105 },
+ { -28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814 },
+ },
+},
+{
+ {
+ { 793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852 },
+ { 5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581 },
+ { -4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646 },
+ },
+ {
+ { 10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844 },
+ { 10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025 },
+ { 27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453 },
+ },
+ {
+ { -23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068 },
+ { 4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192 },
+ { -17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921 },
+ },
+ {
+ { -9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259 },
+ { -12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426 },
+ { -5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072 },
+ },
+ {
+ { -17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305 },
+ { 13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832 },
+ { 28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943 },
+ },
+ {
+ { -16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011 },
+ { 24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447 },
+ { 17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494 },
+ },
+ {
+ { -28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245 },
+ { -20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859 },
+ { 28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915 },
+ },
+ {
+ { 16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707 },
+ { 10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848 },
+ { -11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224 },
+ },
+},
+{
+ {
+ { -25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391 },
+ { 15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215 },
+ { -23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101 },
+ },
+ {
+ { 23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713 },
+ { 21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849 },
+ { -7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930 },
+ },
+ {
+ { -29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940 },
+ { -21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031 },
+ { -17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404 },
+ },
+ {
+ { -25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243 },
+ { -23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116 },
+ { -24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525 },
+ },
+ {
+ { -23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509 },
+ { -10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883 },
+ { 15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865 },
+ },
+ {
+ { -3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660 },
+ { 4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273 },
+ { -28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138 },
+ },
+ {
+ { -25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560 },
+ { -10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135 },
+ { 2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941 },
+ },
+ {
+ { -4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739 },
+ { 18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756 },
+ { -30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819 },
+ },
+},
+{
+ {
+ { -6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347 },
+ { -27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028 },
+ { 21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075 },
+ },
+ {
+ { 16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799 },
+ { -2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609 },
+ { -25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817 },
+ },
+ {
+ { -23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989 },
+ { -30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523 },
+ { 4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278 },
+ },
+ {
+ { 31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045 },
+ { 19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377 },
+ { 24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480 },
+ },
+ {
+ { 17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016 },
+ { 510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426 },
+ { 18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525 },
+ },
+ {
+ { 13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396 },
+ { 9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080 },
+ { 12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892 },
+ },
+ {
+ { 15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275 },
+ { 11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074 },
+ { 20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140 },
+ },
+ {
+ { -16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717 },
+ { -1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101 },
+ { 24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127 },
+ },
+},
+{
+ {
+ { -12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632 },
+ { -26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415 },
+ { -31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160 },
+ },
+ {
+ { 31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876 },
+ { 22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625 },
+ { -15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478 },
+ },
+ {
+ { 27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164 },
+ { 26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595 },
+ { -7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248 },
+ },
+ {
+ { -16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858 },
+ { 15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193 },
+ { 8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184 },
+ },
+ {
+ { -18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942 },
+ { -1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635 },
+ { 21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948 },
+ },
+ {
+ { 11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935 },
+ { -25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415 },
+ { -15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416 },
+ },
+ {
+ { -7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018 },
+ { 4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778 },
+ { 366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659 },
+ },
+ {
+ { -24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385 },
+ { 18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503 },
+ { 476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329 },
+ },
+},
+{
+ {
+ { 20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056 },
+ { -13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838 },
+ { 24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948 },
+ },
+ {
+ { -3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691 },
+ { -15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118 },
+ { -23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517 },
+ },
+ {
+ { -20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269 },
+ { -6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904 },
+ { -23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589 },
+ },
+ {
+ { -28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193 },
+ { -7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910 },
+ { -30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930 },
+ },
+ {
+ { -7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667 },
+ { 25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481 },
+ { -9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876 },
+ },
+ {
+ { 22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640 },
+ { -8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278 },
+ { -21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112 },
+ },
+ {
+ { 26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272 },
+ { 17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012 },
+ { -10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221 },
+ },
+ {
+ { 30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046 },
+ { 13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345 },
+ { -19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310 },
+ },
+},
+{
+ {
+ { 19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937 },
+ { 31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636 },
+ { -9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008 },
+ },
+ {
+ { -2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429 },
+ { -15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576 },
+ { 31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066 },
+ },
+ {
+ { -9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490 },
+ { -12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104 },
+ { 33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053 },
+ },
+ {
+ { 31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275 },
+ { -20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511 },
+ { 22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095 },
+ },
+ {
+ { -28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439 },
+ { 23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939 },
+ { -23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424 },
+ },
+ {
+ { 2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310 },
+ { 3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608 },
+ { -32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079 },
+ },
+ {
+ { -23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101 },
+ { 21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418 },
+ { 18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576 },
+ },
+ {
+ { 30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356 },
+ { 9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996 },
+ { -26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099 },
+ },
+},
+{
+ {
+ { -26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728 },
+ { -13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658 },
+ { -10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242 },
+ },
+ {
+ { -21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001 },
+ { -4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766 },
+ { 18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373 },
+ },
+ {
+ { 26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458 },
+ { -17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628 },
+ { -13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657 },
+ },
+ {
+ { -23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062 },
+ { 25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616 },
+ { 31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014 },
+ },
+ {
+ { 24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383 },
+ { -25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814 },
+ { -20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718 },
+ },
+ {
+ { 30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417 },
+ { 2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222 },
+ { 33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444 },
+ },
+ {
+ { -20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597 },
+ { 23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970 },
+ { 1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799 },
+ },
+ {
+ { -5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647 },
+ { 13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511 },
+ { -29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032 },
+ },
+},
+{
+ {
+ { 9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834 },
+ { -23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461 },
+ { 29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062 },
+ },
+ {
+ { -25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516 },
+ { -20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547 },
+ { -24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240 },
+ },
+ {
+ { -17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038 },
+ { -33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741 },
+ { 16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103 },
+ },
+ {
+ { -19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747 },
+ { -1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323 },
+ { 31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016 },
+ },
+ {
+ { -14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373 },
+ { 15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228 },
+ { -2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141 },
+ },
+ {
+ { 16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399 },
+ { 11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831 },
+ { -185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376 },
+ },
+ {
+ { -32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313 },
+ { -18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958 },
+ { -6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577 },
+ },
+ {
+ { -22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743 },
+ { 29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684 },
+ { -20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476 },
+ },
+},
diff --git a/src/ext/ed25519/ref10/base.py b/src/ext/ed25519/ref10/base.py
new file mode 100644
index 0000000000..84accc8580
--- /dev/null
+++ b/src/ext/ed25519/ref10/base.py
@@ -0,0 +1,65 @@
+b = 256
+q = 2**255 - 19
+l = 2**252 + 27742317777372353535851937790883648493
+
+def expmod(b,e,m):
+ if e == 0: return 1
+ t = expmod(b,e/2,m)**2 % m
+ if e & 1: t = (t*b) % m
+ return t
+
+def inv(x):
+ return expmod(x,q-2,q)
+
+d = -121665 * inv(121666)
+I = expmod(2,(q-1)/4,q)
+
+def xrecover(y):
+ xx = (y*y-1) * inv(d*y*y+1)
+ x = expmod(xx,(q+3)/8,q)
+ if (x*x - xx) % q != 0: x = (x*I) % q
+ if x % 2 != 0: x = q-x
+ return x
+
+By = 4 * inv(5)
+Bx = xrecover(By)
+B = [Bx % q,By % q]
+
+def edwards(P,Q):
+ x1 = P[0]
+ y1 = P[1]
+ x2 = Q[0]
+ y2 = Q[1]
+ x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
+ y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
+ return [x3 % q,y3 % q]
+
+def radix255(x):
+ x = x % q
+ if x + x > q: x -= q
+ x = [x,0,0,0,0,0,0,0,0,0]
+ bits = [26,25,26,25,26,25,26,25,26,25]
+ for i in range(9):
+ carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+ x[i] -= carry * 2**bits[i]
+ x[i + 1] += carry
+ result = ""
+ for i in range(9):
+ result = result+str(x[i])+","
+ result = result+str(x[9])
+ return result
+
+Bi = B
+for i in range(32):
+ print "{"
+ Bij = Bi
+ for j in range(8):
+ print " {"
+ print " {",radix255(Bij[1]+Bij[0]),"},"
+ print " {",radix255(Bij[1]-Bij[0]),"},"
+ print " {",radix255(2*d*Bij[0]*Bij[1]),"},"
+ Bij = edwards(Bij,Bi)
+ print " },"
+ print "},"
+ for k in range(8):
+ Bi = edwards(Bi,Bi)
diff --git a/src/ext/ed25519/ref10/base2.h b/src/ext/ed25519/ref10/base2.h
new file mode 100644
index 0000000000..8c538440ff
--- /dev/null
+++ b/src/ext/ed25519/ref10/base2.h
@@ -0,0 +1,40 @@
+ {
+ { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+ { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+ { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+ { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+ { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+ { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+ { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+ { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+ { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+ { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+ { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+ { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+ { -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 },
+ { -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 },
+ { 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 },
+ },
+ {
+ { -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 },
+ { 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 },
+ { 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 },
+ },
+ {
+ { -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 },
+ { -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 },
+ { -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 },
+ },
+ {
+ { -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 },
+ { -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 },
+ { -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 },
+ },
diff --git a/src/ext/ed25519/ref10/base2.py b/src/ext/ed25519/ref10/base2.py
new file mode 100644
index 0000000000..5e4e8739d0
--- /dev/null
+++ b/src/ext/ed25519/ref10/base2.py
@@ -0,0 +1,60 @@
+b = 256
+q = 2**255 - 19
+l = 2**252 + 27742317777372353535851937790883648493
+
+def expmod(b,e,m):
+ if e == 0: return 1
+ t = expmod(b,e/2,m)**2 % m
+ if e & 1: t = (t*b) % m
+ return t
+
+def inv(x):
+ return expmod(x,q-2,q)
+
+d = -121665 * inv(121666)
+I = expmod(2,(q-1)/4,q)
+
+def xrecover(y):
+ xx = (y*y-1) * inv(d*y*y+1)
+ x = expmod(xx,(q+3)/8,q)
+ if (x*x - xx) % q != 0: x = (x*I) % q
+ if x % 2 != 0: x = q-x
+ return x
+
+By = 4 * inv(5)
+Bx = xrecover(By)
+B = [Bx % q,By % q]
+
+def edwards(P,Q):
+ x1 = P[0]
+ y1 = P[1]
+ x2 = Q[0]
+ y2 = Q[1]
+ x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
+ y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
+ return [x3 % q,y3 % q]
+
+def radix255(x):
+ x = x % q
+ if x + x > q: x -= q
+ x = [x,0,0,0,0,0,0,0,0,0]
+ bits = [26,25,26,25,26,25,26,25,26,25]
+ for i in range(9):
+ carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+ x[i] -= carry * 2**bits[i]
+ x[i + 1] += carry
+ result = ""
+ for i in range(9):
+ result = result+str(x[i])+","
+ result = result+str(x[9])
+ return result
+
+Bi = B
+
+for i in range(8):
+ print " {"
+ print " {",radix255(Bi[1]+Bi[0]),"},"
+ print " {",radix255(Bi[1]-Bi[0]),"},"
+ print " {",radix255(2*d*Bi[0]*Bi[1]),"},"
+ print " },"
+ Bi = edwards(B,edwards(B,Bi))
diff --git a/src/ext/ed25519/ref10/blinding.c b/src/ext/ed25519/ref10/blinding.c
new file mode 100644
index 0000000000..4d9a9cbbe7
--- /dev/null
+++ b/src/ext/ed25519/ref10/blinding.c
@@ -0,0 +1,76 @@
+/* Added to ref10 for Tor. We place this in the public domain. Alternatively,
+ * you may have it under the Creative Commons 0 "CC0" license. */
+//#include "fe.h"
+#include "ge.h"
+#include "sc.h"
+#include "crypto_hash_sha512.h"
+#include "ed25519_ref10.h"
+
+#include <string.h>
+#include "crypto.h"
+
+static void
+gettweak(unsigned char *out, const unsigned char *param)
+{
+ const char str[] = "Derive temporary signing key";
+ crypto_hash_sha512_2(out, (const unsigned char*)str, strlen(str), param, 32);
+ out[0] &= 248; /* Is this necessary necessary ? */
+ out[31] &= 63;
+ out[31] |= 64;
+}
+
+int ed25519_ref10_blind_secret_key(unsigned char *out,
+ const unsigned char *inp,
+ const unsigned char *param)
+{
+ const char str[] = "Derive temporary signing key hash input";
+ unsigned char tweak[64];
+ unsigned char zero[32];
+ gettweak(tweak, param);
+
+ memset(zero, 0, 32);
+ sc_muladd(out, inp, tweak, zero);
+
+ crypto_hash_sha512_2(tweak, (const unsigned char *)str, strlen(str),
+ inp+32, 32);
+ memcpy(out+32, tweak, 32);
+
+ memwipe(tweak, 0, sizeof(tweak));
+
+ return 0;
+}
+
+int ed25519_ref10_blind_public_key(unsigned char *out,
+ const unsigned char *inp,
+ const unsigned char *param)
+{
+ unsigned char tweak[64];
+ unsigned char zero[32];
+ unsigned char pkcopy[32];
+ ge_p3 A;
+ ge_p2 Aprime;
+
+ gettweak(tweak, param);
+
+ memset(zero, 0, sizeof(zero));
+ /* Not the greatest implementation of all of this. I wish I had
+ * better-suited primitives to work with here... (but I don't wish that so
+ * strongly that I'm about to code my own ge_scalarmult_vartime). */
+
+ /* We negate the public key first, so that we can pass it to
+ * frombytes_negate_vartime, which negates it again. If there were a
+ * "ge_frombytes", we'd use that, but there isn't. */
+ memcpy(pkcopy, inp, 32);
+ pkcopy[31] ^= (1<<7);
+ ge_frombytes_negate_vartime(&A, pkcopy);
+ /* There isn't a regular ge_scalarmult -- we have to do tweak*A + zero*B. */
+ ge_double_scalarmult_vartime(&Aprime, tweak, &A, zero);
+ ge_tobytes(out, &Aprime);
+
+ memwipe(tweak, 0, sizeof(tweak));
+ memwipe(&A, 0, sizeof(A));
+ memwipe(&Aprime, 0, sizeof(Aprime));
+ memwipe(pkcopy, 0, sizeof(pkcopy));
+
+ return 0;
+}
diff --git a/src/ext/ed25519/ref10/crypto_hash_sha512.h b/src/ext/ed25519/ref10/crypto_hash_sha512.h
new file mode 100644
index 0000000000..0278571522
--- /dev/null
+++ b/src/ext/ed25519/ref10/crypto_hash_sha512.h
@@ -0,0 +1,30 @@
+/* Added for Tor. */
+#include <openssl/sha.h>
+
+/* Set 'out' to the 512-bit SHA512 hash of the 'len'-byte string in 'inp' */
+#define crypto_hash_sha512(out, inp, len) \
+ SHA512((inp), (len), (out))
+
+/* Set 'out' to the 512-bit SHA512 hash of the 'len1'-byte string in 'inp1',
+ * concatenated with the 'len2'-byte string in 'inp2'. */
+#define crypto_hash_sha512_2(out, inp1, len1, inp2, len2) \
+ do { \
+ SHA512_CTX sha_ctx_; \
+ SHA512_Init(&sha_ctx_); \
+ SHA512_Update(&sha_ctx_, (inp1), (len1)); \
+ SHA512_Update(&sha_ctx_, (inp2), (len2)); \
+ SHA512_Final((out), &sha_ctx_); \
+ } while(0)
+
+/* Set 'out' to the 512-bit SHA512 hash of the 'len1'-byte string in 'inp1',
+ * concatenated with the 'len2'-byte string in 'inp2', concatenated with
+ * the 'len3'-byte string in 'len3'. */
+#define crypto_hash_sha512_3(out, inp1, len1, inp2, len2, inp3, len3) \
+ do { \
+ SHA512_CTX sha_ctx_; \
+ SHA512_Init(&sha_ctx_); \
+ SHA512_Update(&sha_ctx_, (inp1), (len1)); \
+ SHA512_Update(&sha_ctx_, (inp2), (len2)); \
+ SHA512_Update(&sha_ctx_, (inp3), (len3)); \
+ SHA512_Final((out), &sha_ctx_); \
+ } while(0)
diff --git a/src/ext/ed25519/ref10/crypto_int32.h b/src/ext/ed25519/ref10/crypto_int32.h
new file mode 100644
index 0000000000..dd13c91bd0
--- /dev/null
+++ b/src/ext/ed25519/ref10/crypto_int32.h
@@ -0,0 +1,25 @@
+/* Added for Tor. */
+
+#ifndef CRYPTO_INT32_H
+#define CRYPTO_INT32_H
+
+#include "torint.h"
+#define crypto_int32 int32_t
+#define crypto_uint32 uint32_t
+
+/*
+ Stop signed left shifts overflowing
+ by using unsigned types for bitwise operations
+ */
+
+#ifndef OVERFLOW_SAFE_SIGNED_LSHIFT
+#define OVERFLOW_SAFE_SIGNED_LSHIFT(s, lshift, utype, stype) \
+ ((stype)((utype)(s) << (utype)(lshift)))
+#endif
+
+#define SHL32(s, lshift) \
+ OVERFLOW_SAFE_SIGNED_LSHIFT(s, lshift, crypto_uint32, crypto_int32)
+#define SHL8(s, lshift) \
+ OVERFLOW_SAFE_SIGNED_LSHIFT(s, lshift, unsigned char, signed char)
+
+#endif /* CRYPTO_INT32_H */
diff --git a/src/ext/ed25519/ref10/crypto_int64.h b/src/ext/ed25519/ref10/crypto_int64.h
new file mode 100644
index 0000000000..46e8852ed0
--- /dev/null
+++ b/src/ext/ed25519/ref10/crypto_int64.h
@@ -0,0 +1,23 @@
+/* Added for Tor. */
+
+#ifndef CRYPTO_INT64_H
+#define CRYPTO_INT64_H
+
+#include "torint.h"
+#define crypto_int64 int64_t
+#define crypto_uint64 uint64_t
+
+/*
+ Stop signed left shifts overflowing
+ by using unsigned types for bitwise operations
+ */
+
+#ifndef OVERFLOW_SAFE_SIGNED_LSHIFT
+#define OVERFLOW_SAFE_SIGNED_LSHIFT(s, lshift, utype, stype) \
+ ((stype)((utype)(s) << (utype)(lshift)))
+#endif
+
+#define SHL64(s, lshift) \
+ OVERFLOW_SAFE_SIGNED_LSHIFT(s, lshift, crypto_uint64, crypto_int64)
+
+#endif /* CRYPTO_INT64_H */
diff --git a/src/ext/ed25519/ref10/crypto_sign.h b/src/ext/ed25519/ref10/crypto_sign.h
new file mode 100644
index 0000000000..549626793a
--- /dev/null
+++ b/src/ext/ed25519/ref10/crypto_sign.h
@@ -0,0 +1,9 @@
+/* Added for Tor */
+#define crypto_sign ed25519_ref10_sign
+#define crypto_sign_keypair ed25519_ref10_keygen
+#define crypto_sign_seckey ed25519_ref10_seckey
+#define crypto_sign_seckey_expand ed25519_ref10_seckey_expand
+#define crypto_sign_pubkey ed25519_ref10_pubkey
+#define crypto_sign_open ed25519_ref10_open
+
+#include "ed25519_ref10.h"
diff --git a/src/ext/ed25519/ref10/crypto_uint32.h b/src/ext/ed25519/ref10/crypto_uint32.h
new file mode 100644
index 0000000000..62655a5b66
--- /dev/null
+++ b/src/ext/ed25519/ref10/crypto_uint32.h
@@ -0,0 +1,3 @@
+/* Added for Tor. */
+#include "torint.h"
+#define crypto_uint32 uint32_t
diff --git a/src/ext/ed25519/ref10/crypto_uint64.h b/src/ext/ed25519/ref10/crypto_uint64.h
new file mode 100644
index 0000000000..cbda882a6a
--- /dev/null
+++ b/src/ext/ed25519/ref10/crypto_uint64.h
@@ -0,0 +1,3 @@
+/* Added for Tor. */
+#include "torint.h"
+#define crypto_uint64 uint64_t
diff --git a/src/ext/ed25519/ref10/crypto_verify_32.h b/src/ext/ed25519/ref10/crypto_verify_32.h
new file mode 100644
index 0000000000..0f63efc7a3
--- /dev/null
+++ b/src/ext/ed25519/ref10/crypto_verify_32.h
@@ -0,0 +1,5 @@
+/* Added for Tor. */
+#include "di_ops.h"
+#define crypto_verify_32(a,b) \
+ (! tor_memeq((a), (b), 32))
+
diff --git a/src/ext/ed25519/ref10/d.h b/src/ext/ed25519/ref10/d.h
new file mode 100644
index 0000000000..e25f578350
--- /dev/null
+++ b/src/ext/ed25519/ref10/d.h
@@ -0,0 +1 @@
+-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116
diff --git a/src/ext/ed25519/ref10/d.py b/src/ext/ed25519/ref10/d.py
new file mode 100644
index 0000000000..8995bb86a3
--- /dev/null
+++ b/src/ext/ed25519/ref10/d.py
@@ -0,0 +1,28 @@
+q = 2**255 - 19
+
+def expmod(b,e,m):
+ if e == 0: return 1
+ t = expmod(b,e/2,m)**2 % m
+ if e & 1: t = (t*b) % m
+ return t
+
+def inv(x):
+ return expmod(x,q-2,q)
+
+def radix255(x):
+ x = x % q
+ if x + x > q: x -= q
+ x = [x,0,0,0,0,0,0,0,0,0]
+ bits = [26,25,26,25,26,25,26,25,26,25]
+ for i in range(9):
+ carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+ x[i] -= carry * 2**bits[i]
+ x[i + 1] += carry
+ result = ""
+ for i in range(9):
+ result = result+str(x[i])+","
+ result = result+str(x[9])
+ return result
+
+d = -121665 * inv(121666)
+print radix255(d)
diff --git a/src/ext/ed25519/ref10/d2.h b/src/ext/ed25519/ref10/d2.h
new file mode 100644
index 0000000000..01aaec7512
--- /dev/null
+++ b/src/ext/ed25519/ref10/d2.h
@@ -0,0 +1 @@
+-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199
diff --git a/src/ext/ed25519/ref10/d2.py b/src/ext/ed25519/ref10/d2.py
new file mode 100644
index 0000000000..79841758be
--- /dev/null
+++ b/src/ext/ed25519/ref10/d2.py
@@ -0,0 +1,28 @@
+q = 2**255 - 19
+
+def expmod(b,e,m):
+ if e == 0: return 1
+ t = expmod(b,e/2,m)**2 % m
+ if e & 1: t = (t*b) % m
+ return t
+
+def inv(x):
+ return expmod(x,q-2,q)
+
+def radix255(x):
+ x = x % q
+ if x + x > q: x -= q
+ x = [x,0,0,0,0,0,0,0,0,0]
+ bits = [26,25,26,25,26,25,26,25,26,25]
+ for i in range(9):
+ carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+ x[i] -= carry * 2**bits[i]
+ x[i + 1] += carry
+ result = ""
+ for i in range(9):
+ result = result+str(x[i])+","
+ result = result+str(x[9])
+ return result
+
+d = -121665 * inv(121666)
+print radix255(d*2)
diff --git a/src/ext/ed25519/ref10/ed25519_ref10.h b/src/ext/ed25519/ref10/ed25519_ref10.h
new file mode 100644
index 0000000000..af7e21a2ad
--- /dev/null
+++ b/src/ext/ed25519/ref10/ed25519_ref10.h
@@ -0,0 +1,30 @@
+/* Added for Tor */
+#ifndef SRC_EXT_ED25519_REF10_H_INCLUDED_
+#define SRC_EXT_ED25519_REF10_H_INCLUDED_
+#include <torint.h>
+
+int ed25519_ref10_seckey(unsigned char *sk);
+int ed25519_ref10_seckey_expand(unsigned char *sk, const unsigned char *sk_seed);
+int ed25519_ref10_pubkey(unsigned char *pk,const unsigned char *sk);
+int ed25519_ref10_keygen(unsigned char *pk,unsigned char *sk);
+int ed25519_ref10_open(
+ const unsigned char *signature,
+ const unsigned char *m, size_t mlen,
+ const unsigned char *pk);
+int ed25519_ref10_sign(
+ unsigned char *sig,
+ const unsigned char *m, size_t mlen,
+ const unsigned char *sk, const unsigned char *pk);
+
+/* Added in Tor */
+int ed25519_ref10_pubkey_from_curve25519_pubkey(unsigned char *out,
+ const unsigned char *inp,
+ int signbit);
+int ed25519_ref10_blind_secret_key(unsigned char *out,
+ const unsigned char *inp,
+ const unsigned char *param);
+int ed25519_ref10_blind_public_key(unsigned char *out,
+ const unsigned char *inp,
+ const unsigned char *param);
+
+#endif
diff --git a/src/ext/ed25519/ref10/fe.h b/src/ext/ed25519/ref10/fe.h
new file mode 100644
index 0000000000..60c308ba46
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe.h
@@ -0,0 +1,56 @@
+#ifndef FE_H
+#define FE_H
+
+#include "crypto_int32.h"
+
+typedef crypto_int32 fe[10];
+
+/*
+fe means field element.
+Here the field is \Z/(2^255-19).
+An element t, entries t[0]...t[9], represents the integer
+t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+Bounds on each t[i] vary depending on context.
+*/
+
+#define fe_frombytes crypto_sign_ed25519_ref10_fe_frombytes
+#define fe_tobytes crypto_sign_ed25519_ref10_fe_tobytes
+#define fe_copy crypto_sign_ed25519_ref10_fe_copy
+#define fe_isnonzero crypto_sign_ed25519_ref10_fe_isnonzero
+#define fe_isnegative crypto_sign_ed25519_ref10_fe_isnegative
+#define fe_0 crypto_sign_ed25519_ref10_fe_0
+#define fe_1 crypto_sign_ed25519_ref10_fe_1
+#define fe_cswap crypto_sign_ed25519_ref10_fe_cswap
+#define fe_cmov crypto_sign_ed25519_ref10_fe_cmov
+#define fe_add crypto_sign_ed25519_ref10_fe_add
+#define fe_sub crypto_sign_ed25519_ref10_fe_sub
+#define fe_neg crypto_sign_ed25519_ref10_fe_neg
+#define fe_mul crypto_sign_ed25519_ref10_fe_mul
+#define fe_sq crypto_sign_ed25519_ref10_fe_sq
+#define fe_sq2 crypto_sign_ed25519_ref10_fe_sq2
+#define fe_mul121666 crypto_sign_ed25519_ref10_fe_mul121666
+#define fe_invert crypto_sign_ed25519_ref10_fe_invert
+#define fe_pow22523 crypto_sign_ed25519_ref10_fe_pow22523
+
+extern void fe_frombytes(fe,const unsigned char *);
+extern void fe_tobytes(unsigned char *,const fe);
+
+extern void fe_copy(fe,const fe);
+extern int fe_isnonzero(const fe);
+extern int fe_isnegative(const fe);
+extern void fe_0(fe);
+extern void fe_1(fe);
+extern void fe_cswap(fe,fe,unsigned int);
+extern void fe_cmov(fe,const fe,unsigned int);
+
+extern void fe_add(fe,const fe,const fe);
+extern void fe_sub(fe,const fe,const fe);
+extern void fe_neg(fe,const fe);
+extern void fe_mul(fe,const fe,const fe);
+extern void fe_sq(fe,const fe);
+extern void fe_sq2(fe,const fe);
+extern void fe_mul121666(fe,const fe);
+extern void fe_invert(fe,const fe);
+extern void fe_pow22523(fe,const fe);
+
+#endif
diff --git a/src/ext/ed25519/ref10/fe_0.c b/src/ext/ed25519/ref10/fe_0.c
new file mode 100644
index 0000000000..ec879d7337
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_0.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 0
+*/
+
+void fe_0(fe h)
+{
+ h[0] = 0;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
diff --git a/src/ext/ed25519/ref10/fe_1.c b/src/ext/ed25519/ref10/fe_1.c
new file mode 100644
index 0000000000..8cf7784844
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_1.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 1
+*/
+
+void fe_1(fe h)
+{
+ h[0] = 1;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
diff --git a/src/ext/ed25519/ref10/fe_add.c b/src/ext/ed25519/ref10/fe_add.c
new file mode 100644
index 0000000000..e6a81da202
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_add.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_add(fe h,const fe f,const fe g)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 h0 = f0 + g0;
+ crypto_int32 h1 = f1 + g1;
+ crypto_int32 h2 = f2 + g2;
+ crypto_int32 h3 = f3 + g3;
+ crypto_int32 h4 = f4 + g4;
+ crypto_int32 h5 = f5 + g5;
+ crypto_int32 h6 = f6 + g6;
+ crypto_int32 h7 = f7 + g7;
+ crypto_int32 h8 = f8 + g8;
+ crypto_int32 h9 = f9 + g9;
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/src/ext/ed25519/ref10/fe_cmov.c b/src/ext/ed25519/ref10/fe_cmov.c
new file mode 100644
index 0000000000..8ca584fb19
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_cmov.c
@@ -0,0 +1,63 @@
+#include "fe.h"
+
+/*
+Replace (f,g) with (g,g) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+void fe_cmov(fe f,const fe g,unsigned int b)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 x0 = f0 ^ g0;
+ crypto_int32 x1 = f1 ^ g1;
+ crypto_int32 x2 = f2 ^ g2;
+ crypto_int32 x3 = f3 ^ g3;
+ crypto_int32 x4 = f4 ^ g4;
+ crypto_int32 x5 = f5 ^ g5;
+ crypto_int32 x6 = f6 ^ g6;
+ crypto_int32 x7 = f7 ^ g7;
+ crypto_int32 x8 = f8 ^ g8;
+ crypto_int32 x9 = f9 ^ g9;
+ b = -b;
+ x0 &= b;
+ x1 &= b;
+ x2 &= b;
+ x3 &= b;
+ x4 &= b;
+ x5 &= b;
+ x6 &= b;
+ x7 &= b;
+ x8 &= b;
+ x9 &= b;
+ f[0] = f0 ^ x0;
+ f[1] = f1 ^ x1;
+ f[2] = f2 ^ x2;
+ f[3] = f3 ^ x3;
+ f[4] = f4 ^ x4;
+ f[5] = f5 ^ x5;
+ f[6] = f6 ^ x6;
+ f[7] = f7 ^ x7;
+ f[8] = f8 ^ x8;
+ f[9] = f9 ^ x9;
+}
diff --git a/src/ext/ed25519/ref10/fe_copy.c b/src/ext/ed25519/ref10/fe_copy.c
new file mode 100644
index 0000000000..9c5bf865a2
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_copy.c
@@ -0,0 +1,29 @@
+#include "fe.h"
+
+/*
+h = f
+*/
+
+void fe_copy(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ h[0] = f0;
+ h[1] = f1;
+ h[2] = f2;
+ h[3] = f3;
+ h[4] = f4;
+ h[5] = f5;
+ h[6] = f6;
+ h[7] = f7;
+ h[8] = f8;
+ h[9] = f9;
+}
diff --git a/src/ext/ed25519/ref10/fe_frombytes.c b/src/ext/ed25519/ref10/fe_frombytes.c
new file mode 100644
index 0000000000..98b8e5f7c1
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_frombytes.c
@@ -0,0 +1,73 @@
+#include "fe.h"
+#include "crypto_int64.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ result |= ((crypto_uint64) in[3]) << 24;
+ return result;
+}
+
+/*
+Ignores top bit of h.
+*/
+
+void fe_frombytes(fe h,const unsigned char *s)
+{
+ crypto_int64 h0 = load_4(s);
+ crypto_int64 h1 = load_3(s + 4) << 6;
+ crypto_int64 h2 = load_3(s + 7) << 5;
+ crypto_int64 h3 = load_3(s + 10) << 3;
+ crypto_int64 h4 = load_3(s + 13) << 2;
+ crypto_int64 h5 = load_4(s + 16);
+ crypto_int64 h6 = load_3(s + 20) << 7;
+ crypto_int64 h7 = load_3(s + 23) << 5;
+ crypto_int64 h8 = load_3(s + 26) << 4;
+ crypto_int64 h9 = (load_3(s + 29) & 8388607) << 2;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= SHL64(carry9,25);
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= SHL64(carry1,25);
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= SHL64(carry3,25);
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= SHL64(carry5,25);
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= SHL64(carry7,25);
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26);
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= SHL64(carry2,26);
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26);
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= SHL64(carry6,26);
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= SHL64(carry8,26);
+
+ h[0] = (crypto_int32) h0;
+ h[1] = (crypto_int32) h1;
+ h[2] = (crypto_int32) h2;
+ h[3] = (crypto_int32) h3;
+ h[4] = (crypto_int32) h4;
+ h[5] = (crypto_int32) h5;
+ h[6] = (crypto_int32) h6;
+ h[7] = (crypto_int32) h7;
+ h[8] = (crypto_int32) h8;
+ h[9] = (crypto_int32) h9;
+}
diff --git a/src/ext/ed25519/ref10/fe_invert.c b/src/ext/ed25519/ref10/fe_invert.c
new file mode 100644
index 0000000000..bcfdb8ff87
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_invert.c
@@ -0,0 +1,14 @@
+#include "fe.h"
+
+void fe_invert(fe out,const fe z)
+{
+ fe t0;
+ fe t1;
+ fe t2;
+ fe t3;
+ int i;
+
+#include "pow225521.h"
+
+ return;
+}
diff --git a/src/ext/ed25519/ref10/fe_isnegative.c b/src/ext/ed25519/ref10/fe_isnegative.c
new file mode 100644
index 0000000000..3b2c8b8d52
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_isnegative.c
@@ -0,0 +1,16 @@
+#include "fe.h"
+
+/*
+return 1 if f is in {1,3,5,...,q-2}
+return 0 if f is in {0,2,4,...,q-1}
+
+Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+int fe_isnegative(const fe f)
+{
+ unsigned char s[32];
+ fe_tobytes(s,f);
+ return s[0] & 1;
+}
diff --git a/src/ext/ed25519/ref10/fe_isnonzero.c b/src/ext/ed25519/ref10/fe_isnonzero.c
new file mode 100644
index 0000000000..47568001ce
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_isnonzero.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+#include "crypto_verify_32.h"
+
+/*
+return 1 if f == 0
+return 0 if f != 0
+
+Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+static const unsigned char zero[32];
+
+int fe_isnonzero(const fe f)
+{
+ unsigned char s[32];
+ fe_tobytes(s,f);
+ return crypto_verify_32(s,zero);
+}
diff --git a/src/ext/ed25519/ref10/fe_mul.c b/src/ext/ed25519/ref10/fe_mul.c
new file mode 100644
index 0000000000..ace63e64c1
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_mul.c
@@ -0,0 +1,253 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+ |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+Notes on implementation strategy:
+
+Using schoolbook multiplication.
+Karatsuba would save a little in some cost models.
+
+Most multiplications by 2 and 19 are 32-bit precomputations;
+cheaper than 64-bit postcomputations.
+
+There is one remaining multiplication by 19 in the carry chain;
+one *19 precomputation can be merged into this,
+but the resulting data flow is considerably less clean.
+
+There are 12 carries below.
+10 of them are 2-way parallelizable and vectorizable.
+Can get away with 11 carries, but then data flow is much deeper.
+
+With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+void fe_mul(fe h,const fe f,const fe g)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 g1_19 = 19 * g1; /* 1.959375*2^29 */
+ crypto_int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+ crypto_int32 g3_19 = 19 * g3;
+ crypto_int32 g4_19 = 19 * g4;
+ crypto_int32 g5_19 = 19 * g5;
+ crypto_int32 g6_19 = 19 * g6;
+ crypto_int32 g7_19 = 19 * g7;
+ crypto_int32 g8_19 = 19 * g8;
+ crypto_int32 g9_19 = 19 * g9;
+ crypto_int32 f1_2 = 2 * f1;
+ crypto_int32 f3_2 = 2 * f3;
+ crypto_int32 f5_2 = 2 * f5;
+ crypto_int32 f7_2 = 2 * f7;
+ crypto_int32 f9_2 = 2 * f9;
+ crypto_int64 f0g0 = f0 * (crypto_int64) g0;
+ crypto_int64 f0g1 = f0 * (crypto_int64) g1;
+ crypto_int64 f0g2 = f0 * (crypto_int64) g2;
+ crypto_int64 f0g3 = f0 * (crypto_int64) g3;
+ crypto_int64 f0g4 = f0 * (crypto_int64) g4;
+ crypto_int64 f0g5 = f0 * (crypto_int64) g5;
+ crypto_int64 f0g6 = f0 * (crypto_int64) g6;
+ crypto_int64 f0g7 = f0 * (crypto_int64) g7;
+ crypto_int64 f0g8 = f0 * (crypto_int64) g8;
+ crypto_int64 f0g9 = f0 * (crypto_int64) g9;
+ crypto_int64 f1g0 = f1 * (crypto_int64) g0;
+ crypto_int64 f1g1_2 = f1_2 * (crypto_int64) g1;
+ crypto_int64 f1g2 = f1 * (crypto_int64) g2;
+ crypto_int64 f1g3_2 = f1_2 * (crypto_int64) g3;
+ crypto_int64 f1g4 = f1 * (crypto_int64) g4;
+ crypto_int64 f1g5_2 = f1_2 * (crypto_int64) g5;
+ crypto_int64 f1g6 = f1 * (crypto_int64) g6;
+ crypto_int64 f1g7_2 = f1_2 * (crypto_int64) g7;
+ crypto_int64 f1g8 = f1 * (crypto_int64) g8;
+ crypto_int64 f1g9_38 = f1_2 * (crypto_int64) g9_19;
+ crypto_int64 f2g0 = f2 * (crypto_int64) g0;
+ crypto_int64 f2g1 = f2 * (crypto_int64) g1;
+ crypto_int64 f2g2 = f2 * (crypto_int64) g2;
+ crypto_int64 f2g3 = f2 * (crypto_int64) g3;
+ crypto_int64 f2g4 = f2 * (crypto_int64) g4;
+ crypto_int64 f2g5 = f2 * (crypto_int64) g5;
+ crypto_int64 f2g6 = f2 * (crypto_int64) g6;
+ crypto_int64 f2g7 = f2 * (crypto_int64) g7;
+ crypto_int64 f2g8_19 = f2 * (crypto_int64) g8_19;
+ crypto_int64 f2g9_19 = f2 * (crypto_int64) g9_19;
+ crypto_int64 f3g0 = f3 * (crypto_int64) g0;
+ crypto_int64 f3g1_2 = f3_2 * (crypto_int64) g1;
+ crypto_int64 f3g2 = f3 * (crypto_int64) g2;
+ crypto_int64 f3g3_2 = f3_2 * (crypto_int64) g3;
+ crypto_int64 f3g4 = f3 * (crypto_int64) g4;
+ crypto_int64 f3g5_2 = f3_2 * (crypto_int64) g5;
+ crypto_int64 f3g6 = f3 * (crypto_int64) g6;
+ crypto_int64 f3g7_38 = f3_2 * (crypto_int64) g7_19;
+ crypto_int64 f3g8_19 = f3 * (crypto_int64) g8_19;
+ crypto_int64 f3g9_38 = f3_2 * (crypto_int64) g9_19;
+ crypto_int64 f4g0 = f4 * (crypto_int64) g0;
+ crypto_int64 f4g1 = f4 * (crypto_int64) g1;
+ crypto_int64 f4g2 = f4 * (crypto_int64) g2;
+ crypto_int64 f4g3 = f4 * (crypto_int64) g3;
+ crypto_int64 f4g4 = f4 * (crypto_int64) g4;
+ crypto_int64 f4g5 = f4 * (crypto_int64) g5;
+ crypto_int64 f4g6_19 = f4 * (crypto_int64) g6_19;
+ crypto_int64 f4g7_19 = f4 * (crypto_int64) g7_19;
+ crypto_int64 f4g8_19 = f4 * (crypto_int64) g8_19;
+ crypto_int64 f4g9_19 = f4 * (crypto_int64) g9_19;
+ crypto_int64 f5g0 = f5 * (crypto_int64) g0;
+ crypto_int64 f5g1_2 = f5_2 * (crypto_int64) g1;
+ crypto_int64 f5g2 = f5 * (crypto_int64) g2;
+ crypto_int64 f5g3_2 = f5_2 * (crypto_int64) g3;
+ crypto_int64 f5g4 = f5 * (crypto_int64) g4;
+ crypto_int64 f5g5_38 = f5_2 * (crypto_int64) g5_19;
+ crypto_int64 f5g6_19 = f5 * (crypto_int64) g6_19;
+ crypto_int64 f5g7_38 = f5_2 * (crypto_int64) g7_19;
+ crypto_int64 f5g8_19 = f5 * (crypto_int64) g8_19;
+ crypto_int64 f5g9_38 = f5_2 * (crypto_int64) g9_19;
+ crypto_int64 f6g0 = f6 * (crypto_int64) g0;
+ crypto_int64 f6g1 = f6 * (crypto_int64) g1;
+ crypto_int64 f6g2 = f6 * (crypto_int64) g2;
+ crypto_int64 f6g3 = f6 * (crypto_int64) g3;
+ crypto_int64 f6g4_19 = f6 * (crypto_int64) g4_19;
+ crypto_int64 f6g5_19 = f6 * (crypto_int64) g5_19;
+ crypto_int64 f6g6_19 = f6 * (crypto_int64) g6_19;
+ crypto_int64 f6g7_19 = f6 * (crypto_int64) g7_19;
+ crypto_int64 f6g8_19 = f6 * (crypto_int64) g8_19;
+ crypto_int64 f6g9_19 = f6 * (crypto_int64) g9_19;
+ crypto_int64 f7g0 = f7 * (crypto_int64) g0;
+ crypto_int64 f7g1_2 = f7_2 * (crypto_int64) g1;
+ crypto_int64 f7g2 = f7 * (crypto_int64) g2;
+ crypto_int64 f7g3_38 = f7_2 * (crypto_int64) g3_19;
+ crypto_int64 f7g4_19 = f7 * (crypto_int64) g4_19;
+ crypto_int64 f7g5_38 = f7_2 * (crypto_int64) g5_19;
+ crypto_int64 f7g6_19 = f7 * (crypto_int64) g6_19;
+ crypto_int64 f7g7_38 = f7_2 * (crypto_int64) g7_19;
+ crypto_int64 f7g8_19 = f7 * (crypto_int64) g8_19;
+ crypto_int64 f7g9_38 = f7_2 * (crypto_int64) g9_19;
+ crypto_int64 f8g0 = f8 * (crypto_int64) g0;
+ crypto_int64 f8g1 = f8 * (crypto_int64) g1;
+ crypto_int64 f8g2_19 = f8 * (crypto_int64) g2_19;
+ crypto_int64 f8g3_19 = f8 * (crypto_int64) g3_19;
+ crypto_int64 f8g4_19 = f8 * (crypto_int64) g4_19;
+ crypto_int64 f8g5_19 = f8 * (crypto_int64) g5_19;
+ crypto_int64 f8g6_19 = f8 * (crypto_int64) g6_19;
+ crypto_int64 f8g7_19 = f8 * (crypto_int64) g7_19;
+ crypto_int64 f8g8_19 = f8 * (crypto_int64) g8_19;
+ crypto_int64 f8g9_19 = f8 * (crypto_int64) g9_19;
+ crypto_int64 f9g0 = f9 * (crypto_int64) g0;
+ crypto_int64 f9g1_38 = f9_2 * (crypto_int64) g1_19;
+ crypto_int64 f9g2_19 = f9 * (crypto_int64) g2_19;
+ crypto_int64 f9g3_38 = f9_2 * (crypto_int64) g3_19;
+ crypto_int64 f9g4_19 = f9 * (crypto_int64) g4_19;
+ crypto_int64 f9g5_38 = f9_2 * (crypto_int64) g5_19;
+ crypto_int64 f9g6_19 = f9 * (crypto_int64) g6_19;
+ crypto_int64 f9g7_38 = f9_2 * (crypto_int64) g7_19;
+ crypto_int64 f9g8_19 = f9 * (crypto_int64) g8_19;
+ crypto_int64 f9g9_38 = f9_2 * (crypto_int64) g9_19;
+ crypto_int64 h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+ crypto_int64 h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+ crypto_int64 h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+ crypto_int64 h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+ crypto_int64 h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+ crypto_int64 h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+ crypto_int64 h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38;
+ crypto_int64 h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19;
+ crypto_int64 h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38;
+ crypto_int64 h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ /*
+ |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
+ i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
+ |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
+ i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9
+ */
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26);
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26);
+ /* |h0| <= 2^25 */
+ /* |h4| <= 2^25 */
+ /* |h1| <= 1.71*2^59 */
+ /* |h5| <= 1.71*2^59 */
+
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= SHL64(carry1,25);
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= SHL64(carry5,25);
+ /* |h1| <= 2^24; from now on fits into int32 */
+ /* |h5| <= 2^24; from now on fits into int32 */
+ /* |h2| <= 1.41*2^60 */
+ /* |h6| <= 1.41*2^60 */
+
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= SHL64(carry2,26);
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= SHL64(carry6,26);
+ /* |h2| <= 2^25; from now on fits into int32 unchanged */
+ /* |h6| <= 2^25; from now on fits into int32 unchanged */
+ /* |h3| <= 1.71*2^59 */
+ /* |h7| <= 1.71*2^59 */
+
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= SHL64(carry3,25);
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= SHL64(carry7,25);
+ /* |h3| <= 2^24; from now on fits into int32 unchanged */
+ /* |h7| <= 2^24; from now on fits into int32 unchanged */
+ /* |h4| <= 1.72*2^34 */
+ /* |h8| <= 1.41*2^60 */
+
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26);
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= SHL64(carry8,26);
+ /* |h4| <= 2^25; from now on fits into int32 unchanged */
+ /* |h8| <= 2^25; from now on fits into int32 unchanged */
+ /* |h5| <= 1.01*2^24 */
+ /* |h9| <= 1.71*2^59 */
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= SHL64(carry9,25);
+ /* |h9| <= 2^24; from now on fits into int32 unchanged */
+ /* |h0| <= 1.1*2^39 */
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26);
+ /* |h0| <= 2^25; from now on fits into int32 unchanged */
+ /* |h1| <= 1.01*2^24 */
+
+ h[0] = (crypto_int32) h0;
+ h[1] = (crypto_int32) h1;
+ h[2] = (crypto_int32) h2;
+ h[3] = (crypto_int32) h3;
+ h[4] = (crypto_int32) h4;
+ h[5] = (crypto_int32) h5;
+ h[6] = (crypto_int32) h6;
+ h[7] = (crypto_int32) h7;
+ h[8] = (crypto_int32) h8;
+ h[9] = (crypto_int32) h9;
+}
diff --git a/src/ext/ed25519/ref10/fe_neg.c b/src/ext/ed25519/ref10/fe_neg.c
new file mode 100644
index 0000000000..2078ce5284
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_neg.c
@@ -0,0 +1,45 @@
+#include "fe.h"
+
+/*
+h = -f
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_neg(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 h0 = -f0;
+ crypto_int32 h1 = -f1;
+ crypto_int32 h2 = -f2;
+ crypto_int32 h3 = -f3;
+ crypto_int32 h4 = -f4;
+ crypto_int32 h5 = -f5;
+ crypto_int32 h6 = -f6;
+ crypto_int32 h7 = -f7;
+ crypto_int32 h8 = -f8;
+ crypto_int32 h9 = -f9;
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/src/ext/ed25519/ref10/fe_pow22523.c b/src/ext/ed25519/ref10/fe_pow22523.c
new file mode 100644
index 0000000000..56675a5902
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_pow22523.c
@@ -0,0 +1,13 @@
+#include "fe.h"
+
+void fe_pow22523(fe out,const fe z)
+{
+ fe t0;
+ fe t1;
+ fe t2;
+ int i;
+
+#include "pow22523.h"
+
+ return;
+}
diff --git a/src/ext/ed25519/ref10/fe_sq.c b/src/ext/ed25519/ref10/fe_sq.c
new file mode 100644
index 0000000000..0022a17510
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_sq.c
@@ -0,0 +1,149 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 f0_2 = 2 * f0;
+ crypto_int32 f1_2 = 2 * f1;
+ crypto_int32 f2_2 = 2 * f2;
+ crypto_int32 f3_2 = 2 * f3;
+ crypto_int32 f4_2 = 2 * f4;
+ crypto_int32 f5_2 = 2 * f5;
+ crypto_int32 f6_2 = 2 * f6;
+ crypto_int32 f7_2 = 2 * f7;
+ crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+ crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+ crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+ crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+ crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+ crypto_int64 f0f0 = f0 * (crypto_int64) f0;
+ crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1;
+ crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2;
+ crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3;
+ crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4;
+ crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5;
+ crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6;
+ crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7;
+ crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8;
+ crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9;
+ crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1;
+ crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2;
+ crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2;
+ crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4;
+ crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2;
+ crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6;
+ crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2;
+ crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8;
+ crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+ crypto_int64 f2f2 = f2 * (crypto_int64) f2;
+ crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3;
+ crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4;
+ crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5;
+ crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6;
+ crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7;
+ crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+ crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38;
+ crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3;
+ crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4;
+ crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2;
+ crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6;
+ crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+ crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+ crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+ crypto_int64 f4f4 = f4 * (crypto_int64) f4;
+ crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5;
+ crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+ crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38;
+ crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+ crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38;
+ crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38;
+ crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+ crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+ crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+ crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+ crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19;
+ crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38;
+ crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+ crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38;
+ crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38;
+ crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+ crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+ crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19;
+ crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38;
+ crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38;
+ crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+ crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+ crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+ crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+ crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38;
+ crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+ crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+ crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+ crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38;
+ crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26);
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26);
+
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= SHL64(carry1,25);
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= SHL64(carry5,25);
+
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= SHL64(carry2,26);
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= SHL64(carry6,26);
+
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= SHL64(carry3,25);
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= SHL64(carry7,25);
+
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26);
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= SHL64(carry8,26);
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= SHL64(carry9,25);
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26);
+
+ h[0] = (crypto_int32) h0;
+ h[1] = (crypto_int32) h1;
+ h[2] = (crypto_int32) h2;
+ h[3] = (crypto_int32) h3;
+ h[4] = (crypto_int32) h4;
+ h[5] = (crypto_int32) h5;
+ h[6] = (crypto_int32) h6;
+ h[7] = (crypto_int32) h7;
+ h[8] = (crypto_int32) h8;
+ h[9] = (crypto_int32) h9;
+}
diff --git a/src/ext/ed25519/ref10/fe_sq2.c b/src/ext/ed25519/ref10/fe_sq2.c
new file mode 100644
index 0000000000..e8faa69ec9
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_sq2.c
@@ -0,0 +1,160 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq2(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 f0_2 = 2 * f0;
+ crypto_int32 f1_2 = 2 * f1;
+ crypto_int32 f2_2 = 2 * f2;
+ crypto_int32 f3_2 = 2 * f3;
+ crypto_int32 f4_2 = 2 * f4;
+ crypto_int32 f5_2 = 2 * f5;
+ crypto_int32 f6_2 = 2 * f6;
+ crypto_int32 f7_2 = 2 * f7;
+ crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+ crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+ crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+ crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+ crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+ crypto_int64 f0f0 = f0 * (crypto_int64) f0;
+ crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1;
+ crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2;
+ crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3;
+ crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4;
+ crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5;
+ crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6;
+ crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7;
+ crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8;
+ crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9;
+ crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1;
+ crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2;
+ crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2;
+ crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4;
+ crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2;
+ crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6;
+ crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2;
+ crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8;
+ crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+ crypto_int64 f2f2 = f2 * (crypto_int64) f2;
+ crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3;
+ crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4;
+ crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5;
+ crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6;
+ crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7;
+ crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+ crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38;
+ crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3;
+ crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4;
+ crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2;
+ crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6;
+ crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+ crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+ crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+ crypto_int64 f4f4 = f4 * (crypto_int64) f4;
+ crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5;
+ crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+ crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38;
+ crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+ crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38;
+ crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38;
+ crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+ crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+ crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+ crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+ crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19;
+ crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38;
+ crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+ crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38;
+ crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38;
+ crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+ crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+ crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19;
+ crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38;
+ crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38;
+ crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+ crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+ crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+ crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+ crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38;
+ crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+ crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+ crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+ crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38;
+ crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ h0 += h0;
+ h1 += h1;
+ h2 += h2;
+ h3 += h3;
+ h4 += h4;
+ h5 += h5;
+ h6 += h6;
+ h7 += h7;
+ h8 += h8;
+ h9 += h9;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26);
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26);
+
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= SHL64(carry1,25);
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= SHL64(carry5,25);
+
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= SHL64(carry2,26);
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= SHL64(carry6,26);
+
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= SHL64(carry3,25);
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= SHL64(carry7,25);
+
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= SHL64(carry4,26);
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= SHL64(carry8,26);
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= SHL64(carry9,25);
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= SHL64(carry0,26);
+
+ h[0] = (crypto_int32) h0;
+ h[1] = (crypto_int32) h1;
+ h[2] = (crypto_int32) h2;
+ h[3] = (crypto_int32) h3;
+ h[4] = (crypto_int32) h4;
+ h[5] = (crypto_int32) h5;
+ h[6] = (crypto_int32) h6;
+ h[7] = (crypto_int32) h7;
+ h[8] = (crypto_int32) h8;
+ h[9] = (crypto_int32) h9;
+}
diff --git a/src/ext/ed25519/ref10/fe_sub.c b/src/ext/ed25519/ref10/fe_sub.c
new file mode 100644
index 0000000000..6e26b7df8f
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_sub.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_sub(fe h,const fe f,const fe g)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 h0 = f0 - g0;
+ crypto_int32 h1 = f1 - g1;
+ crypto_int32 h2 = f2 - g2;
+ crypto_int32 h3 = f3 - g3;
+ crypto_int32 h4 = f4 - g4;
+ crypto_int32 h5 = f5 - g5;
+ crypto_int32 h6 = f6 - g6;
+ crypto_int32 h7 = f7 - g7;
+ crypto_int32 h8 = f8 - g8;
+ crypto_int32 h9 = f9 - g9;
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/src/ext/ed25519/ref10/fe_tobytes.c b/src/ext/ed25519/ref10/fe_tobytes.c
new file mode 100644
index 0000000000..3c7f389622
--- /dev/null
+++ b/src/ext/ed25519/ref10/fe_tobytes.c
@@ -0,0 +1,119 @@
+#include "fe.h"
+
+/*
+Preconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+ Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+ Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+ Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+ Then 0<y<1.
+
+ Write r=h-pq.
+ Have 0<=r<=p-1=2^255-20.
+ Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+ Write x=r+19(2^-255)r+y.
+ Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+ Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+ so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+void fe_tobytes(unsigned char *s,const fe h)
+{
+ crypto_int32 h0 = h[0];
+ crypto_int32 h1 = h[1];
+ crypto_int32 h2 = h[2];
+ crypto_int32 h3 = h[3];
+ crypto_int32 h4 = h[4];
+ crypto_int32 h5 = h[5];
+ crypto_int32 h6 = h[6];
+ crypto_int32 h7 = h[7];
+ crypto_int32 h8 = h[8];
+ crypto_int32 h9 = h[9];
+ crypto_int32 q;
+ crypto_int32 carry0;
+ crypto_int32 carry1;
+ crypto_int32 carry2;
+ crypto_int32 carry3;
+ crypto_int32 carry4;
+ crypto_int32 carry5;
+ crypto_int32 carry6;
+ crypto_int32 carry7;
+ crypto_int32 carry8;
+ crypto_int32 carry9;
+
+ q = (19 * h9 + (((crypto_int32) 1) << 24)) >> 25;
+ q = (h0 + q) >> 26;
+ q = (h1 + q) >> 25;
+ q = (h2 + q) >> 26;
+ q = (h3 + q) >> 25;
+ q = (h4 + q) >> 26;
+ q = (h5 + q) >> 25;
+ q = (h6 + q) >> 26;
+ q = (h7 + q) >> 25;
+ q = (h8 + q) >> 26;
+ q = (h9 + q) >> 25;
+
+ /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+ h0 += 19 * q;
+ /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+ carry0 = h0 >> 26; h1 += carry0; h0 -= SHL32(carry0,26);
+ carry1 = h1 >> 25; h2 += carry1; h1 -= SHL32(carry1,25);
+ carry2 = h2 >> 26; h3 += carry2; h2 -= SHL32(carry2,26);
+ carry3 = h3 >> 25; h4 += carry3; h3 -= SHL32(carry3,25);
+ carry4 = h4 >> 26; h5 += carry4; h4 -= SHL32(carry4,26);
+ carry5 = h5 >> 25; h6 += carry5; h5 -= SHL32(carry5,25);
+ carry6 = h6 >> 26; h7 += carry6; h6 -= SHL32(carry6,26);
+ carry7 = h7 >> 25; h8 += carry7; h7 -= SHL32(carry7,25);
+ carry8 = h8 >> 26; h9 += carry8; h8 -= SHL32(carry8,26);
+ carry9 = h9 >> 25; h9 -= SHL32(carry9,25);
+ /* h10 = carry9 */
+
+ /*
+ Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ Have h0+...+2^230 h9 between 0 and 2^255-1;
+ evidently 2^255 h10-2^255 q = 0.
+ Goal: Output h0+...+2^230 h9.
+ */
+
+ s[0] = h0 >> 0;
+ s[1] = h0 >> 8;
+ s[2] = h0 >> 16;
+ s[3] = (h0 >> 24) | SHL32(h1,2);
+ s[4] = h1 >> 6;
+ s[5] = h1 >> 14;
+ s[6] = (h1 >> 22) | SHL32(h2,3);
+ s[7] = h2 >> 5;
+ s[8] = h2 >> 13;
+ s[9] = (h2 >> 21) | SHL32(h3,5);
+ s[10] = h3 >> 3;
+ s[11] = h3 >> 11;
+ s[12] = (h3 >> 19) | SHL32(h4,6);
+ s[13] = h4 >> 2;
+ s[14] = h4 >> 10;
+ s[15] = h4 >> 18;
+ s[16] = h5 >> 0;
+ s[17] = h5 >> 8;
+ s[18] = h5 >> 16;
+ s[19] = (h5 >> 24) | SHL32(h6,1);
+ s[20] = h6 >> 7;
+ s[21] = h6 >> 15;
+ s[22] = (h6 >> 23) | SHL32(h7,3);
+ s[23] = h7 >> 5;
+ s[24] = h7 >> 13;
+ s[25] = (h7 >> 21) | SHL32(h8,4);
+ s[26] = h8 >> 4;
+ s[27] = h8 >> 12;
+ s[28] = (h8 >> 20) | SHL32(h9,6);
+ s[29] = h9 >> 2;
+ s[30] = h9 >> 10;
+ s[31] = h9 >> 18;
+}
diff --git a/src/ext/ed25519/ref10/ge.h b/src/ext/ed25519/ref10/ge.h
new file mode 100644
index 0000000000..55e95f95b6
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge.h
@@ -0,0 +1,95 @@
+#ifndef GE_H
+#define GE_H
+
+/*
+ge means group element.
+
+Here the group is the set of pairs (x,y) of field elements (see fe.h)
+satisfying -x^2 + y^2 = 1 + d x^2y^2
+where d = -121665/121666.
+
+Representations:
+ ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+ ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+ ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+ ge_precomp (Duif): (y+x,y-x,2dxy)
+*/
+
+#include "fe.h"
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+} ge_p2;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p3;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p1p1;
+
+typedef struct {
+ fe yplusx;
+ fe yminusx;
+ fe xy2d;
+} ge_precomp;
+
+typedef struct {
+ fe YplusX;
+ fe YminusX;
+ fe Z;
+ fe T2d;
+} ge_cached;
+
+#define ge_frombytes_negate_vartime crypto_sign_ed25519_ref10_ge_frombytes_negate_vartime
+#define ge_tobytes crypto_sign_ed25519_ref10_ge_tobytes
+#define ge_p3_tobytes crypto_sign_ed25519_ref10_ge_p3_tobytes
+
+#define ge_p2_0 crypto_sign_ed25519_ref10_ge_p2_0
+#define ge_p3_0 crypto_sign_ed25519_ref10_ge_p3_0
+#define ge_precomp_0 crypto_sign_ed25519_ref10_ge_precomp_0
+#define ge_p3_to_p2 crypto_sign_ed25519_ref10_ge_p3_to_p2
+#define ge_p3_to_cached crypto_sign_ed25519_ref10_ge_p3_to_cached
+#define ge_p1p1_to_p2 crypto_sign_ed25519_ref10_ge_p1p1_to_p2
+#define ge_p1p1_to_p3 crypto_sign_ed25519_ref10_ge_p1p1_to_p3
+#define ge_p2_dbl crypto_sign_ed25519_ref10_ge_p2_dbl
+#define ge_p3_dbl crypto_sign_ed25519_ref10_ge_p3_dbl
+
+#define ge_madd crypto_sign_ed25519_ref10_ge_madd
+#define ge_msub crypto_sign_ed25519_ref10_ge_msub
+#define ge_add crypto_sign_ed25519_ref10_ge_add
+#define ge_sub crypto_sign_ed25519_ref10_ge_sub
+#define ge_scalarmult_base crypto_sign_ed25519_ref10_ge_scalarmult_base
+#define ge_double_scalarmult_vartime crypto_sign_ed25519_ref10_ge_double_scalarmult_vartime
+
+extern void ge_tobytes(unsigned char *,const ge_p2 *);
+extern void ge_p3_tobytes(unsigned char *,const ge_p3 *);
+extern int ge_frombytes_negate_vartime(ge_p3 *,const unsigned char *);
+
+extern void ge_p2_0(ge_p2 *);
+extern void ge_p3_0(ge_p3 *);
+extern void ge_precomp_0(ge_precomp *);
+extern void ge_p3_to_p2(ge_p2 *,const ge_p3 *);
+extern void ge_p3_to_cached(ge_cached *,const ge_p3 *);
+extern void ge_p1p1_to_p2(ge_p2 *,const ge_p1p1 *);
+extern void ge_p1p1_to_p3(ge_p3 *,const ge_p1p1 *);
+extern void ge_p2_dbl(ge_p1p1 *,const ge_p2 *);
+extern void ge_p3_dbl(ge_p1p1 *,const ge_p3 *);
+
+extern void ge_madd(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_msub(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_add(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_sub(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_scalarmult_base(ge_p3 *,const unsigned char *);
+extern void ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,const ge_p3 *,const unsigned char *);
+
+#endif
diff --git a/src/ext/ed25519/ref10/ge_add.c b/src/ext/ed25519/ref10/ge_add.c
new file mode 100644
index 0000000000..da7ff5d2eb
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_add.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+ fe t0;
+#include "ge_add.h"
+}
diff --git a/src/ext/ed25519/ref10/ge_add.h b/src/ext/ed25519/ref10/ge_add.h
new file mode 100644
index 0000000000..7481f8ffbe
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_add.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_add */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YpX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YpX2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YpX2=q->YplusX); */
+fe_mul(r->Z,r->X,q->YplusX);
+
+/* qhasm: B = YmX1*YmX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YmX2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YmX2=q->YminusX); */
+fe_mul(r->Y,r->Y,q->YminusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/src/ext/ed25519/ref10/ge_add.q b/src/ext/ed25519/ref10/ge_add.q
new file mode 100644
index 0000000000..a6572ab0f8
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_add.q
@@ -0,0 +1,49 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->YplusX:q->YminusX:q->Z:q->T2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>YpX2=fe#15:>YmX2=fe#16:>Z2=fe#17:>T2d2=fe#18:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_add
+
+fe X1
+fe Y1
+fe Z1
+fe Z2
+fe T1
+fe ZZ
+fe YpX2
+fe YmX2
+fe T2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*YpX2
+B = YmX1*YmX2
+C = T2d2*T1
+ZZ = Z1*Z2
+D = 2*ZZ
+X3 = A-B
+Y3 = A+B
+Z3 = D+C
+T3 = D-C
+
+return
diff --git a/src/ext/ed25519/ref10/ge_double_scalarmult.c b/src/ext/ed25519/ref10/ge_double_scalarmult.c
new file mode 100644
index 0000000000..f8bf4bf775
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_double_scalarmult.c
@@ -0,0 +1,96 @@
+#include "ge.h"
+
+static void slide(signed char *r,const unsigned char *a)
+{
+ int i;
+ int b;
+ int k;
+
+ for (i = 0;i < 256;++i)
+ r[i] = 1 & (a[i >> 3] >> (i & 7));
+
+ for (i = 0;i < 256;++i)
+ if (r[i]) {
+ for (b = 1;b <= 6 && i + b < 256;++b) {
+ if (r[i + b]) {
+ if (r[i] + (r[i + b] << b) <= 15) {
+ r[i] += r[i + b] << b; r[i + b] = 0;
+ } else if (r[i] - (r[i + b] << b) >= -15) {
+ r[i] -= r[i + b] << b;
+ for (k = i + b;k < 256;++k) {
+ if (!r[k]) {
+ r[k] = 1;
+ break;
+ }
+ r[k] = 0;
+ }
+ } else
+ break;
+ }
+ }
+ }
+
+}
+
+static ge_precomp Bi[8] = {
+#include "base2.h"
+} ;
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+void ge_double_scalarmult_vartime(ge_p2 *r,const unsigned char *a,const ge_p3 *A,const unsigned char *b)
+{
+ signed char aslide[256];
+ signed char bslide[256];
+ ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
+ ge_p1p1 t;
+ ge_p3 u;
+ ge_p3 A2;
+ int i;
+
+ slide(aslide,a);
+ slide(bslide,b);
+
+ ge_p3_to_cached(&Ai[0],A);
+ ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
+ ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
+ ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
+ ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
+ ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
+ ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
+ ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
+ ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
+
+ ge_p2_0(r);
+
+ for (i = 255;i >= 0;--i) {
+ if (aslide[i] || bslide[i]) break;
+ }
+
+ for (;i >= 0;--i) {
+ ge_p2_dbl(&t,r);
+
+ if (aslide[i] > 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_add(&t,&u,&Ai[aslide[i]/2]);
+ } else if (aslide[i] < 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
+ }
+
+ if (bslide[i] > 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_madd(&t,&u,&Bi[bslide[i]/2]);
+ } else if (bslide[i] < 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
+ }
+
+ ge_p1p1_to_p2(r,&t);
+ }
+}
diff --git a/src/ext/ed25519/ref10/ge_frombytes.c b/src/ext/ed25519/ref10/ge_frombytes.c
new file mode 100644
index 0000000000..1a059ee93f
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_frombytes.c
@@ -0,0 +1,50 @@
+#include "ge.h"
+
+static const fe d = {
+#include "d.h"
+} ;
+
+static const fe sqrtm1 = {
+#include "sqrtm1.h"
+} ;
+
+int ge_frombytes_negate_vartime(ge_p3 *h,const unsigned char *s)
+{
+ fe u;
+ fe v;
+ fe v3;
+ fe vxx;
+ fe check;
+
+ fe_frombytes(h->Y,s);
+ fe_1(h->Z);
+ fe_sq(u,h->Y);
+ fe_mul(v,u,d);
+ fe_sub(u,u,h->Z); /* u = y^2-1 */
+ fe_add(v,v,h->Z); /* v = dy^2+1 */
+
+ fe_sq(v3,v);
+ fe_mul(v3,v3,v); /* v3 = v^3 */
+ fe_sq(h->X,v3);
+ fe_mul(h->X,h->X,v);
+ fe_mul(h->X,h->X,u); /* x = uv^7 */
+
+ fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
+ fe_mul(h->X,h->X,v3);
+ fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */
+
+ fe_sq(vxx,h->X);
+ fe_mul(vxx,vxx,v);
+ fe_sub(check,vxx,u); /* vx^2-u */
+ if (fe_isnonzero(check)) {
+ fe_add(check,vxx,u); /* vx^2+u */
+ if (fe_isnonzero(check)) return -1;
+ fe_mul(h->X,h->X,sqrtm1);
+ }
+
+ if (fe_isnegative(h->X) == (s[31] >> 7))
+ fe_neg(h->X,h->X);
+
+ fe_mul(h->T,h->X,h->Y);
+ return 0;
+}
diff --git a/src/ext/ed25519/ref10/ge_madd.c b/src/ext/ed25519/ref10/ge_madd.c
new file mode 100644
index 0000000000..622571774b
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_madd.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_madd(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+ fe t0;
+#include "ge_madd.h"
+}
diff --git a/src/ext/ed25519/ref10/ge_madd.h b/src/ext/ed25519/ref10/ge_madd.h
new file mode 100644
index 0000000000..ecae84952b
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_madd.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_madd */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ypx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ypx2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ypx2=q->yplusx); */
+fe_mul(r->Z,r->X,q->yplusx);
+
+/* qhasm: B = YmX1*ymx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ymx2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ymx2=q->yminusx); */
+fe_mul(r->Y,r->Y,q->yminusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/src/ext/ed25519/ref10/ge_madd.q b/src/ext/ed25519/ref10/ge_madd.q
new file mode 100644
index 0000000000..aa3db454e6
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_madd.q
@@ -0,0 +1,46 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->yplusx:q->yminusx:q->xy2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>ypx2=fe#15:>ymx2=fe#16:>xy2d2=fe#17:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_madd
+
+fe X1
+fe Y1
+fe Z1
+fe T1
+fe ypx2
+fe ymx2
+fe xy2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*ypx2
+B = YmX1*ymx2
+C = xy2d2*T1
+D = 2*Z1
+X3 = A-B
+Y3 = A+B
+Z3 = D+C
+T3 = D-C
+
+return
diff --git a/src/ext/ed25519/ref10/ge_msub.c b/src/ext/ed25519/ref10/ge_msub.c
new file mode 100644
index 0000000000..741ecbf113
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_msub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_msub(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+ fe t0;
+#include "ge_msub.h"
+}
diff --git a/src/ext/ed25519/ref10/ge_msub.h b/src/ext/ed25519/ref10/ge_msub.h
new file mode 100644
index 0000000000..500f986ba0
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_msub.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_msub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ymx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ymx2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ymx2=q->yminusx); */
+fe_mul(r->Z,r->X,q->yminusx);
+
+/* qhasm: B = YmX1*ypx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ypx2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ypx2=q->yplusx); */
+fe_mul(r->Y,r->Y,q->yplusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/src/ext/ed25519/ref10/ge_msub.q b/src/ext/ed25519/ref10/ge_msub.q
new file mode 100644
index 0000000000..e3cadd882d
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_msub.q
@@ -0,0 +1,46 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->yplusx:q->yminusx:q->xy2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>ypx2=fe#15:>ymx2=fe#16:>xy2d2=fe#17:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_msub
+
+fe X1
+fe Y1
+fe Z1
+fe T1
+fe ypx2
+fe ymx2
+fe xy2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*ymx2
+B = YmX1*ypx2
+C = xy2d2*T1
+D = 2*Z1
+X3 = A-B
+Y3 = A+B
+Z3 = D-C
+T3 = D+C
+
+return
diff --git a/src/ext/ed25519/ref10/ge_p1p1_to_p2.c b/src/ext/ed25519/ref10/ge_p1p1_to_p2.c
new file mode 100644
index 0000000000..9bb5013d66
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p1p1_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p)
+{
+ fe_mul(r->X,p->X,p->T);
+ fe_mul(r->Y,p->Y,p->Z);
+ fe_mul(r->Z,p->Z,p->T);
+}
diff --git a/src/ext/ed25519/ref10/ge_p1p1_to_p3.c b/src/ext/ed25519/ref10/ge_p1p1_to_p3.c
new file mode 100644
index 0000000000..2f57b10968
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p1p1_to_p3.c
@@ -0,0 +1,13 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p)
+{
+ fe_mul(r->X,p->X,p->T);
+ fe_mul(r->Y,p->Y,p->Z);
+ fe_mul(r->Z,p->Z,p->T);
+ fe_mul(r->T,p->X,p->Y);
+}
diff --git a/src/ext/ed25519/ref10/ge_p2_0.c b/src/ext/ed25519/ref10/ge_p2_0.c
new file mode 100644
index 0000000000..6191d1e6e4
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p2_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_p2_0(ge_p2 *h)
+{
+ fe_0(h->X);
+ fe_1(h->Y);
+ fe_1(h->Z);
+}
diff --git a/src/ext/ed25519/ref10/ge_p2_dbl.c b/src/ext/ed25519/ref10/ge_p2_dbl.c
new file mode 100644
index 0000000000..2e332b5cee
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p2_dbl.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p2_dbl(ge_p1p1 *r,const ge_p2 *p)
+{
+ fe t0;
+#include "ge_p2_dbl.h"
+}
diff --git a/src/ext/ed25519/ref10/ge_p2_dbl.h b/src/ext/ed25519/ref10/ge_p2_dbl.h
new file mode 100644
index 0000000000..128efed907
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p2_dbl.h
@@ -0,0 +1,73 @@
+
+/* qhasm: enter ge_p2_dbl */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe AA */
+
+/* qhasm: fe XX */
+
+/* qhasm: fe YY */
+
+/* qhasm: fe B */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: XX=X1^2 */
+/* asm 1: fe_sq(>XX=fe#1,<X1=fe#11); */
+/* asm 2: fe_sq(>XX=r->X,<X1=p->X); */
+fe_sq(r->X,p->X);
+
+/* qhasm: YY=Y1^2 */
+/* asm 1: fe_sq(>YY=fe#3,<Y1=fe#12); */
+/* asm 2: fe_sq(>YY=r->Z,<Y1=p->Y); */
+fe_sq(r->Z,p->Y);
+
+/* qhasm: B=2*Z1^2 */
+/* asm 1: fe_sq2(>B=fe#4,<Z1=fe#13); */
+/* asm 2: fe_sq2(>B=r->T,<Z1=p->Z); */
+fe_sq2(r->T,p->Z);
+
+/* qhasm: A=X1+Y1 */
+/* asm 1: fe_add(>A=fe#2,<X1=fe#11,<Y1=fe#12); */
+/* asm 2: fe_add(>A=r->Y,<X1=p->X,<Y1=p->Y); */
+fe_add(r->Y,p->X,p->Y);
+
+/* qhasm: AA=A^2 */
+/* asm 1: fe_sq(>AA=fe#5,<A=fe#2); */
+/* asm 2: fe_sq(>AA=t0,<A=r->Y); */
+fe_sq(t0,r->Y);
+
+/* qhasm: Y3=YY+XX */
+/* asm 1: fe_add(>Y3=fe#2,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_add(>Y3=r->Y,<YY=r->Z,<XX=r->X); */
+fe_add(r->Y,r->Z,r->X);
+
+/* qhasm: Z3=YY-XX */
+/* asm 1: fe_sub(>Z3=fe#3,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_sub(>Z3=r->Z,<YY=r->Z,<XX=r->X); */
+fe_sub(r->Z,r->Z,r->X);
+
+/* qhasm: X3=AA-Y3 */
+/* asm 1: fe_sub(>X3=fe#1,<AA=fe#5,<Y3=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<AA=t0,<Y3=r->Y); */
+fe_sub(r->X,t0,r->Y);
+
+/* qhasm: T3=B-Z3 */
+/* asm 1: fe_sub(>T3=fe#4,<B=fe#4,<Z3=fe#3); */
+/* asm 2: fe_sub(>T3=r->T,<B=r->T,<Z3=r->Z); */
+fe_sub(r->T,r->T,r->Z);
+
+/* qhasm: return */
diff --git a/src/ext/ed25519/ref10/ge_p2_dbl.q b/src/ext/ed25519/ref10/ge_p2_dbl.q
new file mode 100644
index 0000000000..170d42f9a7
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p2_dbl.q
@@ -0,0 +1,41 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*f^2:<f=fe:>h=fe:asm/fe_sq2(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_p2_dbl
+
+fe X1
+fe Y1
+fe Z1
+fe A
+fe AA
+fe XX
+fe YY
+fe B
+fe X3
+fe Y3
+fe Z3
+fe T3
+
+XX=X1^2
+YY=Y1^2
+B=2*Z1^2
+A=X1+Y1
+AA=A^2
+Y3=YY+XX
+Z3=YY-XX
+X3=AA-Y3
+T3=B-Z3
+
+return
diff --git a/src/ext/ed25519/ref10/ge_p3_0.c b/src/ext/ed25519/ref10/ge_p3_0.c
new file mode 100644
index 0000000000..401b2935a1
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p3_0.c
@@ -0,0 +1,9 @@
+#include "ge.h"
+
+void ge_p3_0(ge_p3 *h)
+{
+ fe_0(h->X);
+ fe_1(h->Y);
+ fe_1(h->Z);
+ fe_0(h->T);
+}
diff --git a/src/ext/ed25519/ref10/ge_p3_dbl.c b/src/ext/ed25519/ref10/ge_p3_dbl.c
new file mode 100644
index 0000000000..0d8a05915d
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p3_dbl.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p)
+{
+ ge_p2 q;
+ ge_p3_to_p2(&q,p);
+ ge_p2_dbl(r,&q);
+}
diff --git a/src/ext/ed25519/ref10/ge_p3_to_cached.c b/src/ext/ed25519/ref10/ge_p3_to_cached.c
new file mode 100644
index 0000000000..bde64228cf
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p3_to_cached.c
@@ -0,0 +1,17 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+static const fe d2 = {
+#include "d2.h"
+} ;
+
+extern void ge_p3_to_cached(ge_cached *r,const ge_p3 *p)
+{
+ fe_add(r->YplusX,p->Y,p->X);
+ fe_sub(r->YminusX,p->Y,p->X);
+ fe_copy(r->Z,p->Z);
+ fe_mul(r->T2d,p->T,d2);
+}
diff --git a/src/ext/ed25519/ref10/ge_p3_to_p2.c b/src/ext/ed25519/ref10/ge_p3_to_p2.c
new file mode 100644
index 0000000000..e532a9e4cb
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p3_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p)
+{
+ fe_copy(r->X,p->X);
+ fe_copy(r->Y,p->Y);
+ fe_copy(r->Z,p->Z);
+}
diff --git a/src/ext/ed25519/ref10/ge_p3_tobytes.c b/src/ext/ed25519/ref10/ge_p3_tobytes.c
new file mode 100644
index 0000000000..21cb2fc656
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_p3_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_p3_tobytes(unsigned char *s,const ge_p3 *h)
+{
+ fe recip;
+ fe x;
+ fe y;
+
+ fe_invert(recip,h->Z);
+ fe_mul(x,h->X,recip);
+ fe_mul(y,h->Y,recip);
+ fe_tobytes(s,y);
+ s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/src/ext/ed25519/ref10/ge_precomp_0.c b/src/ext/ed25519/ref10/ge_precomp_0.c
new file mode 100644
index 0000000000..2e218861d8
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_precomp_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_precomp_0(ge_precomp *h)
+{
+ fe_1(h->yplusx);
+ fe_1(h->yminusx);
+ fe_0(h->xy2d);
+}
diff --git a/src/ext/ed25519/ref10/ge_scalarmult_base.c b/src/ext/ed25519/ref10/ge_scalarmult_base.c
new file mode 100644
index 0000000000..5292f83221
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_scalarmult_base.c
@@ -0,0 +1,109 @@
+#include "ge.h"
+#include "crypto_uint32.h"
+
+/* Rename this so as not to interfere with select() which torint.h apparently
+ * grabs. :p */
+#define select ed25519_ref10_select
+
+static unsigned char equal(signed char b,signed char c)
+{
+ unsigned char ub = b;
+ unsigned char uc = c;
+ unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+ crypto_uint32 y = x; /* 0: yes; 1..255: no */
+ y -= 1; /* 4294967295: yes; 0..254: no */
+ y >>= 31; /* 1: yes; 0: no */
+ return y;
+}
+
+static unsigned char negative(signed char b)
+{
+ uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+ x >>= 63; /* 1: yes; 0: no */
+ return x;
+}
+
+static void cmov(ge_precomp *t,ge_precomp *u,unsigned char b)
+{
+ fe_cmov(t->yplusx,u->yplusx,b);
+ fe_cmov(t->yminusx,u->yminusx,b);
+ fe_cmov(t->xy2d,u->xy2d,b);
+}
+
+/* base[i][j] = (j+1)*256^i*B */
+static ge_precomp base[32][8] = {
+#include "base.h"
+} ;
+
+static void select(ge_precomp *t,int pos,signed char b)
+{
+ ge_precomp minust;
+ unsigned char bnegative = negative(b);
+ unsigned char babs = b - SHL8( (-bnegative) & (unsigned char)b, 1);
+
+ ge_precomp_0(t);
+ cmov(t,&base[pos][0],equal(babs,1));
+ cmov(t,&base[pos][1],equal(babs,2));
+ cmov(t,&base[pos][2],equal(babs,3));
+ cmov(t,&base[pos][3],equal(babs,4));
+ cmov(t,&base[pos][4],equal(babs,5));
+ cmov(t,&base[pos][5],equal(babs,6));
+ cmov(t,&base[pos][6],equal(babs,7));
+ cmov(t,&base[pos][7],equal(babs,8));
+ fe_copy(minust.yplusx,t->yminusx);
+ fe_copy(minust.yminusx,t->yplusx);
+ fe_neg(minust.xy2d,t->xy2d);
+ cmov(t,&minust,bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+ a[31] <= 127
+*/
+
+void ge_scalarmult_base(ge_p3 *h,const unsigned char *a)
+{
+ signed char e[64];
+ signed char carry;
+ ge_p1p1 r;
+ ge_p2 s;
+ ge_precomp t;
+ int i;
+
+ for (i = 0;i < 32;++i) {
+ e[2 * i + 0] = (a[i] >> 0) & 15;
+ e[2 * i + 1] = (a[i] >> 4) & 15;
+ }
+ /* each e[i] is between 0 and 15 */
+ /* e[63] is between 0 and 7 */
+
+ carry = 0;
+ for (i = 0;i < 63;++i) {
+ e[i] += carry;
+ carry = e[i] + 8;
+ carry >>= 4;
+ e[i] -= SHL8(carry,4);
+ }
+ e[63] += carry;
+ /* each e[i] is between -8 and 8 */
+
+ ge_p3_0(h);
+ for (i = 1;i < 64;i += 2) {
+ select(&t,i / 2,e[i]);
+ ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+ }
+
+ ge_p3_dbl(&r,h); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r);
+
+ for (i = 0;i < 64;i += 2) {
+ select(&t,i / 2,e[i]);
+ ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+ }
+}
diff --git a/src/ext/ed25519/ref10/ge_sub.c b/src/ext/ed25519/ref10/ge_sub.c
new file mode 100644
index 0000000000..69f3d54062
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_sub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_sub(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+ fe t0;
+#include "ge_sub.h"
+}
diff --git a/src/ext/ed25519/ref10/ge_sub.h b/src/ext/ed25519/ref10/ge_sub.h
new file mode 100644
index 0000000000..b4ef1f5dd0
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_sub.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_sub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YmX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YmX2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YmX2=q->YminusX); */
+fe_mul(r->Z,r->X,q->YminusX);
+
+/* qhasm: B = YmX1*YpX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YpX2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YpX2=q->YplusX); */
+fe_mul(r->Y,r->Y,q->YplusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/src/ext/ed25519/ref10/ge_sub.q b/src/ext/ed25519/ref10/ge_sub.q
new file mode 100644
index 0000000000..2779a4a201
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_sub.q
@@ -0,0 +1,49 @@
+:name:fe:r->X:r->Y:r->Z:r->T:t0:t1:t2:t3:t4:t5:p->X:p->Y:p->Z:p->T:q->YplusX:q->YminusX:q->Z:q->T2d:
+fe r:var/r=fe:
+
+enter f:enter/f:>X1=fe#11:>Y1=fe#12:>Z1=fe#13:>T1=fe#14:>YpX2=fe#15:>YmX2=fe#16:>Z2=fe#17:>T2d2=fe#18:
+return:nofallthrough:<X3=fe#1:<Y3=fe#2:<Z3=fe#3:<T3=fe#4:leave:
+
+h=f+g:<f=fe:<g=fe:>h=fe:asm/fe_add(>h,<f,<g);:
+h=f-g:<f=fe:<g=fe:>h=fe:asm/fe_sub(>h,<f,<g);:
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2:<f=fe:>h=fe:asm/fe_sq(>h,<f);:
+h=2*g:<g=fe:>h=fe:asm/fe_add(>h,<g,<g);:
+
+:
+
+enter ge_sub
+
+fe X1
+fe Y1
+fe Z1
+fe Z2
+fe T1
+fe ZZ
+fe YpX2
+fe YmX2
+fe T2d2
+fe X3
+fe Y3
+fe Z3
+fe T3
+fe YpX1
+fe YmX1
+fe A
+fe B
+fe C
+fe D
+
+YpX1 = Y1+X1
+YmX1 = Y1-X1
+A = YpX1*YmX2
+B = YmX1*YpX2
+C = T2d2*T1
+ZZ = Z1*Z2
+D = 2*ZZ
+X3 = A-B
+Y3 = A+B
+Z3 = D-C
+T3 = D+C
+
+return
diff --git a/src/ext/ed25519/ref10/ge_tobytes.c b/src/ext/ed25519/ref10/ge_tobytes.c
new file mode 100644
index 0000000000..31b3d33e09
--- /dev/null
+++ b/src/ext/ed25519/ref10/ge_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_tobytes(unsigned char *s,const ge_p2 *h)
+{
+ fe recip;
+ fe x;
+ fe y;
+
+ fe_invert(recip,h->Z);
+ fe_mul(x,h->X,recip);
+ fe_mul(y,h->Y,recip);
+ fe_tobytes(s,y);
+ s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/src/ext/ed25519/ref10/keyconv.c b/src/ext/ed25519/ref10/keyconv.c
new file mode 100644
index 0000000000..854b150d69
--- /dev/null
+++ b/src/ext/ed25519/ref10/keyconv.c
@@ -0,0 +1,37 @@
+/* Added to ref10 for Tor. We place this in the public domain. Alternatively,
+ * you may have it under the Creative Commons 0 "CC0" license. */
+#include "fe.h"
+#include "ed25519_ref10.h"
+
+int ed25519_ref10_pubkey_from_curve25519_pubkey(unsigned char *out,
+ const unsigned char *inp,
+ int signbit)
+{
+ fe u;
+ fe one;
+ fe y;
+ fe uplus1;
+ fe uminus1;
+ fe inv_uplus1;
+
+ /* From prop228:
+
+ Given a curve25519 x-coordinate (u), we can get the y coordinate
+ of the ed25519 key using
+
+ y = (u-1)/(u+1)
+ */
+ fe_frombytes(u, inp);
+ fe_1(one);
+ fe_sub(uminus1, u, one);
+ fe_add(uplus1, u, one);
+ fe_invert(inv_uplus1, uplus1);
+ fe_mul(y, uminus1, inv_uplus1);
+
+ fe_tobytes(out, y);
+
+ /* propagate sign. */
+ out[31] |= (!!signbit) << 7;
+
+ return 0;
+}
diff --git a/src/ext/ed25519/ref10/keypair.c b/src/ext/ed25519/ref10/keypair.c
new file mode 100644
index 0000000000..7ddbaa971e
--- /dev/null
+++ b/src/ext/ed25519/ref10/keypair.c
@@ -0,0 +1,51 @@
+/* Modified for Tor: new API, 64-byte secret keys. */
+#include <string.h>
+#include "randombytes.h"
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+
+int
+crypto_sign_seckey(unsigned char *sk)
+{
+ unsigned char seed[32];
+
+ if (randombytes(seed,32) < 0)
+ return -1;
+
+ crypto_sign_seckey_expand(sk, seed);
+
+ memwipe(seed, 0, 32);
+
+ return 0;
+}
+
+int crypto_sign_seckey_expand(unsigned char *sk, const unsigned char *skseed)
+{
+ crypto_hash_sha512(sk,skseed,32);
+ sk[0] &= 248;
+ sk[31] &= 63;
+ sk[31] |= 64;
+
+ return 0;
+}
+
+int crypto_sign_pubkey(unsigned char *pk,const unsigned char *sk)
+{
+ ge_p3 A;
+
+ ge_scalarmult_base(&A,sk);
+ ge_p3_tobytes(pk,&A);
+
+ return 0;
+}
+
+
+int crypto_sign_keypair(unsigned char *pk,unsigned char *sk)
+{
+ crypto_sign_seckey(sk);
+ crypto_sign_pubkey(pk, sk);
+
+ return 0;
+}
+
diff --git a/src/ext/ed25519/ref10/open.c b/src/ext/ed25519/ref10/open.c
new file mode 100644
index 0000000000..9dbeb4cdd0
--- /dev/null
+++ b/src/ext/ed25519/ref10/open.c
@@ -0,0 +1,42 @@
+/* (Modified by Tor to verify signature separately from message) */
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "crypto_verify_32.h"
+#include "ge.h"
+#include "sc.h"
+
+/* 'signature' must be 64-bytes long. */
+int crypto_sign_open(
+ const unsigned char *signature,
+ const unsigned char *m, size_t mlen,
+ const unsigned char *pk
+)
+{
+ unsigned char pkcopy[32];
+ unsigned char rcopy[32];
+ unsigned char scopy[32];
+ unsigned char h[64];
+ unsigned char rcheck[32];
+ ge_p3 A;
+ ge_p2 R;
+
+ if (signature[63] & 224) goto badsig;
+ if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig;
+
+ memmove(pkcopy,pk,32);
+ memmove(rcopy,signature,32);
+ memmove(scopy,signature + 32,32);
+
+ crypto_hash_sha512_3(h, rcopy, 32, pkcopy, 32, m, mlen);
+ sc_reduce(h);
+
+ ge_double_scalarmult_vartime(&R,h,&A,scopy);
+ ge_tobytes(rcheck,&R);
+ if (crypto_verify_32(rcheck,rcopy) == 0) {
+ return 0;
+ }
+
+badsig:
+ return -1;
+}
diff --git a/src/ext/ed25519/ref10/pow22523.h b/src/ext/ed25519/ref10/pow22523.h
new file mode 100644
index 0000000000..9204ff838f
--- /dev/null
+++ b/src/ext/ed25519/ref10/pow22523.h
@@ -0,0 +1,161 @@
+/* Modified by Tor: pointless loops removed to appease analysis tools */
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_252_2 */
+
+/* qhasm: fe z_252_3 */
+
+/* qhasm: enter pow22523 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); /* DEADCODE This loop has no effect: for (i = 1;i < 1;++i) fe_sq(t0,t0); */
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#1,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#1,>z22=fe#1); */
+/* asm 2: fe_sq(>z22=t0,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t0,>z22=t0); */
+fe_sq(t0,t0); /* DEADCODE This loop has no effect: for (i = 1;i < 1;++i) fe_sq(t0,t0); */
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#1,<z9=fe#2,<z22=fe#1); */
+/* asm 2: fe_mul(>z_5_0=t0,<z9=t1,<z22=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#2,<z_5_0=fe#1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#2,>z_10_5=fe#2); */
+/* asm 2: fe_sq(>z_10_5=t1,<z_5_0=t0); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t1,>z_10_5=t1); */
+fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#1,<z_10_5=fe#2,<z_5_0=fe#1); */
+/* asm 2: fe_mul(>z_10_0=t0,<z_10_5=t1,<z_5_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#2,<z_10_0=fe#1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#2,>z_20_10=fe#2); */
+/* asm 2: fe_sq(>z_20_10=t1,<z_10_0=t0); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t1,>z_20_10=t1); */
+fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#2,<z_20_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_20_0=t1,<z_20_10=t1,<z_10_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#3,<z_20_0=fe#2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#3,>z_40_20=fe#3); */
+/* asm 2: fe_sq(>z_40_20=t2,<z_20_0=t1); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t2,>z_40_20=t2); */
+fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq(t2,t2);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#2,<z_40_20=fe#3,<z_20_0=fe#2); */
+/* asm 2: fe_mul(>z_40_0=t1,<z_40_20=t2,<z_20_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#2,<z_40_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#2,>z_50_10=fe#2); */
+/* asm 2: fe_sq(>z_50_10=t1,<z_40_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t1,>z_50_10=t1); */
+fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#1,<z_50_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_50_0=t0,<z_50_10=t1,<z_10_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#2,<z_50_0=fe#1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#2,>z_100_50=fe#2); */
+/* asm 2: fe_sq(>z_100_50=t1,<z_50_0=t0); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t1,>z_100_50=t1); */
+fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#2,<z_100_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_100_0=t1,<z_100_50=t1,<z_50_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#3,<z_100_0=fe#2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#3,>z_200_100=fe#3); */
+/* asm 2: fe_sq(>z_200_100=t2,<z_100_0=t1); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t2,>z_200_100=t2); */
+fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq(t2,t2);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#2,<z_200_100=fe#3,<z_100_0=fe#2); */
+/* asm 2: fe_mul(>z_200_0=t1,<z_200_100=t2,<z_100_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#2,<z_200_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#2,>z_250_50=fe#2); */
+/* asm 2: fe_sq(>z_250_50=t1,<z_200_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t1,>z_250_50=t1); */
+fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#1,<z_250_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_250_0=t0,<z_250_50=t1,<z_50_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_252_2 = z_250_0^2^2 */
+/* asm 1: fe_sq(>z_252_2=fe#1,<z_250_0=fe#1); for (i = 1;i < 2;++i) fe_sq(>z_252_2=fe#1,>z_252_2=fe#1); */
+/* asm 2: fe_sq(>z_252_2=t0,<z_250_0=t0); for (i = 1;i < 2;++i) fe_sq(>z_252_2=t0,>z_252_2=t0); */
+fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq(t0,t0);
+
+/* qhasm: z_252_3 = z_252_2*z1 */
+/* asm 1: fe_mul(>z_252_3=fe#12,<z_252_2=fe#1,<z1=fe#11); */
+/* asm 2: fe_mul(>z_252_3=out,<z_252_2=t0,<z1=z); */
+fe_mul(out,t0,z);
+
+/* qhasm: return */
diff --git a/src/ext/ed25519/ref10/pow22523.q b/src/ext/ed25519/ref10/pow22523.q
new file mode 100644
index 0000000000..2ce1da9d4d
--- /dev/null
+++ b/src/ext/ed25519/ref10/pow22523.q
@@ -0,0 +1,61 @@
+:name:fe:t0:t1:t2:t3:t4:t5:t6:t7:t8:t9:z:out:
+fe r:var/r=fe:
+
+enter f:enter/f:>z1=fe#11:
+return:nofallthrough:<z_252_3=fe#12:leave:
+
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2^k:<f=fe:>h=fe:#k:asm/fe_sq(>h,<f); for (i = 1;i !lt; #k;++i) fe_sq(>h,>h);:
+
+:
+
+fe z1
+fe z2
+fe z8
+fe z9
+fe z11
+fe z22
+fe z_5_0
+fe z_10_5
+fe z_10_0
+fe z_20_10
+fe z_20_0
+fe z_40_20
+fe z_40_0
+fe z_50_10
+fe z_50_0
+fe z_100_50
+fe z_100_0
+fe z_200_100
+fe z_200_0
+fe z_250_50
+fe z_250_0
+fe z_252_2
+fe z_252_3
+
+enter pow22523
+
+z2 = z1^2^1
+z8 = z2^2^2
+z9 = z1*z8
+z11 = z2*z9
+z22 = z11^2^1
+z_5_0 = z9*z22
+z_10_5 = z_5_0^2^5
+z_10_0 = z_10_5*z_5_0
+z_20_10 = z_10_0^2^10
+z_20_0 = z_20_10*z_10_0
+z_40_20 = z_20_0^2^20
+z_40_0 = z_40_20*z_20_0
+z_50_10 = z_40_0^2^10
+z_50_0 = z_50_10*z_10_0
+z_100_50 = z_50_0^2^50
+z_100_0 = z_100_50*z_50_0
+z_200_100 = z_100_0^2^100
+z_200_0 = z_200_100*z_100_0
+z_250_50 = z_200_0^2^50
+z_250_0 = z_250_50*z_50_0
+z_252_2 = z_250_0^2^2
+z_252_3 = z_252_2*z1
+
+return
diff --git a/src/ext/ed25519/ref10/pow225521.h b/src/ext/ed25519/ref10/pow225521.h
new file mode 100644
index 0000000000..fe2af94c03
--- /dev/null
+++ b/src/ext/ed25519/ref10/pow225521.h
@@ -0,0 +1,161 @@
+/* Modified by Tor: pointless loops removed to appease analysis tools */
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_255_5 */
+
+/* qhasm: fe z_255_21 */
+
+/* qhasm: enter pow225521 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); /* DEADCODE This loop has no effect: for (i = 1;i < 1;++i) fe_sq(t0,t0); */
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#3,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#3,>z22=fe#3); */
+/* asm 2: fe_sq(>z22=t2,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t2,>z22=t2); */
+fe_sq(t2,t0); /* DEADCODE This loop has no effect for (i = 1;i < 1;++i) fe_sq(t2,t2); */
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#2,<z9=fe#2,<z22=fe#3); */
+/* asm 2: fe_mul(>z_5_0=t1,<z9=t1,<z22=t2); */
+fe_mul(t1,t1,t2);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#3,<z_5_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#3,>z_10_5=fe#3); */
+/* asm 2: fe_sq(>z_10_5=t2,<z_5_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t2,>z_10_5=t2); */
+fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#2,<z_10_5=fe#3,<z_5_0=fe#2); */
+/* asm 2: fe_mul(>z_10_0=t1,<z_10_5=t2,<z_5_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#3,<z_10_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#3,>z_20_10=fe#3); */
+/* asm 2: fe_sq(>z_20_10=t2,<z_10_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t2,>z_20_10=t2); */
+fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#3,<z_20_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_20_0=t2,<z_20_10=t2,<z_10_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#4,<z_20_0=fe#3); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#4,>z_40_20=fe#4); */
+/* asm 2: fe_sq(>z_40_20=t3,<z_20_0=t2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t3,>z_40_20=t3); */
+fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#3,<z_40_20=fe#4,<z_20_0=fe#3); */
+/* asm 2: fe_mul(>z_40_0=t2,<z_40_20=t3,<z_20_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#3,<z_40_0=fe#3); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#3,>z_50_10=fe#3); */
+/* asm 2: fe_sq(>z_50_10=t2,<z_40_0=t2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t2,>z_50_10=t2); */
+fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#2,<z_50_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_50_0=t1,<z_50_10=t2,<z_10_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#3,<z_50_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#3,>z_100_50=fe#3); */
+/* asm 2: fe_sq(>z_100_50=t2,<z_50_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t2,>z_100_50=t2); */
+fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#3,<z_100_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_100_0=t2,<z_100_50=t2,<z_50_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#4,<z_100_0=fe#3); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#4,>z_200_100=fe#4); */
+/* asm 2: fe_sq(>z_200_100=t3,<z_100_0=t2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t3,>z_200_100=t3); */
+fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#3,<z_200_100=fe#4,<z_100_0=fe#3); */
+/* asm 2: fe_mul(>z_200_0=t2,<z_200_100=t3,<z_100_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#3,<z_200_0=fe#3); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#3,>z_250_50=fe#3); */
+/* asm 2: fe_sq(>z_250_50=t2,<z_200_0=t2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t2,>z_250_50=t2); */
+fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#2,<z_250_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_250_0=t1,<z_250_50=t2,<z_50_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_255_5 = z_250_0^2^5 */
+/* asm 1: fe_sq(>z_255_5=fe#2,<z_250_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_255_5=fe#2,>z_255_5=fe#2); */
+/* asm 2: fe_sq(>z_255_5=t1,<z_250_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_255_5=t1,>z_255_5=t1); */
+fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_255_21 = z_255_5*z11 */
+/* asm 1: fe_mul(>z_255_21=fe#12,<z_255_5=fe#2,<z11=fe#1); */
+/* asm 2: fe_mul(>z_255_21=out,<z_255_5=t1,<z11=t0); */
+fe_mul(out,t1,t0);
+
+/* qhasm: return */
diff --git a/src/ext/ed25519/ref10/pow225521.q b/src/ext/ed25519/ref10/pow225521.q
new file mode 100644
index 0000000000..45be57c08a
--- /dev/null
+++ b/src/ext/ed25519/ref10/pow225521.q
@@ -0,0 +1,61 @@
+:name:fe:t0:t1:t2:t3:t4:t5:t6:t7:t8:t9:z:out:
+fe r:var/r=fe:
+
+enter f:enter/f:>z1=fe#11:
+return:nofallthrough:<z_255_21=fe#12:leave:
+
+h=f*g:<f=fe:<g=fe:>h=fe:asm/fe_mul(>h,<f,<g);:
+h=f^2^k:<f=fe:>h=fe:#k:asm/fe_sq(>h,<f); for (i = 1;i !lt; #k;++i) fe_sq(>h,>h);:
+
+:
+
+fe z1
+fe z2
+fe z8
+fe z9
+fe z11
+fe z22
+fe z_5_0
+fe z_10_5
+fe z_10_0
+fe z_20_10
+fe z_20_0
+fe z_40_20
+fe z_40_0
+fe z_50_10
+fe z_50_0
+fe z_100_50
+fe z_100_0
+fe z_200_100
+fe z_200_0
+fe z_250_50
+fe z_250_0
+fe z_255_5
+fe z_255_21
+
+enter pow225521
+
+z2 = z1^2^1
+z8 = z2^2^2
+z9 = z1*z8
+z11 = z2*z9
+z22 = z11^2^1
+z_5_0 = z9*z22
+z_10_5 = z_5_0^2^5
+z_10_0 = z_10_5*z_5_0
+z_20_10 = z_10_0^2^10
+z_20_0 = z_20_10*z_10_0
+z_40_20 = z_20_0^2^20
+z_40_0 = z_40_20*z_20_0
+z_50_10 = z_40_0^2^10
+z_50_0 = z_50_10*z_10_0
+z_100_50 = z_50_0^2^50
+z_100_0 = z_100_50*z_50_0
+z_200_100 = z_100_0^2^100
+z_200_0 = z_200_100*z_100_0
+z_250_50 = z_200_0^2^50
+z_250_0 = z_250_50*z_50_0
+z_255_5 = z_250_0^2^5
+z_255_21 = z_255_5*z11
+
+return
diff --git a/src/ext/ed25519/ref10/q2h.sh b/src/ext/ed25519/ref10/q2h.sh
new file mode 100755
index 0000000000..47ec5110e8
--- /dev/null
+++ b/src/ext/ed25519/ref10/q2h.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+sed 's/^#.*//' \
+| qhasm-generic \
+| sed 's_//\(.*\)$_/*\1 */_'
diff --git a/src/ext/ed25519/ref10/randombytes.h b/src/ext/ed25519/ref10/randombytes.h
new file mode 100644
index 0000000000..fc709fcefc
--- /dev/null
+++ b/src/ext/ed25519/ref10/randombytes.h
@@ -0,0 +1,4 @@
+/* Added for Tor. */
+#include "crypto.h"
+#define randombytes(b, n) \
+ (crypto_strongest_rand((b), (n)))
diff --git a/src/ext/ed25519/ref10/sc.h b/src/ext/ed25519/ref10/sc.h
new file mode 100644
index 0000000000..d32ed2e8ca
--- /dev/null
+++ b/src/ext/ed25519/ref10/sc.h
@@ -0,0 +1,15 @@
+#ifndef SC_H
+#define SC_H
+
+/*
+The set of scalars is \Z/l
+where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+#define sc_reduce crypto_sign_ed25519_ref10_sc_reduce
+#define sc_muladd crypto_sign_ed25519_ref10_sc_muladd
+
+extern void sc_reduce(unsigned char *);
+extern void sc_muladd(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *);
+
+#endif
diff --git a/src/ext/ed25519/ref10/sc_muladd.c b/src/ext/ed25519/ref10/sc_muladd.c
new file mode 100644
index 0000000000..20b94c1049
--- /dev/null
+++ b/src/ext/ed25519/ref10/sc_muladd.c
@@ -0,0 +1,368 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ result |= ((crypto_uint64) in[3]) << 24;
+ return result;
+}
+
+/*
+Input:
+ a[0]+256*a[1]+...+256^31*a[31] = a
+ b[0]+256*b[1]+...+256^31*b[31] = b
+ c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+void sc_muladd(unsigned char *s,const unsigned char *a,const unsigned char *b,const unsigned char *c)
+{
+ crypto_int64 a0 = 2097151 & load_3(a);
+ crypto_int64 a1 = 2097151 & (load_4(a + 2) >> 5);
+ crypto_int64 a2 = 2097151 & (load_3(a + 5) >> 2);
+ crypto_int64 a3 = 2097151 & (load_4(a + 7) >> 7);
+ crypto_int64 a4 = 2097151 & (load_4(a + 10) >> 4);
+ crypto_int64 a5 = 2097151 & (load_3(a + 13) >> 1);
+ crypto_int64 a6 = 2097151 & (load_4(a + 15) >> 6);
+ crypto_int64 a7 = 2097151 & (load_3(a + 18) >> 3);
+ crypto_int64 a8 = 2097151 & load_3(a + 21);
+ crypto_int64 a9 = 2097151 & (load_4(a + 23) >> 5);
+ crypto_int64 a10 = 2097151 & (load_3(a + 26) >> 2);
+ crypto_int64 a11 = (load_4(a + 28) >> 7);
+ crypto_int64 b0 = 2097151 & load_3(b);
+ crypto_int64 b1 = 2097151 & (load_4(b + 2) >> 5);
+ crypto_int64 b2 = 2097151 & (load_3(b + 5) >> 2);
+ crypto_int64 b3 = 2097151 & (load_4(b + 7) >> 7);
+ crypto_int64 b4 = 2097151 & (load_4(b + 10) >> 4);
+ crypto_int64 b5 = 2097151 & (load_3(b + 13) >> 1);
+ crypto_int64 b6 = 2097151 & (load_4(b + 15) >> 6);
+ crypto_int64 b7 = 2097151 & (load_3(b + 18) >> 3);
+ crypto_int64 b8 = 2097151 & load_3(b + 21);
+ crypto_int64 b9 = 2097151 & (load_4(b + 23) >> 5);
+ crypto_int64 b10 = 2097151 & (load_3(b + 26) >> 2);
+ crypto_int64 b11 = (load_4(b + 28) >> 7);
+ crypto_int64 c0 = 2097151 & load_3(c);
+ crypto_int64 c1 = 2097151 & (load_4(c + 2) >> 5);
+ crypto_int64 c2 = 2097151 & (load_3(c + 5) >> 2);
+ crypto_int64 c3 = 2097151 & (load_4(c + 7) >> 7);
+ crypto_int64 c4 = 2097151 & (load_4(c + 10) >> 4);
+ crypto_int64 c5 = 2097151 & (load_3(c + 13) >> 1);
+ crypto_int64 c6 = 2097151 & (load_4(c + 15) >> 6);
+ crypto_int64 c7 = 2097151 & (load_3(c + 18) >> 3);
+ crypto_int64 c8 = 2097151 & load_3(c + 21);
+ crypto_int64 c9 = 2097151 & (load_4(c + 23) >> 5);
+ crypto_int64 c10 = 2097151 & (load_3(c + 26) >> 2);
+ crypto_int64 c11 = (load_4(c + 28) >> 7);
+ crypto_int64 s0;
+ crypto_int64 s1;
+ crypto_int64 s2;
+ crypto_int64 s3;
+ crypto_int64 s4;
+ crypto_int64 s5;
+ crypto_int64 s6;
+ crypto_int64 s7;
+ crypto_int64 s8;
+ crypto_int64 s9;
+ crypto_int64 s10;
+ crypto_int64 s11;
+ crypto_int64 s12;
+ crypto_int64 s13;
+ crypto_int64 s14;
+ crypto_int64 s15;
+ crypto_int64 s16;
+ crypto_int64 s17;
+ crypto_int64 s18;
+ crypto_int64 s19;
+ crypto_int64 s20;
+ crypto_int64 s21;
+ crypto_int64 s22;
+ crypto_int64 s23;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+ crypto_int64 carry10;
+ crypto_int64 carry11;
+ crypto_int64 carry12;
+ crypto_int64 carry13;
+ crypto_int64 carry14;
+ crypto_int64 carry15;
+ crypto_int64 carry16;
+ crypto_int64 carry17;
+ crypto_int64 carry18;
+ crypto_int64 carry19;
+ crypto_int64 carry20;
+ crypto_int64 carry21;
+ crypto_int64 carry22;
+
+ s0 = c0 + a0*b0;
+ s1 = c1 + a0*b1 + a1*b0;
+ s2 = c2 + a0*b2 + a1*b1 + a2*b0;
+ s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0;
+ s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0;
+ s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0;
+ s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0;
+ s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0;
+ s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0;
+ s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0;
+ s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0;
+ s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0;
+ s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1;
+ s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2;
+ s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3;
+ s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4;
+ s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5;
+ s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6;
+ s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7;
+ s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8;
+ s20 = a9*b11 + a10*b10 + a11*b9;
+ s21 = a10*b11 + a11*b10;
+ s22 = a11*b11;
+ s23 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= SHL64(carry0,21);
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= SHL64(carry2,21);
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= SHL64(carry4,21);
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= SHL64(carry6,21);
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= SHL64(carry8,21);
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= SHL64(carry10,21);
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= SHL64(carry12,21);
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= SHL64(carry14,21);
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= SHL64(carry16,21);
+ carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= SHL64(carry18,21);
+ carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= SHL64(carry20,21);
+ carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= SHL64(carry22,21);
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= SHL64(carry1,21);
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= SHL64(carry3,21);
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= SHL64(carry5,21);
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= SHL64(carry7,21);
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= SHL64(carry9,21);
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= SHL64(carry11,21);
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= SHL64(carry13,21);
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= SHL64(carry15,21);
+ carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= SHL64(carry17,21);
+ carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= SHL64(carry19,21);
+ carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= SHL64(carry21,21);
+
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= SHL64(carry6,21);
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= SHL64(carry8,21);
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= SHL64(carry10,21);
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= SHL64(carry12,21);
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= SHL64(carry14,21);
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= SHL64(carry16,21);
+
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= SHL64(carry7,21);
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= SHL64(carry9,21);
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= SHL64(carry11,21);
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= SHL64(carry13,21);
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= SHL64(carry15,21);
+
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= SHL64(carry0,21);
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= SHL64(carry2,21);
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= SHL64(carry4,21);
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= SHL64(carry6,21);
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= SHL64(carry8,21);
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= SHL64(carry10,21);
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= SHL64(carry1,21);
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= SHL64(carry3,21);
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= SHL64(carry5,21);
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= SHL64(carry7,21);
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= SHL64(carry9,21);
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= SHL64(carry11,21);
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= SHL64(carry0,21);
+ carry1 = s1 >> 21; s2 += carry1; s1 -= SHL64(carry1,21);
+ carry2 = s2 >> 21; s3 += carry2; s2 -= SHL64(carry2,21);
+ carry3 = s3 >> 21; s4 += carry3; s3 -= SHL64(carry3,21);
+ carry4 = s4 >> 21; s5 += carry4; s4 -= SHL64(carry4,21);
+ carry5 = s5 >> 21; s6 += carry5; s5 -= SHL64(carry5,21);
+ carry6 = s6 >> 21; s7 += carry6; s6 -= SHL64(carry6,21);
+ carry7 = s7 >> 21; s8 += carry7; s7 -= SHL64(carry7,21);
+ carry8 = s8 >> 21; s9 += carry8; s8 -= SHL64(carry8,21);
+ carry9 = s9 >> 21; s10 += carry9; s9 -= SHL64(carry9,21);
+ carry10 = s10 >> 21; s11 += carry10; s10 -= SHL64(carry10,21);
+ carry11 = s11 >> 21; s12 += carry11; s11 -= SHL64(carry11,21);
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= SHL64(carry0,21);
+ carry1 = s1 >> 21; s2 += carry1; s1 -= SHL64(carry1,21);
+ carry2 = s2 >> 21; s3 += carry2; s2 -= SHL64(carry2,21);
+ carry3 = s3 >> 21; s4 += carry3; s3 -= SHL64(carry3,21);
+ carry4 = s4 >> 21; s5 += carry4; s4 -= SHL64(carry4,21);
+ carry5 = s5 >> 21; s6 += carry5; s5 -= SHL64(carry5,21);
+ carry6 = s6 >> 21; s7 += carry6; s6 -= SHL64(carry6,21);
+ carry7 = s7 >> 21; s8 += carry7; s7 -= SHL64(carry7,21);
+ carry8 = s8 >> 21; s9 += carry8; s8 -= SHL64(carry8,21);
+ carry9 = s9 >> 21; s10 += carry9; s9 -= SHL64(carry9,21);
+ carry10 = s10 >> 21; s11 += carry10; s10 -= SHL64(carry10,21);
+
+ s[0] = s0 >> 0;
+ s[1] = s0 >> 8;
+ s[2] = (s0 >> 16) | SHL64(s1,5);
+ s[3] = s1 >> 3;
+ s[4] = s1 >> 11;
+ s[5] = (s1 >> 19) | SHL64(s2,2);
+ s[6] = s2 >> 6;
+ s[7] = (s2 >> 14) | SHL64(s3,7);
+ s[8] = s3 >> 1;
+ s[9] = s3 >> 9;
+ s[10] = (s3 >> 17) | SHL64(s4,4);
+ s[11] = s4 >> 4;
+ s[12] = s4 >> 12;
+ s[13] = (s4 >> 20) | SHL64(s5,1);
+ s[14] = s5 >> 7;
+ s[15] = (s5 >> 15) | SHL64(s6,6);
+ s[16] = s6 >> 2;
+ s[17] = s6 >> 10;
+ s[18] = (s6 >> 18) | SHL64(s7,3);
+ s[19] = s7 >> 5;
+ s[20] = s7 >> 13;
+ s[21] = s8 >> 0;
+ s[22] = s8 >> 8;
+ s[23] = (s8 >> 16) | SHL64(s9,5);
+ s[24] = s9 >> 3;
+ s[25] = s9 >> 11;
+ s[26] = (s9 >> 19) | SHL64(s10,2);
+ s[27] = s10 >> 6;
+ s[28] = (s10 >> 14) | SHL64(s11,7);
+ s[29] = s11 >> 1;
+ s[30] = s11 >> 9;
+ s[31] = s11 >> 17;
+}
diff --git a/src/ext/ed25519/ref10/sc_reduce.c b/src/ext/ed25519/ref10/sc_reduce.c
new file mode 100644
index 0000000000..c5afa53741
--- /dev/null
+++ b/src/ext/ed25519/ref10/sc_reduce.c
@@ -0,0 +1,275 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ result |= ((crypto_uint64) in[3]) << 24;
+ return result;
+}
+
+/*
+Input:
+ s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = s mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+ Overwrites s in place.
+*/
+
+void sc_reduce(unsigned char *s)
+{
+ crypto_int64 s0 = 2097151 & load_3(s);
+ crypto_int64 s1 = 2097151 & (load_4(s + 2) >> 5);
+ crypto_int64 s2 = 2097151 & (load_3(s + 5) >> 2);
+ crypto_int64 s3 = 2097151 & (load_4(s + 7) >> 7);
+ crypto_int64 s4 = 2097151 & (load_4(s + 10) >> 4);
+ crypto_int64 s5 = 2097151 & (load_3(s + 13) >> 1);
+ crypto_int64 s6 = 2097151 & (load_4(s + 15) >> 6);
+ crypto_int64 s7 = 2097151 & (load_3(s + 18) >> 3);
+ crypto_int64 s8 = 2097151 & load_3(s + 21);
+ crypto_int64 s9 = 2097151 & (load_4(s + 23) >> 5);
+ crypto_int64 s10 = 2097151 & (load_3(s + 26) >> 2);
+ crypto_int64 s11 = 2097151 & (load_4(s + 28) >> 7);
+ crypto_int64 s12 = 2097151 & (load_4(s + 31) >> 4);
+ crypto_int64 s13 = 2097151 & (load_3(s + 34) >> 1);
+ crypto_int64 s14 = 2097151 & (load_4(s + 36) >> 6);
+ crypto_int64 s15 = 2097151 & (load_3(s + 39) >> 3);
+ crypto_int64 s16 = 2097151 & load_3(s + 42);
+ crypto_int64 s17 = 2097151 & (load_4(s + 44) >> 5);
+ crypto_int64 s18 = 2097151 & (load_3(s + 47) >> 2);
+ crypto_int64 s19 = 2097151 & (load_4(s + 49) >> 7);
+ crypto_int64 s20 = 2097151 & (load_4(s + 52) >> 4);
+ crypto_int64 s21 = 2097151 & (load_3(s + 55) >> 1);
+ crypto_int64 s22 = 2097151 & (load_4(s + 57) >> 6);
+ crypto_int64 s23 = (load_4(s + 60) >> 3);
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+ crypto_int64 carry10;
+ crypto_int64 carry11;
+ crypto_int64 carry12;
+ crypto_int64 carry13;
+ crypto_int64 carry14;
+ crypto_int64 carry15;
+ crypto_int64 carry16;
+
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= SHL64(carry6,21);
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= SHL64(carry8,21);
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= SHL64(carry10,21);
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= SHL64(carry12,21);
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= SHL64(carry14,21);
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= SHL64(carry16,21);
+
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= SHL64(carry7,21);
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= SHL64(carry9,21);
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= SHL64(carry11,21);
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= SHL64(carry13,21);
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= SHL64(carry15,21);
+
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= SHL64(carry0,21);
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= SHL64(carry2,21);
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= SHL64(carry4,21);
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= SHL64(carry6,21);
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= SHL64(carry8,21);
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= SHL64(carry10,21);
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= SHL64(carry1,21);
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= SHL64(carry3,21);
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= SHL64(carry5,21);
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= SHL64(carry7,21);
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= SHL64(carry9,21);
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= SHL64(carry11,21);
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= SHL64(carry0,21);
+ carry1 = s1 >> 21; s2 += carry1; s1 -= SHL64(carry1,21);
+ carry2 = s2 >> 21; s3 += carry2; s2 -= SHL64(carry2,21);
+ carry3 = s3 >> 21; s4 += carry3; s3 -= SHL64(carry3,21);
+ carry4 = s4 >> 21; s5 += carry4; s4 -= SHL64(carry4,21);
+ carry5 = s5 >> 21; s6 += carry5; s5 -= SHL64(carry5,21);
+ carry6 = s6 >> 21; s7 += carry6; s6 -= SHL64(carry6,21);
+ carry7 = s7 >> 21; s8 += carry7; s7 -= SHL64(carry7,21);
+ carry8 = s8 >> 21; s9 += carry8; s8 -= SHL64(carry8,21);
+ carry9 = s9 >> 21; s10 += carry9; s9 -= SHL64(carry9,21);
+ carry10 = s10 >> 21; s11 += carry10; s10 -= SHL64(carry10,21);
+ carry11 = s11 >> 21; s12 += carry11; s11 -= SHL64(carry11,21);
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= SHL64(carry0,21);
+ carry1 = s1 >> 21; s2 += carry1; s1 -= SHL64(carry1,21);
+ carry2 = s2 >> 21; s3 += carry2; s2 -= SHL64(carry2,21);
+ carry3 = s3 >> 21; s4 += carry3; s3 -= SHL64(carry3,21);
+ carry4 = s4 >> 21; s5 += carry4; s4 -= SHL64(carry4,21);
+ carry5 = s5 >> 21; s6 += carry5; s5 -= SHL64(carry5,21);
+ carry6 = s6 >> 21; s7 += carry6; s6 -= SHL64(carry6,21);
+ carry7 = s7 >> 21; s8 += carry7; s7 -= SHL64(carry7,21);
+ carry8 = s8 >> 21; s9 += carry8; s8 -= SHL64(carry8,21);
+ carry9 = s9 >> 21; s10 += carry9; s9 -= SHL64(carry9,21);
+ carry10 = s10 >> 21; s11 += carry10; s10 -= SHL64(carry10,21);
+
+ s[0] = s0 >> 0;
+ s[1] = s0 >> 8;
+ s[2] = (s0 >> 16) | SHL64(s1,5);
+ s[3] = s1 >> 3;
+ s[4] = s1 >> 11;
+ s[5] = (s1 >> 19) | SHL64(s2,2);
+ s[6] = s2 >> 6;
+ s[7] = (s2 >> 14) | SHL64(s3,7);
+ s[8] = s3 >> 1;
+ s[9] = s3 >> 9;
+ s[10] = (s3 >> 17) | SHL64(s4,4);
+ s[11] = s4 >> 4;
+ s[12] = s4 >> 12;
+ s[13] = (s4 >> 20) | SHL64(s5,1);
+ s[14] = s5 >> 7;
+ s[15] = (s5 >> 15) | SHL64(s6,6);
+ s[16] = s6 >> 2;
+ s[17] = s6 >> 10;
+ s[18] = (s6 >> 18) | SHL64(s7,3);
+ s[19] = s7 >> 5;
+ s[20] = s7 >> 13;
+ s[21] = s8 >> 0;
+ s[22] = s8 >> 8;
+ s[23] = (s8 >> 16) | SHL64(s9,5);
+ s[24] = s9 >> 3;
+ s[25] = s9 >> 11;
+ s[26] = (s9 >> 19) | SHL64(s10,2);
+ s[27] = s10 >> 6;
+ s[28] = (s10 >> 14) | SHL64(s11,7);
+ s[29] = s11 >> 1;
+ s[30] = s11 >> 9;
+ s[31] = s11 >> 17;
+}
diff --git a/src/ext/ed25519/ref10/sign.c b/src/ext/ed25519/ref10/sign.c
new file mode 100644
index 0000000000..1190a0fc99
--- /dev/null
+++ b/src/ext/ed25519/ref10/sign.c
@@ -0,0 +1,29 @@
+/* (Modified by Tor to generate detached signatures.) */
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+#include "sc.h"
+
+int crypto_sign(
+ unsigned char *sig,
+ const unsigned char *m, size_t mlen,
+ const unsigned char *sk,const unsigned char *pk
+)
+{
+ unsigned char nonce[64];
+ unsigned char hram[64];
+ ge_p3 R;
+
+ crypto_hash_sha512_2(nonce, sk+32, 32, m, mlen);
+
+ sc_reduce(nonce);
+ ge_scalarmult_base(&R,nonce);
+ ge_p3_tobytes(sig,&R);
+
+ crypto_hash_sha512_3(hram, sig, 32, pk, 32, m, mlen);
+ sc_reduce(hram);
+ sc_muladd(sig + 32,hram,sk,nonce);
+
+ return 0;
+}
diff --git a/src/ext/ed25519/ref10/sqrtm1.h b/src/ext/ed25519/ref10/sqrtm1.h
new file mode 100644
index 0000000000..d8caa23b6a
--- /dev/null
+++ b/src/ext/ed25519/ref10/sqrtm1.h
@@ -0,0 +1 @@
+-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482
diff --git a/src/ext/ed25519/ref10/sqrtm1.py b/src/ext/ed25519/ref10/sqrtm1.py
new file mode 100644
index 0000000000..9a47fbc12a
--- /dev/null
+++ b/src/ext/ed25519/ref10/sqrtm1.py
@@ -0,0 +1,28 @@
+q = 2**255 - 19
+
+def expmod(b,e,m):
+ if e == 0: return 1
+ t = expmod(b,e/2,m)**2 % m
+ if e & 1: t = (t*b) % m
+ return t
+
+def inv(x):
+ return expmod(x,q-2,q)
+
+def radix255(x):
+ x = x % q
+ if x + x > q: x -= q
+ x = [x,0,0,0,0,0,0,0,0,0]
+ bits = [26,25,26,25,26,25,26,25,26,25]
+ for i in range(9):
+ carry = (x[i] + 2**(bits[i]-1)) / 2**bits[i]
+ x[i] -= carry * 2**bits[i]
+ x[i + 1] += carry
+ result = ""
+ for i in range(9):
+ result = result+str(x[i])+","
+ result = result+str(x[9])
+ return result
+
+I = expmod(2,(q-1)/4,q)
+print radix255(I)
diff --git a/src/ext/ht.h b/src/ext/ht.h
index 838710784f..19a67a6a41 100644
--- a/src/ext/ht.h
+++ b/src/ext/ht.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2002, Christopher Clark.
* Copyright (c) 2005-2006, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See license at end. */
/* Based on ideas by Christopher Clark and interfaces from Niels Provos. */
@@ -38,8 +38,9 @@
}
#endif
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
#define HT_EMPTY(head) \
- ((head)->hth_n_entries == 0)
+ (((head)->hth_n_entries == 0) || 0)
/* How many elements in 'head'? */
#define HT_SIZE(head) \
@@ -120,16 +121,24 @@ ht_string_hash(const char *s)
((void)0)
#endif
+#define HT_BUCKET_NUM_(head, field, elm, hashfn) \
+ (HT_ELT_HASH_(elm,field,hashfn) % head->hth_table_length)
+
/* Helper: alias for the bucket containing 'elm'. */
#define HT_BUCKET_(head, field, elm, hashfn) \
- ((head)->hth_table[HT_ELT_HASH_(elm,field,hashfn) \
- % head->hth_table_length])
+ ((head)->hth_table[HT_BUCKET_NUM_(head, field, elm, hashfn)])
#define HT_FOREACH(x, name, head) \
for ((x) = HT_START(name, head); \
(x) != NULL; \
(x) = HT_NEXT(name, head, x))
+#ifndef HT_NDEBUG
+#define HT_ASSERT_(x) tor_assert(x)
+#else
+#define HT_ASSERT_(x) (void)0
+#endif
+
#define HT_PROTOTYPE(name, type, field, hashfn, eqfn) \
int name##_HT_GROW(struct name *ht, unsigned min_capacity); \
void name##_HT_CLEAR(struct name *ht); \
@@ -256,8 +265,11 @@ ht_string_hash(const char *s)
{ \
unsigned b = 0; \
while (b < head->hth_table_length) { \
- if (head->hth_table[b]) \
+ if (head->hth_table[b]) { \
+ HT_ASSERT_(b == \
+ HT_BUCKET_NUM_(head,field,head->hth_table[b],hashfn)); \
return &head->hth_table[b]; \
+ } \
++b; \
} \
return NULL; \
@@ -271,13 +283,17 @@ ht_string_hash(const char *s)
name##_HT_NEXT(struct name *head, struct type **elm) \
{ \
if ((*elm)->field.hte_next) { \
+ HT_ASSERT_(HT_BUCKET_NUM_(head,field,*elm,hashfn) == \
+ HT_BUCKET_NUM_(head,field,(*elm)->field.hte_next,hashfn)); \
return &(*elm)->field.hte_next; \
} else { \
- unsigned b = (HT_ELT_HASH_(*elm, field, hashfn) \
- % head->hth_table_length)+1; \
+ unsigned b = HT_BUCKET_NUM_(head,field,*elm,hashfn)+1; \
while (b < head->hth_table_length) { \
- if (head->hth_table[b]) \
+ if (head->hth_table[b]) { \
+ HT_ASSERT_(b == \
+ HT_BUCKET_NUM_(head,field,head->hth_table[b],hashfn)); \
return &head->hth_table[b]; \
+ } \
++b; \
} \
return NULL; \
@@ -302,8 +318,8 @@ ht_string_hash(const char *s)
} \
}
-#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn, \
- reallocfn, freefn) \
+#define HT_GENERATE2(name, type, field, hashfn, eqfn, load, reallocarrayfn, \
+ freefn) \
/* Primes that aren't too far from powers of two. We stop at */ \
/* P=402653189 because P*sizeof(void*) is less than SSIZE_MAX */ \
/* even on a 32-bit platform. */ \
@@ -336,7 +352,7 @@ ht_string_hash(const char *s)
new_load_limit = (unsigned)(load*new_len); \
} while (new_load_limit <= size && \
prime_idx < (int)name##_N_PRIMES); \
- if ((new_table = mallocfn(new_len*sizeof(struct type*)))) { \
+ if ((new_table = reallocarrayfn(NULL, new_len, sizeof(struct type*)))) { \
unsigned b; \
memset(new_table, 0, new_len*sizeof(struct type*)); \
for (b = 0; b < head->hth_table_length; ++b) { \
@@ -356,7 +372,7 @@ ht_string_hash(const char *s)
head->hth_table = new_table; \
} else { \
unsigned b, b2; \
- new_table = reallocfn(head->hth_table, new_len*sizeof(struct type*)); \
+ new_table = reallocarrayfn(head->hth_table, new_len, sizeof(struct type*)); \
if (!new_table) return -1; \
memset(new_table + head->hth_table_length, 0, \
(new_len - head->hth_table_length)*sizeof(struct type*)); \
@@ -417,7 +433,7 @@ ht_string_hash(const char *s)
for (elm = head->hth_table[i]; elm; elm = elm->field.hte_next) { \
if (HT_ELT_HASH_(elm, field, hashfn) != hashfn(elm)) \
return 1000 + i; \
- if ((HT_ELT_HASH_(elm, field, hashfn) % head->hth_table_length) != i) \
+ if (HT_BUCKET_NUM_(head,field,elm,hashfn) != i) \
return 10000 + i; \
++n; \
} \
@@ -427,6 +443,21 @@ ht_string_hash(const char *s)
return 0; \
}
+#define HT_GENERATE(name, type, field, hashfn, eqfn, load, mallocfn, \
+ reallocfn, freefn) \
+ static void * \
+ name##_reallocarray(void *arg, size_t a, size_t b) \
+ { \
+ if ((b) && (a) > SIZE_MAX / (b)) \
+ return NULL; \
+ if (arg) \
+ return reallocfn((arg),(a)*(b)); \
+ else \
+ return mallocfn((a)*(b)); \
+ } \
+ HT_GENERATE2(name, type, field, hashfn, eqfn, load, \
+ name##_reallocarray, freefn)
+
/** Implements an over-optimized "find and insert if absent" block;
* not meant for direct usage by typical code, or usage outside the critical
* path.*/
diff --git a/src/ext/include.am b/src/ext/include.am
index 26e194e88e..576fd4efb8 100644
--- a/src/ext/include.am
+++ b/src/ext/include.am
@@ -15,4 +15,80 @@ EXTHEADERS = \
noinst_HEADERS+= $(EXTHEADERS)
+src_ext_ed25519_ref10_libed25519_ref10_a_CFLAGS=
+
+src_ext_ed25519_ref10_libed25519_ref10_a_SOURCES= \
+ src/ext/ed25519/ref10/fe_0.c \
+ src/ext/ed25519/ref10/fe_1.c \
+ src/ext/ed25519/ref10/fe_add.c \
+ src/ext/ed25519/ref10/fe_cmov.c \
+ src/ext/ed25519/ref10/fe_copy.c \
+ src/ext/ed25519/ref10/fe_frombytes.c \
+ src/ext/ed25519/ref10/fe_invert.c \
+ src/ext/ed25519/ref10/fe_isnegative.c \
+ src/ext/ed25519/ref10/fe_isnonzero.c \
+ src/ext/ed25519/ref10/fe_mul.c \
+ src/ext/ed25519/ref10/fe_neg.c \
+ src/ext/ed25519/ref10/fe_pow22523.c \
+ src/ext/ed25519/ref10/fe_sq.c \
+ src/ext/ed25519/ref10/fe_sq2.c \
+ src/ext/ed25519/ref10/fe_sub.c \
+ src/ext/ed25519/ref10/fe_tobytes.c \
+ src/ext/ed25519/ref10/ge_add.c \
+ src/ext/ed25519/ref10/ge_double_scalarmult.c \
+ src/ext/ed25519/ref10/ge_frombytes.c \
+ src/ext/ed25519/ref10/ge_madd.c \
+ src/ext/ed25519/ref10/ge_msub.c \
+ src/ext/ed25519/ref10/ge_p1p1_to_p2.c \
+ src/ext/ed25519/ref10/ge_p1p1_to_p3.c \
+ src/ext/ed25519/ref10/ge_p2_0.c \
+ src/ext/ed25519/ref10/ge_p2_dbl.c \
+ src/ext/ed25519/ref10/ge_p3_0.c \
+ src/ext/ed25519/ref10/ge_p3_dbl.c \
+ src/ext/ed25519/ref10/ge_p3_to_cached.c \
+ src/ext/ed25519/ref10/ge_p3_to_p2.c \
+ src/ext/ed25519/ref10/ge_p3_tobytes.c \
+ src/ext/ed25519/ref10/ge_precomp_0.c \
+ src/ext/ed25519/ref10/ge_scalarmult_base.c \
+ src/ext/ed25519/ref10/ge_sub.c \
+ src/ext/ed25519/ref10/ge_tobytes.c \
+ src/ext/ed25519/ref10/keypair.c \
+ src/ext/ed25519/ref10/open.c \
+ src/ext/ed25519/ref10/sc_muladd.c \
+ src/ext/ed25519/ref10/sc_reduce.c \
+ src/ext/ed25519/ref10/sign.c \
+ src/ext/ed25519/ref10/keyconv.c \
+ src/ext/ed25519/ref10/blinding.c
+
+ED25519_REF10_HDRS = \
+ src/ext/ed25519/ref10/api.h \
+ src/ext/ed25519/ref10/base.h \
+ src/ext/ed25519/ref10/base2.h \
+ src/ext/ed25519/ref10/crypto_hash_sha512.h \
+ src/ext/ed25519/ref10/crypto_int32.h \
+ src/ext/ed25519/ref10/crypto_int64.h \
+ src/ext/ed25519/ref10/crypto_sign.h \
+ src/ext/ed25519/ref10/crypto_uint32.h \
+ src/ext/ed25519/ref10/crypto_uint64.h \
+ src/ext/ed25519/ref10/crypto_verify_32.h \
+ src/ext/ed25519/ref10/d.h \
+ src/ext/ed25519/ref10/d2.h \
+ src/ext/ed25519/ref10/ed25519_ref10.h \
+ src/ext/ed25519/ref10/fe.h \
+ src/ext/ed25519/ref10/ge.h \
+ src/ext/ed25519/ref10/ge_add.h \
+ src/ext/ed25519/ref10/ge_madd.h \
+ src/ext/ed25519/ref10/ge_msub.h \
+ src/ext/ed25519/ref10/ge_p2_dbl.h \
+ src/ext/ed25519/ref10/ge_sub.h \
+ src/ext/ed25519/ref10/pow22523.h \
+ src/ext/ed25519/ref10/pow225521.h \
+ src/ext/ed25519/ref10/randombytes.h \
+ src/ext/ed25519/ref10/sc.h \
+ src/ext/ed25519/ref10/sqrtm1.h
+
+noinst_HEADERS += $(ED25519_REF10_HDRS)
+
+LIBED25519_REF10=src/ext/ed25519/ref10/libed25519_ref10.a
+noinst_LIBRARIES += $(LIBED25519_REF10)
diff --git a/src/ext/tinytest.c b/src/ext/tinytest.c
index cc054ad340..f6baeeb9a5 100644
--- a/src/ext/tinytest.c
+++ b/src/ext/tinytest.c
@@ -490,7 +490,7 @@ tinytest_format_hex_(const void *val_, unsigned long len)
return strdup("<allocation failure>");
cp = result;
for (i=0;i<len;++i) {
- *cp++ = "0123456789ABCDEF"[val[i] >> 4];
+ *cp++ = "0123456789ABCDEF"[(val[i] >> 4)&0x0f];
*cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
}
while (ellipses--)
diff --git a/src/ext/tinytest_demo.c b/src/ext/tinytest_demo.c
index 634e112cb8..c07f099791 100644
--- a/src/ext/tinytest_demo.c
+++ b/src/ext/tinytest_demo.c
@@ -74,13 +74,13 @@ test_strcmp(void *data)
values of the failing things.
Fail unless strcmp("abc, "abc") == 0 */
- tt_int_op(strcmp("abc", "abc"), ==, 0);
+ tt_int_op(strcmp("abc", "abc"), OP_EQ, 0);
/* Fail unless strcmp("abc, "abcd") is less than 0 */
- tt_int_op(strcmp("abc", "abcd"), < , 0);
+ tt_int_op(strcmp("abc", "abcd"), OP_LT, 0);
/* Incidentally, there's a test_str_op that uses strcmp internally. */
- tt_str_op("abc", <, "abcd");
+ tt_str_op("abc", OP_LT, "abcd");
/* Every test-case function needs to finish with an "end:"
@@ -153,11 +153,11 @@ test_memcpy(void *ptr)
/* Let's make sure that memcpy does what we'd like. */
strcpy(db->buffer1, "String 0");
memcpy(db->buffer2, db->buffer1, sizeof(db->buffer1));
- tt_str_op(db->buffer1, ==, db->buffer2);
+ tt_str_op(db->buffer1, OP_EQ, db->buffer2);
/* tt_mem_op() does a memcmp, as opposed to the strcmp in tt_str_op() */
db->buffer2[100] = 3; /* Make the buffers unequal */
- tt_mem_op(db->buffer1, <, db->buffer2, sizeof(db->buffer1));
+ tt_mem_op(db->buffer1, OP_LT, db->buffer2, sizeof(db->buffer1));
/* Now we've allocated memory that's referenced by a local variable.
The end block of the function will clean it up. */
@@ -165,7 +165,7 @@ test_memcpy(void *ptr)
tt_assert(mem);
/* Another rather trivial test. */
- tt_str_op(db->buffer1, !=, mem);
+ tt_str_op(db->buffer1, OP_NE, mem);
end:
/* This time our end block has something to do. */
@@ -186,9 +186,9 @@ test_timeout(void *ptr)
#endif
t2 = time(NULL);
- tt_int_op(t2-t1, >=, 4);
+ tt_int_op(t2-t1, OP_GE, 4);
- tt_int_op(t2-t1, <=, 6);
+ tt_int_op(t2-t1, OP_LE, 6);
end:
;
diff --git a/src/ext/tor_queue.h b/src/ext/tor_queue.h
index f05e48c18e..a6530c2b9b 100644
--- a/src/ext/tor_queue.h
+++ b/src/ext/tor_queue.h
@@ -109,7 +109,8 @@ struct { \
*/
#define TOR_SLIST_FIRST(head) ((head)->slh_first)
#define TOR_SLIST_END(head) NULL
-#define TOR_SLIST_EMPTY(head) (SLIST_FIRST(head) == TOR_SLIST_END(head))
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
+#define TOR_SLIST_EMPTY(head) ((SLIST_FIRST(head) == TOR_SLIST_END(head)) || 0)
#define TOR_SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define TOR_SLIST_FOREACH(var, head, field) \
@@ -181,9 +182,11 @@ struct { \
/*
* List access methods
*/
-#define TOR_LIST_FIRST(head) ((head)->lh_first)
-#define TOR_LIST_END(head) NULL
-#define TOR_LIST_EMPTY(head) (TOR_LIST_FIRST(head) == TOR_LIST_END(head))
+#define TOR_LIST_FIRST(head) ((head)->lh_first)
+#define TOR_LIST_END(head) NULL
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
+#define TOR_LIST_EMPTY(head) \
+ ((TOR_LIST_FIRST(head) == TOR_LIST_END(head)) || 0)
#define TOR_LIST_NEXT(elm, field) ((elm)->field.le_next)
#define TOR_LIST_FOREACH(var, head, field) \
@@ -265,8 +268,10 @@ struct { \
* Simple queue access methods.
*/
#define TOR_SIMPLEQ_FIRST(head) ((head)->sqh_first)
-#define TOR_SIMPLEQ_END(head) NULL
-#define TOR_SIMPLEQ_EMPTY(head) (TOR_SIMPLEQ_FIRST(head) == TOR_SIMPLEQ_END(head))
+#define TOR_SIMPLEQ_END(head) NULL
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
+#define TOR_SIMPLEQ_EMPTY(head) \
+ ((TOR_SIMPLEQ_FIRST(head) == TOR_SIMPLEQ_END(head)) || 0)
#define TOR_SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define TOR_SIMPLEQ_FOREACH(var, head, field) \
@@ -345,8 +350,9 @@ struct { \
/* XXX */
#define TOR_TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
#define TOR_TAILQ_EMPTY(head) \
- (TOR_TAILQ_FIRST(head) == TOR_TAILQ_END(head))
+ ((TOR_TAILQ_FIRST(head) == TOR_TAILQ_END(head)) || 0)
#define TOR_TAILQ_FOREACH(var, head, field) \
for((var) = TOR_TAILQ_FIRST(head); \
@@ -462,8 +468,9 @@ struct { \
#define TOR_CIRCLEQ_END(head) ((void *)(head))
#define TOR_CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define TOR_CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
#define TOR_CIRCLEQ_EMPTY(head) \
- (TOR_CIRCLEQ_FIRST(head) == TOR_CIRCLEQ_END(head))
+ ((TOR_CIRCLEQ_FIRST(head) == TOR_CIRCLEQ_END(head)) || 0)
#define TOR_CIRCLEQ_FOREACH(var, head, field) \
for((var) = TOR_CIRCLEQ_FIRST(head); \
diff --git a/src/ext/trunnel/trunnel-impl.h b/src/ext/trunnel/trunnel-impl.h
new file mode 100644
index 0000000000..8714fded9f
--- /dev/null
+++ b/src/ext/trunnel/trunnel-impl.h
@@ -0,0 +1,310 @@
+/* trunnel-impl.h -- copied from Trunnel v1.2
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+/* trunnel-impl.h -- Implementation helpers for trunnel, included by
+ * generated trunnel files
+ *
+ * Copyright 2014-2015, The Tor Project, Inc.
+ * See license at the end of this file for copying information.
+ */
+
+#ifndef TRUNNEL_IMPL_H_INCLUDED_
+#define TRUNNEL_IMPL_H_INCLUDED_
+#include "trunnel.h"
+#include <assert.h>
+#include <string.h>
+#ifdef TRUNNEL_LOCAL_H
+#include "trunnel-local.h"
+#endif
+
+#ifdef _MSC_VER
+#define uint8_t unsigned char
+#define uint16_t unsigned short
+#define uint32_t unsigned int
+#define uint64_t unsigned __int64
+#define inline __inline
+#else
+#include <stdint.h>
+#endif
+
+#ifdef _WIN32
+uint32_t trunnel_htonl(uint32_t a);
+uint32_t trunnel_ntohl(uint32_t a);
+uint16_t trunnel_htons(uint16_t a);
+uint16_t trunnel_ntohs(uint16_t a);
+#else
+#include <arpa/inet.h>
+#define trunnel_htonl(x) htonl(x)
+#define trunnel_htons(x) htons(x)
+#define trunnel_ntohl(x) ntohl(x)
+#define trunnel_ntohs(x) ntohs(x)
+#endif
+uint64_t trunnel_htonll(uint64_t a);
+uint64_t trunnel_ntohll(uint64_t a);
+
+#ifndef trunnel_assert
+#define trunnel_assert(x) assert(x)
+#endif
+
+static inline void
+trunnel_set_uint64(void *p, uint64_t v) {
+ memcpy(p, &v, 8);
+}
+static inline void
+trunnel_set_uint32(void *p, uint32_t v) {
+ memcpy(p, &v, 4);
+}
+static inline void
+trunnel_set_uint16(void *p, uint16_t v) {
+ memcpy(p, &v, 2);
+}
+static inline void
+trunnel_set_uint8(void *p, uint8_t v) {
+ memcpy(p, &v, 1);
+}
+
+static inline uint64_t
+trunnel_get_uint64(const void *p) {
+ uint64_t x;
+ memcpy(&x, p, 8);
+ return x;
+}
+static inline uint32_t
+trunnel_get_uint32(const void *p) {
+ uint32_t x;
+ memcpy(&x, p, 4);
+ return x;
+}
+static inline uint16_t
+trunnel_get_uint16(const void *p) {
+ uint16_t x;
+ memcpy(&x, p, 2);
+ return x;
+}
+static inline uint8_t
+trunnel_get_uint8(const void *p) {
+ return *(const uint8_t*)p;
+}
+
+
+#ifdef TRUNNEL_DEBUG_FAILING_ALLOC
+extern int trunnel_provoke_alloc_failure;
+
+static inline void *
+trunnel_malloc(size_t n)
+{
+ if (trunnel_provoke_alloc_failure) {
+ if (--trunnel_provoke_alloc_failure == 0)
+ return NULL;
+ }
+ return malloc(n);
+}
+static inline void *
+trunnel_calloc(size_t a, size_t b)
+{
+ if (trunnel_provoke_alloc_failure) {
+ if (--trunnel_provoke_alloc_failure == 0)
+ return NULL;
+ }
+ return calloc(a,b);
+}
+static inline char *
+trunnel_strdup(const char *s)
+{
+ if (trunnel_provoke_alloc_failure) {
+ if (--trunnel_provoke_alloc_failure == 0)
+ return NULL;
+ }
+ return strdup(s);
+}
+#else
+#ifndef trunnel_malloc
+#define trunnel_malloc(x) (malloc((x)))
+#endif
+#ifndef trunnel_calloc
+#define trunnel_calloc(a,b) (calloc((a),(b)))
+#endif
+#ifndef trunnel_strdup
+#define trunnel_strdup(s) (strdup((s)))
+#endif
+#endif
+
+#ifndef trunnel_realloc
+#define trunnel_realloc(a,b) realloc((a),(b))
+#endif
+
+#ifndef trunnel_free_
+#define trunnel_free_(x) (free(x))
+#endif
+#define trunnel_free(x) ((x) ? (trunnel_free_(x),0) : (0))
+
+#ifndef trunnel_abort
+#define trunnel_abort() abort()
+#endif
+
+#ifndef trunnel_memwipe
+#define trunnel_memwipe(mem, len) ((void)0)
+#define trunnel_wipestr(s) ((void)0)
+#else
+#define trunnel_wipestr(s) do { \
+ if (s) \
+ trunnel_memwipe(s, strlen(s)); \
+ } while (0)
+#endif
+
+/* ====== dynamic arrays ======== */
+
+#ifdef NDEBUG
+#define TRUNNEL_DYNARRAY_GET(da, n) \
+ ((da)->elts_[(n)])
+#else
+/** Return the 'n'th element of 'da'. */
+#define TRUNNEL_DYNARRAY_GET(da, n) \
+ (((n) >= (da)->n_ ? (trunnel_abort(),0) : 0), (da)->elts_[(n)])
+#endif
+
+/** Change the 'n'th element of 'da' to 'v'. */
+#define TRUNNEL_DYNARRAY_SET(da, n, v) do { \
+ trunnel_assert((n) < (da)->n_); \
+ (da)->elts_[(n)] = (v); \
+ } while (0)
+
+/** Expand the dynamic array 'da' of 'elttype' so that it can hold at least
+ * 'howmanymore' elements than its current capacity. Always tries to increase
+ * the length of the array. On failure, run the code in 'on_fail' and goto
+ * trunnel_alloc_failed. */
+#define TRUNNEL_DYNARRAY_EXPAND(elttype, da, howmanymore, on_fail) do { \
+ elttype *newarray; \
+ newarray = trunnel_dynarray_expand(&(da)->allocated_, \
+ (da)->elts_, (howmanymore), \
+ sizeof(elttype)); \
+ if (newarray == NULL) { \
+ on_fail; \
+ goto trunnel_alloc_failed; \
+ } \
+ (da)->elts_ = newarray; \
+ } while (0)
+
+/** Add 'v' to the end of the dynamic array 'da' of 'elttype', expanding it if
+ * necessary. code in 'on_fail' and goto trunnel_alloc_failed. */
+#define TRUNNEL_DYNARRAY_ADD(elttype, da, v, on_fail) do { \
+ if ((da)->n_ == (da)->allocated_) { \
+ TRUNNEL_DYNARRAY_EXPAND(elttype, da, 1, on_fail); \
+ } \
+ (da)->elts_[(da)->n_++] = (v); \
+ } while (0)
+
+/** Return the number of elements in 'da'. */
+#define TRUNNEL_DYNARRAY_LEN(da) ((da)->n_)
+
+/** Remove all storage held by 'da' and set it to be empty. Does not free
+ * storage held by the elements themselves. */
+#define TRUNNEL_DYNARRAY_CLEAR(da) do { \
+ trunnel_free((da)->elts_); \
+ (da)->elts_ = NULL; \
+ (da)->n_ = (da)->allocated_ = 0; \
+ } while (0)
+
+/** Remove all storage held by 'da' and set it to be empty. Does not free
+ * storage held by the elements themselves. */
+#define TRUNNEL_DYNARRAY_WIPE(da) do { \
+ trunnel_memwipe((da)->elts_, (da)->allocated_ * sizeof((da)->elts_[0])); \
+ } while (0)
+
+/** Helper: wraps or implements an OpenBSD-style reallocarray. Behaves
+ * as realloc(a, x*y), but verifies that no overflow will occur in the
+ * multiplication. Returns NULL on failure. */
+#ifndef trunnel_reallocarray
+void *trunnel_reallocarray(void *a, size_t x, size_t y);
+#endif
+
+/** Helper to expand a dynamic array. Behaves as TRUNNEL_DYNARRAY_EXPAND(),
+ * taking the array of elements in 'ptr', a pointer to thethe current number
+ * of allocated elements in allocated_p, the minimum numbeer of elements to
+ * add in 'howmanymore', and the size of a single element in 'eltsize'.
+ *
+ * On success, adjust *allocated_p, and return the new value for the array of
+ * elements. On failure, adjust nothing and return NULL.
+ */
+void *trunnel_dynarray_expand(size_t *allocated_p, void *ptr,
+ size_t howmanymore, size_t eltsize);
+
+/** Type for a function to free members of a dynarray of pointers. */
+typedef void (*trunnel_free_fn_t)(void *);
+
+/**
+ * Helper to change the length of a dynamic array. Takes pointers to the
+ * current allocated and n fields of the array in 'allocated_p' and 'len_p',
+ * and the current array of elements in 'ptr'; takes the length of a single
+ * element in 'eltsize'. Changes the length to 'newlen'. If 'newlen' is
+ * greater than the current length, pads the new elements with 0. If newlen
+ * is less than the current length, and free_fn is non-NULL, treat the
+ * array as an array of void *, and invoke free_fn() on each removed element.
+ *
+ * On success, adjust *allocated_p and *len_p, and return the new value for
+ * the array of elements. On failure, adjust nothing, set *errcode_ptr to 1,
+ * and return NULL.
+ */
+void *trunnel_dynarray_setlen(size_t *allocated_p, size_t *len_p,
+ void *ptr, size_t newlen,
+ size_t eltsize, trunnel_free_fn_t free_fn,
+ uint8_t *errcode_ptr);
+
+/**
+ * Helper: return a pointer to the value of 'str' as a NUL-terminated string.
+ * Might have to reallocate the storage for 'str' in order to fit in the final
+ * NUL character. On allocation failure, return NULL.
+ */
+const char *trunnel_string_getstr(trunnel_string_t *str);
+
+/**
+ * Helper: change the contents of 'str' to hold the 'len'-byte string in
+ * 'inp'. Adjusts the storage to have a terminating NUL that doesn't count
+ * towards the length of the string. On success, return 0. On failure, set
+ * *errcode_ptr to 1 and return -1.
+ */
+int trunnel_string_setstr0(trunnel_string_t *str, const char *inp, size_t len,
+ uint8_t *errcode_ptr);
+
+/**
+ * As trunnel_dynarray_setlen, but adjusts a string rather than a dynamic
+ * array, and ensures that the new string is NUL-terminated.
+ */
+int trunnel_string_setlen(trunnel_string_t *str, size_t newlen,
+ uint8_t *errcode_ptr);
+
+#endif
+
+
+/*
+Copyright 2014 The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/src/ext/trunnel/trunnel.c b/src/ext/trunnel/trunnel.c
new file mode 100644
index 0000000000..735323798f
--- /dev/null
+++ b/src/ext/trunnel/trunnel.c
@@ -0,0 +1,247 @@
+/* trunnel.c -- copied from Trunnel v1.4-pre
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+/* trunnel.c -- Helper functions to implement trunnel.
+ *
+ * Copyright 2014-2015, The Tor Project, Inc.
+ * See license at the end of this file for copying information.
+ *
+ * See trunnel-impl.h for documentation of these functions.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "trunnel-impl.h"
+
+#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
+ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define IS_LITTLE_ENDIAN 1
+#elif defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && \
+ BYTE_ORDER == __ORDER_LITTLE_ENDIAN
+# define IS_LITTLE_ENDIAN 1
+#elif defined(_WIN32)
+# define IS_LITTLE_ENDIAN 1
+#elif defined(__APPLE__)
+# include <libkern/OSByteOrder.h>
+# define BSWAP64(x) OSSwapLittleToHostInt64(x)
+#elif defined(sun) || defined(__sun)
+# include <sys/byteorder.h>
+# ifndef _BIG_ENDIAN
+# define IS_LITTLE_ENDIAN
+# endif
+#else
+# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+# include <sys/endian.h>
+# else
+# include <endian.h>
+# endif
+# if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
+ __BYTE_ORDER == __LITTLE_ENDIAN
+# define IS_LITTLE_ENDIAN
+# endif
+#endif
+
+#ifdef _WIN32
+uint16_t
+trunnel_htons(uint16_t s)
+{
+ return (s << 8) | (s >> 8);
+}
+uint16_t
+trunnel_ntohs(uint16_t s)
+{
+ return (s << 8) | (s >> 8);
+}
+uint32_t
+trunnel_htonl(uint32_t s)
+{
+ return (s << 24) |
+ ((s << 8)&0xff0000) |
+ ((s >> 8)&0xff00) |
+ (s >> 24);
+}
+uint32_t
+trunnel_ntohl(uint32_t s)
+{
+ return (s << 24) |
+ ((s << 8)&0xff0000) |
+ ((s >> 8)&0xff00) |
+ (s >> 24);
+}
+#endif
+
+uint64_t
+trunnel_htonll(uint64_t a)
+{
+#ifdef IS_LITTLE_ENDIAN
+ return trunnel_htonl((uint32_t)(a>>32))
+ | (((uint64_t)trunnel_htonl((uint32_t)a))<<32);
+#else
+ return a;
+#endif
+}
+
+uint64_t
+trunnel_ntohll(uint64_t a)
+{
+ return trunnel_htonll(a);
+}
+
+#ifdef TRUNNEL_DEBUG_FAILING_ALLOC
+/** Used for debugging and running tricky test cases: Makes the nth
+ * memoryation allocation call from now fail.
+ */
+int trunnel_provoke_alloc_failure = 0;
+#endif
+
+void *
+trunnel_dynarray_expand(size_t *allocated_p, void *ptr,
+ size_t howmanymore, size_t eltsize)
+{
+ size_t newsize = howmanymore + *allocated_p;
+ void *newarray = NULL;
+ if (newsize < 8)
+ newsize = 8;
+ if (newsize < *allocated_p * 2)
+ newsize = *allocated_p * 2;
+ if (newsize <= *allocated_p || newsize < howmanymore)
+ return NULL;
+ newarray = trunnel_reallocarray(ptr, newsize, eltsize);
+ if (newarray == NULL)
+ return NULL;
+
+ *allocated_p = newsize;
+ return newarray;
+}
+
+#ifndef trunnel_reallocarray
+void *
+trunnel_reallocarray(void *a, size_t x, size_t y)
+{
+#ifdef TRUNNEL_DEBUG_FAILING_ALLOC
+ if (trunnel_provoke_alloc_failure) {
+ if (--trunnel_provoke_alloc_failure == 0)
+ return NULL;
+ }
+#endif
+ if (x > SIZE_MAX / y)
+ return NULL;
+ return trunnel_realloc(a, x * y);
+}
+#endif
+
+const char *
+trunnel_string_getstr(trunnel_string_t *str)
+{
+ trunnel_assert(str->allocated_ >= str->n_);
+ if (str->allocated_ == str->n_) {
+ TRUNNEL_DYNARRAY_EXPAND(char, str, 1, {});
+ }
+ str->elts_[str->n_] = 0;
+ return str->elts_;
+trunnel_alloc_failed:
+ return NULL;
+}
+
+int
+trunnel_string_setstr0(trunnel_string_t *str, const char *val, size_t len,
+ uint8_t *errcode_ptr)
+{
+ if (len == SIZE_MAX)
+ goto trunnel_alloc_failed;
+ if (str->allocated_ <= len) {
+ TRUNNEL_DYNARRAY_EXPAND(char, str, len + 1 - str->allocated_, {});
+ }
+ memcpy(str->elts_, val, len);
+ str->n_ = len;
+ str->elts_[len] = 0;
+ return 0;
+trunnel_alloc_failed:
+ *errcode_ptr = 1;
+ return -1;
+}
+
+int
+trunnel_string_setlen(trunnel_string_t *str, size_t newlen,
+ uint8_t *errcode_ptr)
+{
+ if (newlen == SIZE_MAX)
+ goto trunnel_alloc_failed;
+ if (str->allocated_ < newlen + 1) {
+ TRUNNEL_DYNARRAY_EXPAND(char, str, newlen + 1 - str->allocated_, {});
+ }
+ if (str->n_ < newlen) {
+ memset(& (str->elts_[str->n_]), 0, (newlen - str->n_));
+ }
+ str->n_ = newlen;
+ str->elts_[newlen] = 0;
+ return 0;
+
+ trunnel_alloc_failed:
+ *errcode_ptr = 1;
+ return -1;
+}
+
+void *
+trunnel_dynarray_setlen(size_t *allocated_p, size_t *len_p,
+ void *ptr, size_t newlen,
+ size_t eltsize, trunnel_free_fn_t free_fn,
+ uint8_t *errcode_ptr)
+{
+ if (*allocated_p < newlen) {
+ void *newptr = trunnel_dynarray_expand(allocated_p, ptr,
+ newlen - *allocated_p, eltsize);
+ if (newptr == NULL)
+ goto trunnel_alloc_failed;
+ ptr = newptr;
+ }
+ if (free_fn && *len_p > newlen) {
+ size_t i;
+ void **elts = (void **) ptr;
+ for (i = newlen; i < *len_p; ++i) {
+ free_fn(elts[i]);
+ elts[i] = NULL;
+ }
+ }
+ if (*len_p < newlen) {
+ memset( ((char*)ptr) + (eltsize * *len_p), 0, (newlen - *len_p) * eltsize);
+ }
+ *len_p = newlen;
+ return ptr;
+ trunnel_alloc_failed:
+ *errcode_ptr = 1;
+ return NULL;
+}
+
+/*
+Copyright 2014 The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/src/ext/trunnel/trunnel.h b/src/ext/trunnel/trunnel.h
new file mode 100644
index 0000000000..22c1ed80c9
--- /dev/null
+++ b/src/ext/trunnel/trunnel.h
@@ -0,0 +1,64 @@
+/* trunnel.h -- copied from Trunnel v1.2
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+/* trunnel.h -- Public declarations for trunnel, to be included
+ * in trunnel header files.
+
+ * Copyright 2014-2015, The Tor Project, Inc.
+ * See license at the end of this file for copying information.
+ */
+
+#ifndef TRUNNEL_H_INCLUDED_
+#define TRUNNEL_H_INCLUDED_
+
+#include <sys/types.h>
+
+/** Macro to declare a variable-length dynamically allocated array. Trunnel
+ * uses these to store all variable-length arrays. */
+#define TRUNNEL_DYNARRAY_HEAD(name, elttype) \
+ struct name { \
+ size_t n_; \
+ size_t allocated_; \
+ elttype *elts_; \
+ }
+
+/** Initializer for a dynamic array of a given element type. */
+#define TRUNNEL_DYNARRAY_INIT(elttype) { 0, 0, (elttype*)NULL }
+
+/** Typedef used for storing variable-length arrays of char. */
+typedef TRUNNEL_DYNARRAY_HEAD(trunnel_string_st, char) trunnel_string_t;
+
+#endif
+
+/*
+Copyright 2014 The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
diff --git a/src/include.am b/src/include.am
index d0693e25b0..c468af3649 100644
--- a/src/include.am
+++ b/src/include.am
@@ -1,7 +1,9 @@
include src/ext/include.am
+include src/trunnel/include.am
include src/common/include.am
include src/or/include.am
include src/test/include.am
include src/tools/include.am
include src/win32/include.am
include src/config/include.am
+
diff --git a/src/or/Makefile.nmake b/src/or/Makefile.nmake
index 523bf3306b..2ac98cd372 100644
--- a/src/or/Makefile.nmake
+++ b/src/or/Makefile.nmake
@@ -63,6 +63,7 @@ LIBTOR_OBJECTS = \
routerlist.obj \
routerparse.obj \
routerset.obj \
+ scheduler.obj \
statefile.obj \
status.obj \
transports.obj
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
index d4b7acf274..9c29fb2acb 100644
--- a/src/or/addressmap.c
+++ b/src/or/addressmap.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESSMAP_PRIVATE
@@ -94,7 +94,7 @@ addressmap_ent_free(void *_ent)
tor_free(ent);
}
-/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
+/** Free storage held by a virtaddress_entry_t* entry in <b>_ent</b>. */
static void
addressmap_virtaddress_ent_free(void *_ent)
{
@@ -104,11 +104,13 @@ addressmap_virtaddress_ent_free(void *_ent)
ent = _ent;
tor_free(ent->ipv4_address);
+ tor_free(ent->ipv6_address);
tor_free(ent->hostname_address);
tor_free(ent);
}
-/** Free storage held by a virtaddress_entry_t* entry in <b>ent</b>. */
+/** Remove <b>address</b> (which must map to <b>ent</b>) from the
+ * virtual address map. */
static void
addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
{
@@ -120,9 +122,11 @@ addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
if (ve) {
if (!strcmp(address, ve->ipv4_address))
tor_free(ve->ipv4_address);
+ if (!strcmp(address, ve->ipv6_address))
+ tor_free(ve->ipv6_address);
if (!strcmp(address, ve->hostname_address))
tor_free(ve->hostname_address);
- if (!ve->ipv4_address && !ve->hostname_address) {
+ if (!ve->ipv4_address && !ve->ipv6_address && !ve->hostname_address) {
tor_free(ve);
strmap_remove(virtaddress_reversemap, ent->new_address);
}
@@ -131,7 +135,7 @@ addressmap_virtaddress_remove(const char *address, addressmap_entry_t *ent)
}
/** Remove <b>ent</b> (which must be mapped to by <b>address</b>) from the
- * client address maps. */
+ * client address maps, and then free it. */
static void
addressmap_ent_remove(const char *address, addressmap_entry_t *ent)
{
@@ -226,6 +230,8 @@ addressmap_address_should_automap(const char *address,
return 0;
SMARTLIST_FOREACH_BEGIN(suffix_list, const char *, suffix) {
+ if (!strcmp(suffix, "."))
+ return 1;
if (!strcasecmpend(address, suffix))
return 1;
} SMARTLIST_FOREACH_END(suffix);
@@ -384,13 +390,35 @@ addressmap_rewrite(char *address, size_t maxlen,
goto done;
}
- if (ent && ent->source == ADDRMAPSRC_DNS) {
- sa_family_t f;
- tor_addr_t tmp;
- f = tor_addr_parse(&tmp, ent->new_address);
- if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS))
- goto done;
- else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS))
+ switch (ent->source) {
+ case ADDRMAPSRC_DNS:
+ {
+ sa_family_t f;
+ tor_addr_t tmp;
+ f = tor_addr_parse(&tmp, ent->new_address);
+ if (f == AF_INET && !(flags & AMR_FLAG_USE_IPV4_DNS))
+ goto done;
+ else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS))
+ goto done;
+ }
+ break;
+ case ADDRMAPSRC_CONTROLLER:
+ case ADDRMAPSRC_TORRC:
+ if (!(flags & AMR_FLAG_USE_MAPADDRESS))
+ goto done;
+ break;
+ case ADDRMAPSRC_AUTOMAP:
+ if (!(flags & AMR_FLAG_USE_AUTOMAP))
+ goto done;
+ break;
+ case ADDRMAPSRC_TRACKEXIT:
+ if (!(flags & AMR_FLAG_USE_TRACKEXIT))
+ goto done;
+ break;
+ case ADDRMAPSRC_NONE:
+ default:
+ log_warn(LD_BUG, "Unknown addrmap source value %d. Ignoring it.",
+ (int) ent->source);
goto done;
}
@@ -425,7 +453,7 @@ addressmap_rewrite(char *address, size_t maxlen,
if (exit_source_out)
*exit_source_out = exit_source;
if (expires_out)
- *expires_out = TIME_MAX;
+ *expires_out = expires;
return (rewrites > 0);
}
@@ -449,6 +477,8 @@ addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags,
return 0;
else if (f == AF_INET6 && !(flags & AMR_FLAG_USE_IPV6_DNS))
return 0;
+ /* FFFF we should reverse-map virtual addresses even if we haven't
+ * enabled DNS cacheing. */
}
tor_asprintf(&s, "REVERSE[%s]", address);
@@ -496,7 +526,7 @@ addressmap_have_mapping(const char *address, int update_expiry)
* equal to <b>address</b>, or any address ending with a period followed by
* <b>address</b>. If <b>wildcard_addr</b> and <b>wildcard_new_addr</b> are
* both true, the mapping will rewrite addresses that end with
- * ".<b>address</b>" into ones that end with ".<b>new_address</b>."
+ * ".<b>address</b>" into ones that end with ".<b>new_address</b>".
*
* If <b>new_address</b> is NULL, or <b>new_address</b> is equal to
* <b>address</b> and <b>wildcard_addr</b> is equal to
@@ -535,9 +565,9 @@ addressmap_register(const char *address, char *new_address, time_t expires,
if (expires > 1) {
log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, "
"since it's already mapped to '%s'",
- safe_str_client(address),
- safe_str_client(new_address),
- safe_str_client(ent->new_address));
+ safe_str_client(address),
+ safe_str_client(new_address),
+ safe_str_client(ent->new_address));
tor_free(new_address);
return;
}
@@ -670,10 +700,10 @@ client_dns_set_addressmap(entry_connection_t *for_conn,
return; /* If address was an IP address already, don't add a mapping. */
if (tor_addr_family(val) == AF_INET) {
- if (! for_conn->cache_ipv4_answers)
+ if (! for_conn->entry_cfg.cache_ipv4_answers)
return;
} else if (tor_addr_family(val) == AF_INET6) {
- if (! for_conn->cache_ipv6_answers)
+ if (! for_conn->entry_cfg.cache_ipv6_answers)
return;
}
@@ -702,8 +732,8 @@ client_dns_set_reverse_addressmap(entry_connection_t *for_conn,
{
tor_addr_t tmp_addr;
sa_family_t f = tor_addr_parse(&tmp_addr, address);
- if ((f == AF_INET && ! for_conn->cache_ipv4_answers) ||
- (f == AF_INET6 && ! for_conn->cache_ipv6_answers))
+ if ((f == AF_INET && ! for_conn->entry_cfg.cache_ipv4_answers) ||
+ (f == AF_INET6 && ! for_conn->entry_cfg.cache_ipv6_answers))
return;
}
tor_asprintf(&s, "REVERSE[%s]", address);
@@ -845,8 +875,8 @@ get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
}
/** Return a newly allocated string holding an address of <b>type</b>
- * (one of RESOLVED_TYPE_{IPV4|HOSTNAME}) that has not yet been mapped,
- * and that is very unlikely to be the address of any real host.
+ * (one of RESOLVED_TYPE_{IPV4|IPV6|HOSTNAME}) that has not yet been
+ * mapped, and that is very unlikely to be the address of any real host.
*
* May return NULL if we have run out of virtual addresses.
*/
@@ -894,7 +924,7 @@ addressmap_get_virtual_address(int type)
/* XXXX This code is to make sure I didn't add an undecorated version
* by mistake. I hope it's needless. */
char tmp[TOR_ADDR_BUF_LEN];
- tor_addr_to_str(buf, &addr, sizeof(tmp), 0);
+ tor_addr_to_str(tmp, &addr, sizeof(tmp), 0);
if (strmap_get(addressmap, tmp)) {
log_warn(LD_BUG, "%s wasn't in the addressmap, but %s was.",
buf, tmp);
@@ -975,6 +1005,8 @@ addressmap_register_virtual_address(int type, char *new_address)
strmap_set(virtaddress_reversemap, new_address, vent);
addressmap_register(*addrp, new_address, 2, ADDRMAPSRC_AUTOMAP, 0, 0);
+ /* FFFF register corresponding reverse mapping. */
+
#if 0
{
/* Try to catch possible bugs */
diff --git a/src/or/addressmap.h b/src/or/addressmap.h
index 417832b31f..ff108df024 100644
--- a/src/or/addressmap.h
+++ b/src/or/addressmap.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_ADDRESSMAP_H
@@ -16,8 +16,11 @@ void addressmap_clean(time_t now);
void addressmap_clear_configured(void);
void addressmap_clear_transient(void);
void addressmap_free_all(void);
-#define AMR_FLAG_USE_IPV4_DNS (1u<<0)
-#define AMR_FLAG_USE_IPV6_DNS (1u<<1)
+#define AMR_FLAG_USE_IPV4_DNS (1u<<0)
+#define AMR_FLAG_USE_IPV6_DNS (1u<<1)
+#define AMR_FLAG_USE_MAPADDRESS (1u<<2)
+#define AMR_FLAG_USE_AUTOMAP (1u<<3)
+#define AMR_FLAG_USE_TRACKEXIT (1u<<4)
int addressmap_rewrite(char *address, size_t maxlen, unsigned flags,
time_t *expires_out,
addressmap_entry_source_t *exit_source_out);
diff --git a/src/or/buffers.c b/src/or/buffers.c
index a60c7c0f02..74aebccb77 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -55,6 +55,9 @@
* forever.
*/
+static void socks_request_set_socks5_error(socks_request_t *req,
+ socks5_reply_status_t reason);
+
static int parse_socks(const char *data, size_t datalen, socks_request_t *req,
int log_sockstype, int safe_socks, ssize_t *drain_out,
size_t *want_length_out);
@@ -123,115 +126,6 @@ chunk_repack(chunk_t *chunk)
/** Keep track of total size of allocated chunks for consistency asserts */
static size_t total_bytes_allocated_in_chunks = 0;
-
-#if defined(ENABLE_BUF_FREELISTS) || defined(RUNNING_DOXYGEN)
-/** A freelist of chunks. */
-typedef struct chunk_freelist_t {
- size_t alloc_size; /**< What size chunks does this freelist hold? */
- int max_length; /**< Never allow more than this number of chunks in the
- * freelist. */
- int slack; /**< When trimming the freelist, leave this number of extra
- * chunks beyond lowest_length.*/
- int cur_length; /**< How many chunks on the freelist now? */
- int lowest_length; /**< What's the smallest value of cur_length since the
- * last time we cleaned this freelist? */
- uint64_t n_alloc;
- uint64_t n_free;
- uint64_t n_hit;
- chunk_t *head; /**< First chunk on the freelist. */
-} chunk_freelist_t;
-
-/** Macro to help define freelists. */
-#define FL(a,m,s) { a, m, s, 0, 0, 0, 0, 0, NULL }
-
-/** Static array of freelists, sorted by alloc_len, terminated by an entry
- * with alloc_size of 0. */
-static chunk_freelist_t freelists[] = {
- FL(4096, 256, 8), FL(8192, 128, 4), FL(16384, 64, 4), FL(32768, 32, 2),
- FL(0, 0, 0)
-};
-#undef FL
-/** How many times have we looked for a chunk of a size that no freelist
- * could help with? */
-static uint64_t n_freelist_miss = 0;
-
-static void assert_freelist_ok(chunk_freelist_t *fl);
-
-/** Return the freelist to hold chunks of size <b>alloc</b>, or NULL if
- * no freelist exists for that size. */
-static INLINE chunk_freelist_t *
-get_freelist(size_t alloc)
-{
- int i;
- for (i=0; (freelists[i].alloc_size <= alloc &&
- freelists[i].alloc_size); ++i ) {
- if (freelists[i].alloc_size == alloc) {
- return &freelists[i];
- }
- }
- return NULL;
-}
-
-/** Deallocate a chunk or put it on a freelist */
-static void
-chunk_free_unchecked(chunk_t *chunk)
-{
- size_t alloc;
- chunk_freelist_t *freelist;
-
- alloc = CHUNK_ALLOC_SIZE(chunk->memlen);
- freelist = get_freelist(alloc);
- if (freelist && freelist->cur_length < freelist->max_length) {
- chunk->next = freelist->head;
- freelist->head = chunk;
- ++freelist->cur_length;
- } else {
- if (freelist)
- ++freelist->n_free;
-#ifdef DEBUG_CHUNK_ALLOC
- tor_assert(alloc == chunk->DBG_alloc);
-#endif
- tor_assert(total_bytes_allocated_in_chunks >= alloc);
- total_bytes_allocated_in_chunks -= alloc;
- tor_free(chunk);
- }
-}
-
-/** Allocate a new chunk with a given allocation size, or get one from the
- * freelist. Note that a chunk with allocation size A can actually hold only
- * CHUNK_SIZE_WITH_ALLOC(A) bytes in its mem field. */
-static INLINE chunk_t *
-chunk_new_with_alloc_size(size_t alloc)
-{
- chunk_t *ch;
- chunk_freelist_t *freelist;
- tor_assert(alloc >= sizeof(chunk_t));
- freelist = get_freelist(alloc);
- if (freelist && freelist->head) {
- ch = freelist->head;
- freelist->head = ch->next;
- if (--freelist->cur_length < freelist->lowest_length)
- freelist->lowest_length = freelist->cur_length;
- ++freelist->n_hit;
- } else {
- if (freelist)
- ++freelist->n_alloc;
- else
- ++n_freelist_miss;
- ch = tor_malloc(alloc);
-#ifdef DEBUG_CHUNK_ALLOC
- ch->DBG_alloc = alloc;
-#endif
- total_bytes_allocated_in_chunks += alloc;
- }
- ch->next = NULL;
- ch->datalen = 0;
- ch->memlen = CHUNK_SIZE_WITH_ALLOC(alloc);
- ch->data = &ch->mem[0];
- CHUNK_SET_SENTINEL(ch, alloc);
- return ch;
-}
-#else
static void
chunk_free_unchecked(chunk_t *chunk)
{
@@ -261,7 +155,6 @@ chunk_new_with_alloc_size(size_t alloc)
CHUNK_SET_SENTINEL(ch, alloc);
return ch;
}
-#endif
/** Expand <b>chunk</b> until it can hold <b>sz</b> bytes, and return a
* new pointer to <b>chunk</b>. Old pointers are no longer valid. */
@@ -306,115 +199,6 @@ preferred_chunk_size(size_t target)
return sz;
}
-/** Remove from the freelists most chunks that have not been used since the
- * last call to buf_shrink_freelists(). Return the amount of memory
- * freed. */
-size_t
-buf_shrink_freelists(int free_all)
-{
-#ifdef ENABLE_BUF_FREELISTS
- int i;
- size_t total_freed = 0;
- disable_control_logging();
- for (i = 0; freelists[i].alloc_size; ++i) {
- int slack = freelists[i].slack;
- assert_freelist_ok(&freelists[i]);
- if (free_all || freelists[i].lowest_length > slack) {
- int n_to_free = free_all ? freelists[i].cur_length :
- (freelists[i].lowest_length - slack);
- int n_to_skip = freelists[i].cur_length - n_to_free;
- int orig_length = freelists[i].cur_length;
- int orig_n_to_free = n_to_free, n_freed=0;
- int orig_n_to_skip = n_to_skip;
- int new_length = n_to_skip;
- chunk_t **chp = &freelists[i].head;
- chunk_t *chunk;
- while (n_to_skip) {
- if (!(*chp) || ! (*chp)->next) {
- log_warn(LD_BUG, "I wanted to skip %d chunks in the freelist for "
- "%d-byte chunks, but only found %d. (Length %d)",
- orig_n_to_skip, (int)freelists[i].alloc_size,
- orig_n_to_skip-n_to_skip, freelists[i].cur_length);
- assert_freelist_ok(&freelists[i]);
- goto done;
- }
- // tor_assert((*chp)->next);
- chp = &(*chp)->next;
- --n_to_skip;
- }
- chunk = *chp;
- *chp = NULL;
- while (chunk) {
- chunk_t *next = chunk->next;
-#ifdef DEBUG_CHUNK_ALLOC
- tor_assert(chunk->DBG_alloc == CHUNK_ALLOC_SIZE(chunk->memlen));
-#endif
- tor_assert(total_bytes_allocated_in_chunks >=
- CHUNK_ALLOC_SIZE(chunk->memlen));
- total_bytes_allocated_in_chunks -= CHUNK_ALLOC_SIZE(chunk->memlen);
- total_freed += CHUNK_ALLOC_SIZE(chunk->memlen);
- tor_free(chunk);
- chunk = next;
- --n_to_free;
- ++n_freed;
- ++freelists[i].n_free;
- }
- if (n_to_free) {
- log_warn(LD_BUG, "Freelist length for %d-byte chunks may have been "
- "messed up somehow.", (int)freelists[i].alloc_size);
- log_warn(LD_BUG, "There were %d chunks at the start. I decided to "
- "keep %d. I wanted to free %d. I freed %d. I somehow think "
- "I have %d left to free.",
- freelists[i].cur_length, n_to_skip, orig_n_to_free,
- n_freed, n_to_free);
- }
- // tor_assert(!n_to_free);
- freelists[i].cur_length = new_length;
- tor_assert(orig_n_to_skip == new_length);
- log_info(LD_MM, "Cleaned freelist for %d-byte chunks: original "
- "length %d, kept %d, dropped %d. New length is %d",
- (int)freelists[i].alloc_size, orig_length,
- orig_n_to_skip, orig_n_to_free, new_length);
- }
- freelists[i].lowest_length = freelists[i].cur_length;
- assert_freelist_ok(&freelists[i]);
- }
- done:
- enable_control_logging();
- return total_freed;
-#else
- (void) free_all;
- return 0;
-#endif
-}
-
-/** Describe the current status of the freelists at log level <b>severity</b>.
- */
-void
-buf_dump_freelist_sizes(int severity)
-{
-#ifdef ENABLE_BUF_FREELISTS
- int i;
- tor_log(severity, LD_MM, "====== Buffer freelists:");
- for (i = 0; freelists[i].alloc_size; ++i) {
- uint64_t total = ((uint64_t)freelists[i].cur_length) *
- freelists[i].alloc_size;
- tor_log(severity, LD_MM,
- U64_FORMAT" bytes in %d %d-byte chunks ["U64_FORMAT
- " misses; "U64_FORMAT" frees; "U64_FORMAT" hits]",
- U64_PRINTF_ARG(total),
- freelists[i].cur_length, (int)freelists[i].alloc_size,
- U64_PRINTF_ARG(freelists[i].n_alloc),
- U64_PRINTF_ARG(freelists[i].n_free),
- U64_PRINTF_ARG(freelists[i].n_hit));
- }
- tor_log(severity, LD_MM, U64_FORMAT" allocations in non-freelist sizes",
- U64_PRINTF_ARG(n_freelist_miss));
-#else
- (void)severity;
-#endif
-}
-
/** Collapse data from the first N chunks from <b>buf</b> into buf->head,
* growing it as necessary, until buf->head has the first <b>bytes</b> bytes
* of data from the buffer, or until buf->head has all the data in <b>buf</b>.
@@ -510,15 +294,6 @@ buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz)
}
#endif
-/** Resize buf so it won't hold extra memory that we haven't been
- * using lately.
- */
-void
-buf_shrink(buf_t *buf)
-{
- (void)buf;
-}
-
/** Remove the first <b>n</b> bytes from buf. */
static INLINE void
buf_remove_from_front(buf_t *buf, size_t n)
@@ -584,8 +359,8 @@ buf_clear(buf_t *buf)
}
/** Return the number of bytes stored in <b>buf</b> */
-size_t
-buf_datalen(const buf_t *buf)
+MOCK_IMPL(size_t,
+buf_datalen, (const buf_t *buf))
{
return buf->datalen;
}
@@ -1856,6 +1631,21 @@ fetch_ext_or_command_from_evbuffer(struct evbuffer *buf, ext_or_cmd_t **out)
}
#endif
+/** Create a SOCKS5 reply message with <b>reason</b> in its REP field and
+ * have Tor send it as error response to <b>req</b>.
+ */
+static void
+socks_request_set_socks5_error(socks_request_t *req,
+ socks5_reply_status_t reason)
+{
+ req->replylen = 10;
+ memset(req->reply,0,10);
+
+ req->reply[0] = 0x05; // VER field.
+ req->reply[1] = reason; // REP field.
+ req->reply[3] = 0x01; // ATYP field.
+}
+
/** Implementation helper to implement fetch_from_*_socks. Instead of looking
* at a buffer's contents, we look at the <b>datalen</b> bytes of data in
* <b>data</b>. Instead of removing data from the buffer, we set
@@ -1919,7 +1709,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
}
*drain_out = 2u + usernamelen + 1u + passlen;
req->got_auth = 1;
- *want_length_out = 7; /* Minimal socks5 sommand. */
+ *want_length_out = 7; /* Minimal socks5 command. */
return 0;
} else if (req->auth_type == SOCKS_USER_PASS) {
/* unknown version byte */
@@ -1991,6 +1781,8 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
req->command != SOCKS_COMMAND_RESOLVE &&
req->command != SOCKS_COMMAND_RESOLVE_PTR) {
/* not a connect or resolve or a resolve_ptr? we don't support it. */
+ socks_request_set_socks5_error(req,SOCKS5_COMMAND_NOT_SUPPORTED);
+
log_warn(LD_APP,"socks5: command %d not recognized. Rejecting.",
req->command);
return -1;
@@ -2014,6 +1806,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
tor_addr_to_str(tmpbuf, &destaddr, sizeof(tmpbuf), 1);
if (strlen(tmpbuf)+1 > MAX_SOCKS_ADDR_LEN) {
+ socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
log_warn(LD_APP,
"socks5 IP takes %d bytes, which doesn't fit in %d. "
"Rejecting.",
@@ -2026,14 +1819,18 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
if (req->command != SOCKS_COMMAND_RESOLVE_PTR &&
!addressmap_have_mapping(req->address,0)) {
log_unsafe_socks_warning(5, req->address, req->port, safe_socks);
- if (safe_socks)
+ if (safe_socks) {
+ socks_request_set_socks5_error(req, SOCKS5_NOT_ALLOWED);
return -1;
+ }
}
return 1;
}
case 3: /* fqdn */
log_debug(LD_APP,"socks5: fqdn address type");
if (req->command == SOCKS_COMMAND_RESOLVE_PTR) {
+ socks_request_set_socks5_error(req,
+ SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED);
log_warn(LD_APP, "socks5 received RESOLVE_PTR command with "
"hostname type. Rejecting.");
return -1;
@@ -2044,6 +1841,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
return 0; /* not yet */
}
if (len+1 > MAX_SOCKS_ADDR_LEN) {
+ socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
log_warn(LD_APP,
"socks5 hostname is %d bytes, which doesn't fit in "
"%d. Rejecting.", len+1,MAX_SOCKS_ADDR_LEN);
@@ -2053,7 +1851,18 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
req->address[len] = 0;
req->port = ntohs(get_uint16(data+5+len));
*drain_out = 5+len+2;
- if (!tor_strisprint(req->address) || strchr(req->address,'\"')) {
+
+ if (string_is_valid_ipv4_address(req->address) ||
+ string_is_valid_ipv6_address(req->address)) {
+ log_unsafe_socks_warning(5,req->address,req->port,safe_socks);
+
+ if (safe_socks) {
+ socks_request_set_socks5_error(req, SOCKS5_NOT_ALLOWED);
+ return -1;
+ }
+ } else if (!string_is_valid_hostname(req->address)) {
+ socks_request_set_socks5_error(req, SOCKS5_GENERAL_ERROR);
+
log_warn(LD_PROTOCOL,
"Your application (using socks5 to port %d) gave Tor "
"a malformed hostname: %s. Rejecting the connection.",
@@ -2067,6 +1876,8 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
"necessary. This is good.", req->port);
return 1;
default: /* unsupported */
+ socks_request_set_socks5_error(req,
+ SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED);
log_warn(LD_APP,"socks5: unsupported address type %d. Rejecting.",
(int) *(data+3));
return -1;
@@ -2665,23 +2476,3 @@ assert_buf_ok(buf_t *buf)
}
}
-#ifdef ENABLE_BUF_FREELISTS
-/** Log an error and exit if <b>fl</b> is corrupted.
- */
-static void
-assert_freelist_ok(chunk_freelist_t *fl)
-{
- chunk_t *ch;
- int n;
- tor_assert(fl->alloc_size > 0);
- n = 0;
- for (ch = fl->head; ch; ch = ch->next) {
- tor_assert(CHUNK_ALLOC_SIZE(ch->memlen) == fl->alloc_size);
- ++n;
- }
- tor_assert(n == fl->cur_length);
- tor_assert(n >= fl->lowest_length);
- tor_assert(n <= fl->max_length);
-}
-#endif
-
diff --git a/src/or/buffers.h b/src/or/buffers.h
index c90e14750e..6d0c68500b 100644
--- a/src/or/buffers.h
+++ b/src/or/buffers.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -20,11 +20,8 @@ size_t buf_get_default_chunk_size(const buf_t *buf);
void buf_free(buf_t *buf);
void buf_clear(buf_t *buf);
buf_t *buf_copy(const buf_t *buf);
-void buf_shrink(buf_t *buf);
-size_t buf_shrink_freelists(int free_all);
-void buf_dump_freelist_sizes(int severity);
-size_t buf_datalen(const buf_t *buf);
+MOCK_DECL(size_t, buf_datalen, (const buf_t *buf));
size_t buf_allocation(const buf_t *buf);
size_t buf_slack(const buf_t *buf);
@@ -108,9 +105,9 @@ STATIC void buf_pullup(buf_t *buf, size_t bytes, int nulterminate);
void buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz);
#define DEBUG_CHUNK_ALLOC
-/** A single chunk on a buffer or in a freelist. */
+/** A single chunk on a buffer. */
typedef struct chunk_t {
- struct chunk_t *next; /**< The next chunk on the buffer or freelist. */
+ struct chunk_t *next; /**< The next chunk on the buffer. */
size_t datalen; /**< The number of bytes stored in this chunk */
size_t memlen; /**< The number of usable bytes of storage in <b>mem</b>. */
#ifdef DEBUG_CHUNK_ALLOC
diff --git a/src/or/channel.c b/src/or/channel.c
index b2b670e4fb..bf0387f10e 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,6 +13,9 @@
#define TOR_CHANNEL_INTERNAL_
+/* This one's for stuff only channel.c and the test suite should see */
+#define CHANNEL_PRIVATE_
+
#include "or.h"
#include "channel.h"
#include "channeltls.h"
@@ -29,29 +32,7 @@
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
-
-/* Cell queue structure */
-
-typedef struct cell_queue_entry_s cell_queue_entry_t;
-struct cell_queue_entry_s {
- TOR_SIMPLEQ_ENTRY(cell_queue_entry_s) next;
- enum {
- CELL_QUEUE_FIXED,
- CELL_QUEUE_VAR,
- CELL_QUEUE_PACKED
- } type;
- union {
- struct {
- cell_t *cell;
- } fixed;
- struct {
- var_cell_t *var_cell;
- } var;
- struct {
- packed_cell_t *packed_cell;
- } packed;
- } u;
-};
+#include "scheduler.h"
/* Global lists of channels */
@@ -75,6 +56,59 @@ static smartlist_t *finished_listeners = NULL;
/* Counter for ID numbers */
static uint64_t n_channels_allocated = 0;
+/*
+ * Channel global byte/cell counters, for statistics and for scheduler high
+ * /low-water marks.
+ */
+
+/*
+ * Total number of cells ever given to any channel with the
+ * channel_write_*_cell() functions.
+ */
+
+static uint64_t n_channel_cells_queued = 0;
+
+/*
+ * Total number of cells ever passed to a channel lower layer with the
+ * write_*_cell() methods.
+ */
+
+static uint64_t n_channel_cells_passed_to_lower_layer = 0;
+
+/*
+ * Current number of cells in all channel queues; should be
+ * n_channel_cells_queued - n_channel_cells_passed_to_lower_layer.
+ */
+
+static uint64_t n_channel_cells_in_queues = 0;
+
+/*
+ * Total number of bytes for all cells ever queued to a channel and
+ * counted in n_channel_cells_queued.
+ */
+
+static uint64_t n_channel_bytes_queued = 0;
+
+/*
+ * Total number of bytes for all cells ever passed to a channel lower layer
+ * and counted in n_channel_cells_passed_to_lower_layer.
+ */
+
+static uint64_t n_channel_bytes_passed_to_lower_layer = 0;
+
+/*
+ * Current number of bytes in all channel queues; should be
+ * n_channel_bytes_queued - n_channel_bytes_passed_to_lower_layer.
+ */
+
+static uint64_t n_channel_bytes_in_queues = 0;
+
+/*
+ * Current total estimated queue size *including lower layer queues and
+ * transmit overhead*
+ */
+
+STATIC uint64_t estimated_total_queue_size = 0;
/* Digest->channel map
*
@@ -108,11 +142,10 @@ channel_idmap_eq(const channel_idmap_entry_t *a,
HT_PROTOTYPE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
channel_idmap_eq);
-HT_GENERATE(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
- channel_idmap_eq, 0.5, tor_malloc, tor_realloc, tor_free_);
+HT_GENERATE2(channel_idmap, channel_idmap_entry_s, node, channel_idmap_hash,
+ channel_idmap_eq, 0.5, tor_reallocarray_, tor_free_);
static cell_queue_entry_t * cell_queue_entry_dup(cell_queue_entry_t *q);
-static void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off);
#if 0
static int cell_queue_entry_is_padding(cell_queue_entry_t *q);
#endif
@@ -123,6 +156,8 @@ cell_queue_entry_new_var(var_cell_t *var_cell);
static int is_destroy_cell(channel_t *chan,
const cell_queue_entry_t *q, circid_t *circid_out);
+static void channel_assert_counter_consistency(void);
+
/* Functions to maintain the digest map */
static void channel_add_to_digest_map(channel_t *chan);
static void channel_remove_from_digest_map(channel_t *chan);
@@ -140,6 +175,8 @@ channel_free_list(smartlist_t *channels, int mark_for_close);
static void
channel_listener_free_list(smartlist_t *channels, int mark_for_close);
static void channel_listener_force_free(channel_listener_t *chan_l);
+static size_t channel_get_cell_queue_entry_size(channel_t *chan,
+ cell_queue_entry_t *q);
static void
channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q);
@@ -378,8 +415,7 @@ channel_register(channel_t *chan)
smartlist_add(all_channels, chan);
/* Is it finished? */
- if (chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR) {
+ if (CHANNEL_FINISHED(chan)) {
/* Put it in the finished list, creating it if necessary */
if (!finished_channels) finished_channels = smartlist_new();
smartlist_add(finished_channels, chan);
@@ -388,7 +424,7 @@ channel_register(channel_t *chan)
if (!active_channels) active_channels = smartlist_new();
smartlist_add(active_channels, chan);
- if (chan->state != CHANNEL_STATE_CLOSING) {
+ if (!CHANNEL_IS_CLOSING(chan)) {
/* It should have a digest set */
if (!tor_digest_is_zero(chan->identity_digest)) {
/* Yeah, we're good, add it to the map */
@@ -423,8 +459,7 @@ channel_unregister(channel_t *chan)
if (!(chan->registered)) return;
/* Is it finished? */
- if (chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR) {
+ if (CHANNEL_FINISHED(chan)) {
/* Get it out of the finished list */
if (finished_channels) smartlist_remove(finished_channels, chan);
} else {
@@ -440,9 +475,7 @@ channel_unregister(channel_t *chan)
/* Should it be in the digest map? */
if (!tor_digest_is_zero(chan->identity_digest) &&
- !(chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR)) {
+ !(CHANNEL_CONDEMNED(chan))) {
/* Remove it */
channel_remove_from_digest_map(chan);
}
@@ -542,9 +575,7 @@ channel_add_to_digest_map(channel_t *chan)
tor_assert(chan);
/* Assert that the state makes sense */
- tor_assert(!(chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR));
+ tor_assert(!CHANNEL_CONDEMNED(chan));
/* Assert that there is a digest */
tor_assert(!tor_digest_is_zero(chan->identity_digest));
@@ -746,6 +777,9 @@ channel_init(channel_t *chan)
/* It hasn't been open yet. */
chan->has_been_open = 0;
+
+ /* Scheduler state is idle */
+ chan->scheduler_state = SCHED_CHAN_IDLE;
}
/**
@@ -779,8 +813,8 @@ channel_free(channel_t *chan)
if (!chan) return;
/* It must be closed or errored */
- tor_assert(chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR);
+ tor_assert(CHANNEL_FINISHED(chan));
+
/* It must be deregistered */
tor_assert(!(chan->registered));
@@ -788,6 +822,9 @@ channel_free(channel_t *chan)
"Freeing channel " U64_FORMAT " at %p",
U64_PRINTF_ARG(chan->global_identifier), chan);
+ /* Get this one out of the scheduler */
+ scheduler_release_channel(chan);
+
/*
* Get rid of cmux policy before we do anything, so cmux policies don't
* see channels in weird half-freed states.
@@ -863,6 +900,9 @@ channel_force_free(channel_t *chan)
"Force-freeing channel " U64_FORMAT " at %p",
U64_PRINTF_ARG(chan->global_identifier), chan);
+ /* Get this one out of the scheduler */
+ scheduler_release_channel(chan);
+
/*
* Get rid of cmux policy before we do anything, so cmux policies don't
* see channels in weird half-freed states.
@@ -988,9 +1028,7 @@ channel_get_cell_handler(channel_t *chan)
{
tor_assert(chan);
- if (chan->state == CHANNEL_STATE_OPENING ||
- chan->state == CHANNEL_STATE_OPEN ||
- chan->state == CHANNEL_STATE_MAINT)
+ if (CHANNEL_CAN_HANDLE_CELLS(chan))
return chan->cell_handler;
return NULL;
@@ -1008,9 +1046,7 @@ channel_get_var_cell_handler(channel_t *chan)
{
tor_assert(chan);
- if (chan->state == CHANNEL_STATE_OPENING ||
- chan->state == CHANNEL_STATE_OPEN ||
- chan->state == CHANNEL_STATE_MAINT)
+ if (CHANNEL_CAN_HANDLE_CELLS(chan))
return chan->var_cell_handler;
return NULL;
@@ -1033,9 +1069,7 @@ channel_set_cell_handlers(channel_t *chan,
int try_again = 0;
tor_assert(chan);
- tor_assert(chan->state == CHANNEL_STATE_OPENING ||
- chan->state == CHANNEL_STATE_OPEN ||
- chan->state == CHANNEL_STATE_MAINT);
+ tor_assert(CHANNEL_CAN_HANDLE_CELLS(chan));
log_debug(LD_CHANNEL,
"Setting cell_handler callback for channel %p to %p",
@@ -1089,9 +1123,8 @@ channel_mark_for_close(channel_t *chan)
tor_assert(chan->close != NULL);
/* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
- if (chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR) return;
+ if (CHANNEL_CONDEMNED(chan))
+ return;
log_debug(LD_CHANNEL,
"Closing channel %p (global ID " U64_FORMAT ") "
@@ -1170,9 +1203,8 @@ channel_close_from_lower_layer(channel_t *chan)
tor_assert(chan != NULL);
/* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
- if (chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR) return;
+ if (CHANNEL_CONDEMNED(chan))
+ return;
log_debug(LD_CHANNEL,
"Closing channel %p (global ID " U64_FORMAT ") "
@@ -1230,9 +1262,8 @@ channel_close_for_error(channel_t *chan)
tor_assert(chan != NULL);
/* If it's already in CLOSING, CLOSED or ERROR, this is a no-op */
- if (chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR) return;
+ if (CHANNEL_CONDEMNED(chan))
+ return;
log_debug(LD_CHANNEL,
"Closing channel %p due to lower-layer error",
@@ -1288,18 +1319,16 @@ void
channel_closed(channel_t *chan)
{
tor_assert(chan);
- tor_assert(chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR);
+ tor_assert(CHANNEL_CONDEMNED(chan));
/* No-op if already inactive */
- if (chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR) return;
+ if (CHANNEL_FINISHED(chan))
+ return;
/* Inform any pending (not attached) circs that they should
* give up. */
if (! chan->has_been_open)
- circuit_n_chan_done(chan, 0);
+ circuit_n_chan_done(chan, 0, 0);
/* Now close all the attached circuits on it. */
circuit_unlink_all_from_channel(chan, END_CIRC_REASON_CHANNEL_CLOSED);
@@ -1357,10 +1386,7 @@ channel_clear_identity_digest(channel_t *chan)
"global ID " U64_FORMAT,
chan, U64_PRINTF_ARG(chan->global_identifier));
- state_not_in_map =
- (chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR);
+ state_not_in_map = CHANNEL_CONDEMNED(chan);
if (!state_not_in_map && chan->registered &&
!tor_digest_is_zero(chan->identity_digest))
@@ -1393,10 +1419,8 @@ channel_set_identity_digest(channel_t *chan,
identity_digest ?
hex_str(identity_digest, DIGEST_LEN) : "(null)");
- state_not_in_map =
- (chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR);
+ state_not_in_map = CHANNEL_CONDEMNED(chan);
+
was_in_digest_map =
!state_not_in_map &&
chan->registered &&
@@ -1446,10 +1470,7 @@ channel_clear_remote_end(channel_t *chan)
"global ID " U64_FORMAT,
chan, U64_PRINTF_ARG(chan->global_identifier));
- state_not_in_map =
- (chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR);
+ state_not_in_map = CHANNEL_CONDEMNED(chan);
if (!state_not_in_map && chan->registered &&
!tor_digest_is_zero(chan->identity_digest))
@@ -1485,10 +1506,8 @@ channel_set_remote_end(channel_t *chan,
identity_digest ?
hex_str(identity_digest, DIGEST_LEN) : "(null)");
- state_not_in_map =
- (chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR);
+ state_not_in_map = CHANNEL_CONDEMNED(chan);
+
was_in_digest_map =
!state_not_in_map &&
chan->registered &&
@@ -1548,7 +1567,7 @@ cell_queue_entry_dup(cell_queue_entry_t *q)
* them) or not (we should free).
*/
-static void
+STATIC void
cell_queue_entry_free(cell_queue_entry_t *q, int handed_off)
{
if (!q) return;
@@ -1666,6 +1685,36 @@ cell_queue_entry_new_var(var_cell_t *var_cell)
}
/**
+ * Ask how big the cell contained in a cell_queue_entry_t is
+ */
+
+static size_t
+channel_get_cell_queue_entry_size(channel_t *chan, cell_queue_entry_t *q)
+{
+ size_t rv = 0;
+
+ tor_assert(chan);
+ tor_assert(q);
+
+ switch (q->type) {
+ case CELL_QUEUE_FIXED:
+ rv = get_cell_network_size(chan->wide_circ_ids);
+ break;
+ case CELL_QUEUE_VAR:
+ rv = get_var_cell_header_size(chan->wide_circ_ids) +
+ (q->u.var.var_cell ? q->u.var.var_cell->payload_len : 0);
+ break;
+ case CELL_QUEUE_PACKED:
+ rv = get_cell_network_size(chan->wide_circ_ids);
+ break;
+ default:
+ tor_assert(1);
+ }
+
+ return rv;
+}
+
+/**
* Write to a channel based on a cell_queue_entry_t
*
* Given a cell_queue_entry_t filled out by the caller, try to send the cell
@@ -1677,14 +1726,13 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
{
int result = 0, sent = 0;
cell_queue_entry_t *tmp = NULL;
+ size_t cell_bytes;
tor_assert(chan);
tor_assert(q);
/* Assert that the state makes sense for a cell write */
- tor_assert(chan->state == CHANNEL_STATE_OPENING ||
- chan->state == CHANNEL_STATE_OPEN ||
- chan->state == CHANNEL_STATE_MAINT);
+ tor_assert(CHANNEL_CAN_HANDLE_CELLS(chan));
{
circid_t circ_id;
@@ -1693,9 +1741,12 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
}
}
+ /* For statistical purposes, figure out how big this cell is */
+ cell_bytes = channel_get_cell_queue_entry_size(chan, q);
+
/* Can we send it right out? If so, try */
if (TOR_SIMPLEQ_EMPTY(&chan->outgoing_queue) &&
- chan->state == CHANNEL_STATE_OPEN) {
+ CHANNEL_IS_OPEN(chan)) {
/* Pick the right write function for this cell type and save the result */
switch (q->type) {
case CELL_QUEUE_FIXED:
@@ -1726,6 +1777,13 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
channel_timestamp_drained(chan);
/* Update the counter */
++(chan->n_cells_xmitted);
+ chan->n_bytes_xmitted += cell_bytes;
+ /* Update global counters */
+ ++n_channel_cells_queued;
+ ++n_channel_cells_passed_to_lower_layer;
+ n_channel_bytes_queued += cell_bytes;
+ n_channel_bytes_passed_to_lower_layer += cell_bytes;
+ channel_assert_counter_consistency();
}
}
@@ -1737,8 +1795,16 @@ channel_write_cell_queue_entry(channel_t *chan, cell_queue_entry_t *q)
*/
tmp = cell_queue_entry_dup(q);
TOR_SIMPLEQ_INSERT_TAIL(&chan->outgoing_queue, tmp, next);
+ /* Update global counters */
+ ++n_channel_cells_queued;
+ ++n_channel_cells_in_queues;
+ n_channel_bytes_queued += cell_bytes;
+ n_channel_bytes_in_queues += cell_bytes;
+ channel_assert_counter_consistency();
+ /* Update channel queue size */
+ chan->bytes_in_queue += cell_bytes;
/* Try to process the queue? */
- if (chan->state == CHANNEL_STATE_OPEN) channel_flush_cells(chan);
+ if (CHANNEL_IS_OPEN(chan)) channel_flush_cells(chan);
}
}
@@ -1759,7 +1825,7 @@ channel_write_cell(channel_t *chan, cell_t *cell)
tor_assert(chan);
tor_assert(cell);
- if (chan->state == CHANNEL_STATE_CLOSING) {
+ if (CHANNEL_IS_CLOSING(chan)) {
log_debug(LD_CHANNEL, "Discarding cell_t %p on closing channel %p with "
"global ID "U64_FORMAT, cell, chan,
U64_PRINTF_ARG(chan->global_identifier));
@@ -1775,6 +1841,9 @@ channel_write_cell(channel_t *chan, cell_t *cell)
q.type = CELL_QUEUE_FIXED;
q.u.fixed.cell = cell;
channel_write_cell_queue_entry(chan, &q);
+
+ /* Update the queue size estimate */
+ channel_update_xmit_queue_size(chan);
}
/**
@@ -1793,7 +1862,7 @@ channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell)
tor_assert(chan);
tor_assert(packed_cell);
- if (chan->state == CHANNEL_STATE_CLOSING) {
+ if (CHANNEL_IS_CLOSING(chan)) {
log_debug(LD_CHANNEL, "Discarding packed_cell_t %p on closing channel %p "
"with global ID "U64_FORMAT, packed_cell, chan,
U64_PRINTF_ARG(chan->global_identifier));
@@ -1810,6 +1879,9 @@ channel_write_packed_cell(channel_t *chan, packed_cell_t *packed_cell)
q.type = CELL_QUEUE_PACKED;
q.u.packed.packed_cell = packed_cell;
channel_write_cell_queue_entry(chan, &q);
+
+ /* Update the queue size estimate */
+ channel_update_xmit_queue_size(chan);
}
/**
@@ -1829,7 +1901,7 @@ channel_write_var_cell(channel_t *chan, var_cell_t *var_cell)
tor_assert(chan);
tor_assert(var_cell);
- if (chan->state == CHANNEL_STATE_CLOSING) {
+ if (CHANNEL_IS_CLOSING(chan)) {
log_debug(LD_CHANNEL, "Discarding var_cell_t %p on closing channel %p "
"with global ID "U64_FORMAT, var_cell, chan,
U64_PRINTF_ARG(chan->global_identifier));
@@ -1846,6 +1918,9 @@ channel_write_var_cell(channel_t *chan, var_cell_t *var_cell)
q.type = CELL_QUEUE_VAR;
q.u.var.var_cell = var_cell;
channel_write_cell_queue_entry(chan, &q);
+
+ /* Update the queue size estimate */
+ channel_update_xmit_queue_size(chan);
}
/**
@@ -1941,6 +2016,41 @@ channel_change_state(channel_t *chan, channel_state_t to_state)
}
}
+ /*
+ * If we're going to a closed/closing state, we don't need scheduling any
+ * more; in CHANNEL_STATE_MAINT we can't accept writes.
+ */
+ if (to_state == CHANNEL_STATE_CLOSING ||
+ to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR) {
+ scheduler_release_channel(chan);
+ } else if (to_state == CHANNEL_STATE_MAINT) {
+ scheduler_channel_doesnt_want_writes(chan);
+ }
+
+ /*
+ * If we're closing, this channel no longer counts toward the global
+ * estimated queue size; if we're open, it now does.
+ */
+ if ((to_state == CHANNEL_STATE_CLOSING ||
+ to_state == CHANNEL_STATE_CLOSED ||
+ to_state == CHANNEL_STATE_ERROR) &&
+ (from_state == CHANNEL_STATE_OPEN ||
+ from_state == CHANNEL_STATE_MAINT)) {
+ estimated_total_queue_size -= chan->bytes_in_queue;
+ }
+
+ /*
+ * If we're opening, this channel now does count toward the global
+ * estimated queue size.
+ */
+ if ((to_state == CHANNEL_STATE_OPEN ||
+ to_state == CHANNEL_STATE_MAINT) &&
+ !(from_state == CHANNEL_STATE_OPEN ||
+ from_state == CHANNEL_STATE_MAINT)) {
+ estimated_total_queue_size += chan->bytes_in_queue;
+ }
+
/* Tell circuits if we opened and stuff */
if (to_state == CHANNEL_STATE_OPEN) {
channel_do_open_actions(chan);
@@ -2056,12 +2166,13 @@ channel_listener_change_state(channel_listener_t *chan_l,
#define MAX_CELLS_TO_GET_FROM_CIRCUITS_FOR_UNLIMITED 256
-ssize_t
-channel_flush_some_cells(channel_t *chan, ssize_t num_cells)
+MOCK_IMPL(ssize_t,
+channel_flush_some_cells, (channel_t *chan, ssize_t num_cells))
{
unsigned int unlimited = 0;
ssize_t flushed = 0;
int num_cells_from_circs, clamped_num_cells;
+ int q_len_before, q_len_after;
tor_assert(chan);
@@ -2069,7 +2180,7 @@ channel_flush_some_cells(channel_t *chan, ssize_t num_cells)
if (!unlimited && num_cells <= flushed) goto done;
/* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */
- if (chan->state == CHANNEL_STATE_OPEN) {
+ if (CHANNEL_IS_OPEN(chan)) {
/* Try to flush as much as we can that's already queued */
flushed += channel_flush_some_cells_from_outgoing_queue(chan,
(unlimited ? -1 : num_cells - flushed));
@@ -2087,14 +2198,45 @@ channel_flush_some_cells(channel_t *chan, ssize_t num_cells)
clamped_num_cells = (int)(num_cells - flushed);
}
}
+
+ /*
+ * Keep track of the change in queue size; we have to count cells
+ * channel_flush_from_first_active_circuit() writes out directly,
+ * but not double-count ones we might get later in
+ * channel_flush_some_cells_from_outgoing_queue()
+ */
+ q_len_before = chan_cell_queue_len(&(chan->outgoing_queue));
+
/* Try to get more cells from any active circuits */
num_cells_from_circs = channel_flush_from_first_active_circuit(
chan, clamped_num_cells);
- /* If it claims we got some, process the queue again */
+ q_len_after = chan_cell_queue_len(&(chan->outgoing_queue));
+
+ /*
+ * If it claims we got some, adjust the flushed counter and consider
+ * processing the queue again
+ */
if (num_cells_from_circs > 0) {
- flushed += channel_flush_some_cells_from_outgoing_queue(chan,
- (unlimited ? -1 : num_cells - flushed));
+ /*
+ * Adjust flushed by the number of cells counted in
+ * num_cells_from_circs that didn't go to the cell queue.
+ */
+
+ if (q_len_after > q_len_before) {
+ num_cells_from_circs -= (q_len_after - q_len_before);
+ if (num_cells_from_circs < 0) num_cells_from_circs = 0;
+ }
+
+ flushed += num_cells_from_circs;
+
+ /* Now process the queue if necessary */
+
+ if ((q_len_after > q_len_before) &&
+ (unlimited || (flushed < num_cells))) {
+ flushed += channel_flush_some_cells_from_outgoing_queue(chan,
+ (unlimited ? -1 : num_cells - flushed));
+ }
}
}
}
@@ -2117,6 +2259,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
unsigned int unlimited = 0;
ssize_t flushed = 0;
cell_queue_entry_t *q = NULL;
+ size_t cell_size;
+ int free_q = 0, handed_off = 0;
tor_assert(chan);
tor_assert(chan->write_cell);
@@ -2127,11 +2271,15 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
if (!unlimited && num_cells <= flushed) return 0;
/* If we aren't in CHANNEL_STATE_OPEN, nothing goes through */
- if (chan->state == CHANNEL_STATE_OPEN) {
+ if (CHANNEL_IS_OPEN(chan)) {
while ((unlimited || num_cells > flushed) &&
NULL != (q = TOR_SIMPLEQ_FIRST(&chan->outgoing_queue))) {
+ free_q = 0;
+ handed_off = 0;
if (1) {
+ /* Figure out how big it is for statistical purposes */
+ cell_size = channel_get_cell_queue_entry_size(chan, q);
/*
* Okay, we have a good queue entry, try to give it to the lower
* layer.
@@ -2144,8 +2292,9 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
++flushed;
channel_timestamp_xmit(chan);
++(chan->n_cells_xmitted);
- cell_queue_entry_free(q, 1);
- q = NULL;
+ chan->n_bytes_xmitted += cell_size;
+ free_q = 1;
+ handed_off = 1;
}
/* Else couldn't write it; leave it on the queue */
} else {
@@ -2156,8 +2305,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
"(global ID " U64_FORMAT ").",
chan, U64_PRINTF_ARG(chan->global_identifier));
/* Throw it away */
- cell_queue_entry_free(q, 0);
- q = NULL;
+ free_q = 1;
+ handed_off = 0;
}
break;
case CELL_QUEUE_PACKED:
@@ -2167,8 +2316,9 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
++flushed;
channel_timestamp_xmit(chan);
++(chan->n_cells_xmitted);
- cell_queue_entry_free(q, 1);
- q = NULL;
+ chan->n_bytes_xmitted += cell_size;
+ free_q = 1;
+ handed_off = 1;
}
/* Else couldn't write it; leave it on the queue */
} else {
@@ -2179,8 +2329,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
"(global ID " U64_FORMAT ").",
chan, U64_PRINTF_ARG(chan->global_identifier));
/* Throw it away */
- cell_queue_entry_free(q, 0);
- q = NULL;
+ free_q = 1;
+ handed_off = 0;
}
break;
case CELL_QUEUE_VAR:
@@ -2190,8 +2340,9 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
++flushed;
channel_timestamp_xmit(chan);
++(chan->n_cells_xmitted);
- cell_queue_entry_free(q, 1);
- q = NULL;
+ chan->n_bytes_xmitted += cell_size;
+ free_q = 1;
+ handed_off = 1;
}
/* Else couldn't write it; leave it on the queue */
} else {
@@ -2202,8 +2353,8 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
"(global ID " U64_FORMAT ").",
chan, U64_PRINTF_ARG(chan->global_identifier));
/* Throw it away */
- cell_queue_entry_free(q, 0);
- q = NULL;
+ free_q = 1;
+ handed_off = 0;
}
break;
default:
@@ -2213,12 +2364,32 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
"(global ID " U64_FORMAT "; ignoring it."
" Someone should fix this.",
q->type, chan, U64_PRINTF_ARG(chan->global_identifier));
- cell_queue_entry_free(q, 0);
- q = NULL;
+ free_q = 1;
+ handed_off = 0;
}
- /* if q got NULLed out, we used it and should remove the queue entry */
- if (!q) TOR_SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next);
+ /*
+ * if free_q is set, we used it and should remove the queue entry;
+ * we have to do the free down here so TOR_SIMPLEQ_REMOVE_HEAD isn't
+ * accessing freed memory
+ */
+ if (free_q) {
+ TOR_SIMPLEQ_REMOVE_HEAD(&chan->outgoing_queue, next);
+ /*
+ * ...and we handed a cell off to the lower layer, so we should
+ * update the counters.
+ */
+ ++n_channel_cells_passed_to_lower_layer;
+ --n_channel_cells_in_queues;
+ n_channel_bytes_passed_to_lower_layer += cell_size;
+ n_channel_bytes_in_queues -= cell_size;
+ channel_assert_counter_consistency();
+ /* Update the channel's queue size too */
+ chan->bytes_in_queue -= cell_size;
+ /* Finally, free q */
+ cell_queue_entry_free(q, handed_off);
+ q = NULL;
+ }
/* No cell removed from list, so we can't go on any further */
else break;
}
@@ -2230,6 +2401,9 @@ channel_flush_some_cells_from_outgoing_queue(channel_t *chan,
channel_timestamp_drained(chan);
}
+ /* Update the estimate queue size */
+ channel_update_xmit_queue_size(chan);
+
return flushed;
}
@@ -2352,8 +2526,9 @@ void
channel_do_open_actions(channel_t *chan)
{
tor_addr_t remote_addr;
- int started_here, not_using = 0;
+ int started_here;
time_t now = time(NULL);
+ int close_origin_circuits = 0;
tor_assert(chan);
@@ -2370,8 +2545,7 @@ channel_do_open_actions(channel_t *chan)
log_debug(LD_OR,
"New entry guard was reachable, but closing this "
"connection so we can retry the earlier entry guards.");
- circuit_n_chan_done(chan, 0);
- not_using = 1;
+ close_origin_circuits = 1;
}
router_set_status(chan->identity_digest, 1);
} else {
@@ -2391,7 +2565,7 @@ channel_do_open_actions(channel_t *chan)
}
}
- if (!not_using) circuit_n_chan_done(chan, 1);
+ circuit_n_chan_done(chan, 1, close_origin_circuits);
}
/**
@@ -2462,9 +2636,8 @@ channel_process_cells(channel_t *chan)
{
cell_queue_entry_t *q;
tor_assert(chan);
- tor_assert(chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_MAINT ||
- chan->state == CHANNEL_STATE_OPEN);
+ tor_assert(CHANNEL_IS_CLOSING(chan) || CHANNEL_IS_MAINT(chan) ||
+ CHANNEL_IS_OPEN(chan));
log_debug(LD_CHANNEL,
"Processing as many incoming cells as we can for channel %p",
@@ -2531,7 +2704,7 @@ channel_queue_cell(channel_t *chan, cell_t *cell)
tor_assert(chan);
tor_assert(cell);
- tor_assert(chan->state == CHANNEL_STATE_OPEN);
+ tor_assert(CHANNEL_IS_OPEN(chan));
/* Do we need to queue it, or can we just call the handler right away? */
if (!(chan->cell_handler)) need_to_queue = 1;
@@ -2541,8 +2714,9 @@ channel_queue_cell(channel_t *chan, cell_t *cell)
/* Timestamp for receiving */
channel_timestamp_recv(chan);
- /* Update the counter */
+ /* Update the counters */
++(chan->n_cells_recved);
+ chan->n_bytes_recved += get_cell_network_size(chan->wide_circ_ids);
/* If we don't need to queue we can just call cell_handler */
if (!need_to_queue) {
@@ -2584,7 +2758,7 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
tor_assert(chan);
tor_assert(var_cell);
- tor_assert(chan->state == CHANNEL_STATE_OPEN);
+ tor_assert(CHANNEL_IS_OPEN(chan));
/* Do we need to queue it, or can we just call the handler right away? */
if (!(chan->var_cell_handler)) need_to_queue = 1;
@@ -2596,6 +2770,8 @@ channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell)
/* Update the counter */
++(chan->n_cells_recved);
+ chan->n_bytes_recved += get_var_cell_header_size(chan->wide_circ_ids) +
+ var_cell->payload_len;
/* If we don't need to queue we can just call cell_handler */
if (!need_to_queue) {
@@ -2645,6 +2821,19 @@ packed_cell_is_destroy(channel_t *chan,
return 0;
}
+/**
+ * Assert that the global channel stats counters are internally consistent
+ */
+
+static void
+channel_assert_counter_consistency(void)
+{
+ tor_assert(n_channel_cells_queued ==
+ (n_channel_cells_in_queues + n_channel_cells_passed_to_lower_layer));
+ tor_assert(n_channel_bytes_queued ==
+ (n_channel_bytes_in_queues + n_channel_bytes_passed_to_lower_layer));
+}
+
/** DOCDOC */
static int
is_destroy_cell(channel_t *chan,
@@ -2692,10 +2881,7 @@ channel_send_destroy(circid_t circ_id, channel_t *chan, int reason)
}
/* Check to make sure we can send on this channel first */
- if (!(chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR) &&
- chan->cmux) {
+ if (!CHANNEL_CONDEMNED(chan) && chan->cmux) {
channel_note_destroy_pending(chan, circ_id);
circuitmux_append_destroy_cell(chan, chan->cmux, circ_id, reason);
log_debug(LD_OR,
@@ -2727,6 +2913,19 @@ channel_dumpstats(int severity)
{
if (all_channels && smartlist_len(all_channels) > 0) {
tor_log(severity, LD_GENERAL,
+ "Channels have queued " U64_FORMAT " bytes in " U64_FORMAT " cells, "
+ "and handed " U64_FORMAT " bytes in " U64_FORMAT " cells to the lower"
+ " layer.",
+ U64_PRINTF_ARG(n_channel_bytes_queued),
+ U64_PRINTF_ARG(n_channel_cells_queued),
+ U64_PRINTF_ARG(n_channel_bytes_passed_to_lower_layer),
+ U64_PRINTF_ARG(n_channel_cells_passed_to_lower_layer));
+ tor_log(severity, LD_GENERAL,
+ "There are currently " U64_FORMAT " bytes in " U64_FORMAT " cells "
+ "in channel queues.",
+ U64_PRINTF_ARG(n_channel_bytes_in_queues),
+ U64_PRINTF_ARG(n_channel_cells_in_queues));
+ tor_log(severity, LD_GENERAL,
"Dumping statistics about %d channels:",
smartlist_len(all_channels));
tor_log(severity, LD_GENERAL,
@@ -2872,9 +3071,7 @@ channel_free_list(smartlist_t *channels, int mark_for_close)
}
channel_unregister(curr);
if (mark_for_close) {
- if (!(curr->state == CHANNEL_STATE_CLOSING ||
- curr->state == CHANNEL_STATE_CLOSED ||
- curr->state == CHANNEL_STATE_ERROR)) {
+ if (!CHANNEL_CONDEMNED(curr)) {
channel_mark_for_close(curr);
}
channel_force_free(curr);
@@ -3088,9 +3285,7 @@ channel_get_for_extend(const char *digest,
tor_assert(tor_memeq(chan->identity_digest,
digest, DIGEST_LEN));
- if (chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR)
+ if (CHANNEL_CONDEMNED(chan))
continue;
/* Never return a channel on which the other end appears to be
@@ -3100,7 +3295,7 @@ channel_get_for_extend(const char *digest,
}
/* Never return a non-open connection. */
- if (chan->state != CHANNEL_STATE_OPEN) {
+ if (!CHANNEL_IS_OPEN(chan)) {
/* If the address matches, don't launch a new connection for this
* circuit. */
if (channel_matches_target_addr_for_extend(chan, target_addr))
@@ -3200,7 +3395,7 @@ channel_listener_describe_transport(channel_listener_t *chan_l)
/**
* Return the number of entries in <b>queue</b>
*/
-static int
+STATIC int
chan_cell_queue_len(const chan_cell_queue_t *queue)
{
int r = 0;
@@ -3216,8 +3411,8 @@ chan_cell_queue_len(const chan_cell_queue_t *queue)
* Dump statistics for one channel to the log
*/
-void
-channel_dump_statistics(channel_t *chan, int severity)
+MOCK_IMPL(void,
+channel_dump_statistics, (channel_t *chan, int severity))
{
double avg, interval, age;
time_t now = time(NULL);
@@ -3369,12 +3564,22 @@ channel_dump_statistics(channel_t *chan, int severity)
/* Describe counters and rates */
tor_log(severity, LD_GENERAL,
" * Channel " U64_FORMAT " has received "
- U64_FORMAT " cells and transmitted " U64_FORMAT,
+ U64_FORMAT " bytes in " U64_FORMAT " cells and transmitted "
+ U64_FORMAT " bytes in " U64_FORMAT " cells",
U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(chan->n_bytes_recved),
U64_PRINTF_ARG(chan->n_cells_recved),
+ U64_PRINTF_ARG(chan->n_bytes_xmitted),
U64_PRINTF_ARG(chan->n_cells_xmitted));
if (now > chan->timestamp_created &&
chan->timestamp_created > 0) {
+ if (chan->n_bytes_recved > 0) {
+ avg = (double)(chan->n_bytes_recved) / age;
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "bytes received per second",
+ U64_PRINTF_ARG(chan->global_identifier), avg);
+ }
if (chan->n_cells_recved > 0) {
avg = (double)(chan->n_cells_recved) / age;
if (avg >= 1.0) {
@@ -3390,6 +3595,13 @@ channel_dump_statistics(channel_t *chan, int severity)
U64_PRINTF_ARG(chan->global_identifier), interval);
}
}
+ if (chan->n_bytes_xmitted > 0) {
+ avg = (double)(chan->n_bytes_xmitted) / age;
+ tor_log(severity, LD_GENERAL,
+ " * Channel " U64_FORMAT " has averaged %f "
+ "bytes transmitted per second",
+ U64_PRINTF_ARG(chan->global_identifier), avg);
+ }
if (chan->n_cells_xmitted > 0) {
avg = (double)(chan->n_cells_xmitted) / age;
if (avg >= 1.0) {
@@ -3807,6 +4019,50 @@ channel_mark_outgoing(channel_t *chan)
chan->is_incoming = 0;
}
+/************************
+ * Flow control queries *
+ ***********************/
+
+/*
+ * Get the latest estimate for the total queue size of all open channels
+ */
+
+uint64_t
+channel_get_global_queue_estimate(void)
+{
+ return estimated_total_queue_size;
+}
+
+/*
+ * Estimate the number of writeable cells
+ *
+ * Ask the lower layer for an estimate of how many cells it can accept, and
+ * then subtract the length of our outgoing_queue, if any, to produce an
+ * estimate of the number of cells this channel can accept for writes.
+ */
+
+int
+channel_num_cells_writeable(channel_t *chan)
+{
+ int result;
+
+ tor_assert(chan);
+ tor_assert(chan->num_cells_writeable);
+
+ if (chan->state == CHANNEL_STATE_OPEN) {
+ /* Query lower layer */
+ result = chan->num_cells_writeable(chan);
+ /* Subtract cell queue length, if any */
+ result -= chan_cell_queue_len(&chan->outgoing_queue);
+ if (result < 0) result = 0;
+ } else {
+ /* No cells are writeable in any other state */
+ result = 0;
+ }
+
+ return result;
+}
+
/*********************
* Timestamp updates *
********************/
@@ -4209,3 +4465,87 @@ channel_set_circid_type(channel_t *chan,
}
}
+/**
+ * Update the estimated number of bytes queued to transmit for this channel,
+ * and notify the scheduler. The estimate includes both the channel queue and
+ * the queue size reported by the lower layer, and an overhead estimate
+ * optionally provided by the lower layer.
+ */
+
+void
+channel_update_xmit_queue_size(channel_t *chan)
+{
+ uint64_t queued, adj;
+ double overhead;
+
+ tor_assert(chan);
+ tor_assert(chan->num_bytes_queued);
+
+ /*
+ * First, get the number of bytes we have queued without factoring in
+ * lower-layer overhead.
+ */
+ queued = chan->num_bytes_queued(chan) + chan->bytes_in_queue;
+ /* Next, adjust by the overhead factor, if any is available */
+ if (chan->get_overhead_estimate) {
+ overhead = chan->get_overhead_estimate(chan);
+ if (overhead >= 1.0f) {
+ queued *= overhead;
+ } else {
+ /* Ignore silly overhead factors */
+ log_notice(LD_CHANNEL, "Ignoring silly overhead factor %f", overhead);
+ }
+ }
+
+ /* Now, compare to the previous estimate */
+ if (queued > chan->bytes_queued_for_xmit) {
+ adj = queued - chan->bytes_queued_for_xmit;
+ log_debug(LD_CHANNEL,
+ "Increasing queue size for channel " U64_FORMAT " by " U64_FORMAT
+ " from " U64_FORMAT " to " U64_FORMAT,
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(adj),
+ U64_PRINTF_ARG(chan->bytes_queued_for_xmit),
+ U64_PRINTF_ARG(queued));
+ /* Update the channel's estimate */
+ chan->bytes_queued_for_xmit = queued;
+
+ /* Update the global queue size estimate if appropriate */
+ if (chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT) {
+ estimated_total_queue_size += adj;
+ log_debug(LD_CHANNEL,
+ "Increasing global queue size by " U64_FORMAT " for channel "
+ U64_FORMAT ", new size is " U64_FORMAT,
+ U64_PRINTF_ARG(adj), U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(estimated_total_queue_size));
+ /* Tell the scheduler we're increasing the queue size */
+ scheduler_adjust_queue_size(chan, 1, adj);
+ }
+ } else if (queued < chan->bytes_queued_for_xmit) {
+ adj = chan->bytes_queued_for_xmit - queued;
+ log_debug(LD_CHANNEL,
+ "Decreasing queue size for channel " U64_FORMAT " by " U64_FORMAT
+ " from " U64_FORMAT " to " U64_FORMAT,
+ U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(adj),
+ U64_PRINTF_ARG(chan->bytes_queued_for_xmit),
+ U64_PRINTF_ARG(queued));
+ /* Update the channel's estimate */
+ chan->bytes_queued_for_xmit = queued;
+
+ /* Update the global queue size estimate if appropriate */
+ if (chan->state == CHANNEL_STATE_OPEN ||
+ chan->state == CHANNEL_STATE_MAINT) {
+ estimated_total_queue_size -= adj;
+ log_debug(LD_CHANNEL,
+ "Decreasing global queue size by " U64_FORMAT " for channel "
+ U64_FORMAT ", new size is " U64_FORMAT,
+ U64_PRINTF_ARG(adj), U64_PRINTF_ARG(chan->global_identifier),
+ U64_PRINTF_ARG(estimated_total_queue_size));
+ /* Tell the scheduler we're decreasing the queue size */
+ scheduler_adjust_queue_size(chan, -1, adj);
+ }
+ }
+}
+
diff --git a/src/or/channel.h b/src/or/channel.h
index 148199235a..ecc2a092e4 100644
--- a/src/or/channel.h
+++ b/src/or/channel.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -57,6 +57,32 @@ struct channel_s {
CHANNEL_CLOSE_FOR_ERROR
} reason_for_closing;
+ /** State variable for use by the scheduler */
+ enum {
+ /*
+ * The channel is not open, or it has a full output buffer but no queued
+ * cells.
+ */
+ SCHED_CHAN_IDLE = 0,
+ /*
+ * The channel has space on its output buffer to write, but no queued
+ * cells.
+ */
+ SCHED_CHAN_WAITING_FOR_CELLS,
+ /*
+ * The scheduler has queued cells but no output buffer space to write.
+ */
+ SCHED_CHAN_WAITING_TO_WRITE,
+ /*
+ * The scheduler has both queued cells and output buffer space, and is
+ * eligible for the scheduler loop.
+ */
+ SCHED_CHAN_PENDING
+ } scheduler_state;
+
+ /** Heap index for use by the scheduler */
+ int sched_heap_idx;
+
/** Timestamps for both cell channels and listeners */
time_t timestamp_created; /* Channel created */
time_t timestamp_active; /* Any activity */
@@ -79,6 +105,11 @@ struct channel_s {
/* Methods implemented by the lower layer */
/**
+ * Ask the lower layer for an estimate of the average overhead for
+ * transmissions on this channel.
+ */
+ double (*get_overhead_estimate)(channel_t *);
+ /*
* Ask the underlying transport what the remote endpoint address is, in
* a tor_addr_t. This is optional and subclasses may leave this NULL.
* If they implement it, they should write the address out to the
@@ -110,7 +141,11 @@ struct channel_s {
int (*matches_extend_info)(channel_t *, extend_info_t *);
/** Check if this channel matches a target address when extending */
int (*matches_target)(channel_t *, const tor_addr_t *);
- /** Write a cell to an open channel */
+ /* Ask the lower layer how many bytes it has queued but not yet sent */
+ size_t (*num_bytes_queued)(channel_t *);
+ /* Ask the lower layer how many cells can be written */
+ int (*num_cells_writeable)(channel_t *);
+ /* Write a cell to an open channel */
int (*write_cell)(channel_t *, cell_t *);
/** Write a packed cell to an open channel */
int (*write_packed_cell)(channel_t *, packed_cell_t *);
@@ -198,8 +233,16 @@ struct channel_s {
uint64_t dirreq_id;
/** Channel counters for cell channels */
- uint64_t n_cells_recved;
- uint64_t n_cells_xmitted;
+ uint64_t n_cells_recved, n_bytes_recved;
+ uint64_t n_cells_xmitted, n_bytes_xmitted;
+
+ /** Our current contribution to the scheduler's total xmit queue */
+ uint64_t bytes_queued_for_xmit;
+
+ /** Number of bytes in this channel's cell queue; does not include
+ * lower-layer queueing.
+ */
+ uint64_t bytes_in_queue;
};
struct channel_listener_s {
@@ -311,6 +354,36 @@ void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol);
#ifdef TOR_CHANNEL_INTERNAL_
+#ifdef CHANNEL_PRIVATE_
+/* Cell queue structure (here rather than channel.c for test suite use) */
+
+typedef struct cell_queue_entry_s cell_queue_entry_t;
+struct cell_queue_entry_s {
+ TOR_SIMPLEQ_ENTRY(cell_queue_entry_s) next;
+ enum {
+ CELL_QUEUE_FIXED,
+ CELL_QUEUE_VAR,
+ CELL_QUEUE_PACKED
+ } type;
+ union {
+ struct {
+ cell_t *cell;
+ } fixed;
+ struct {
+ var_cell_t *var_cell;
+ } var;
+ struct {
+ packed_cell_t *packed_cell;
+ } packed;
+ } u;
+};
+
+/* Cell queue functions for benefit of test suite */
+STATIC int chan_cell_queue_len(const chan_cell_queue_t *queue);
+
+STATIC void cell_queue_entry_free(cell_queue_entry_t *q, int handed_off);
+#endif
+
/* Channel operations for subclasses and internal use only */
/* Initialize a newly allocated channel - do this first in subclass
@@ -384,7 +457,8 @@ void channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell);
void channel_flush_cells(channel_t *chan);
/* Request from lower layer for more cells if available */
-ssize_t channel_flush_some_cells(channel_t *chan, ssize_t num_cells);
+MOCK_DECL(ssize_t, channel_flush_some_cells,
+ (channel_t *chan, ssize_t num_cells));
/* Query if data available on this channel */
int channel_more_to_flush(channel_t *chan);
@@ -431,11 +505,44 @@ channel_t * channel_find_by_remote_digest(const char *identity_digest);
channel_t * channel_next_with_digest(channel_t *chan);
/*
+ * Helper macros to lookup state of given channel.
+ */
+
+#define CHANNEL_IS_CLOSED(chan) (channel_is_in_state((chan), \
+ CHANNEL_STATE_CLOSED))
+#define CHANNEL_IS_OPENING(chan) (channel_is_in_state((chan), \
+ CHANNEL_STATE_OPENING))
+#define CHANNEL_IS_OPEN(chan) (channel_is_in_state((chan), \
+ CHANNEL_STATE_OPEN))
+#define CHANNEL_IS_MAINT(chan) (channel_is_in_state((chan), \
+ CHANNEL_STATE_MAINT))
+#define CHANNEL_IS_CLOSING(chan) (channel_is_in_state((chan), \
+ CHANNEL_STATE_CLOSING))
+#define CHANNEL_IS_ERROR(chan) (channel_is_in_state((chan), \
+ CHANNEL_STATE_ERROR))
+
+#define CHANNEL_FINISHED(chan) (CHANNEL_IS_CLOSED(chan) || \
+ CHANNEL_IS_ERROR(chan))
+
+#define CHANNEL_CONDEMNED(chan) (CHANNEL_IS_CLOSING(chan) || \
+ CHANNEL_FINISHED(chan))
+
+#define CHANNEL_CAN_HANDLE_CELLS(chan) (CHANNEL_IS_OPENING(chan) || \
+ CHANNEL_IS_OPEN(chan) || \
+ CHANNEL_IS_MAINT(chan))
+
+static INLINE int
+channel_is_in_state(channel_t *chan, channel_state_t state)
+{
+ return chan->state == state;
+}
+
+/*
* Metadata queries/updates
*/
const char * channel_describe_transport(channel_t *chan);
-void channel_dump_statistics(channel_t *chan, int severity);
+MOCK_DECL(void, channel_dump_statistics, (channel_t *chan, int severity));
void channel_dump_transport_statistics(channel_t *chan, int severity);
const char * channel_get_actual_remote_descr(channel_t *chan);
const char * channel_get_actual_remote_address(channel_t *chan);
@@ -458,6 +565,7 @@ unsigned int channel_num_circuits(channel_t *chan);
void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd,
int consider_identity);
void channel_timestamp_client(channel_t *chan);
+void channel_update_xmit_queue_size(channel_t *chan);
const char * channel_listener_describe_transport(channel_listener_t *chan_l);
void channel_listener_dump_statistics(channel_listener_t *chan_l,
@@ -465,6 +573,10 @@ void channel_listener_dump_statistics(channel_listener_t *chan_l,
void channel_listener_dump_transport_statistics(channel_listener_t *chan_l,
int severity);
+/* Flow control queries */
+uint64_t channel_get_global_queue_estimate(void);
+int channel_num_cells_writeable(channel_t *chan);
+
/* Timestamp queries */
time_t channel_when_created(channel_t *chan);
time_t channel_when_last_active(channel_t *chan);
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index 245e33583b..1cf697ccc5 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,8 +23,10 @@
#include "connection_or.h"
#include "control.h"
#include "relay.h"
+#include "rephist.h"
#include "router.h"
#include "routerlist.h"
+#include "scheduler.h"
/** How many CELL_PADDING cells have we received, ever? */
uint64_t stats_n_padding_cells_processed = 0;
@@ -54,6 +56,7 @@ static void channel_tls_common_init(channel_tls_t *tlschan);
static void channel_tls_close_method(channel_t *chan);
static const char * channel_tls_describe_transport_method(channel_t *chan);
static void channel_tls_free_method(channel_t *chan);
+static double channel_tls_get_overhead_estimate_method(channel_t *chan);
static int
channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out);
static int
@@ -67,6 +70,8 @@ channel_tls_matches_extend_info_method(channel_t *chan,
extend_info_t *extend_info);
static int channel_tls_matches_target_method(channel_t *chan,
const tor_addr_t *target);
+static int channel_tls_num_cells_writeable_method(channel_t *chan);
+static size_t channel_tls_num_bytes_queued_method(channel_t *chan);
static int channel_tls_write_cell_method(channel_t *chan,
cell_t *cell);
static int channel_tls_write_packed_cell_method(channel_t *chan,
@@ -116,6 +121,7 @@ channel_tls_common_init(channel_tls_t *tlschan)
chan->close = channel_tls_close_method;
chan->describe_transport = channel_tls_describe_transport_method;
chan->free = channel_tls_free_method;
+ chan->get_overhead_estimate = channel_tls_get_overhead_estimate_method;
chan->get_remote_addr = channel_tls_get_remote_addr_method;
chan->get_remote_descr = channel_tls_get_remote_descr_method;
chan->get_transport_name = channel_tls_get_transport_name_method;
@@ -123,6 +129,8 @@ channel_tls_common_init(channel_tls_t *tlschan)
chan->is_canonical = channel_tls_is_canonical_method;
chan->matches_extend_info = channel_tls_matches_extend_info_method;
chan->matches_target = channel_tls_matches_target_method;
+ chan->num_bytes_queued = channel_tls_num_bytes_queued_method;
+ chan->num_cells_writeable = channel_tls_num_cells_writeable_method;
chan->write_cell = channel_tls_write_cell_method;
chan->write_packed_cell = channel_tls_write_packed_cell_method;
chan->write_var_cell = channel_tls_write_var_cell_method;
@@ -435,6 +443,40 @@ channel_tls_free_method(channel_t *chan)
}
/**
+ * Get an estimate of the average TLS overhead for the upper layer
+ */
+
+static double
+channel_tls_get_overhead_estimate_method(channel_t *chan)
+{
+ double overhead = 1.0f;
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(tlschan->conn);
+
+ /* Just return 1.0f if we don't have sensible data */
+ if (tlschan->conn->bytes_xmitted > 0 &&
+ tlschan->conn->bytes_xmitted_by_tls >=
+ tlschan->conn->bytes_xmitted) {
+ overhead = ((double)(tlschan->conn->bytes_xmitted_by_tls)) /
+ ((double)(tlschan->conn->bytes_xmitted));
+
+ /*
+ * Never estimate more than 2.0; otherwise we get silly large estimates
+ * at the very start of a new TLS connection.
+ */
+ if (overhead > 2.0f) overhead = 2.0f;
+ }
+
+ log_debug(LD_CHANNEL,
+ "Estimated overhead ratio for TLS chan " U64_FORMAT " is %f",
+ U64_PRINTF_ARG(chan->global_identifier), overhead);
+
+ return overhead;
+}
+
+/**
* Get the remote address of a channel_tls_t
*
* This implements the get_remote_addr method for channel_tls_t; copy the
@@ -673,6 +715,53 @@ channel_tls_matches_target_method(channel_t *chan,
}
/**
+ * Tell the upper layer how many bytes we have queued and not yet
+ * sent.
+ */
+
+static size_t
+channel_tls_num_bytes_queued_method(channel_t *chan)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(tlschan->conn);
+
+ return connection_get_outbuf_len(TO_CONN(tlschan->conn));
+}
+
+/**
+ * Tell the upper layer how many cells we can accept to write
+ *
+ * This implements the num_cells_writeable method for channel_tls_t; it
+ * returns an estimate of the number of cells we can accept with
+ * channel_tls_write_*_cell().
+ */
+
+static int
+channel_tls_num_cells_writeable_method(channel_t *chan)
+{
+ size_t outbuf_len;
+ ssize_t n;
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ size_t cell_network_size;
+
+ tor_assert(tlschan);
+ tor_assert(tlschan->conn);
+
+ cell_network_size = get_cell_network_size(tlschan->conn->wide_circ_ids);
+ outbuf_len = connection_get_outbuf_len(TO_CONN(tlschan->conn));
+ /* Get the number of cells */
+ n = CEIL_DIV(OR_CONN_HIGHWATER - outbuf_len, cell_network_size);
+ if (n < 0) n = 0;
+#if SIZEOF_SIZE_T > SIZEOF_INT
+ if (n > INT_MAX) n = INT_MAX;
+#endif
+
+ return (int)n;
+}
+
+/**
* Write a cell to a channel_tls_t
*
* This implements the write_cell method for channel_tls_t; given a
@@ -847,18 +936,18 @@ channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
tor_assert(conn);
tor_assert(conn->chan == chan);
tor_assert(chan->conn == conn);
- /* -Werror appeasement */
- tor_assert(old_state == old_state);
+ /* Shut the compiler up without triggering -Wtautological-compare */
+ (void)old_state;
base_chan = TLS_CHAN_TO_BASE(chan);
- /* Make sure the base connection state makes sense - shouldn't be error,
- * closed or listening. */
+ /* Make sure the base connection state makes sense - shouldn't be error
+ * or closed. */
- tor_assert(base_chan->state == CHANNEL_STATE_OPENING ||
- base_chan->state == CHANNEL_STATE_OPEN ||
- base_chan->state == CHANNEL_STATE_MAINT ||
- base_chan->state == CHANNEL_STATE_CLOSING);
+ tor_assert(CHANNEL_IS_OPENING(base_chan) ||
+ CHANNEL_IS_OPEN(base_chan) ||
+ CHANNEL_IS_MAINT(base_chan) ||
+ CHANNEL_IS_CLOSING(base_chan));
/* Did we just go to state open? */
if (state == OR_CONN_STATE_OPEN) {
@@ -867,69 +956,21 @@ channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
* CHANNEL_STATE_MAINT on this.
*/
channel_change_state(base_chan, CHANNEL_STATE_OPEN);
+ /* We might have just become writeable; check and tell the scheduler */
+ if (connection_or_num_cells_writeable(conn) > 0) {
+ scheduler_channel_wants_writes(base_chan);
+ }
} else {
/*
* Not open, so from CHANNEL_STATE_OPEN we go to CHANNEL_STATE_MAINT,
* otherwise no change.
*/
- if (base_chan->state == CHANNEL_STATE_OPEN) {
+ if (CHANNEL_IS_OPEN(base_chan)) {
channel_change_state(base_chan, CHANNEL_STATE_MAINT);
}
}
}
-/**
- * Flush cells from a channel_tls_t
- *
- * Try to flush up to about num_cells cells, and return how many we flushed.
- */
-
-ssize_t
-channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells)
-{
- ssize_t flushed = 0;
-
- tor_assert(chan);
-
- if (flushed >= num_cells) goto done;
-
- /*
- * If channel_tls_t ever buffers anything below the channel_t layer, flush
- * that first here.
- */
-
- flushed += channel_flush_some_cells(TLS_CHAN_TO_BASE(chan),
- num_cells - flushed);
-
- /*
- * If channel_tls_t ever buffers anything below the channel_t layer, check
- * how much we actually got and push it on down here.
- */
-
- done:
- return flushed;
-}
-
-/**
- * Check if a channel_tls_t has anything to flush
- *
- * Return true if there is any more to flush on this channel (cells in queue
- * or active circuits).
- */
-
-int
-channel_tls_more_to_flush(channel_tls_t *chan)
-{
- tor_assert(chan);
-
- /*
- * If channel_tls_t ever buffers anything below channel_t, the
- * check for that should go here first.
- */
-
- return channel_more_to_flush(TLS_CHAN_TO_BASE(chan));
-}
-
#ifdef KEEP_TIMING_STATS
/**
@@ -1423,6 +1464,8 @@ channel_tls_process_versions_cell(var_cell_t *cell, channel_tls_t *chan)
return;
}
+ rep_hist_note_negotiated_link_proto(highest_supported_version, started_here);
+
chan->conn->link_proto = highest_supported_version;
chan->conn->handshake_state->received_versions = 1;
diff --git a/src/or/channeltls.h b/src/or/channeltls.h
index c872a09d79..507429420b 100644
--- a/src/or/channeltls.h
+++ b/src/or/channeltls.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -40,8 +40,6 @@ channel_t * channel_tls_to_base(channel_tls_t *tlschan);
channel_tls_t * channel_tls_from_base(channel_t *chan);
/* Things for connection_or.c to call back into */
-ssize_t channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells);
-int channel_tls_more_to_flush(channel_tls_t *chan);
void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn);
void channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
or_connection_t *conn,
diff --git a/src/or/circpathbias.c b/src/or/circpathbias.c
index 51a75cf502..a0115cc6ec 100644
--- a/src/or/circpathbias.c
+++ b/src/or/circpathbias.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -768,8 +768,8 @@ pathbias_send_usable_probe(circuit_t *circ)
/* Can't probe if the channel isn't open */
if (circ->n_chan == NULL ||
- (circ->n_chan->state != CHANNEL_STATE_OPEN
- && circ->n_chan->state != CHANNEL_STATE_MAINT)) {
+ (!CHANNEL_IS_OPEN(circ->n_chan)
+ && !CHANNEL_IS_MAINT(circ->n_chan))) {
log_info(LD_CIRC,
"Skipping pathbias probe for circuit %d: Channel is not open.",
ocirc->global_identifier);
@@ -1140,11 +1140,10 @@ pathbias_count_circs_in_states(entry_guard_t *guard,
path_state_t from,
path_state_t to)
{
- circuit_t *circ;
int open_circuits = 0;
/* Count currently open circuits. Give them the benefit of the doubt. */
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
origin_circuit_t *ocirc = NULL;
if (!CIRCUIT_IS_ORIGIN(circ) || /* didn't originate here */
circ->marked_for_close) /* already counted */
@@ -1167,6 +1166,7 @@ pathbias_count_circs_in_states(entry_guard_t *guard,
open_circuits++;
}
}
+ SMARTLIST_FOREACH_END(circ);
return open_circuits;
}
diff --git a/src/or/circpathbias.h b/src/or/circpathbias.h
index c95d801a4b..9e973850d5 100644
--- a/src/or/circpathbias.h
+++ b/src/or/circpathbias.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 897f90fe4c..946c002735 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,6 +14,7 @@
#include "or.h"
#include "channel.h"
#include "circpathbias.h"
+#define CIRCUITBUILD_PRIVATE
#include "circuitbuild.h"
#include "circuitlist.h"
#include "circuitstats.h"
@@ -59,9 +60,7 @@ static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath);
static int onion_extend_cpath(origin_circuit_t *circ);
static int count_acceptable_nodes(smartlist_t *routers);
static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
-#ifdef CURVE25519_ENABLED
static int circuits_can_use_ntor(void);
-#endif
/** This function tries to get a channel to the specified endpoint,
* and then calls command_setup_channel() to give it the right
@@ -368,7 +367,6 @@ circuit_rep_hist_note_result(origin_circuit_t *circ)
} while (hop!=circ->cpath);
}
-#ifdef CURVE25519_ENABLED
/** Return 1 iff at least one node in circ's cpath supports ntor. */
static int
circuit_cpath_supports_ntor(const origin_circuit_t *circ)
@@ -388,9 +386,6 @@ circuit_cpath_supports_ntor(const origin_circuit_t *circ)
return 0;
}
-#else
-#define circuit_cpath_supports_ntor(circ) 0
-#endif
/** Pick all the entries in our cpath. Stop and return 0 when we're
* happy, or return -1 if an error occurs. */
@@ -398,11 +393,7 @@ static int
onion_populate_cpath(origin_circuit_t *circ)
{
int n_tries = 0;
-#ifdef CURVE25519_ENABLED
const int using_ntor = circuits_can_use_ntor();
-#else
- const int using_ntor = 0;
-#endif
#define MAX_POPULATE_ATTEMPTS 32
@@ -560,9 +551,13 @@ circuit_handle_first_hop(origin_circuit_t *circ)
* open and get them to send their create cells forward.
*
* Status is 1 if connect succeeded, or 0 if connect failed.
+ *
+ * Close_origin_circuits is 1 if we should close all the origin circuits
+ * through this channel, or 0 otherwise. (This happens when we want to retry
+ * an older guard.)
*/
void
-circuit_n_chan_done(channel_t *chan, int status)
+circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits)
{
smartlist_t *pending_circs;
int err_reason = 0;
@@ -600,6 +595,11 @@ circuit_n_chan_done(channel_t *chan, int status)
circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED);
continue;
}
+ if (close_origin_circuits && CIRCUIT_IS_ORIGIN(circ)) {
+ log_info(LD_CIRC,"Channel deprecated for origin circs; closing circ.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED);
+ continue;
+ }
log_debug(LD_CIRC, "Found circ, sending create cell.");
/* circuit_deliver_create_cell will set n_circ_id and add us to
* chan_circuid_circuit_map, so we don't need to call
@@ -681,7 +681,7 @@ circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell,
if (CIRCUIT_IS_ORIGIN(circ)) {
/* Update began timestamp for circuits starting their first hop */
if (TO_ORIGIN_CIRCUIT(circ)->cpath->state == CPATH_STATE_CLOSED) {
- if (circ->n_chan->state != CHANNEL_STATE_OPEN) {
+ if (!CHANNEL_IS_OPEN(circ->n_chan)) {
log_warn(LD_CIRC,
"Got first hop for a circuit without an opened channel. "
"State: %s.", channel_state_to_string(circ->n_chan->state));
@@ -772,7 +772,6 @@ circuit_timeout_want_to_count_circ(origin_circuit_t *circ)
&& circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN;
}
-#ifdef CURVE25519_ENABLED
/** Return true if the ntor handshake is enabled in the configuration, or if
* it's been set to "auto" in the configuration and it's enabled in the
* consensus. */
@@ -784,7 +783,6 @@ circuits_can_use_ntor(void)
return options->UseNTorHandshake;
return networkstatus_get_param(NULL, "UseNTorHandshake", 0, 0, 1);
}
-#endif
/** Decide whether to use a TAP or ntor handshake for connecting to <b>ei</b>
* directly, and set *<b>cell_type_out</b> and *<b>handshake_type_out</b>
@@ -794,7 +792,6 @@ circuit_pick_create_handshake(uint8_t *cell_type_out,
uint16_t *handshake_type_out,
const extend_info_t *ei)
{
-#ifdef CURVE25519_ENABLED
if (!tor_mem_is_zero((const char*)ei->curve25519_onion_key.public_key,
CURVE25519_PUBKEY_LEN) &&
circuits_can_use_ntor()) {
@@ -802,9 +799,6 @@ circuit_pick_create_handshake(uint8_t *cell_type_out,
*handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR;
return;
}
-#else
- (void) ei;
-#endif
*cell_type_out = CELL_CREATE;
*handshake_type_out = ONION_HANDSHAKE_TYPE_TAP;
@@ -959,14 +953,18 @@ circuit_send_next_onion_skin(origin_circuit_t *circ)
circuit_rep_hist_note_result(circ);
circuit_has_opened(circ); /* do other actions as necessary */
- if (!can_complete_circuit && !circ->build_state->onehop_tunnel) {
+ if (!have_completed_a_circuit() && !circ->build_state->onehop_tunnel) {
const or_options_t *options = get_options();
- can_complete_circuit=1;
+ note_that_we_completed_a_circuit();
/* FFFF Log a count of known routers here */
log_notice(LD_GENERAL,
"Tor has successfully opened a circuit. "
"Looks like client functionality is working.");
- control_event_bootstrap(BOOTSTRAP_STATUS_DONE, 0);
+ if (control_event_bootstrap(BOOTSTRAP_STATUS_DONE, 0) == 0) {
+ log_notice(LD_GENERAL,
+ "Tor has successfully opened a circuit. "
+ "Looks like client functionality is working.");
+ }
control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED");
clear_broken_connection_map(1);
if (server_mode(options) && !check_whether_orport_reachable()) {
@@ -1049,7 +1047,8 @@ circuit_note_clock_jumped(int seconds_elapsed)
seconds_elapsed >=0 ? "forward" : "backward");
control_event_general_status(LOG_WARN, "CLOCK_JUMPED TIME=%d",
seconds_elapsed);
- can_complete_circuit=0; /* so it'll log when it works again */
+ /* so we log when it works again */
+ note_that_we_maybe_cant_complete_circuits();
control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s",
"CLOCK_JUMPED");
circuit_mark_all_unused_circs();
@@ -1256,8 +1255,10 @@ circuit_finish_handshake(origin_circuit_t *circ,
crypt_path_t *hop;
int rv;
- if ((rv = pathbias_count_build_attempt(circ)) < 0)
+ if ((rv = pathbias_count_build_attempt(circ)) < 0) {
+ log_warn(LD_CIRC, "pathbias_count_build_attempt failed: %d", rv);
return rv;
+ }
if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) {
hop = circ->cpath;
@@ -1271,12 +1272,15 @@ circuit_finish_handshake(origin_circuit_t *circ,
tor_assert(hop->state == CPATH_STATE_AWAITING_KEYS);
{
+ const char *msg = NULL;
if (onion_skin_client_handshake(hop->handshake_state.tag,
&hop->handshake_state,
reply->reply, reply->handshake_len,
(uint8_t*)keys, sizeof(keys),
- (uint8_t*)hop->rend_circ_nonce) < 0) {
- log_warn(LD_CIRC,"onion_skin_client_handshake failed.");
+ (uint8_t*)hop->rend_circ_nonce,
+ &msg) < 0) {
+ if (msg)
+ log_warn(LD_CIRC,"onion_skin_client_handshake failed: %s", msg);
return -END_CIRC_REASON_TORPROTOCOL;
}
}
@@ -1392,8 +1396,10 @@ onionskin_answer(or_circuit_t *circ,
log_debug(LD_CIRC,"Finished sending '%s' cell.",
circ->is_first_hop ? "created_fast" : "created");
- if (!channel_is_local(circ->p_chan) &&
- !channel_is_outgoing(circ->p_chan)) {
+ /* Ignore the local bit when testing - many test networks run on local
+ * addresses */
+ if ((!channel_is_local(circ->p_chan) || get_options()->TestingTorNetwork)
+ && !channel_is_outgoing(circ->p_chan)) {
/* record that we could process create cells from a non-local conn
* that we didn't initiate; presumably this means that create cells
* can reach us too. */
@@ -1564,7 +1570,7 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
* -1 means "Don't use this router at all."
*/
the_nodes = nodelist_get_list();
- n_supported = tor_malloc(sizeof(int)*smartlist_len(the_nodes));
+ n_supported = tor_calloc(smartlist_len(the_nodes), sizeof(int));
SMARTLIST_FOREACH_BEGIN(the_nodes, const node_t *, node) {
const int i = node_sl_idx;
if (router_digest_is_me(node->identity)) {
@@ -1735,6 +1741,83 @@ choose_good_exit_server_general(int need_uptime, int need_capacity)
return NULL;
}
+#if defined(ENABLE_TOR2WEB_MODE) || defined(TOR_UNIT_TESTS)
+/* The config option Tor2webRendezvousPoints has been set and we need
+ * to pick an RP out of that set. Make sure that the RP we choose is
+ * alive, and return it. Return NULL if no usable RP could be found in
+ * Tor2webRendezvousPoints. */
+STATIC const node_t *
+pick_tor2web_rendezvous_node(router_crn_flags_t flags,
+ const or_options_t *options)
+{
+ const node_t *rp_node = NULL;
+ const int allow_invalid = (flags & CRN_ALLOW_INVALID) != 0;
+ const int need_desc = (flags & CRN_NEED_DESC) != 0;
+
+ smartlist_t *whitelisted_live_rps = smartlist_new();
+ smartlist_t *all_live_nodes = smartlist_new();
+
+ tor_assert(options->Tor2webRendezvousPoints);
+
+ /* Add all running nodes to all_live_nodes */
+ router_add_running_nodes_to_smartlist(all_live_nodes,
+ allow_invalid,
+ 0, 0, 0,
+ need_desc);
+
+ /* Filter all_live_nodes to only add live *and* whitelisted RPs to
+ * the list whitelisted_live_rps. */
+ SMARTLIST_FOREACH_BEGIN(all_live_nodes, node_t *, live_node) {
+ if (routerset_contains_node(options->Tor2webRendezvousPoints, live_node)) {
+ smartlist_add(whitelisted_live_rps, live_node);
+ }
+ } SMARTLIST_FOREACH_END(live_node);
+
+ /* Honor ExcludeNodes */
+ if (options->ExcludeNodes) {
+ routerset_subtract_nodes(whitelisted_live_rps, options->ExcludeNodes);
+ }
+
+ /* Now pick randomly amongst the whitelisted RPs. No need to waste time
+ doing bandwidth load balancing, for most use cases
+ 'whitelisted_live_rps' contains a single OR anyway. */
+ rp_node = smartlist_choose(whitelisted_live_rps);
+
+ if (!rp_node) {
+ log_warn(LD_REND, "Could not find a Rendezvous Point that suits "
+ "the purposes of Tor2webRendezvousPoints. Choosing random one.");
+ }
+
+ smartlist_free(whitelisted_live_rps);
+ smartlist_free(all_live_nodes);
+
+ return rp_node;
+}
+#endif
+
+/* Pick a Rendezvous Point for our HS circuits according to <b>flags</b>. */
+static const node_t *
+pick_rendezvous_node(router_crn_flags_t flags)
+{
+ const or_options_t *options = get_options();
+
+ if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS)
+ flags |= CRN_ALLOW_INVALID;
+
+#ifdef ENABLE_TOR2WEB_MODE
+ /* The user wants us to pick specific RPs. */
+ if (options->Tor2webRendezvousPoints) {
+ const node_t *tor2web_rp = pick_tor2web_rendezvous_node(flags, options);
+ if (tor2web_rp) {
+ return tor2web_rp;
+ }
+ /* Else, if no tor2web RP was found, fall back to choosing a random node */
+ }
+#endif
+
+ return router_choose_random_node(NULL, options->ExcludeNodes, flags);
+}
+
/** Return a pointer to a suitable router to be the exit node for the
* circuit of purpose <b>purpose</b> that we're about to build (or NULL
* if no router is suitable).
@@ -1765,9 +1848,13 @@ choose_good_exit_server(uint8_t purpose,
else
return choose_good_exit_server_general(need_uptime,need_capacity);
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
- if (options->AllowInvalid_ & ALLOW_INVALID_RENDEZVOUS)
- flags |= CRN_ALLOW_INVALID;
- return router_choose_random_node(NULL, options->ExcludeNodes, flags);
+ {
+ /* Pick a new RP */
+ const node_t *rendezvous_node = pick_rendezvous_node(flags);
+ log_info(LD_REND, "Picked new RP: %s",
+ safe_str_client(node_describe(rendezvous_node)));
+ return rendezvous_node;
+ }
}
log_warn(LD_BUG,"Unhandled purpose %d", purpose);
tor_fragile_assert();
@@ -1877,7 +1964,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
choose_good_exit_server(circ->base_.purpose, state->need_uptime,
state->need_capacity, state->is_internal);
if (!node) {
- log_warn(LD_CIRC,"failed to choose an exit server");
+ log_warn(LD_CIRC,"Failed to choose an exit server");
return -1;
}
exit = extend_info_from_node(node, 0);
@@ -2004,7 +2091,8 @@ choose_good_middle_server(uint8_t purpose,
tor_assert(CIRCUIT_PURPOSE_MIN_ <= purpose &&
purpose <= CIRCUIT_PURPOSE_MAX_);
- log_debug(LD_CIRC, "Contemplating intermediate hop: random choice.");
+ log_debug(LD_CIRC, "Contemplating intermediate hop %d: random choice.",
+ cur_len);
excluded = smartlist_new();
if ((r = build_state_get_exit_node(state))) {
nodelist_add_node_and_family(excluded, r);
@@ -2066,9 +2154,18 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state)
smartlist_add(excluded, (void*)node);
});
}
- /* and exclude current entry guards and their families, if applicable */
+ /* and exclude current entry guards and their families,
+ * unless we're in a test network, and excluding guards
+ * would exclude all nodes (i.e. we're in an incredibly small tor network,
+ * or we're using TestingAuthVoteGuard *).
+ * This is an incomplete fix, but is no worse than the previous behaviour,
+ * and only applies to minimal, testing tor networks
+ * (so it's no less secure) */
/*XXXX025 use the using_as_guard flag to accomplish this.*/
- if (options->UseEntryGuards) {
+ if (options->UseEntryGuards
+ && (!options->TestingTorNetwork ||
+ smartlist_len(nodelist_get_list()) > smartlist_len(get_entry_guards())
+ )) {
SMARTLIST_FOREACH(get_entry_guards(), const entry_guard_t *, entry,
{
if ((node = node_get_by_id(entry->identity))) {
@@ -2198,13 +2295,9 @@ extend_info_new(const char *nickname, const char *digest,
strlcpy(info->nickname, nickname, sizeof(info->nickname));
if (onion_key)
info->onion_key = crypto_pk_dup_key(onion_key);
-#ifdef CURVE25519_ENABLED
if (curve25519_key)
memcpy(&info->curve25519_onion_key, curve25519_key,
sizeof(curve25519_public_key_t));
-#else
- (void)curve25519_key;
-#endif
tor_addr_copy(&info->addr, addr);
info->port = port;
return info;
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index 71caea94ed..01563791b7 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -22,7 +22,8 @@ origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
extend_info_t *exit,
int flags);
int circuit_handle_first_hop(origin_circuit_t *circ);
-void circuit_n_chan_done(channel_t *chan, int status);
+void circuit_n_chan_done(channel_t *chan, int status,
+ int close_origin_circuits);
int inform_testing_reachability(void);
int circuit_timeout_want_to_count_circ(origin_circuit_t *circ);
int circuit_send_next_onion_skin(origin_circuit_t *circ);
@@ -60,6 +61,11 @@ const node_t *choose_good_entry_server(uint8_t purpose,
#ifdef CIRCUITBUILD_PRIVATE
STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan);
+#if defined(ENABLE_TOR2WEB_MODE) || defined(TOR_UNIT_TESTS)
+STATIC const node_t *pick_tor2web_rendezvous_node(router_crn_flags_t flags,
+ const or_options_t *options);
+#endif
+
#endif
#endif
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index f3a83503ef..bf7f8daca7 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -1,7 +1,7 @@
/* Copyright 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,6 +21,7 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
+#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "onion.h"
@@ -38,8 +39,7 @@
/********* START VARIABLES **********/
/** A global list of all circuits at this hop. */
-struct global_circuitlist_s global_circuitlist =
- TOR_LIST_HEAD_INITIALIZER(global_circuitlist);
+static smartlist_t *global_circuitlist = NULL;
/** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */
static smartlist_t *circuits_pending_chans = NULL;
@@ -94,9 +94,9 @@ static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t)
chan_circid_map = HT_INITIALIZER();
HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node,
chan_circid_entry_hash_, chan_circid_entries_eq_)
-HT_GENERATE(chan_circid_map, chan_circid_circuit_map_t, node,
- chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6,
- malloc, realloc, free)
+HT_GENERATE2(chan_circid_map, chan_circid_circuit_map_t, node,
+ chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6,
+ tor_reallocarray_, tor_free_)
/** The most recently returned entry from circuit_get_by_circid_chan;
* used to improve performance when many cells arrive in a row from the
@@ -302,8 +302,8 @@ channel_note_destroy_pending(channel_t *chan, circid_t id)
/** Called to indicate that a DESTROY is no longer pending on <b>chan</b> with
* circuit ID <b>id</b> -- typically, because it has been sent. */
-void
-channel_note_destroy_not_pending(channel_t *chan, circid_t id)
+MOCK_IMPL(void, channel_note_destroy_not_pending,
+ (channel_t *chan, circid_t id))
{
circuit_t *circ = circuit_get_by_circid_channel_even_if_marked(id,chan);
if (circ) {
@@ -451,17 +451,25 @@ circuit_count_pending_on_channel(channel_t *chan)
void
circuit_close_all_marked(void)
{
- circuit_t *circ, *tmp;
- TOR_LIST_FOREACH_SAFE(circ, &global_circuitlist, head, tmp)
- if (circ->marked_for_close)
+ smartlist_t *lst = circuit_get_global_list();
+ SMARTLIST_FOREACH_BEGIN(lst, circuit_t *, circ) {
+ /* Fix up index if SMARTLIST_DEL_CURRENT just moved this one. */
+ circ->global_circuitlist_idx = circ_sl_idx;
+ if (circ->marked_for_close) {
+ circ->global_circuitlist_idx = -1;
circuit_free(circ);
+ SMARTLIST_DEL_CURRENT(lst, circ);
+ }
+ } SMARTLIST_FOREACH_END(circ);
}
/** Return the head of the global linked list of circuits. */
-MOCK_IMPL(struct global_circuitlist_s *,
+MOCK_IMPL(smartlist_t *,
circuit_get_global_list,(void))
{
- return &global_circuitlist;
+ if (NULL == global_circuitlist)
+ global_circuitlist = smartlist_new();
+ return global_circuitlist;
}
/** Function to make circ-\>state human-readable */
@@ -678,7 +686,8 @@ init_circuit_base(circuit_t *circ)
circ->deliver_window = CIRCWINDOW_START;
cell_queue_init(&circ->n_chan_cells);
- TOR_LIST_INSERT_HEAD(&global_circuitlist, circ, head);
+ smartlist_add(circuit_get_global_list(), circ);
+ circ->global_circuitlist_idx = smartlist_len(circuit_get_global_list()) - 1;
}
/** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
@@ -736,6 +745,7 @@ circuit_free(circuit_t *circ)
{
void *mem;
size_t memlen;
+ int should_free = 1;
if (!circ)
return;
@@ -775,6 +785,8 @@ circuit_free(circuit_t *circ)
memlen = sizeof(or_circuit_t);
tor_assert(circ->magic == OR_CIRCUIT_MAGIC);
+ should_free = (ocirc->workqueue_entry == NULL);
+
crypto_cipher_free(ocirc->p_crypto);
crypto_digest_free(ocirc->p_digest);
crypto_cipher_free(ocirc->n_crypto);
@@ -799,7 +811,16 @@ circuit_free(circuit_t *circ)
extend_info_free(circ->n_hop);
tor_free(circ->n_chan_create_cell);
- TOR_LIST_REMOVE(circ, head);
+ if (circ->global_circuitlist_idx != -1) {
+ int idx = circ->global_circuitlist_idx;
+ circuit_t *c2 = smartlist_get(global_circuitlist, idx);
+ tor_assert(c2 == circ);
+ smartlist_del(global_circuitlist, idx);
+ if (idx < smartlist_len(global_circuitlist)) {
+ c2 = smartlist_get(global_circuitlist, idx);
+ c2->global_circuitlist_idx = idx;
+ }
+ }
/* Remove from map. */
circuit_set_n_circid_chan(circ, 0, NULL);
@@ -808,8 +829,18 @@ circuit_free(circuit_t *circ)
* "active" checks will be violated. */
cell_queue_clear(&circ->n_chan_cells);
- memwipe(mem, 0xAA, memlen); /* poison memory */
- tor_free(mem);
+ if (should_free) {
+ memwipe(mem, 0xAA, memlen); /* poison memory */
+ tor_free(mem);
+ } else {
+ /* If we made it here, this is an or_circuit_t that still has a pending
+ * cpuworker request which we weren't able to cancel. Instead, set up
+ * the magic value so that when the reply comes back, we'll know to discard
+ * the reply and free this structure.
+ */
+ memwipe(mem, 0xAA, memlen);
+ circ->magic = DEAD_CIRCUIT_MAGIC;
+ }
}
/** Deallocate the linked list circ-><b>cpath</b>, and remove the cpath from
@@ -841,9 +872,9 @@ circuit_clear_cpath(origin_circuit_t *circ)
void
circuit_free_all(void)
{
- circuit_t *tmp, *tmp2;
+ smartlist_t *lst = circuit_get_global_list();
- TOR_LIST_FOREACH_SAFE(tmp, &global_circuitlist, head, tmp2) {
+ SMARTLIST_FOREACH_BEGIN(lst, circuit_t *, tmp) {
if (! CIRCUIT_IS_ORIGIN(tmp)) {
or_circuit_t *or_circ = TO_OR_CIRCUIT(tmp);
while (or_circ->resolving_streams) {
@@ -853,8 +884,13 @@ circuit_free_all(void)
or_circ->resolving_streams = next_conn;
}
}
+ tmp->global_circuitlist_idx = -1;
circuit_free(tmp);
- }
+ SMARTLIST_DEL_CURRENT(lst, tmp);
+ } SMARTLIST_FOREACH_END(tmp);
+
+ smartlist_free(lst);
+ global_circuitlist = NULL;
smartlist_free(circuits_pending_chans);
circuits_pending_chans = NULL;
@@ -932,10 +968,9 @@ circuit_dump_conn_details(int severity,
void
circuit_dump_by_conn(connection_t *conn, int severity)
{
- circuit_t *circ;
edge_connection_t *tmpconn;
- TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
if (circ->marked_for_close) {
@@ -966,6 +1001,7 @@ circuit_dump_by_conn(connection_t *conn, int severity)
}
}
}
+ SMARTLIST_FOREACH_END(circ);
}
/** Return the circuit whose global ID is <b>id</b>, or NULL if no
@@ -973,8 +1009,7 @@ circuit_dump_by_conn(connection_t *conn, int severity)
origin_circuit_t *
circuit_get_by_global_id(uint32_t id)
{
- circuit_t *circ;
- TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (CIRCUIT_IS_ORIGIN(circ) &&
TO_ORIGIN_CIRCUIT(circ)->global_identifier == id) {
if (circ->marked_for_close)
@@ -983,6 +1018,7 @@ circuit_get_by_global_id(uint32_t id)
return TO_ORIGIN_CIRCUIT(circ);
}
}
+ SMARTLIST_FOREACH_END(circ);
return NULL;
}
@@ -1151,17 +1187,17 @@ circuit_unlink_all_from_channel(channel_t *chan, int reason)
#ifdef DEBUG_CIRCUIT_UNLINK_ALL
{
- circuit_t *circ;
smartlist_t *detached_2 = smartlist_new();
int mismatch = 0, badlen = 0;
- TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (circ->n_chan == chan ||
(!CIRCUIT_IS_ORIGIN(circ) &&
TO_OR_CIRCUIT(circ)->p_chan == chan)) {
smartlist_add(detached_2, circ);
}
}
+ SMARTLIST_FOREACH_END(circ);
if (smartlist_len(detached) != smartlist_len(detached_2)) {
log_warn(LD_BUG, "List of detached circuits had the wrong length! "
@@ -1235,8 +1271,7 @@ circuit_unlink_all_from_channel(channel_t *chan, int reason)
origin_circuit_t *
circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data)
{
- circuit_t *circ;
- TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (!circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
@@ -1249,6 +1284,7 @@ circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data)
return ocirc;
}
}
+ SMARTLIST_FOREACH_END(circ);
return NULL;
}
@@ -1261,14 +1297,17 @@ origin_circuit_t *
circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
const char *digest, uint8_t purpose)
{
- circuit_t *circ;
+ int idx;
+ smartlist_t *lst = circuit_get_global_list();
tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(purpose));
if (start == NULL)
- circ = TOR_LIST_FIRST(&global_circuitlist);
+ idx = 0;
else
- circ = TOR_LIST_NEXT(TO_CIRCUIT(start), head);
+ idx = TO_CIRCUIT(start)->global_circuitlist_idx + 1;
+
+ for ( ; idx < smartlist_len(lst); ++idx) {
+ circuit_t *circ = smartlist_get(lst, idx);
- for ( ; circ; circ = TOR_LIST_NEXT(circ, head)) {
if (circ->marked_for_close)
continue;
if (circ->purpose != purpose)
@@ -1469,7 +1508,6 @@ origin_circuit_t *
circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
int flags)
{
- circuit_t *circ_;
origin_circuit_t *best=NULL;
int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0;
int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0;
@@ -1485,7 +1523,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
"capacity %d, internal %d",
purpose, need_uptime, need_capacity, internal);
- TOR_LIST_FOREACH(circ_, &global_circuitlist, head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ_) {
if (CIRCUIT_IS_ORIGIN(circ_) &&
circ_->state == CIRCUIT_STATE_OPEN &&
!circ_->marked_for_close &&
@@ -1507,7 +1545,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
do {
const node_t *ri2;
if (tor_memeq(hop->extend_info->identity_digest,
- info->identity_digest, DIGEST_LEN))
+ info->identity_digest, DIGEST_LEN))
goto next;
if (ri1 &&
(ri2 = node_get_by_id(hop->extend_info->identity_digest))
@@ -1535,6 +1573,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
}
}
}
+ SMARTLIST_FOREACH_END(circ_);
return best;
}
@@ -1574,13 +1613,13 @@ circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum)
void
circuit_mark_all_unused_circs(void)
{
- circuit_t *circ;
- TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (CIRCUIT_IS_ORIGIN(circ) &&
!circ->marked_for_close &&
!circ->timestamp_dirty)
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
}
+ SMARTLIST_FOREACH_END(circ);
}
/** Go through the circuitlist; for each circuit that starts at us
@@ -1593,14 +1632,14 @@ circuit_mark_all_unused_circs(void)
void
circuit_mark_all_dirty_circs_as_unusable(void)
{
- circuit_t *circ;
- TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (CIRCUIT_IS_ORIGIN(circ) &&
!circ->marked_for_close &&
circ->timestamp_dirty) {
mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
}
}
+ SMARTLIST_FOREACH_END(circ);
}
/** Mark <b>circ</b> to be closed next time we call
@@ -1693,36 +1732,40 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
tor_assert(circ->state == CIRCUIT_STATE_OPEN);
tor_assert(ocirc->build_state->chosen_exit);
tor_assert(ocirc->rend_data);
- /* treat this like getting a nack from it */
- log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s",
- safe_str_client(ocirc->rend_data->onion_address),
- safe_str_client(build_state_get_exit_nickname(ocirc->build_state)),
- timed_out ? "Recording timeout." : "Removing from descriptor.");
- rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
- ocirc->rend_data,
- timed_out ?
- INTRO_POINT_FAILURE_TIMEOUT :
- INTRO_POINT_FAILURE_GENERIC);
+ if (orig_reason != END_CIRC_REASON_IP_NOW_REDUNDANT) {
+ /* treat this like getting a nack from it */
+ log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s",
+ safe_str_client(ocirc->rend_data->onion_address),
+ safe_str_client(build_state_get_exit_nickname(ocirc->build_state)),
+ timed_out ? "Recording timeout." : "Removing from descriptor.");
+ rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
+ ocirc->rend_data,
+ timed_out ?
+ INTRO_POINT_FAILURE_TIMEOUT :
+ INTRO_POINT_FAILURE_GENERIC);
+ }
} else if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING &&
reason != END_CIRC_REASON_TIMEOUT) {
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
if (ocirc->build_state->chosen_exit && ocirc->rend_data) {
- log_info(LD_REND, "Failed intro circ %s to %s "
- "(building circuit to intro point). "
- "Marking intro point as possibly unreachable.",
- safe_str_client(ocirc->rend_data->onion_address),
- safe_str_client(build_state_get_exit_nickname(ocirc->build_state)));
- rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
- ocirc->rend_data,
- INTRO_POINT_FAILURE_UNREACHABLE);
+ if (orig_reason != END_CIRC_REASON_IP_NOW_REDUNDANT) {
+ log_info(LD_REND, "Failed intro circ %s to %s "
+ "(building circuit to intro point). "
+ "Marking intro point as possibly unreachable.",
+ safe_str_client(ocirc->rend_data->onion_address),
+ safe_str_client(build_state_get_exit_nickname(
+ ocirc->build_state)));
+ rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit,
+ ocirc->rend_data,
+ INTRO_POINT_FAILURE_UNREACHABLE);
+ }
}
}
+
if (circ->n_chan) {
circuit_clear_cell_queue(circ, circ->n_chan);
/* Only send destroy if the channel isn't closing anyway */
- if (!(circ->n_chan->state == CHANNEL_STATE_CLOSING ||
- circ->n_chan->state == CHANNEL_STATE_CLOSED ||
- circ->n_chan->state == CHANNEL_STATE_ERROR)) {
+ if (!CHANNEL_CONDEMNED(circ->n_chan)) {
channel_send_destroy(circ->n_circ_id, circ->n_chan, reason);
}
circuitmux_detach_circuit(circ->n_chan->cmux, circ);
@@ -1754,9 +1797,7 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
if (or_circ->p_chan) {
circuit_clear_cell_queue(circ, or_circ->p_chan);
/* Only send destroy if the channel isn't closing anyway */
- if (!(or_circ->p_chan->state == CHANNEL_STATE_CLOSING ||
- or_circ->p_chan->state == CHANNEL_STATE_CLOSED ||
- or_circ->p_chan->state == CHANNEL_STATE_ERROR)) {
+ if (!CHANNEL_CONDEMNED(or_circ->p_chan)) {
channel_send_destroy(or_circ->p_circ_id, or_circ->p_chan, reason);
}
circuitmux_detach_circuit(or_circ->p_chan->cmux, circ);
@@ -1799,6 +1840,29 @@ marked_circuit_free_cells(circuit_t *circ)
cell_queue_clear(& TO_OR_CIRCUIT(circ)->p_chan_cells);
}
+static size_t
+single_conn_free_bytes(connection_t *conn)
+{
+ size_t result = 0;
+ if (conn->inbuf) {
+ result += buf_allocation(conn->inbuf);
+ buf_clear(conn->inbuf);
+ }
+ if (conn->outbuf) {
+ result += buf_allocation(conn->outbuf);
+ buf_clear(conn->outbuf);
+ }
+ if (conn->type == CONN_TYPE_DIR) {
+ dir_connection_t *dir_conn = TO_DIR_CONN(conn);
+ if (dir_conn->zlib_state) {
+ result += tor_zlib_state_size(dir_conn->zlib_state);
+ tor_zlib_free(dir_conn->zlib_state);
+ dir_conn->zlib_state = NULL;
+ }
+ }
+ return result;
+}
+
/** Aggressively free buffer contents on all the buffers of all streams in the
* list starting at <b>stream</b>. Return the number of bytes recovered. */
static size_t
@@ -1807,13 +1871,9 @@ marked_circuit_streams_free_bytes(edge_connection_t *stream)
size_t result = 0;
for ( ; stream; stream = stream->next_stream) {
connection_t *conn = TO_CONN(stream);
- if (conn->inbuf) {
- result += buf_allocation(conn->inbuf);
- buf_clear(conn->inbuf);
- }
- if (conn->outbuf) {
- result += buf_allocation(conn->outbuf);
- buf_clear(conn->outbuf);
+ result += single_conn_free_bytes(conn);
+ if (conn->linked_conn) {
+ result += single_conn_free_bytes(conn->linked_conn);
}
}
return result;
@@ -1871,6 +1931,28 @@ circuit_max_queued_cell_age(const circuit_t *c, uint32_t now)
return age;
}
+/** Return the age in milliseconds of the oldest buffer chunk on <b>conn</b>,
+ * where age is taken in milliseconds before the time <b>now</b> (in truncated
+ * milliseconds since the epoch). If the connection has no data, treat
+ * it as having age zero.
+ **/
+static uint32_t
+conn_get_buffer_age(const connection_t *conn, uint32_t now)
+{
+ uint32_t age = 0, age2;
+ if (conn->outbuf) {
+ age2 = buf_get_oldest_chunk_timestamp(conn->outbuf, now);
+ if (age2 > age)
+ age = age2;
+ }
+ if (conn->inbuf) {
+ age2 = buf_get_oldest_chunk_timestamp(conn->inbuf, now);
+ if (age2 > age)
+ age = age2;
+ }
+ return age;
+}
+
/** Return the age in milliseconds of the oldest buffer chunk on any stream in
* the linked list <b>stream</b>, where age is taken in milliseconds before
* the time <b>now</b> (in truncated milliseconds since the epoch). */
@@ -1880,18 +1962,15 @@ circuit_get_streams_max_data_age(const edge_connection_t *stream, uint32_t now)
uint32_t age = 0, age2;
for (; stream; stream = stream->next_stream) {
const connection_t *conn = TO_CONN(stream);
- if (conn->outbuf) {
- age2 = buf_get_oldest_chunk_timestamp(conn->outbuf, now);
- if (age2 > age)
- age = age2;
- }
- if (conn->inbuf) {
- age2 = buf_get_oldest_chunk_timestamp(conn->inbuf, now);
+ age2 = conn_get_buffer_age(conn, now);
+ if (age2 > age)
+ age = age2;
+ if (conn->linked_conn) {
+ age2 = conn_get_buffer_age(conn->linked_conn, now);
if (age2 > age)
age = age2;
}
}
-
return age;
}
@@ -1942,6 +2021,26 @@ circuits_compare_by_oldest_queued_item_(const void **a_, const void **b_)
return -1;
}
+static uint32_t now_ms_for_buf_cmp;
+
+/** Helper to sort a list of circuit_t by age of oldest item, in descending
+ * order. */
+static int
+conns_compare_by_buffer_age_(const void **a_, const void **b_)
+{
+ const connection_t *a = *a_;
+ const connection_t *b = *b_;
+ time_t age_a = conn_get_buffer_age(a, now_ms_for_buf_cmp);
+ time_t age_b = conn_get_buffer_age(b, now_ms_for_buf_cmp);
+
+ if (age_a < age_b)
+ return 1;
+ else if (age_a == age_b)
+ return 0;
+ else
+ return -1;
+}
+
#define FRACTION_OF_DATA_TO_RETAIN_ON_OOM 0.90
/** We're out of memory for cells, having allocated <b>current_allocation</b>
@@ -1950,12 +2049,13 @@ circuits_compare_by_oldest_queued_item_(const void **a_, const void **b_)
void
circuits_handle_oom(size_t current_allocation)
{
- /* Let's hope there's enough slack space for this allocation here... */
- smartlist_t *circlist = smartlist_new();
- circuit_t *circ;
+ smartlist_t *circlist;
+ smartlist_t *connection_array = get_connection_array();
+ int conn_idx;
size_t mem_to_recover;
size_t mem_recovered=0;
int n_circuits_killed=0;
+ int n_dirconns_killed=0;
struct timeval now;
uint32_t now_ms;
log_notice(LD_GENERAL, "We're low on memory. Killing circuits with "
@@ -1963,17 +2063,6 @@ circuits_handle_oom(size_t current_allocation)
"MaxMemInQueues.)");
{
- const size_t recovered = buf_shrink_freelists(1);
- if (recovered >= current_allocation) {
- log_warn(LD_BUG, "We somehow recovered more memory from freelists "
- "than we thought we had allocated");
- current_allocation = 0;
- } else {
- current_allocation -= recovered;
- }
- }
-
- {
size_t mem_target = (size_t)(get_options()->MaxMemInQueues *
FRACTION_OF_DATA_TO_RETAIN_ON_OOM);
if (current_allocation <= mem_target)
@@ -1984,22 +2073,61 @@ circuits_handle_oom(size_t current_allocation)
tor_gettimeofday_cached_monotonic(&now);
now_ms = (uint32_t)tv_to_msec(&now);
- /* This algorithm itself assumes that you've got enough memory slack
- * to actually run it. */
- TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+ circlist = circuit_get_global_list();
+ SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
circ->age_tmp = circuit_max_queued_item_age(circ, now_ms);
- smartlist_add(circlist, circ);
- }
+ } SMARTLIST_FOREACH_END(circ);
/* This is O(n log n); there are faster algorithms we could use instead.
* Let's hope this doesn't happen enough to be in the critical path. */
smartlist_sort(circlist, circuits_compare_by_oldest_queued_item_);
- /* Okay, now the worst circuits are at the front of the list. Let's mark
- * them, and reclaim their storage aggressively. */
+ /* Fix up the indices before we run into trouble */
+ SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
+ circ->global_circuitlist_idx = circ_sl_idx;
+ } SMARTLIST_FOREACH_END(circ);
+
+ /* Now sort the connection array ... */
+ now_ms_for_buf_cmp = now_ms;
+ smartlist_sort(connection_array, conns_compare_by_buffer_age_);
+ now_ms_for_buf_cmp = 0;
+
+ /* Fix up the connection array to its new order. */
+ SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
+ conn->conn_array_index = conn_sl_idx;
+ } SMARTLIST_FOREACH_END(conn);
+
+ /* Okay, now the worst circuits and connections are at the front of their
+ * respective lists. Let's mark them, and reclaim their storage
+ * aggressively. */
+ conn_idx = 0;
SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
- size_t n = n_cells_in_circ_queues(circ);
+ size_t n;
size_t freed;
+
+ /* Free storage in any non-linked directory connections that have buffered
+ * data older than this circuit. */
+ while (conn_idx < smartlist_len(connection_array)) {
+ connection_t *conn = smartlist_get(connection_array, conn_idx);
+ uint32_t conn_age = conn_get_buffer_age(conn, now_ms);
+ if (conn_age < circ->age_tmp) {
+ break;
+ }
+ if (conn->type == CONN_TYPE_DIR && conn->linked_conn == NULL) {
+ if (!conn->marked_for_close)
+ connection_mark_for_close(conn);
+ mem_recovered += single_conn_free_bytes(conn);
+
+ ++n_dirconns_killed;
+
+ if (mem_recovered >= mem_to_recover)
+ goto done_recovering_mem;
+ }
+ ++conn_idx;
+ }
+
+ /* Now, kill the circuit. */
+ n = n_cells_in_circ_queues(circ);
if (! circ->marked_for_close) {
circuit_mark_for_close(circ, END_CIRC_REASON_RESOURCELIMIT);
}
@@ -2012,22 +2140,18 @@ circuits_handle_oom(size_t current_allocation)
mem_recovered += freed;
if (mem_recovered >= mem_to_recover)
- break;
+ goto done_recovering_mem;
} SMARTLIST_FOREACH_END(circ);
-#ifdef ENABLE_MEMPOOLS
- clean_cell_pool(); /* In case this helps. */
-#endif /* ENABLE_MEMPOOLS */
- buf_shrink_freelists(1); /* This is necessary to actually release buffer
- chunks. */
+ done_recovering_mem:
log_notice(LD_GENERAL, "Removed "U64_FORMAT" bytes by killing %d circuits; "
- "%d circuits remain alive.",
+ "%d circuits remain alive. Also killed %d non-linked directory "
+ "connections.",
U64_PRINTF_ARG(mem_recovered),
n_circuits_killed,
- smartlist_len(circlist) - n_circuits_killed);
-
- smartlist_free(circlist);
+ smartlist_len(circlist) - n_circuits_killed,
+ n_dirconns_killed);
}
/** Verify that cpath layer <b>cp</b> has all of its invariants
diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h
index d48d7c3963..4e600da57d 100644
--- a/src/or/circuitlist.h
+++ b/src/or/circuitlist.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,9 +14,7 @@
#include "testsupport.h"
-TOR_LIST_HEAD(global_circuitlist_s, circuit_t);
-
-MOCK_DECL(struct global_circuitlist_s*, circuit_get_global_list, (void));
+MOCK_DECL(smartlist_t *, circuit_get_global_list, (void));
const char *circuit_state_to_string(int state);
const char *circuit_purpose_to_controller_string(uint8_t purpose);
const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose);
@@ -74,7 +72,8 @@ void circuit_free_all(void);
void circuits_handle_oom(size_t current_allocation);
void channel_note_destroy_pending(channel_t *chan, circid_t id);
-void channel_note_destroy_not_pending(channel_t *chan, circid_t id);
+MOCK_DECL(void, channel_note_destroy_not_pending,
+ (channel_t *chan, circid_t id));
#ifdef CIRCUITLIST_PRIVATE
STATIC void circuit_free(circuit_t *circ);
diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c
index e4571ff944..a77bffac90 100644
--- a/src/or/circuitmux.c
+++ b/src/or/circuitmux.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -363,9 +363,9 @@ HT_HEAD(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t);
/* Emit a bunch of hash table stuff */
HT_PROTOTYPE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
chanid_circid_entry_hash, chanid_circid_entries_eq);
-HT_GENERATE(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
- chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6,
- malloc, realloc, free);
+HT_GENERATE2(chanid_circid_muxinfo_map, chanid_circid_muxinfo_t, node,
+ chanid_circid_entry_hash, chanid_circid_entries_eq, 0.6,
+ tor_reallocarray_, tor_free_)
/*
* Circuitmux alloc/free functions
@@ -621,8 +621,8 @@ circuitmux_clear_policy(circuitmux_t *cmux)
* Return the policy currently installed on a circuitmux_t
*/
-const circuitmux_policy_t *
-circuitmux_get_policy(circuitmux_t *cmux)
+MOCK_IMPL(const circuitmux_policy_t *,
+circuitmux_get_policy, (circuitmux_t *cmux))
{
tor_assert(cmux);
@@ -896,8 +896,8 @@ circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
* Query total number of available cells on a circuitmux
*/
-unsigned int
-circuitmux_num_cells(circuitmux_t *cmux)
+MOCK_IMPL(unsigned int,
+circuitmux_num_cells, (circuitmux_t *cmux))
{
tor_assert(cmux);
@@ -1951,3 +1951,51 @@ circuitmux_count_queued_destroy_cells(const channel_t *chan,
return n_destroy_cells;
}
+/**
+ * Compare cmuxes to see which is more preferred; return < 0 if
+ * cmux_1 has higher priority (i.e., cmux_1 < cmux_2 in the scheduler's
+ * sort order), > 0 if cmux_2 has higher priority, or 0 if they are
+ * equally preferred.
+ *
+ * If the cmuxes have different cmux policies or the policy does not
+ * support the cmp_cmux method, return 0.
+ */
+
+MOCK_IMPL(int,
+circuitmux_compare_muxes, (circuitmux_t *cmux_1, circuitmux_t *cmux_2))
+{
+ const circuitmux_policy_t *policy;
+
+ tor_assert(cmux_1);
+ tor_assert(cmux_2);
+
+ if (cmux_1 == cmux_2) {
+ /* Equivalent because they're the same cmux */
+ return 0;
+ }
+
+ if (cmux_1->policy && cmux_2->policy) {
+ if (cmux_1->policy == cmux_2->policy) {
+ policy = cmux_1->policy;
+
+ if (policy->cmp_cmux) {
+ /* Okay, we can compare! */
+ return policy->cmp_cmux(cmux_1, cmux_1->policy_data,
+ cmux_2, cmux_2->policy_data);
+ } else {
+ /*
+ * Equivalent because the policy doesn't know how to compare between
+ * muxes.
+ */
+ return 0;
+ }
+ } else {
+ /* Equivalent because they have different policies */
+ return 0;
+ }
+ } else {
+ /* Equivalent because one or both are missing a policy */
+ return 0;
+ }
+}
+
diff --git a/src/or/circuitmux.h b/src/or/circuitmux.h
index 2b5fb7e51e..837e3961bf 100644
--- a/src/or/circuitmux.h
+++ b/src/or/circuitmux.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -57,6 +57,9 @@ struct circuitmux_policy_s {
/* Choose a circuit */
circuit_t * (*pick_active_circuit)(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data);
+ /* Optional: channel comparator for use by the scheduler */
+ int (*cmp_cmux)(circuitmux_t *cmux_1, circuitmux_policy_data_t *pol_data_1,
+ circuitmux_t *cmux_2, circuitmux_policy_data_t *pol_data_2);
};
/*
@@ -105,7 +108,8 @@ void circuitmux_free(circuitmux_t *cmux);
/* Policy control */
void circuitmux_clear_policy(circuitmux_t *cmux);
-const circuitmux_policy_t * circuitmux_get_policy(circuitmux_t *cmux);
+MOCK_DECL(const circuitmux_policy_t *,
+ circuitmux_get_policy, (circuitmux_t *cmux));
void circuitmux_set_policy(circuitmux_t *cmux,
const circuitmux_policy_t *pol);
@@ -117,7 +121,7 @@ int circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ);
int circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ);
unsigned int circuitmux_num_cells_for_circuit(circuitmux_t *cmux,
circuit_t *circ);
-unsigned int circuitmux_num_cells(circuitmux_t *cmux);
+MOCK_DECL(unsigned int, circuitmux_num_cells, (circuitmux_t *cmux));
unsigned int circuitmux_num_circuits(circuitmux_t *cmux);
unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux);
@@ -148,5 +152,9 @@ void circuitmux_append_destroy_cell(channel_t *chan,
void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux,
channel_t *chan);
+/* Optional interchannel comparisons for scheduling */
+MOCK_DECL(int, circuitmux_compare_muxes,
+ (circuitmux_t *cmux_1, circuitmux_t *cmux_2));
+
#endif /* TOR_CIRCUITMUX_H */
diff --git a/src/or/circuitmux_ewma.c b/src/or/circuitmux_ewma.c
index 3f37d7b9a0..1c0318de06 100644
--- a/src/or/circuitmux_ewma.c
+++ b/src/or/circuitmux_ewma.c
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -187,6 +187,9 @@ ewma_notify_xmit_cells(circuitmux_t *cmux,
static circuit_t *
ewma_pick_active_circuit(circuitmux_t *cmux,
circuitmux_policy_data_t *pol_data);
+static int
+ewma_cmp_cmux(circuitmux_t *cmux_1, circuitmux_policy_data_t *pol_data_1,
+ circuitmux_t *cmux_2, circuitmux_policy_data_t *pol_data_2);
/*** EWMA global variables ***/
@@ -209,7 +212,8 @@ circuitmux_policy_t ewma_policy = {
/*.notify_circ_inactive =*/ ewma_notify_circ_inactive,
/*.notify_set_n_cells =*/ NULL, /* EWMA doesn't need this */
/*.notify_xmit_cells =*/ ewma_notify_xmit_cells,
- /*.pick_active_circuit =*/ ewma_pick_active_circuit
+ /*.pick_active_circuit =*/ ewma_pick_active_circuit,
+ /*.cmp_cmux =*/ ewma_cmp_cmux
};
/*** EWMA method implementations using the below EWMA helper functions ***/
@@ -273,8 +277,8 @@ ewma_alloc_circ_data(circuitmux_t *cmux,
tor_assert(circ);
tor_assert(direction == CELL_DIRECTION_OUT ||
direction == CELL_DIRECTION_IN);
- /* Shut the compiler up */
- tor_assert(cell_count == cell_count);
+ /* Shut the compiler up without triggering -Wtautological-compare */
+ (void)cell_count;
cdata = tor_malloc_zero(sizeof(*cdata));
cdata->base_.magic = EWMA_POL_CIRC_DATA_MAGIC;
@@ -453,6 +457,58 @@ ewma_pick_active_circuit(circuitmux_t *cmux,
return circ;
}
+/**
+ * Compare two EWMA cmuxes, and return -1, 0 or 1 to indicate which should
+ * be more preferred - see circuitmux_compare_muxes() of circuitmux.c.
+ */
+
+static int
+ewma_cmp_cmux(circuitmux_t *cmux_1, circuitmux_policy_data_t *pol_data_1,
+ circuitmux_t *cmux_2, circuitmux_policy_data_t *pol_data_2)
+{
+ ewma_policy_data_t *p1 = NULL, *p2 = NULL;
+ cell_ewma_t *ce1 = NULL, *ce2 = NULL;
+
+ tor_assert(cmux_1);
+ tor_assert(pol_data_1);
+ tor_assert(cmux_2);
+ tor_assert(pol_data_2);
+
+ p1 = TO_EWMA_POL_DATA(pol_data_1);
+ p2 = TO_EWMA_POL_DATA(pol_data_1);
+
+ if (p1 != p2) {
+ /* Get the head cell_ewma_t from each queue */
+ if (smartlist_len(p1->active_circuit_pqueue) > 0) {
+ ce1 = smartlist_get(p1->active_circuit_pqueue, 0);
+ }
+
+ if (smartlist_len(p2->active_circuit_pqueue) > 0) {
+ ce2 = smartlist_get(p2->active_circuit_pqueue, 0);
+ }
+
+ /* Got both of them? */
+ if (ce1 != NULL && ce2 != NULL) {
+ /* Pick whichever one has the better best circuit */
+ return compare_cell_ewma_counts(ce1, ce2);
+ } else {
+ if (ce1 != NULL ) {
+ /* We only have a circuit on cmux_1, so prefer it */
+ return -1;
+ } else if (ce2 != NULL) {
+ /* We only have a circuit on cmux_2, so prefer it */
+ return 1;
+ } else {
+ /* No circuits at all; no preference */
+ return 0;
+ }
+ }
+ } else {
+ /* We got identical params */
+ return 0;
+ }
+}
+
/** Helper for sorting cell_ewma_t values in their priority queue. */
static int
compare_cell_ewma_counts(const void *p1, const void *p2)
diff --git a/src/or/circuitmux_ewma.h b/src/or/circuitmux_ewma.h
index a512745c77..3feef834dd 100644
--- a/src/or/circuitmux_ewma.h
+++ b/src/or/circuitmux_ewma.h
@@ -1,4 +1,4 @@
-/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* * Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
index e362b1b49e..7b3ad56537 100644
--- a/src/or/circuitstats.c
+++ b/src/or/circuitstats.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITSTATS_PRIVATE
@@ -404,7 +404,7 @@ circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
* distress anyway, so memory correctness here is paramount over
* doing acrobatics to preserve the array.
*/
- recent_circs = tor_malloc_zero(sizeof(int8_t)*num);
+ recent_circs = tor_calloc(num, sizeof(int8_t));
if (cbt->liveness.timeouts_after_firsthop &&
cbt->liveness.num_recent_circs > 0) {
memcpy(recent_circs, cbt->liveness.timeouts_after_firsthop,
@@ -508,7 +508,7 @@ circuit_build_times_init(circuit_build_times_t *cbt)
cbt->liveness.num_recent_circs =
circuit_build_times_recent_circuit_count(NULL);
cbt->liveness.timeouts_after_firsthop =
- tor_malloc_zero(sizeof(int8_t)*cbt->liveness.num_recent_circs);
+ tor_calloc(cbt->liveness.num_recent_circs, sizeof(int8_t));
} else {
cbt->liveness.num_recent_circs = 0;
cbt->liveness.timeouts_after_firsthop = NULL;
@@ -649,7 +649,7 @@ circuit_build_times_create_histogram(const circuit_build_times_t *cbt,
int i, c;
*nbins = 1 + (max_build_time / CBT_BIN_WIDTH);
- histogram = tor_malloc_zero(*nbins * sizeof(build_time_t));
+ histogram = tor_calloc(*nbins, sizeof(build_time_t));
// calculate histogram
for (i = 0; i < CBT_NCIRCUITS_TO_OBSERVE; i++) {
@@ -691,7 +691,7 @@ circuit_build_times_get_xm(circuit_build_times_t *cbt)
if (cbt->total_build_times < CBT_NCIRCUITS_TO_OBSERVE)
num_modes = 1;
- nth_max_bin = (build_time_t*)tor_malloc_zero(num_modes*sizeof(build_time_t));
+ nth_max_bin = tor_calloc(num_modes, sizeof(build_time_t));
/* Determine the N most common build times */
for (i = 0; i < nbins; i++) {
@@ -873,7 +873,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
}
/* build_time_t 0 means uninitialized */
- loaded_times = tor_malloc_zero(sizeof(build_time_t)*state->TotalBuildTimes);
+ loaded_times = tor_calloc(state->TotalBuildTimes, sizeof(build_time_t));
for (line = state->BuildtimeHistogram; line; line = line->next) {
smartlist_t *args = smartlist_new();
@@ -1074,7 +1074,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
* random_sample_from_Pareto_distribution
* That's right. I'll cite wikipedia all day long.
*
- * Return value is in milliseconds.
+ * Return value is in milliseconds, clamped to INT32_MAX.
*/
STATIC double
circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
@@ -1085,7 +1085,21 @@ circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
tor_assert(1.0-quantile > 0);
tor_assert(cbt->Xm > 0);
- ret = cbt->Xm/pow(1.0-quantile,1.0/cbt->alpha);
+ /* If either alpha or p are 0, we would divide by zero, yielding an
+ * infinite (double) result; which would be clamped to INT32_MAX.
+ * Instead, initialise ret to INT32_MAX, and skip over these
+ * potentially illegal/trapping divides by zero.
+ */
+ ret = INT32_MAX;
+
+ if (cbt->alpha > 0) {
+ double p;
+ p = pow(1.0-quantile,1.0/cbt->alpha);
+ if (p > 0) {
+ ret = cbt->Xm/p;
+ }
+ }
+
if (ret > INT32_MAX) {
ret = INT32_MAX;
}
@@ -1371,10 +1385,11 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
}
cbt->liveness.after_firsthop_idx = 0;
+#define MAX_TIMEOUT ((int32_t) (INT32_MAX/2))
/* Check to see if this has happened before. If so, double the timeout
* to give people on abysmally bad network connections a shot at access */
if (cbt->timeout_ms >= circuit_build_times_get_initial_timeout()) {
- if (cbt->timeout_ms > INT32_MAX/2 || cbt->close_ms > INT32_MAX/2) {
+ if (cbt->timeout_ms > MAX_TIMEOUT || cbt->close_ms > MAX_TIMEOUT) {
log_warn(LD_CIRC, "Insanely large circuit build timeout value. "
"(timeout = %fmsec, close = %fmsec)",
cbt->timeout_ms, cbt->close_ms);
@@ -1386,6 +1401,7 @@ circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
cbt->close_ms = cbt->timeout_ms
= circuit_build_times_get_initial_timeout();
}
+#undef MAX_TIMEOUT
cbt_control_event_buildtimeout_set(cbt, BUILDTIMEOUT_SET_EVENT_RESET);
diff --git a/src/or/circuitstats.h b/src/or/circuitstats.h
index 3343310b8e..fe05a24e97 100644
--- a/src/or/circuitstats.h
+++ b/src/or/circuitstats.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 714754a672..3b6f982666 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -200,7 +200,7 @@ circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob,
return 1;
} else {
if (a->timestamp_dirty ||
- timercmp(&a->timestamp_began, &b->timestamp_began, >))
+ timercmp(&a->timestamp_began, &b->timestamp_began, OP_GT))
return 1;
if (ob->build_state->is_internal)
/* XXX023 what the heck is this internal thing doing here. I
@@ -268,7 +268,6 @@ circuit_get_best(const entry_connection_t *conn,
int must_be_open, uint8_t purpose,
int need_uptime, int need_internal)
{
- circuit_t *circ;
origin_circuit_t *best=NULL;
struct timeval now;
int intro_going_on_but_too_old = 0;
@@ -281,7 +280,7 @@ circuit_get_best(const entry_connection_t *conn,
tor_gettimeofday(&now);
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
origin_circuit_t *origin_circ;
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
@@ -305,6 +304,7 @@ circuit_get_best(const entry_connection_t *conn,
if (!best || circuit_is_better(origin_circ,best,conn))
best = origin_circ;
}
+ SMARTLIST_FOREACH_END(circ);
if (!best && intro_going_on_but_too_old)
log_info(LD_REND|LD_CIRC, "There is an intro circuit being created "
@@ -318,11 +318,9 @@ circuit_get_best(const entry_connection_t *conn,
static int
count_pending_general_client_circuits(void)
{
- const circuit_t *circ;
-
int count = 0;
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (circ->marked_for_close ||
circ->state == CIRCUIT_STATE_OPEN ||
circ->purpose != CIRCUIT_PURPOSE_C_GENERAL ||
@@ -331,6 +329,7 @@ count_pending_general_client_circuits(void)
++count;
}
+ SMARTLIST_FOREACH_END(circ);
return count;
}
@@ -370,7 +369,6 @@ circuit_conforms_to_options(const origin_circuit_t *circ,
void
circuit_expire_building(void)
{
- circuit_t *victim, *next_circ;
/* circ_times.timeout_ms and circ_times.close_ms are from
* circuit_build_times_get_initial_timeout() if we haven't computed
* custom timeouts yet */
@@ -388,7 +386,7 @@ circuit_expire_building(void)
* we want to be more lenient with timeouts, in case the
* user has relocated and/or changed network connections.
* See bug #3443. */
- TOR_LIST_FOREACH(next_circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, next_circ) {
if (!CIRCUIT_IS_ORIGIN(next_circ) || /* didn't originate here */
next_circ->marked_for_close) { /* don't mess with marked circs */
continue;
@@ -402,7 +400,7 @@ circuit_expire_building(void)
any_opened_circs = 1;
break;
}
- }
+ } SMARTLIST_FOREACH_END(next_circ);
#define SET_CUTOFF(target, msec) do { \
long ms = tor_lround(msec); \
@@ -473,9 +471,8 @@ circuit_expire_building(void)
MAX(get_circuit_build_close_time_ms()*2 + 1000,
options->SocksTimeout * 1000));
- TOR_LIST_FOREACH(next_circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *,victim) {
struct timeval cutoff;
- victim = next_circ;
if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */
victim->marked_for_close) /* don't mess with marked circs */
continue;
@@ -517,7 +514,7 @@ circuit_expire_building(void)
if (TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)
cutoff = hs_extremely_old_cutoff;
- if (timercmp(&victim->timestamp_began, &cutoff, >))
+ if (timercmp(&victim->timestamp_began, &cutoff, OP_GT))
continue; /* it's still young, leave it alone */
/* We need to double-check the opened state here because
@@ -527,7 +524,7 @@ circuit_expire_building(void)
* aren't either. */
if (!any_opened_circs && victim->state != CIRCUIT_STATE_OPEN) {
/* It's still young enough that we wouldn't close it, right? */
- if (timercmp(&victim->timestamp_began, &close_cutoff, >)) {
+ if (timercmp(&victim->timestamp_began, &close_cutoff, OP_GT)) {
if (!TO_ORIGIN_CIRCUIT(victim)->relaxed_timeout) {
int first_hop_succeeded = TO_ORIGIN_CIRCUIT(victim)->cpath->state
== CPATH_STATE_OPEN;
@@ -675,7 +672,7 @@ circuit_expire_building(void)
* it off at, we probably had a suspend event along this codepath,
* and we should discard the value.
*/
- if (timercmp(&victim->timestamp_began, &extremely_old_cutoff, <)) {
+ if (timercmp(&victim->timestamp_began, &extremely_old_cutoff, OP_LT)) {
log_notice(LD_CIRC,
"Extremely large value for circuit build timeout: %lds. "
"Assuming clock jump. Purpose %d (%s)",
@@ -780,7 +777,7 @@ circuit_expire_building(void)
circuit_mark_for_close(victim, END_CIRC_REASON_TIMEOUT);
pathbias_count_timeout(TO_ORIGIN_CIRCUIT(victim));
- }
+ } SMARTLIST_FOREACH_END(victim);
}
/** For debugging #8387: track when we last called
@@ -800,9 +797,8 @@ circuit_log_ancient_one_hop_circuits(int age)
time_t cutoff = now - age;
int n_found = 0;
smartlist_t *log_these = smartlist_new();
- const circuit_t *circ;
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
const origin_circuit_t *ocirc;
if (! CIRCUIT_IS_ORIGIN(circ))
continue;
@@ -817,6 +813,7 @@ circuit_log_ancient_one_hop_circuits(int age)
smartlist_add(log_these, (origin_circuit_t*) ocirc);
}
}
+ SMARTLIST_FOREACH_END(circ);
if (n_found == 0)
goto done;
@@ -831,7 +828,7 @@ circuit_log_ancient_one_hop_circuits(int age)
int stream_num;
const edge_connection_t *conn;
char *dirty = NULL;
- circ = TO_CIRCUIT(ocirc);
+ const circuit_t *circ = TO_CIRCUIT(ocirc);
format_local_iso_time(created,
(time_t)circ->timestamp_created.tv_sec);
@@ -848,12 +845,14 @@ circuit_log_ancient_one_hop_circuits(int age)
}
log_notice(LD_HEARTBEAT, " #%d created at %s. %s, %s. %s for close. "
+ "Package window: %d. "
"%s for new conns. %s.",
ocirc_sl_idx,
created,
circuit_state_to_string(circ->state),
circuit_purpose_to_string(circ->purpose),
circ->marked_for_close ? "Marked" : "Not marked",
+ circ->package_window,
ocirc->unusable_for_new_conns ? "Not usable" : "usable",
dirty);
tor_free(dirty);
@@ -869,12 +868,18 @@ circuit_log_ancient_one_hop_circuits(int age)
log_notice(LD_HEARTBEAT, " Stream#%d created at %s. "
"%s conn in state %s. "
+ "It is %slinked and %sreading from a linked connection %p. "
+ "Package window %d. "
"%s for close (%s:%d). Hold-open is %sset. "
"Has %ssent RELAY_END. %s on circuit.",
stream_num,
stream_created,
conn_type_to_string(c->type),
conn_state_to_string(c->type, c->state),
+ c->linked ? "" : "not ",
+ c->reading_from_linked_conn ? "": "not",
+ c->linked_conn,
+ conn->package_window,
c->marked_for_close ? "Marked" : "Not marked",
c->marked_for_close_file ? c->marked_for_close_file : "--",
c->marked_for_close,
@@ -938,7 +943,6 @@ int
circuit_stream_is_being_handled(entry_connection_t *conn,
uint16_t port, int min)
{
- circuit_t *circ;
const node_t *exitnode;
int num=0;
time_t now = time(NULL);
@@ -946,7 +950,7 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
get_options()->LongLivedPorts,
conn ? conn->socks_request->port : port);
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (CIRCUIT_IS_ORIGIN(circ) &&
!circ->marked_for_close &&
circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
@@ -976,6 +980,7 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
}
}
}
+ SMARTLIST_FOREACH_END(circ);
return 0;
}
@@ -989,7 +994,6 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
static void
circuit_predict_and_launch_new(void)
{
- circuit_t *circ;
int num=0, num_internal=0, num_uptime_internal=0;
int hidserv_needs_uptime=0, hidserv_needs_capacity=1;
int port_needs_uptime=0, port_needs_capacity=1;
@@ -997,7 +1001,7 @@ circuit_predict_and_launch_new(void)
int flags = 0;
/* First, count how many of each type of circuit we have already. */
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
cpath_build_state_t *build_state;
origin_circuit_t *origin_circ;
if (!CIRCUIT_IS_ORIGIN(circ))
@@ -1020,6 +1024,7 @@ circuit_predict_and_launch_new(void)
if (build_state->need_uptime && build_state->is_internal)
num_uptime_internal++;
}
+ SMARTLIST_FOREACH_END(circ);
/* If that's enough, then stop now. */
if (num >= MAX_UNUSED_OPEN_CIRCUITS)
@@ -1027,9 +1032,11 @@ circuit_predict_and_launch_new(void)
/* Second, see if we need any more exit circuits. */
/* check if we know of a port that's been requested recently
- * and no circuit is currently available that can handle it. */
+ * and no circuit is currently available that can handle it.
+ * Exits (obviously) require an exit circuit. */
if (!circuit_all_predicted_ports_handled(now, &port_needs_uptime,
- &port_needs_capacity)) {
+ &port_needs_capacity)
+ && router_have_consensus_path() == CONSENSUS_PATH_EXIT) {
if (port_needs_uptime)
flags |= CIRCLAUNCH_NEED_UPTIME;
if (port_needs_capacity)
@@ -1041,8 +1048,10 @@ circuit_predict_and_launch_new(void)
return;
}
- /* Third, see if we need any more hidden service (server) circuits. */
- if (num_rend_services() && num_uptime_internal < 3) {
+ /* Third, see if we need any more hidden service (server) circuits.
+ * HS servers only need an internal circuit. */
+ if (num_rend_services() && num_uptime_internal < 3
+ && router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
flags = (CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_NEED_UPTIME |
CIRCLAUNCH_IS_INTERNAL);
log_info(LD_CIRC,
@@ -1053,11 +1062,13 @@ circuit_predict_and_launch_new(void)
return;
}
- /* Fourth, see if we need any more hidden service (client) circuits. */
+ /* Fourth, see if we need any more hidden service (client) circuits.
+ * HS clients only need an internal circuit. */
if (rep_hist_get_predicted_internal(now, &hidserv_needs_uptime,
&hidserv_needs_capacity) &&
((num_uptime_internal<2 && hidserv_needs_uptime) ||
- num_internal<2)) {
+ num_internal<2)
+ && router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
if (hidserv_needs_uptime)
flags |= CIRCLAUNCH_NEED_UPTIME;
if (hidserv_needs_capacity)
@@ -1074,15 +1085,23 @@ circuit_predict_and_launch_new(void)
/* Finally, check to see if we still need more circuits to learn
* a good build timeout. But if we're close to our max number we
* want, don't do another -- we want to leave a few slots open so
- * we can still build circuits preemptively as needed. */
- if (num < MAX_UNUSED_OPEN_CIRCUITS-2 &&
- ! circuit_build_times_disabled() &&
- circuit_build_times_needs_circuits_now(get_circuit_build_times())) {
- flags = CIRCLAUNCH_NEED_CAPACITY;
- log_info(LD_CIRC,
- "Have %d clean circs need another buildtime test circ.", num);
- circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
- return;
+ * we can still build circuits preemptively as needed.
+ * XXXX make the assumption that build timeout streams should be
+ * created whenever we can build internal circuits. */
+ if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN) {
+ if (num < MAX_UNUSED_OPEN_CIRCUITS-2 &&
+ ! circuit_build_times_disabled() &&
+ circuit_build_times_needs_circuits_now(get_circuit_build_times())) {
+ flags = CIRCLAUNCH_NEED_CAPACITY;
+ /* if there are no exits in the consensus, make timeout
+ * circuits internal */
+ if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL)
+ flags |= CIRCLAUNCH_IS_INTERNAL;
+ log_info(LD_CIRC,
+ "Have %d clean circs need another buildtime test circ.", num);
+ circuit_launch(CIRCUIT_PURPOSE_C_GENERAL, flags);
+ return;
+ }
}
}
@@ -1099,11 +1118,17 @@ circuit_build_needed_circs(time_t now)
{
const or_options_t *options = get_options();
- /* launch a new circ for any pending streams that need one */
- connection_ap_attach_pending();
+ /* launch a new circ for any pending streams that need one
+ * XXXX make the assumption that (some) AP streams (i.e. HS clients)
+ * don't require an exit circuit, review in #13814.
+ * This allows HSs to function in a consensus without exits. */
+ if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN)
+ connection_ap_attach_pending();
- /* make sure any hidden services have enough intro points */
- rend_services_introduce();
+ /* make sure any hidden services have enough intro points
+ * HS intro point streams only require an internal circuit */
+ if (router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN)
+ rend_services_introduce();
circuit_expire_old_circs_as_needed(now);
@@ -1223,7 +1248,6 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
static void
circuit_expire_old_circuits_clientside(void)
{
- circuit_t *circ;
struct timeval cutoff, now;
tor_gettimeofday(&now);
@@ -1239,7 +1263,7 @@ circuit_expire_old_circuits_clientside(void)
cutoff.tv_sec -= get_options()->CircuitIdleTimeout;
}
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (circ->marked_for_close || !CIRCUIT_IS_ORIGIN(circ))
continue;
/* If the circuit has been dirty for too long, and there are no streams
@@ -1259,7 +1283,7 @@ circuit_expire_old_circuits_clientside(void)
if (circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
} else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) {
- if (timercmp(&circ->timestamp_began, &cutoff, <)) {
+ if (timercmp(&circ->timestamp_began, &cutoff, OP_LT)) {
if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
circ->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT ||
circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -1291,7 +1315,7 @@ circuit_expire_old_circuits_clientside(void)
}
}
}
- }
+ } SMARTLIST_FOREACH_END(circ);
}
/** How long do we wait before killing circuits with the properties
@@ -1318,11 +1342,10 @@ circuit_expire_old_circuits_clientside(void)
void
circuit_expire_old_circuits_serverside(time_t now)
{
- circuit_t *circ;
or_circuit_t *or_circ;
time_t cutoff = now - IDLE_ONE_HOP_CIRC_TIMEOUT;
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (circ->marked_for_close || CIRCUIT_IS_ORIGIN(circ))
continue;
or_circ = TO_OR_CIRCUIT(circ);
@@ -1339,6 +1362,7 @@ circuit_expire_old_circuits_serverside(time_t now)
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
}
}
+ SMARTLIST_FOREACH_END(circ);
}
/** Number of testing circuits we want open before testing our bandwidth. */
@@ -1363,18 +1387,18 @@ reset_bandwidth_test(void)
int
circuit_enough_testing_circs(void)
{
- circuit_t *circ;
int num = 0;
if (have_performed_bandwidth_test)
return 1;
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (!circ->marked_for_close && CIRCUIT_IS_ORIGIN(circ) &&
circ->purpose == CIRCUIT_PURPOSE_TESTING &&
circ->state == CIRCUIT_STATE_OPEN)
num++;
}
+ SMARTLIST_FOREACH_END(circ);
return num >= NUM_PARALLEL_TESTING_CIRCS;
}
@@ -1636,6 +1660,16 @@ circuit_launch(uint8_t purpose, int flags)
return circuit_launch_by_extend_info(purpose, NULL, flags);
}
+/** DOCDOC */
+static int
+have_enough_path_info(int need_exit)
+{
+ if (need_exit)
+ return router_have_consensus_path() == CONSENSUS_PATH_EXIT;
+ else
+ return router_have_consensus_path() != CONSENSUS_PATH_UNKNOWN;
+}
+
/** Launch a new circuit with purpose <b>purpose</b> and exit node
* <b>extend_info</b> (or NULL to select a random exit node). If flags
* contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime. If
@@ -1650,15 +1684,29 @@ circuit_launch_by_extend_info(uint8_t purpose,
{
origin_circuit_t *circ;
int onehop_tunnel = (flags & CIRCLAUNCH_ONEHOP_TUNNEL) != 0;
-
- if (!onehop_tunnel && !router_have_minimum_dir_info()) {
- log_debug(LD_CIRC,"Haven't fetched enough directory info yet; canceling "
- "circuit launch.");
+ int have_path = have_enough_path_info(! (flags & CIRCLAUNCH_IS_INTERNAL) );
+ int need_specific_rp = 0;
+
+ if (!onehop_tunnel && (!router_have_minimum_dir_info() || !have_path)) {
+ log_debug(LD_CIRC,"Haven't %s yet; canceling "
+ "circuit launch.",
+ !router_have_minimum_dir_info() ?
+ "fetched enough directory info" :
+ "received a consensus with exits");
return NULL;
}
+ /* If Tor2webRendezvousPoints is enabled and we are dealing with an
+ RP circuit, we want a specific RP node so we shouldn't canibalize
+ an already existing circuit. */
+ if (get_options()->Tor2webRendezvousPoints &&
+ purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
+ need_specific_rp = 1;
+ }
+
if ((extend_info || purpose != CIRCUIT_PURPOSE_C_GENERAL) &&
- purpose != CIRCUIT_PURPOSE_TESTING && !onehop_tunnel) {
+ purpose != CIRCUIT_PURPOSE_TESTING &&
+ !onehop_tunnel && !need_specific_rp) {
/* see if there are appropriate circs available to cannibalize. */
/* XXX if we're planning to add a hop, perhaps we want to look for
* internal circs rather than exit circs? -RD */
@@ -1810,7 +1858,9 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
return 1; /* we're happy */
}
- if (!want_onehop && !router_have_minimum_dir_info()) {
+ int have_path = have_enough_path_info(!need_internal);
+
+ if (!want_onehop && (!router_have_minimum_dir_info() || !have_path)) {
if (!connection_get_by_type(CONN_TYPE_DIR)) {
int severity = LOG_NOTICE;
/* FFFF if this is a tunneled directory fetch, don't yell
@@ -1818,14 +1868,20 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
if (entry_list_is_constrained(options) &&
entries_known_but_down(options)) {
log_fn(severity, LD_APP|LD_DIR,
- "Application request when we haven't used client functionality "
- "lately. Optimistically trying known %s again.",
+ "Application request when we haven't %s. "
+ "Optimistically trying known %s again.",
+ !router_have_minimum_dir_info() ?
+ "used client functionality lately" :
+ "received a consensus with exits",
options->UseBridges ? "bridges" : "entrynodes");
entries_retry_all(options);
} else if (!options->UseBridges || any_bridge_descriptors_known()) {
log_fn(severity, LD_APP|LD_DIR,
- "Application request when we haven't used client functionality "
- "lately. Optimistically trying directory fetches again.");
+ "Application request when we haven't %s. "
+ "Optimistically trying directory fetches again.",
+ !router_have_minimum_dir_info() ?
+ "used client functionality lately" :
+ "received a consensus with exits");
routerlist_retry_directory_downloads(time(NULL));
}
}
@@ -1980,11 +2036,13 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
else
new_circ_purpose = desired_circuit_purpose;
+#ifdef ENABLE_TOR2WEB_MODE
if (options->Tor2webMode &&
(new_circ_purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND ||
new_circ_purpose == CIRCUIT_PURPOSE_C_INTRODUCING)) {
want_onehop = 1;
}
+#endif
{
int flags = CIRCLAUNCH_NEED_CAPACITY;
@@ -2016,7 +2074,7 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
circ->rend_data = rend_data_dup(ENTRY_TO_EDGE_CONN(conn)->rend_data);
if (circ->base_.purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
circ->base_.state == CIRCUIT_STATE_OPEN)
- rend_client_rendcirc_has_opened(circ);
+ circuit_has_opened(circ);
}
}
} /* endif (!circ) */
@@ -2074,7 +2132,7 @@ static void
link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
crypt_path_t *cpath)
{
- const node_t *exitnode;
+ const node_t *exitnode = NULL;
/* add it into the linked list of streams on this circuit */
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %u.",
@@ -2108,23 +2166,25 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
circ->isolation_any_streams_attached = 1;
connection_edge_update_circuit_isolation(apconn, circ, 0);
+ /* Compute the exitnode if possible, for logging below */
+ if (cpath->extend_info)
+ exitnode = node_get_by_id(cpath->extend_info->identity_digest);
+
/* See if we can use optimistic data on this circuit */
- if (cpath->extend_info &&
- (exitnode = node_get_by_id(cpath->extend_info->identity_digest)) &&
- exitnode->rs) {
- /* Okay; we know what exit node this is. */
- if (optimistic_data_enabled() &&
- circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL &&
- exitnode->rs->version_supports_optimistic_data)
- apconn->may_use_optimistic_data = 1;
- else
- apconn->may_use_optimistic_data = 0;
- log_info(LD_APP, "Looks like completed circuit to %s %s allow "
- "optimistic data for connection to %s",
- safe_str_client(node_describe(exitnode)),
- apconn->may_use_optimistic_data ? "does" : "doesn't",
- safe_str_client(apconn->socks_request->address));
- }
+ if (optimistic_data_enabled() &&
+ (circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL ||
+ circ->base_.purpose == CIRCUIT_PURPOSE_C_REND_JOINED))
+ apconn->may_use_optimistic_data = 1;
+ else
+ apconn->may_use_optimistic_data = 0;
+ log_info(LD_APP, "Looks like completed circuit to %s %s allow "
+ "optimistic data for connection to %s",
+ circ->base_.purpose == CIRCUIT_PURPOSE_C_GENERAL ?
+ /* node_describe() does the right thing if exitnode is NULL */
+ safe_str_client(node_describe(exitnode)) :
+ "hidden service",
+ apconn->may_use_optimistic_data ? "does" : "doesn't",
+ safe_str_client(apconn->socks_request->address));
}
/** Return true iff <b>address</b> is matched by one of the entries in
@@ -2326,7 +2386,7 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
tor_assert(rendcirc);
/* one is already established, attach */
log_info(LD_REND,
- "rend joined circ %d already here. attaching. "
+ "rend joined circ %u already here. attaching. "
"(stream %d sec old)",
(unsigned)rendcirc->base_.n_circ_id, conn_age);
/* Mark rendezvous circuits as 'newly dirty' every time you use
@@ -2346,6 +2406,18 @@ connection_ap_handshake_attach_circuit(entry_connection_t *conn)
return 1;
}
+ /* At this point we need to re-check the state, since it's possible that
+ * our call to circuit_get_open_circ_or_launch() changed the connection's
+ * state from "CIRCUIT_WAIT" to "RENDDESC_WAIT" because we decided to
+ * re-fetch the descriptor.
+ */
+ if (ENTRY_TO_CONN(conn)->state != AP_CONN_STATE_CIRCUIT_WAIT) {
+ log_info(LD_REND, "This connection is no longer ready to attach; its "
+ "state changed."
+ "(We probably have to re-fetch its descriptor.)");
+ return 0;
+ }
+
if (rendcirc && (rendcirc->base_.purpose ==
CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)) {
log_info(LD_REND,
diff --git a/src/or/circuituse.h b/src/or/circuituse.h
index 4c5977bee0..a59f478ac8 100644
--- a/src/or/circuituse.h
+++ b/src/or/circuituse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/command.c b/src/or/command.c
index 1f6f93a868..719b10736b 100644
--- a/src/or/command.c
+++ b/src/or/command.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -310,7 +310,7 @@ command_process_create_cell(cell_t *cell, channel_t *chan)
/* hand it off to the cpuworkers, and then return. */
if (connection_or_digest_is_known_relay(chan->identity_digest))
rep_hist_note_circuit_handshake_requested(create_cell->handshake_type);
- if (assign_onionskin_to_cpuworker(NULL, circ, create_cell) < 0) {
+ if (assign_onionskin_to_cpuworker(circ, create_cell) < 0) {
log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing.");
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
return;
@@ -398,7 +398,6 @@ command_process_created_cell(cell_t *cell, channel_t *chan)
log_debug(LD_OR,"at OP. Finishing handshake.");
if ((err_reason = circuit_finish_handshake(origin_circ,
&extended_cell.created_cell)) < 0) {
- log_warn(LD_OR,"circuit_finish_handshake failed.");
circuit_mark_for_close(circ, -err_reason);
return;
}
@@ -438,6 +437,7 @@ command_process_created_cell(cell_t *cell, channel_t *chan)
static void
command_process_relay_cell(cell_t *cell, channel_t *chan)
{
+ const or_options_t *options = get_options();
circuit_t *circ;
int reason, direction;
@@ -511,6 +511,14 @@ command_process_relay_cell(cell_t *cell, channel_t *chan)
direction==CELL_DIRECTION_OUT?"forward":"backward");
circuit_mark_for_close(circ, -reason);
}
+
+ /* If this is a cell in an RP circuit, count it as part of the
+ hidden service stats */
+ if (options->HiddenServiceStatistics &&
+ !CIRCUIT_IS_ORIGIN(circ) &&
+ TO_OR_CIRCUIT(circ)->circuit_carries_hs_traffic_stats) {
+ rep_hist_seen_new_rp_cell();
+ }
}
/** Process a 'destroy' <b>cell</b> that just arrived from
diff --git a/src/or/command.h b/src/or/command.h
index adea6adeaa..bea96261bb 100644
--- a/src/or/command.h
+++ b/src/or/command.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/config.c b/src/or/config.c
index c60dd11c4d..233940ec95 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -11,6 +11,7 @@
#define CONFIG_PRIVATE
#include "or.h"
+#include "compat.h"
#include "addressmap.h"
#include "channel.h"
#include "circuitbuild.h"
@@ -43,6 +44,7 @@
#include "util.h"
#include "routerlist.h"
#include "routerset.h"
+#include "scheduler.h"
#include "statefile.h"
#include "transports.h"
#include "ext_orport.h"
@@ -53,9 +55,22 @@
#include "procmon.h"
+#ifdef HAVE_SYSTEMD
+# if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__)
+/* Systemd's use of gcc's __INCLUDE_LEVEL__ extension macro appears to confuse
+ * Coverity. Here's a kludge to unconfuse it.
+ */
+# define __INCLUDE_LEVEL__ 2
+# endif
+#include <systemd/sd-daemon.h>
+#endif
+
/* From main.c */
extern int quiet_level;
+/* Prefix used to indicate a Unix socket in a FooPort configuration. */
+static const char unix_socket_prefix[] = "unix:";
+
/** A list of abbreviations and aliases to map command-line options, obsolete
* option names, or alternative option names, to their current values. */
static config_abbrev_t option_abbrevs_[] = {
@@ -63,15 +78,16 @@ static config_abbrev_t option_abbrevs_[] = {
PLURAL(AuthDirBadExitCC),
PLURAL(AuthDirInvalidCC),
PLURAL(AuthDirRejectCC),
- PLURAL(ExitNode),
PLURAL(EntryNode),
PLURAL(ExcludeNode),
+ PLURAL(Tor2webRendezvousPoint),
PLURAL(FirewallPort),
PLURAL(LongLivedPort),
PLURAL(HiddenServiceNode),
PLURAL(HiddenServiceExcludeNode),
PLURAL(NumCPU),
PLURAL(RendNode),
+ PLURAL(RecommendedPackage),
PLURAL(RendExcludeNode),
PLURAL(StrictEntryNode),
PLURAL(StrictExitNode),
@@ -99,8 +115,6 @@ static config_abbrev_t option_abbrevs_[] = {
{ "PreferTunnelledDirConns", "PreferTunneledDirConns", 0, 0},
{ "BridgeAuthoritativeDirectory", "BridgeAuthoritativeDir", 0, 0},
{ "HashedControlPassword", "__HashedControlSessionPassword", 1, 0},
- { "StrictEntryNodes", "StrictNodes", 0, 1},
- { "StrictExitNodes", "StrictNodes", 0, 1},
{ "VirtualAddrNetwork", "VirtualAddrNetworkIPv4", 0, 0},
{ "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1},
{ NULL, NULL, 0, 0},
@@ -127,8 +141,8 @@ static config_abbrev_t option_abbrevs_[] = {
* be chosen first.
*/
static config_var_t option_vars_[] = {
- OBSOLETE("AccountingMaxKB"),
V(AccountingMax, MEMUNIT, "0 bytes"),
+ VAR("AccountingRule", STRING, AccountingRule_option, "max"),
V(AccountingStart, STRING, NULL),
V(Address, STRING, NULL),
V(AllowDotExit, BOOL, "0"),
@@ -140,8 +154,8 @@ static config_var_t option_vars_[] = {
V(AlternateDirAuthority, LINELIST, NULL),
OBSOLETE("AlternateHSAuthority"),
V(AssumeReachable, BOOL, "0"),
- V(AuthDirBadDir, LINELIST, NULL),
- V(AuthDirBadDirCCs, CSV, ""),
+ OBSOLETE("AuthDirBadDir"),
+ OBSOLETE("AuthDirBadDirCCs"),
V(AuthDirBadExit, LINELIST, NULL),
V(AuthDirBadExitCCs, CSV, ""),
V(AuthDirInvalid, LINELIST, NULL),
@@ -150,8 +164,8 @@ static config_var_t option_vars_[] = {
V(AuthDirGuardBWGuarantee, MEMUNIT, "2 MB"),
V(AuthDirReject, LINELIST, NULL),
V(AuthDirRejectCCs, CSV, ""),
- V(AuthDirRejectUnlisted, BOOL, "0"),
- V(AuthDirListBadDirs, BOOL, "0"),
+ OBSOLETE("AuthDirRejectUnlisted"),
+ OBSOLETE("AuthDirListBadDirs"),
V(AuthDirListBadExits, BOOL, "0"),
V(AuthDirMaxServersPerAddr, UINT, "2"),
V(AuthDirMaxServersPerAuthAddr,UINT, "5"),
@@ -191,26 +205,20 @@ static config_var_t option_vars_[] = {
V(ControlPortWriteToFile, FILENAME, NULL),
V(ControlSocket, LINELIST, NULL),
V(ControlSocketsGroupWritable, BOOL, "0"),
+ V(SocksSocketsGroupWritable, BOOL, "0"),
V(CookieAuthentication, BOOL, "0"),
V(CookieAuthFileGroupReadable, BOOL, "0"),
V(CookieAuthFile, STRING, NULL),
V(CountPrivateBandwidth, BOOL, "0"),
V(DataDirectory, FILENAME, NULL),
- OBSOLETE("DebugLogFile"),
V(DisableNetwork, BOOL, "0"),
V(DirAllowPrivateAddresses, BOOL, "0"),
V(TestingAuthDirTimeToLearnReachability, INTERVAL, "30 minutes"),
V(DirListenAddress, LINELIST, NULL),
- OBSOLETE("DirFetchPeriod"),
V(DirPolicy, LINELIST, NULL),
VPORT(DirPort, LINELIST, NULL),
V(DirPortFrontPage, FILENAME, NULL),
- OBSOLETE("DirPostPeriod"),
- OBSOLETE("DirRecordUsageByCountry"),
- OBSOLETE("DirRecordUsageGranularity"),
- OBSOLETE("DirRecordUsageRetainIPs"),
- OBSOLETE("DirRecordUsageSaveInterval"),
- V(DirReqStatistics, BOOL, "1"),
+ VAR("DirReqStatistics", BOOL, DirReqStatistics_option, "1"),
VAR("DirAuthority", LINELIST, DirAuthorities, NULL),
V(DirAuthorityFallbackRate, DOUBLE, "1.0"),
V(DisableAllSwap, BOOL, "0"),
@@ -236,6 +244,7 @@ static config_var_t option_vars_[] = {
V(ExitPolicyRejectPrivate, BOOL, "1"),
V(ExitPortStatistics, BOOL, "0"),
V(ExtendAllowPrivateAddresses, BOOL, "0"),
+ V(ExitRelay, AUTOBOOL, "auto"),
VPORT(ExtORPort, LINELIST, NULL),
V(ExtORPortCookieAuthFile, STRING, NULL),
V(ExtORPortCookieAuthFileGroupReadable, BOOL, "0"),
@@ -262,7 +271,6 @@ static config_var_t option_vars_[] = {
V(GeoIPv6File, FILENAME,
SHARE_DATADIR PATH_SEPARATOR "tor" PATH_SEPARATOR "geoip6"),
#endif
- OBSOLETE("GiveGuardFlagTo_CVE_2011_2768_VulnerableRelays"),
OBSOLETE("Group"),
V(GuardLifetime, INTERVAL, "0 minutes"),
V(HardwareAccel, BOOL, "0"),
@@ -272,15 +280,14 @@ static config_var_t option_vars_[] = {
V(HashedControlPassword, LINELIST, NULL),
V(HidServDirectoryV2, BOOL, "1"),
VAR("HiddenServiceDir", LINELIST_S, RendConfigLines, NULL),
- OBSOLETE("HiddenServiceExcludeNodes"),
- OBSOLETE("HiddenServiceNodes"),
+ VAR("HiddenServiceDirGroupReadable", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceOptions",LINELIST_V, RendConfigLines, NULL),
VAR("HiddenServicePort", LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceVersion",LINELIST_S, RendConfigLines, NULL),
VAR("HiddenServiceAuthorizeClient",LINELIST_S,RendConfigLines, NULL),
+ VAR("HiddenServiceAllowUnknownPorts",LINELIST_S, RendConfigLines, NULL),
+ V(HiddenServiceStatistics, BOOL, "0"),
V(HidServAuth, LINELIST, NULL),
- OBSOLETE("HSAuthoritativeDir"),
- OBSOLETE("HSAuthorityRecordStats"),
V(CloseHSClientCircuitsImmediatelyOnTimeout, BOOL, "0"),
V(CloseHSServiceRendCircuitsImmediatelyOnTimeout, BOOL, "0"),
V(HTTPProxy, STRING, NULL),
@@ -295,14 +302,11 @@ static config_var_t option_vars_[] = {
V(Socks5Proxy, STRING, NULL),
V(Socks5ProxyUsername, STRING, NULL),
V(Socks5ProxyPassword, STRING, NULL),
- OBSOLETE("IgnoreVersion"),
V(KeepalivePeriod, INTERVAL, "5 minutes"),
VAR("Log", LINELIST, Logs, NULL),
V(LogMessageDomains, BOOL, "0"),
- OBSOLETE("LinkPadding"),
- OBSOLETE("LogLevel"),
- OBSOLETE("LogFile"),
V(LogTimeGranularity, MSEC_INTERVAL, "1 second"),
+ V(TruncateLogFile, BOOL, "0"),
V(LongLivedPorts, CSV,
"21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"),
VAR("MapAddress", LINELIST, AddressMap, NULL),
@@ -313,16 +317,14 @@ static config_var_t option_vars_[] = {
OBSOLETE("MaxOnionsPending"),
V(MaxOnionQueueDelay, MSEC_INTERVAL, "1750 msec"),
V(MinMeasuredBWsForAuthToIgnoreAdvertised, INT, "500"),
- OBSOLETE("MonthlyAccountingStart"),
V(MyFamily, STRING, NULL),
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
- VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
+ OBSOLETE("NamingAuthoritativeDirectory"),
V(NATDListenAddress, LINELIST, NULL),
VPORT(NATDPort, LINELIST, NULL),
V(Nickname, STRING, NULL),
V(PredictedPortsRelevanceTime, INTERVAL, "1 hour"),
V(WarnUnsafeSocks, BOOL, "1"),
- OBSOLETE("NoPublish"),
VAR("NodeFamily", LINELIST, NodeFamilies, NULL),
V(NumCPUs, UINT, "0"),
V(NumDirectoryGuards, UINT, "0"),
@@ -348,7 +350,6 @@ static config_var_t option_vars_[] = {
V(PathBiasScaleUseThreshold, INT, "-1"),
V(PathsNeededToBuildCircuits, DOUBLE, "-1"),
- OBSOLETE("PathlenCoinWeight"),
V(PerConnBWBurst, MEMUNIT, "0"),
V(PerConnBWRate, MEMUNIT, "0"),
V(PidFile, STRING, NULL),
@@ -368,18 +369,14 @@ static config_var_t option_vars_[] = {
V(RecommendedVersions, LINELIST, NULL),
V(RecommendedClientVersions, LINELIST, NULL),
V(RecommendedServerVersions, LINELIST, NULL),
- OBSOLETE("RedirectExit"),
+ V(RecommendedPackages, LINELIST, NULL),
V(RefuseUnknownExits, AUTOBOOL, "auto"),
V(RejectPlaintextPorts, CSV, ""),
V(RelayBandwidthBurst, MEMUNIT, "0"),
V(RelayBandwidthRate, MEMUNIT, "0"),
- OBSOLETE("RendExcludeNodes"),
- OBSOLETE("RendNodes"),
V(RendPostPeriod, INTERVAL, "1 hour"),
V(RephistTrackTime, INTERVAL, "24 hours"),
- OBSOLETE("RouterFile"),
V(RunAsDaemon, BOOL, "0"),
-// V(RunTesting, BOOL, "0"),
OBSOLETE("RunTesting"), // currently unused
V(Sandbox, BOOL, "0"),
V(SafeLogging, STRING, "1"),
@@ -392,24 +389,26 @@ static config_var_t option_vars_[] = {
V(ServerDNSSearchDomains, BOOL, "0"),
V(ServerDNSTestAddresses, CSV,
"www.google.com,www.mit.edu,www.yahoo.com,www.slashdot.org"),
+ V(SchedulerLowWaterMark__, MEMUNIT, "100 MB"),
+ V(SchedulerHighWaterMark__, MEMUNIT, "101 MB"),
+ V(SchedulerMaxFlushCells__, UINT, "1000"),
V(ShutdownWaitLength, INTERVAL, "30 seconds"),
V(SocksListenAddress, LINELIST, NULL),
V(SocksPolicy, LINELIST, NULL),
VPORT(SocksPort, LINELIST, NULL),
V(SocksTimeout, INTERVAL, "2 minutes"),
V(SSLKeyLifetime, INTERVAL, "0"),
- OBSOLETE("StatusFetchPeriod"),
+ OBSOLETE("StrictEntryNodes"),
+ OBSOLETE("StrictExitNodes"),
V(StrictNodes, BOOL, "0"),
- V(Support022HiddenServices, AUTOBOOL, "auto"),
- OBSOLETE("SysLog"),
+ OBSOLETE("Support022HiddenServices"),
V(TestSocks, BOOL, "0"),
- OBSOLETE("TestVia"),
V(TokenBucketRefillInterval, MSEC_INTERVAL, "100 msec"),
V(Tor2webMode, BOOL, "0"),
+ V(Tor2webRendezvousPoints, ROUTERSET, NULL),
V(TLSECGroup, STRING, NULL),
V(TrackHostExits, CSV, NULL),
V(TrackHostExitsExpire, INTERVAL, "30 minutes"),
- OBSOLETE("TrafficShaping"),
V(TransListenAddress, LINELIST, NULL),
VPORT(TransPort, LINELIST, NULL),
V(TransProxyType, STRING, "default"),
@@ -418,6 +417,7 @@ static config_var_t option_vars_[] = {
V(UseBridges, BOOL, "0"),
V(UseEntryGuards, BOOL, "1"),
V(UseEntryGuardsAsDirGuards, BOOL, "1"),
+ V(UseGuardFraction, AUTOBOOL, "auto"),
V(UseMicrodescriptors, AUTOBOOL, "auto"),
V(UseNTorHandshake, AUTOBOOL, "1"),
V(User, STRING, NULL),
@@ -435,6 +435,7 @@ static config_var_t option_vars_[] = {
V(V3AuthNIntervalsValid, UINT, "3"),
V(V3AuthUseLegacyKey, BOOL, "0"),
V(V3BandwidthsFile, FILENAME, NULL),
+ V(GuardfractionFile, FILENAME, NULL),
VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
V(VirtualAddrNetworkIPv4, STRING, "127.192.0.0/10"),
V(VirtualAddrNetworkIPv6, STRING, "[FE80::]/10"),
@@ -447,7 +448,7 @@ static config_var_t option_vars_[] = {
VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword,
NULL),
VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL),
- V(MinUptimeHidServDirectoryV2, INTERVAL, "25 hours"),
+ V(MinUptimeHidServDirectoryV2, INTERVAL, "96 hours"),
V(VoteOnHidServDirectoriesV2, BOOL, "1"),
V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 60, 60, 120, "
"300, 900, 2147483647"),
@@ -466,7 +467,9 @@ static config_var_t option_vars_[] = {
V(TestingDescriptorMaxDownloadTries, UINT, "8"),
V(TestingMicrodescMaxDownloadTries, UINT, "8"),
V(TestingCertMaxDownloadTries, UINT, "8"),
+ V(TestingDirAuthVoteExit, ROUTERSET, NULL),
V(TestingDirAuthVoteGuard, ROUTERSET, NULL),
+ V(TestingDirAuthVoteHSDir, ROUTERSET, NULL),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
@@ -489,7 +492,7 @@ static const config_var_t testing_tor_network_defaults[] = {
V(V3AuthVotingInterval, INTERVAL, "5 minutes"),
V(V3AuthVoteDelay, INTERVAL, "20 seconds"),
V(V3AuthDistDelay, INTERVAL, "20 seconds"),
- V(TestingV3AuthInitialVotingInterval, INTERVAL, "5 minutes"),
+ V(TestingV3AuthInitialVotingInterval, INTERVAL, "150 seconds"),
V(TestingV3AuthInitialVoteDelay, INTERVAL, "20 seconds"),
V(TestingV3AuthInitialDistDelay, INTERVAL, "20 seconds"),
V(TestingV3AuthVotingStartOffset, INTERVAL, "0"),
@@ -515,6 +518,7 @@ static const config_var_t testing_tor_network_defaults[] = {
V(TestingEnableCellStatsEvent, BOOL, "1"),
V(TestingEnableTbEmptyEvent, BOOL, "1"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "1"),
+ V(RendPostPeriod, INTERVAL, "2 minutes"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
};
@@ -536,12 +540,6 @@ static int options_transition_affects_workers(
static int options_transition_affects_descriptor(
const or_options_t *old_options, const or_options_t *new_options);
static int check_nickname_list(char **lst, const char *name, char **msg);
-
-static int parse_client_transport_line(const or_options_t *options,
- const char *line, int validate_only);
-
-static int parse_server_transport_line(const or_options_t *options,
- const char *line, int validate_only);
static char *get_bindaddr_from_transport_listen_line(const char *line,
const char *transport);
static int parse_dir_authority_line(const char *line,
@@ -558,7 +556,8 @@ static int check_server_ports(const smartlist_t *ports,
static int validate_data_directory(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
-static int options_init_logs(or_options_t *options, int validate_only);
+static int options_init_logs(const or_options_t *old_options,
+ or_options_t *options, int validate_only);
static void init_libevent(const or_options_t *options);
static int opt_streq(const char *s1, const char *s2);
@@ -843,7 +842,9 @@ escaped_safe_str(const char *address)
}
/** Add the default directory authorities directly into the trusted dir list,
- * but only add them insofar as they share bits with <b>type</b>. */
+ * but only add them insofar as they share bits with <b>type</b>.
+ * Each authority's bits are restricted to the bits shared with <b>type</b>.
+ * If <b>type</b> is ALL_DIRINFO or NO_DIRINFO (zero), add all authorities. */
static void
add_default_trusted_dir_authorities(dirinfo_type_t type)
{
@@ -852,9 +853,11 @@ add_default_trusted_dir_authorities(dirinfo_type_t type)
"moria1 orport=9101 "
"v3ident=D586D18309DED4CD6D57C18FDB97EFA96D330566 "
"128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
- "tor26 orport=443 v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
+ "tor26 orport=443 "
+ "v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
"86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
- "dizum orport=443 v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
+ "dizum orport=443 "
+ "v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
"194.109.206.212:80 7EA6 EAD6 FD83 083C 538F 4403 8BBF A077 587D D755",
"Bifroest orport=443 bridge "
"37.218.247.217:80 1D8F 3A91 C37C 5D1C 4C19 B1AD 1D0C FBE8 BF72 D8E1",
@@ -983,7 +986,10 @@ consider_adding_dir_servers(const or_options_t *options,
type |= BRIDGE_DIRINFO;
if (!options->AlternateDirAuthority)
type |= V3_DIRINFO | EXTRAINFO_DIRINFO | MICRODESC_DIRINFO;
- add_default_trusted_dir_authorities(type);
+ /* if type == NO_DIRINFO, we don't want to add any of the
+ * default authorities, because we've replaced them all */
+ if (type != NO_DIRINFO)
+ add_default_trusted_dir_authorities(type);
}
if (!options->FallbackDir)
add_default_fallback_dir_servers();
@@ -1019,7 +1025,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
int running_tor = options->command == CMD_RUN_TOR;
int set_conn_limit = 0;
int r = -1;
- int logs_marked = 0;
+ int logs_marked = 0, logs_initialized = 0;
int old_min_log_level = get_min_log_level();
/* Daemonize _first_, since we only want to open most of this stuff in
@@ -1030,6 +1036,11 @@ options_act_reversible(const or_options_t *old_options, char **msg)
start_daemon();
}
+#ifdef HAVE_SYSTEMD
+ /* Our PID may have changed, inform supervisor */
+ sd_notifyf(0, "MAINPID=%ld\n", (long int)getpid());
+#endif
+
#ifndef HAVE_SYS_UN_H
if (options->ControlSocket || options->ControlSocketsGroupWritable) {
*msg = tor_strdup("Unix domain sockets (ControlSocket) not supported "
@@ -1065,6 +1076,14 @@ options_act_reversible(const or_options_t *old_options, char **msg)
if (running_tor && !libevent_initialized) {
init_libevent(options);
libevent_initialized = 1;
+
+ /*
+ * Initialize the scheduler - this has to come after
+ * options_init_from_torrc() sets up libevent - why yes, that seems
+ * completely sensible to hide the libevent setup in the option parsing
+ * code! It also needs to happen before init_keys(), so it needs to
+ * happen here too. How yucky. */
+ scheduler_init();
}
/* Adjust the port configuration so we can launch listeners. */
@@ -1094,6 +1113,8 @@ options_act_reversible(const or_options_t *old_options, char **msg)
"non-control network connections. Shutting down all existing "
"connections.");
connection_mark_all_noncontrol_connections();
+ /* We can't complete circuits until the network is re-enabled. */
+ note_that_we_maybe_cant_complete_circuits();
}
}
@@ -1144,10 +1165,12 @@ options_act_reversible(const or_options_t *old_options, char **msg)
mark_logs_temp(); /* Close current logs once new logs are open. */
logs_marked = 1;
- if (options_init_logs(options, 0)<0) { /* Configure the tor_log(s) */
+ /* Configure the tor_log(s) */
+ if (options_init_logs(old_options, options, 0)<0) {
*msg = tor_strdup("Failed to init Log options. See logs for details.");
goto rollback;
}
+ logs_initialized = 1;
commit:
r = 0;
@@ -1160,6 +1183,9 @@ options_act_reversible(const or_options_t *old_options, char **msg)
tor_free(severity);
tor_log_update_sigsafe_err_fds();
}
+ if (logs_initialized) {
+ flush_log_messages_from_startup();
+ }
{
const char *badness = NULL;
@@ -1237,7 +1263,8 @@ options_need_geoip_info(const or_options_t *options, const char **reason_out)
routerset_needs_geoip(options->EntryNodes) ||
routerset_needs_geoip(options->ExitNodes) ||
routerset_needs_geoip(options->ExcludeExitNodes) ||
- routerset_needs_geoip(options->ExcludeNodes);
+ routerset_needs_geoip(options->ExcludeNodes) ||
+ routerset_needs_geoip(options->Tor2webRendezvousPoints);
if (routerset_usage && reason_out) {
*reason_out = "We've been configured to use (or avoid) nodes in certain "
@@ -1370,7 +1397,7 @@ options_act(const or_options_t *old_options)
log_err(LD_CONFIG, "This copy of Tor was not compiled to run in "
"'tor2web mode'. It cannot be run with the Tor2webMode torrc "
"option enabled. To enable Tor2webMode recompile with the "
- "--enable-tor2webmode option.");
+ "--enable-tor2web-mode option.");
return -1;
}
#endif
@@ -1421,26 +1448,35 @@ options_act(const or_options_t *old_options)
rep_hist_load_mtbf_data(time(NULL));
}
+ /* If we have an ExtORPort, initialize its auth cookie. */
+ if (running_tor &&
+ init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) {
+ log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file.");
+ return -1;
+ }
+
mark_transport_list();
pt_prepare_proxy_list_for_config_read();
- if (options->ClientTransportPlugin) {
- for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
- if (parse_client_transport_line(options, cl->value, 0)<0) {
- log_warn(LD_BUG,
- "Previously validated ClientTransportPlugin line "
- "could not be added!");
- return -1;
+ if (!options->DisableNetwork) {
+ if (options->ClientTransportPlugin) {
+ for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
+ if (parse_transport_line(options, cl->value, 0, 0) < 0) {
+ log_warn(LD_BUG,
+ "Previously validated ClientTransportPlugin line "
+ "could not be added!");
+ return -1;
+ }
}
}
- }
- if (options->ServerTransportPlugin && server_mode(options)) {
- for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
- if (parse_server_transport_line(options, cl->value, 0)<0) {
- log_warn(LD_BUG,
- "Previously validated ServerTransportPlugin line "
- "could not be added!");
- return -1;
+ if (options->ServerTransportPlugin && server_mode(options)) {
+ for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
+ if (parse_transport_line(options, cl->value, 0, 1) < 0) {
+ log_warn(LD_BUG,
+ "Previously validated ServerTransportPlugin line "
+ "could not be added!");
+ return -1;
+ }
}
}
}
@@ -1523,12 +1559,6 @@ options_act(const or_options_t *old_options)
return -1;
}
- /* If we have an ExtORPort, initialize its auth cookie. */
- if (init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) {
- log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file.");
- return -1;
- }
-
monitor_owning_controller_process(options->OwningControllerProcess);
/* reload keys as needed for rendezvous services. */
@@ -1537,6 +1567,12 @@ options_act(const or_options_t *old_options)
return -1;
}
+ /* Set up scheduler thresholds */
+ scheduler_set_watermarks((uint32_t)options->SchedulerLowWaterMark__,
+ (uint32_t)options->SchedulerHighWaterMark__,
+ (options->SchedulerMaxFlushCells__ > 0) ?
+ options->SchedulerMaxFlushCells__ : 1000);
+
/* Set up accounting */
if (accounting_parse_options(options, 0)<0) {
log_warn(LD_CONFIG,"Error in accounting options");
@@ -1586,11 +1622,25 @@ options_act(const or_options_t *old_options)
}
if (parse_outbound_addresses(options, 0, &msg) < 0) {
- log_warn(LD_BUG, "Failed parsing oubound bind addresses: %s", msg);
+ log_warn(LD_BUG, "Failed parsing outbound bind addresses: %s", msg);
tor_free(msg);
return -1;
}
+ config_maybe_load_geoip_files_(options, old_options);
+
+ if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) {
+ /* ExcludeUnknown is true or "auto" */
+ const int is_auto = options->GeoIPExcludeUnknown == -1;
+ int changed;
+
+ changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto);
+ changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto);
+
+ if (changed)
+ routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto);
+ }
+
/* Check for transitions that need action. */
if (old_options) {
int revise_trackexithosts = 0;
@@ -1604,6 +1654,8 @@ options_act(const or_options_t *old_options)
options->ExcludeExitNodes) ||
!routerset_equal(old_options->EntryNodes, options->EntryNodes) ||
!routerset_equal(old_options->ExitNodes, options->ExitNodes) ||
+ !routerset_equal(old_options->Tor2webRendezvousPoints,
+ options->Tor2webRendezvousPoints) ||
options->StrictNodes != old_options->StrictNodes) {
log_info(LD_CIRC,
"Changed to using entry guards or bridges, or changed "
@@ -1669,11 +1721,12 @@ options_act(const or_options_t *old_options)
"Worker-related options changed. Rotating workers.");
if (server_mode(options) && !server_mode(old_options)) {
+ cpu_init();
ip_address_changed(0);
- if (can_complete_circuit || !any_predicted_circuits(time(NULL)))
+ if (have_completed_a_circuit() || !any_predicted_circuits(time(NULL)))
inform_testing_reachability();
}
- cpuworkers_rotate();
+ cpuworkers_rotate_keyinfo();
if (dns_reset())
return -1;
} else {
@@ -1686,36 +1739,23 @@ options_act(const or_options_t *old_options)
connection_or_update_token_buckets(get_connection_array(), options);
}
- config_maybe_load_geoip_files_(options, old_options);
-
- if (geoip_is_loaded(AF_INET) && options->GeoIPExcludeUnknown) {
- /* ExcludeUnknown is true or "auto" */
- const int is_auto = options->GeoIPExcludeUnknown == -1;
- int changed;
-
- changed = routerset_add_unknown_ccs(&options->ExcludeNodes, is_auto);
- changed += routerset_add_unknown_ccs(&options->ExcludeExitNodes, is_auto);
-
- if (changed)
- routerset_add_unknown_ccs(&options->ExcludeExitNodesUnion_, is_auto);
- }
+ /* Only collect directory-request statistics on relays and bridges. */
+ options->DirReqStatistics = options->DirReqStatistics_option &&
+ server_mode(options);
if (options->CellStatistics || options->DirReqStatistics ||
options->EntryStatistics || options->ExitPortStatistics ||
options->ConnDirectionStatistics ||
+ options->HiddenServiceStatistics ||
options->BridgeAuthoritativeDir) {
time_t now = time(NULL);
int print_notice = 0;
- /* Only collect directory-request statistics on relays and bridges. */
- if (!server_mode(options)) {
- options->DirReqStatistics = 0;
- }
-
/* Only collect other relay-only statistics on relays. */
if (!public_server_mode(options)) {
options->CellStatistics = 0;
options->EntryStatistics = 0;
+ options->HiddenServiceStatistics = 0;
options->ExitPortStatistics = 0;
}
@@ -1730,8 +1770,8 @@ options_act(const or_options_t *old_options)
geoip_dirreq_stats_init(now);
print_notice = 1;
} else {
+ /* disable statistics collection since we have no geoip file */
options->DirReqStatistics = 0;
- /* Don't warn Tor clients, they don't use statistics */
if (options->ORPort_set)
log_notice(LD_CONFIG, "Configured to measure directory request "
"statistics, but no GeoIP database found. "
@@ -1761,6 +1801,11 @@ options_act(const or_options_t *old_options)
options->ConnDirectionStatistics) {
rep_hist_conn_stats_init(now);
}
+ if ((!old_options || !old_options->HiddenServiceStatistics) &&
+ options->HiddenServiceStatistics) {
+ log_info(LD_CONFIG, "Configured to measure hidden service statistics.");
+ rep_hist_hs_stats_init(now);
+ }
if ((!old_options || !old_options->BridgeAuthoritativeDir) &&
options->BridgeAuthoritativeDir) {
rep_hist_desc_stats_init(now);
@@ -1772,6 +1817,8 @@ options_act(const or_options_t *old_options)
"data directory in 24 hours from now.");
}
+ /* If we used to have statistics enabled but we just disabled them,
+ stop gathering them. */
if (old_options && old_options->CellStatistics &&
!options->CellStatistics)
rep_hist_buffer_stats_term();
@@ -1781,6 +1828,9 @@ options_act(const or_options_t *old_options)
if (old_options && old_options->EntryStatistics &&
!options->EntryStatistics)
geoip_entry_stats_term();
+ if (old_options && old_options->HiddenServiceStatistics &&
+ !options->HiddenServiceStatistics)
+ rep_hist_hs_stats_term();
if (old_options && old_options->ExitPortStatistics &&
!options->ExitPortStatistics)
rep_hist_exit_stats_term();
@@ -1813,7 +1863,7 @@ options_act(const or_options_t *old_options)
directory_fetches_dir_info_early(old_options)) ||
!bool_eq(directory_fetches_dir_info_later(options),
directory_fetches_dir_info_later(old_options))) {
- /* Make sure update_router_have_min_dir_info gets called. */
+ /* Make sure update_router_have_minimum_dir_info() gets called. */
router_dir_info_changed();
/* We might need to download a new consensus status later or sooner than
* we had expected. */
@@ -2027,7 +2077,7 @@ print_usage(void)
printf(
"Copyright (c) 2001-2004, Roger Dingledine\n"
"Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n"
-"Copyright (c) 2007-2013, The Tor Project, Inc.\n\n"
+"Copyright (c) 2007-2015, The Tor Project, Inc.\n\n"
"tor -f <torrc> [args]\n"
"See man page for options, or https://www.torproject.org/ for "
"documentation.\n");
@@ -2059,8 +2109,41 @@ get_last_resolved_addr(void)
return last_resolved_addr;
}
+/** Reset last_resolved_addr from outside this file. */
+void
+reset_last_resolved_addr(void)
+{
+ last_resolved_addr = 0;
+}
+
/**
- * Use <b>options-\>Address</b> to guess our public IP address.
+ * Attempt getting our non-local (as judged by tor_addr_is_internal()
+ * function) IP address using following techniques, listed in
+ * order from best (most desirable, try first) to worst (least
+ * desirable, try if everything else fails).
+ *
+ * First, attempt using <b>options-\>Address</b> to get our
+ * non-local IP address.
+ *
+ * If <b>options-\>Address</b> represents a non-local IP address,
+ * consider it ours.
+ *
+ * If <b>options-\>Address</b> is a DNS name that resolves to
+ * a non-local IP address, consider this IP address ours.
+ *
+ * If <b>options-\>Address</b> is NULL, fall back to getting local
+ * hostname and using it in above-described ways to try and
+ * get our IP address.
+ *
+ * In case local hostname cannot be resolved to a non-local IP
+ * address, try getting an IP address of network interface
+ * in hopes it will be non-local one.
+ *
+ * Fail if one or more of the following is true:
+ * - DNS name in <b>options-\>Address</b> cannot be resolved.
+ * - <b>options-\>Address</b> is a local host address.
+ * - Attempt to getting local hostname fails.
+ * - Attempt to getting network interface address fails.
*
* Return 0 if all is well, or -1 if we can't find a suitable
* public IP address.
@@ -2069,6 +2152,11 @@ get_last_resolved_addr(void)
* - Put our public IP address (in host order) into *<b>addr_out</b>.
* - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
* string describing how we arrived at our answer.
+ * - "CONFIGURED" - parsed from IP address string in
+ * <b>options-\>Address</b>
+ * - "RESOLVED" - resolved from DNS name in <b>options-\>Address</b>
+ * - "GETHOSTNAME" - resolved from a local hostname.
+ * - "INTERFACE" - retrieved from a network interface.
* - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
* get our address, set *<b>hostname_out</b> to a newly allocated string
* holding that hostname. (If we didn't get our address by resolving a
@@ -2107,7 +2195,7 @@ resolve_my_address(int warn_severity, const or_options_t *options,
explicit_ip = 0; /* it's implicit */
explicit_hostname = 0; /* it's implicit */
- if (gethostname(hostname, sizeof(hostname)) < 0) {
+ if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
return -1;
}
@@ -2274,8 +2362,8 @@ resolve_my_address(int warn_severity, const or_options_t *options,
/** Return true iff <b>addr</b> is judged to be on the same network as us, or
* on a private network.
*/
-int
-is_local_addr(const tor_addr_t *addr)
+MOCK_IMPL(int,
+is_local_addr, (const tor_addr_t *addr))
{
if (tor_addr_is_internal(addr, 0))
return 1;
@@ -2434,6 +2522,7 @@ compute_publishserverdescriptor(or_options_t *options)
/** Lowest allowable value for RendPostPeriod; if this is too low, hidden
* services can overload the directory system. */
#define MIN_REND_POST_PERIOD (10*60)
+#define MIN_REND_POST_PERIOD_TESTING (5)
/** Higest allowable value for PredictedPortsRelevanceTime; if this is
* too high, our selection of exits will decrease for an extended
@@ -2547,7 +2636,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
config_line_append(&options->Logs, "Log", "warn stdout");
}
- if (options_init_logs(options, 1)<0) /* Validate the tor_log(s) */
+ /* Validate the tor_log(s) */
+ if (options_init_logs(old_options, options, 1)<0)
REJECT("Failed to validate Log options. See logs for details.");
if (authdir_mode(options)) {
@@ -2557,11 +2647,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("Failed to resolve/guess local address. See logs for details.");
}
-#ifndef _WIN32
- if (options->RunAsDaemon && torrc_fname && path_is_relative(torrc_fname))
- REJECT("Can't use a relative path to torrc when RunAsDaemon is set.");
-#endif
-
if (server_mode(options) && options->RendConfigLines)
log_warn(LD_CONFIG,
"Tor is currently configured as a relay and a hidden service. "
@@ -2583,20 +2668,24 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (!strcasecmp(options->TransProxyType, "default")) {
options->TransProxyType_parsed = TPT_DEFAULT;
} else if (!strcasecmp(options->TransProxyType, "pf-divert")) {
-#ifndef __OpenBSD__
- REJECT("pf-divert is a OpenBSD-specific feature.");
+#if !defined(__OpenBSD__) && !defined( DARWIN )
+ /* Later versions of OS X have pf */
+ REJECT("pf-divert is a OpenBSD-specific "
+ "and OS X/Darwin-specific feature.");
#else
options->TransProxyType_parsed = TPT_PF_DIVERT;
#endif
} else if (!strcasecmp(options->TransProxyType, "tproxy")) {
-#ifndef __linux__
+#if !defined(__linux__)
REJECT("TPROXY is a Linux-specific feature.");
#else
options->TransProxyType_parsed = TPT_TPROXY;
#endif
} else if (!strcasecmp(options->TransProxyType, "ipfw")) {
-#ifndef __FreeBSD__
- REJECT("ipfw is a FreeBSD-specific feature.");
+#if !defined(__FreeBSD__) && !defined( DARWIN )
+ /* Earlier versions of OS X have ipfw */
+ REJECT("ipfw is a FreeBSD-specific"
+ "and OS X/Darwin-specific feature.");
#else
options->TransProxyType_parsed = TPT_IPFW;
#endif
@@ -2627,6 +2716,17 @@ options_validate(or_options_t *old_options, or_options_t *options,
routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeNodes);
}
+ if (options->SchedulerLowWaterMark__ == 0 ||
+ options->SchedulerLowWaterMark__ > UINT32_MAX) {
+ log_warn(LD_GENERAL, "Bad SchedulerLowWaterMark__ option");
+ return -1;
+ } else if (options->SchedulerHighWaterMark__ <=
+ options->SchedulerLowWaterMark__ ||
+ options->SchedulerHighWaterMark__ > UINT32_MAX) {
+ log_warn(LD_GENERAL, "Bad SchedulerHighWaterMark option");
+ return -1;
+ }
+
if (options->NodeFamilies) {
options->NodeFamilySets = smartlist_new();
for (cl = options->NodeFamilies; cl; cl = cl->next) {
@@ -2651,6 +2751,13 @@ options_validate(or_options_t *old_options, or_options_t *options,
"features to be broken in unpredictable ways.");
}
+ for (cl = options->RecommendedPackages; cl; cl = cl->next) {
+ if (! validate_recommended_package_line(cl->value)) {
+ log_warn(LD_CONFIG, "Invalid RecommendedPackage line %s will be ignored",
+ escaped(cl->value));
+ }
+ }
+
if (options->AuthoritativeDir) {
if (!options->ContactInfo && !options->TestingTorNetwork)
REJECT("Authoritative directory servers must set ContactInfo");
@@ -2683,6 +2790,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->V3BandwidthsFile && !old_options) {
dirserv_read_measured_bandwidths(options->V3BandwidthsFile, NULL);
}
+ /* same for guardfraction file */
+ if (options->GuardfractionFile && !old_options) {
+ dirserv_read_guardfraction_file(options->GuardfractionFile, NULL);
+ }
}
if (options->AuthoritativeDir && !options->DirPort_set)
@@ -2837,6 +2948,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->MaxMemInQueues =
compute_real_max_mem_in_queues(options->MaxMemInQueues_raw,
server_mode(options));
+ options->MaxMemInQueues_low_threshold = (options->MaxMemInQueues / 4) * 3;
options->AllowInvalid_ = 0;
@@ -2901,10 +3013,13 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->MinUptimeHidServDirectoryV2 = 0;
}
- if (options->RendPostPeriod < MIN_REND_POST_PERIOD) {
+ const int min_rendpostperiod =
+ options->TestingTorNetwork ?
+ MIN_REND_POST_PERIOD_TESTING : MIN_REND_POST_PERIOD;
+ if (options->RendPostPeriod < min_rendpostperiod) {
log_warn(LD_CONFIG, "RendPostPeriod option is too short; "
- "raising to %d seconds.", MIN_REND_POST_PERIOD);
- options->RendPostPeriod = MIN_REND_POST_PERIOD;
+ "raising to %d seconds.", min_rendpostperiod);
+ options->RendPostPeriod = min_rendpostperiod;;
}
if (options->RendPostPeriod > MAX_DIR_PERIOD) {
@@ -2920,6 +3035,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->PredictedPortsRelevanceTime = MAX_PREDICTED_CIRCS_RELEVANCE;
}
+#ifdef ENABLE_TOR2WEB_MODE
if (options->Tor2webMode && options->LearnCircuitBuildTimeout) {
/* LearnCircuitBuildTimeout and Tor2webMode are incompatible in
* two ways:
@@ -2951,6 +3067,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
"Tor2WebMode is enabled; disabling UseEntryGuards.");
options->UseEntryGuards = 0;
}
+#endif
+
+ if (options->Tor2webRendezvousPoints && !options->Tor2webMode) {
+ REJECT("Tor2webRendezvousPoints cannot be set without Tor2webMode.");
+ }
if (!(options->UseEntryGuards) &&
(options->RendConfigLines != NULL)) {
@@ -3075,29 +3196,34 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->RelayBandwidthRate = options->RelayBandwidthBurst;
if (server_mode(options)) {
- if (options->BandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) {
+ const unsigned required_min_bw =
+ public_server_mode(options) ?
+ RELAY_REQUIRED_MIN_BANDWIDTH : BRIDGE_REQUIRED_MIN_BANDWIDTH;
+ const char * const optbridge =
+ public_server_mode(options) ? "" : "bridge ";
+ if (options->BandwidthRate < required_min_bw) {
tor_asprintf(msg,
"BandwidthRate is set to %d bytes/second. "
- "For servers, it must be at least %d.",
- (int)options->BandwidthRate,
- ROUTER_REQUIRED_MIN_BANDWIDTH);
+ "For %sservers, it must be at least %u.",
+ (int)options->BandwidthRate, optbridge,
+ required_min_bw);
return -1;
} else if (options->MaxAdvertisedBandwidth <
- ROUTER_REQUIRED_MIN_BANDWIDTH/2) {
+ required_min_bw/2) {
tor_asprintf(msg,
"MaxAdvertisedBandwidth is set to %d bytes/second. "
- "For servers, it must be at least %d.",
- (int)options->MaxAdvertisedBandwidth,
- ROUTER_REQUIRED_MIN_BANDWIDTH/2);
+ "For %sservers, it must be at least %u.",
+ (int)options->MaxAdvertisedBandwidth, optbridge,
+ required_min_bw/2);
return -1;
}
if (options->RelayBandwidthRate &&
- options->RelayBandwidthRate < ROUTER_REQUIRED_MIN_BANDWIDTH) {
+ options->RelayBandwidthRate < required_min_bw) {
tor_asprintf(msg,
"RelayBandwidthRate is set to %d bytes/second. "
- "For servers, it must be at least %d.",
- (int)options->RelayBandwidthRate,
- ROUTER_REQUIRED_MIN_BANDWIDTH);
+ "For %sservers, it must be at least %u.",
+ (int)options->RelayBandwidthRate, optbridge,
+ required_min_bw);
return -1;
}
}
@@ -3133,6 +3259,16 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
+ options->AccountingRule = ACCT_MAX;
+ if (options->AccountingRule_option) {
+ if (!strcmp(options->AccountingRule_option, "sum"))
+ options->AccountingRule = ACCT_SUM;
+ else if (!strcmp(options->AccountingRule_option, "max"))
+ options->AccountingRule = ACCT_MAX;
+ else
+ REJECT("AccountingRule must be 'sum' or 'max'");
+ }
+
if (options->HTTPProxy) { /* parse it now */
if (tor_addr_port_lookup(options->HTTPProxy,
&options->HTTPProxyAddr, &options->HTTPProxyPort) < 0)
@@ -3181,11 +3317,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
}
- /* Check if more than one proxy type has been enabled. */
+ /* Check if more than one exclusive proxy type has been enabled. */
if (!!options->Socks4Proxy + !!options->Socks5Proxy +
- !!options->HTTPSProxy + !!options->ClientTransportPlugin > 1)
+ !!options->HTTPSProxy > 1)
REJECT("You have configured more than one proxy type. "
- "(Socks4Proxy|Socks5Proxy|HTTPSProxy|ClientTransportPlugin)");
+ "(Socks4Proxy|Socks5Proxy|HTTPSProxy)");
/* Check if the proxies will give surprising behavior. */
if (options->HTTPProxy && !(options->Socks4Proxy ||
@@ -3293,12 +3429,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
}
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
- if (parse_client_transport_line(options, cl->value, 1)<0)
+ if (parse_transport_line(options, cl->value, 1, 0) < 0)
REJECT("Invalid client transport line. See logs for details.");
}
for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
- if (parse_server_transport_line(options, cl->value, 1)<0)
+ if (parse_transport_line(options, cl->value, 1, 1) < 0)
REJECT("Invalid server transport line. See logs for details.");
}
@@ -3362,19 +3498,68 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
options->V3AuthVotingInterval/2) {
- REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
- "V3AuthVotingInterval");
+ /*
+ This doesn't work, but it seems like it should:
+ what code is preventing the interval being less than twice the lead-up?
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthVoteDelay + options->V3AuthDistDelay >=
+ options->V3AuthVotingInterval) {
+ REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than "
+ "V3AuthVotingInterval");
+ } else {
+ COMPLAIN("V3AuthVoteDelay plus V3AuthDistDelay is more than half "
+ "V3AuthVotingInterval. This may lead to "
+ "consensus instability, particularly if clocks drift.");
+ }
+ } else {
+ */
+ REJECT("V3AuthVoteDelay plus V3AuthDistDelay must be less than half "
+ "V3AuthVotingInterval");
+ /*
+ }
+ */
+ }
+
+ if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS) {
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS_TESTING) {
+ REJECT("V3AuthVoteDelay is way too low.");
+ } else {
+ COMPLAIN("V3AuthVoteDelay is very low. "
+ "This may lead to failure to vote for a consensus.");
+ }
+ } else {
+ REJECT("V3AuthVoteDelay is way too low.");
+ }
+ }
+
+ if (options->V3AuthDistDelay < MIN_DIST_SECONDS) {
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthDistDelay < MIN_DIST_SECONDS_TESTING) {
+ REJECT("V3AuthDistDelay is way too low.");
+ } else {
+ COMPLAIN("V3AuthDistDelay is very low. "
+ "This may lead to missing votes in a consensus.");
+ }
+ } else {
+ REJECT("V3AuthDistDelay is way too low.");
+ }
}
- if (options->V3AuthVoteDelay < MIN_VOTE_SECONDS)
- REJECT("V3AuthVoteDelay is way too low.");
- if (options->V3AuthDistDelay < MIN_DIST_SECONDS)
- REJECT("V3AuthDistDelay is way too low.");
if (options->V3AuthNIntervalsValid < 2)
REJECT("V3AuthNIntervalsValid must be at least 2.");
if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL) {
- REJECT("V3AuthVotingInterval is insanely low.");
+ if (options->TestingTorNetwork) {
+ if (options->V3AuthVotingInterval < MIN_VOTE_INTERVAL_TESTING) {
+ REJECT("V3AuthVotingInterval is insanely low.");
+ } else {
+ COMPLAIN("V3AuthVotingInterval is very low. "
+ "This may lead to failure to synchronise for a consensus.");
+ }
+ } else {
+ REJECT("V3AuthVotingInterval is insanely low.");
+ }
} else if (options->V3AuthVotingInterval > 24*60*60) {
REJECT("V3AuthVotingInterval is insanely high.");
} else if (((24*60*60) % options->V3AuthVotingInterval) != 0) {
@@ -3396,15 +3581,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
AF_INET6, 1, msg)<0)
return -1;
- if (options->AutomapHostsSuffixes) {
- SMARTLIST_FOREACH(options->AutomapHostsSuffixes, char *, suf,
- {
- size_t len = strlen(suf);
- if (len && suf[len-1] == '.')
- suf[len-1] = '\0';
- });
- }
-
if (options->TestingTorNetwork &&
!(options->DirAuthorities ||
(options->AlternateDirAuthority &&
@@ -3449,26 +3625,27 @@ options_validate(or_options_t *old_options, or_options_t *options,
CHECK_DEFAULT(TestingCertMaxDownloadTries);
#undef CHECK_DEFAULT
- if (options->TestingV3AuthInitialVotingInterval < MIN_VOTE_INTERVAL) {
+ if (options->TestingV3AuthInitialVotingInterval
+ < MIN_VOTE_INTERVAL_TESTING_INITIAL) {
REJECT("TestingV3AuthInitialVotingInterval is insanely low.");
} else if (((30*60) % options->TestingV3AuthInitialVotingInterval) != 0) {
REJECT("TestingV3AuthInitialVotingInterval does not divide evenly into "
"30 minutes.");
}
- if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS) {
+ if (options->TestingV3AuthInitialVoteDelay < MIN_VOTE_SECONDS_TESTING) {
REJECT("TestingV3AuthInitialVoteDelay is way too low.");
}
- if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS) {
+ if (options->TestingV3AuthInitialDistDelay < MIN_DIST_SECONDS_TESTING) {
REJECT("TestingV3AuthInitialDistDelay is way too low.");
}
if (options->TestingV3AuthInitialVoteDelay +
options->TestingV3AuthInitialDistDelay >=
- options->TestingV3AuthInitialVotingInterval/2) {
+ options->TestingV3AuthInitialVotingInterval) {
REJECT("TestingV3AuthInitialVoteDelay plus TestingV3AuthInitialDistDelay "
- "must be less than half TestingV3AuthInitialVotingInterval");
+ "must be less than TestingV3AuthInitialVotingInterval");
}
if (options->TestingV3AuthVotingStartOffset >
@@ -3476,6 +3653,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
options->V3AuthVotingInterval)) {
REJECT("TestingV3AuthVotingStartOffset is higher than the voting "
"interval.");
+ } else if (options->TestingV3AuthVotingStartOffset < 0) {
+ REJECT("TestingV3AuthVotingStartOffset must be non-negative.");
}
if (options->TestingAuthDirTimeToLearnReachability < 0) {
@@ -3796,6 +3975,7 @@ options_transition_affects_descriptor(const or_options_t *old_options,
!opt_streq(old_options->Nickname,new_options->Nickname) ||
!opt_streq(old_options->Address,new_options->Address) ||
!config_lines_eq(old_options->ExitPolicy,new_options->ExitPolicy) ||
+ old_options->ExitRelay != new_options->ExitRelay ||
old_options->ExitPolicyRejectPrivate !=
new_options->ExitPolicyRejectPrivate ||
old_options->IPv6Exit != new_options->IPv6Exit ||
@@ -3884,7 +4064,10 @@ get_windows_conf_root(void)
static const char *
get_default_conf_file(int defaults_file)
{
-#ifdef _WIN32
+#ifdef DISABLE_SYSTEM_TORRC
+ (void) defaults_file;
+ return NULL;
+#elif defined(_WIN32)
if (defaults_file) {
static char defaults_path[MAX_PATH+1];
tor_snprintf(defaults_path, MAX_PATH, "%s\\torrc-defaults",
@@ -4011,27 +4194,45 @@ find_torrc_filename(config_line_t *cmd_arg,
if (*using_default_fname) {
/* didn't find one, try CONFDIR */
const char *dflt = get_default_conf_file(defaults_file);
- if (dflt && file_status(dflt) == FN_FILE) {
+ file_status_t st = file_status(dflt);
+ if (dflt && (st == FN_FILE || st == FN_EMPTY)) {
fname = tor_strdup(dflt);
} else {
#ifndef _WIN32
char *fn = NULL;
- if (!defaults_file)
+ if (!defaults_file) {
fn = expand_filename("~/.torrc");
- if (fn && file_status(fn) == FN_FILE) {
- fname = fn;
+ }
+ if (fn) {
+ file_status_t hmst = file_status(fn);
+ if (hmst == FN_FILE || hmst == FN_EMPTY || dflt == NULL) {
+ fname = fn;
+ } else {
+ tor_free(fn);
+ fname = tor_strdup(dflt);
+ }
} else {
- tor_free(fn);
- fname = tor_strdup(dflt);
+ fname = dflt ? tor_strdup(dflt) : NULL;
}
#else
- fname = tor_strdup(dflt);
+ fname = dflt ? tor_strdup(dflt) : NULL;
#endif
}
}
return fname;
}
+/** Read the torrc from standard input and return it as a string.
+ * Upon failure, return NULL.
+ */
+static char *
+load_torrc_from_stdin(void)
+{
+ size_t sz_out;
+
+ return read_file_to_str_until_eof(STDIN_FILENO,SIZE_MAX,&sz_out);
+}
+
/** Load a configuration file from disk, setting torrc_fname or
* torrc_defaults_fname if successful.
*
@@ -4048,16 +4249,20 @@ load_torrc_from_disk(config_line_t *cmd_arg, int defaults_file)
int ignore_missing_torrc = 0;
char **fname_var = defaults_file ? &torrc_defaults_fname : &torrc_fname;
- fname = find_torrc_filename(cmd_arg, defaults_file,
- &using_default_torrc, &ignore_missing_torrc);
- tor_assert(fname);
- log_debug(LD_CONFIG, "Opening config file \"%s\"", fname);
-
- tor_free(*fname_var);
- *fname_var = fname;
+ if (*fname_var == NULL) {
+ fname = find_torrc_filename(cmd_arg, defaults_file,
+ &using_default_torrc, &ignore_missing_torrc);
+ tor_free(*fname_var);
+ *fname_var = fname;
+ } else {
+ fname = *fname_var;
+ }
+ log_debug(LD_CONFIG, "Opening config file \"%s\"", fname?fname:"<NULL>");
/* Open config file */
- if (file_status(fname) != FN_FILE ||
+ file_status_t st = fname ? file_status(fname) : FN_EMPTY;
+ if (fname == NULL ||
+ !(st == FN_FILE || st == FN_EMPTY) ||
!(cf = read_file_to_str(fname,0,NULL))) {
if (using_default_torrc == 1 || ignore_missing_torrc) {
if (!defaults_file)
@@ -4168,7 +4373,19 @@ options_init_from_torrc(int argc, char **argv)
cf = tor_strdup("");
} else {
cf_defaults = load_torrc_from_disk(cmdline_only_options, 1);
- cf = load_torrc_from_disk(cmdline_only_options, 0);
+
+ const config_line_t *f_line = config_line_find(cmdline_only_options,
+ "-f");
+
+ const int read_torrc_from_stdin =
+ (f_line != NULL && strcmp(f_line->value, "-") == 0);
+
+ if (read_torrc_from_stdin) {
+ cf = load_torrc_from_stdin();
+ } else {
+ cf = load_torrc_from_disk(cmdline_only_options, 0);
+ }
+
if (!cf) {
if (config_line_find(cmdline_only_options, "--allow-missing-torrc")) {
cf = tor_strdup("");
@@ -4346,7 +4563,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
return err;
}
-/** Return the location for our configuration file.
+/** Return the location for our configuration file. May return NULL.
*/
const char *
get_torrc_fname(int defaults_fname)
@@ -4453,7 +4670,8 @@ addressmap_register_auto(const char *from, const char *to,
* Initialize the logs based on the configuration file.
*/
static int
-options_init_logs(or_options_t *options, int validate_only)
+options_init_logs(const or_options_t *old_options, or_options_t *options,
+ int validate_only)
{
config_line_t *opt;
int ok;
@@ -4546,7 +4764,21 @@ options_init_logs(or_options_t *options, int validate_only)
!strcasecmp(smartlist_get(elts,0), "file")) {
if (!validate_only) {
char *fname = expand_filename(smartlist_get(elts, 1));
- if (add_file_log(severity, fname) < 0) {
+ /* Truncate if TruncateLogFile is set and we haven't seen this option
+ line before. */
+ int truncate = 0;
+ if (options->TruncateLogFile) {
+ truncate = 1;
+ if (old_options) {
+ config_line_t *opt2;
+ for (opt2 = old_options->Logs; opt2; opt2 = opt2->next)
+ if (!strcmp(opt->value, opt2->value)) {
+ truncate = 0;
+ break;
+ }
+ }
+ }
+ if (add_file_log(severity, fname, truncate) < 0) {
log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s",
opt->value, strerror(errno));
ok = 0;
@@ -4739,46 +4971,52 @@ parse_bridge_line(const char *line)
return bridge_line;
}
-/** Read the contents of a ClientTransportPlugin line from
- * <b>line</b>. Return 0 if the line is well-formed, and -1 if it
- * isn't.
+/** Read the contents of a ClientTransportPlugin or ServerTransportPlugin
+ * line from <b>line</b>, depending on the value of <b>server</b>. Return 0
+ * if the line is well-formed, and -1 if it isn't.
*
- * If <b>validate_only</b> is 0, the line is well-formed, and the
- * transport is needed by some bridge:
+ * If <b>validate_only</b> is 0, the line is well-formed, and the transport is
+ * needed by some bridge:
* - If it's an external proxy line, add the transport described in the line to
* our internal transport list.
- * - If it's a managed proxy line, launch the managed proxy. */
-static int
-parse_client_transport_line(const or_options_t *options,
- const char *line, int validate_only)
+ * - If it's a managed proxy line, launch the managed proxy.
+ */
+
+STATIC int
+parse_transport_line(const or_options_t *options,
+ const char *line, int validate_only,
+ int server)
{
+
smartlist_t *items = NULL;
int r;
- char *field2=NULL;
-
- const char *transports=NULL;
- smartlist_t *transport_list=NULL;
- char *addrport=NULL;
+ const char *transports = NULL;
+ smartlist_t *transport_list = NULL;
+ char *type = NULL;
+ char *addrport = NULL;
tor_addr_t addr;
uint16_t port = 0;
- int socks_ver=PROXY_NONE;
+ int socks_ver = PROXY_NONE;
/* managed proxy options */
- int is_managed=0;
- char **proxy_argv=NULL;
- char **tmp=NULL;
+ int is_managed = 0;
+ char **proxy_argv = NULL;
+ char **tmp = NULL;
int proxy_argc, i;
- int is_useless_proxy=1;
+ int is_useless_proxy = 1;
int line_length;
+ /* Split the line into space-separated tokens */
items = smartlist_new();
smartlist_split_string(items, line, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+ line_length = smartlist_len(items);
- line_length = smartlist_len(items);
if (line_length < 3) {
- log_warn(LD_CONFIG, "Too few arguments on ClientTransportPlugin line.");
+ log_warn(LD_CONFIG,
+ "Too few arguments on %sTransportPlugin line.",
+ server ? "Server" : "Client");
goto err;
}
@@ -4802,64 +5040,97 @@ parse_client_transport_line(const or_options_t *options,
is_useless_proxy = 0;
} SMARTLIST_FOREACH_END(transport_name);
- /* field2 is either a SOCKS version or "exec" */
- field2 = smartlist_get(items, 1);
-
- if (!strcmp(field2,"socks4")) {
+ type = smartlist_get(items, 1);
+ if (!strcmp(type, "exec")) {
+ is_managed = 1;
+ } else if (server && !strcmp(type, "proxy")) {
+ /* 'proxy' syntax only with ServerTransportPlugin */
+ is_managed = 0;
+ } else if (!server && !strcmp(type, "socks4")) {
+ /* 'socks4' syntax only with ClientTransportPlugin */
+ is_managed = 0;
socks_ver = PROXY_SOCKS4;
- } else if (!strcmp(field2,"socks5")) {
+ } else if (!server && !strcmp(type, "socks5")) {
+ /* 'socks5' syntax only with ClientTransportPlugin */
+ is_managed = 0;
socks_ver = PROXY_SOCKS5;
- } else if (!strcmp(field2,"exec")) {
- is_managed=1;
} else {
- log_warn(LD_CONFIG, "Strange ClientTransportPlugin field '%s'.",
- field2);
+ log_warn(LD_CONFIG,
+ "Strange %sTransportPlugin type '%s'",
+ server ? "Server" : "Client", type);
goto err;
}
if (is_managed && options->Sandbox) {
- log_warn(LD_CONFIG, "Managed proxies are not compatible with Sandbox mode."
- "(ClientTransportPlugin line was %s)", escaped(line));
+ log_warn(LD_CONFIG,
+ "Managed proxies are not compatible with Sandbox mode."
+ "(%sTransportPlugin line was %s)",
+ server ? "Server" : "Client", escaped(line));
goto err;
}
- if (is_managed) { /* managed */
- if (!validate_only && is_useless_proxy) {
- log_info(LD_GENERAL, "Pluggable transport proxy (%s) does not provide "
- "any needed transports and will not be launched.", line);
+ if (is_managed) {
+ /* managed */
+
+ if (!server && !validate_only && is_useless_proxy) {
+ log_info(LD_GENERAL,
+ "Pluggable transport proxy (%s) does not provide "
+ "any needed transports and will not be launched.",
+ line);
}
- /* If we are not just validating, use the rest of the line as the
- argv of the proxy to be launched. Also, make sure that we are
- only launching proxies that contribute useful transports. */
- if (!validate_only && !is_useless_proxy) {
- proxy_argc = line_length-2;
+ /*
+ * If we are not just validating, use the rest of the line as the
+ * argv of the proxy to be launched. Also, make sure that we are
+ * only launching proxies that contribute useful transports.
+ */
+
+ if (!validate_only && (server || !is_useless_proxy)) {
+ proxy_argc = line_length - 2;
tor_assert(proxy_argc > 0);
- proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1));
+ proxy_argv = tor_calloc((proxy_argc + 1), sizeof(char *));
tmp = proxy_argv;
- for (i=0;i<proxy_argc;i++) { /* store arguments */
+
+ for (i = 0; i < proxy_argc; i++) {
+ /* store arguments */
*tmp++ = smartlist_get(items, 2);
smartlist_del_keeporder(items, 2);
}
- *tmp = NULL; /*terminated with NULL, just like execve() likes it*/
+ *tmp = NULL; /* terminated with NULL, just like execve() likes it */
/* kickstart the thing */
- pt_kickstart_client_proxy(transport_list, proxy_argv);
+ if (server) {
+ pt_kickstart_server_proxy(transport_list, proxy_argv);
+ } else {
+ pt_kickstart_client_proxy(transport_list, proxy_argv);
+ }
}
- } else { /* external */
+ } else {
+ /* external */
+
+ /* ClientTransportPlugins connecting through a proxy is managed only. */
+ if (!server && (options->Socks4Proxy || options->Socks5Proxy ||
+ options->HTTPSProxy)) {
+ log_warn(LD_CONFIG, "You have configured an external proxy with another "
+ "proxy type. (Socks4Proxy|Socks5Proxy|HTTPSProxy)");
+ goto err;
+ }
+
if (smartlist_len(transport_list) != 1) {
- log_warn(LD_CONFIG, "You can't have an external proxy with "
- "more than one transports.");
+ log_warn(LD_CONFIG,
+ "You can't have an external proxy with more than "
+ "one transport.");
goto err;
}
addrport = smartlist_get(items, 2);
- if (tor_addr_port_lookup(addrport, &addr, &port)<0) {
- log_warn(LD_CONFIG, "Error parsing transport "
- "address '%s'", addrport);
+ if (tor_addr_port_lookup(addrport, &addr, &port) < 0) {
+ log_warn(LD_CONFIG,
+ "Error parsing transport address '%s'", addrport);
goto err;
}
+
if (!port) {
log_warn(LD_CONFIG,
"Transport address '%s' has no port.", addrport);
@@ -4867,11 +5138,15 @@ parse_client_transport_line(const or_options_t *options,
}
if (!validate_only) {
- transport_add_from_config(&addr, port, smartlist_get(transport_list, 0),
- socks_ver);
-
- log_info(LD_DIR, "Transport '%s' found at %s",
+ log_info(LD_DIR, "%s '%s' at %s.",
+ server ? "Server transport" : "Transport",
transports, fmt_addrport(&addr, port));
+
+ if (!server) {
+ transport_add_from_config(&addr, port,
+ smartlist_get(transport_list, 0),
+ socks_ver);
+ }
}
}
@@ -5043,138 +5318,12 @@ get_options_for_server_transport(const char *transport)
return NULL;
}
-/** Read the contents of a ServerTransportPlugin line from
- * <b>line</b>. Return 0 if the line is well-formed, and -1 if it
- * isn't.
- * If <b>validate_only</b> is 0, the line is well-formed, and it's a
- * managed proxy line, launch the managed proxy. */
-static int
-parse_server_transport_line(const or_options_t *options,
- const char *line, int validate_only)
-{
- smartlist_t *items = NULL;
- int r;
- const char *transports=NULL;
- smartlist_t *transport_list=NULL;
- char *type=NULL;
- char *addrport=NULL;
- tor_addr_t addr;
- uint16_t port = 0;
-
- /* managed proxy options */
- int is_managed=0;
- char **proxy_argv=NULL;
- char **tmp=NULL;
- int proxy_argc,i;
-
- int line_length;
-
- items = smartlist_new();
- smartlist_split_string(items, line, NULL,
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
-
- line_length = smartlist_len(items);
- if (line_length < 3) {
- log_warn(LD_CONFIG, "Too few arguments on ServerTransportPlugin line.");
- goto err;
- }
-
- /* Get the first line element, split it to commas into
- transport_list (in case it's multiple transports) and validate
- the transport names. */
- transports = smartlist_get(items, 0);
- transport_list = smartlist_new();
- smartlist_split_string(transport_list, transports, ",",
- SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) {
- if (!string_is_C_identifier(transport_name)) {
- log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
- transport_name);
- goto err;
- }
- } SMARTLIST_FOREACH_END(transport_name);
-
- type = smartlist_get(items, 1);
-
- if (!strcmp(type, "exec")) {
- is_managed=1;
- } else if (!strcmp(type, "proxy")) {
- is_managed=0;
- } else {
- log_warn(LD_CONFIG, "Strange ServerTransportPlugin type '%s'", type);
- goto err;
- }
-
- if (is_managed && options->Sandbox) {
- log_warn(LD_CONFIG, "Managed proxies are not compatible with Sandbox mode."
- "(ServerTransportPlugin line was %s)", escaped(line));
- goto err;
- }
-
- if (is_managed) { /* managed */
- if (!validate_only) {
- proxy_argc = line_length-2;
- tor_assert(proxy_argc > 0);
- proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1));
- tmp = proxy_argv;
-
- for (i=0;i<proxy_argc;i++) { /* store arguments */
- *tmp++ = smartlist_get(items, 2);
- smartlist_del_keeporder(items, 2);
- }
- *tmp = NULL; /*terminated with NULL, just like execve() likes it*/
-
- /* kickstart the thing */
- pt_kickstart_server_proxy(transport_list, proxy_argv);
- }
- } else { /* external */
- if (smartlist_len(transport_list) != 1) {
- log_warn(LD_CONFIG, "You can't have an external proxy with "
- "more than one transports.");
- goto err;
- }
-
- addrport = smartlist_get(items, 2);
-
- if (tor_addr_port_lookup(addrport, &addr, &port)<0) {
- log_warn(LD_CONFIG, "Error parsing transport "
- "address '%s'", addrport);
- goto err;
- }
- if (!port) {
- log_warn(LD_CONFIG,
- "Transport address '%s' has no port.", addrport);
- goto err;
- }
-
- if (!validate_only) {
- log_info(LD_DIR, "Server transport '%s' at %s.",
- transports, fmt_addrport(&addr, port));
- }
- }
-
- r = 0;
- goto done;
-
- err:
- r = -1;
-
- done:
- SMARTLIST_FOREACH(items, char*, s, tor_free(s));
- smartlist_free(items);
- if (transport_list) {
- SMARTLIST_FOREACH(transport_list, char*, s, tor_free(s));
- smartlist_free(transport_list);
- }
-
- return r;
-}
-
/** Read the contents of a DirAuthority line from <b>line</b>. If
* <b>validate_only</b> is 0, and the line is well-formed, and it
* shares any bits with <b>required_type</b> or <b>required_type</b>
- * is 0, then add the dirserver described in the line (minus whatever
- * bits it's missing) as a valid authority. Return 0 on success,
+ * is NO_DIRINFO (zero), then add the dirserver described in the line
+ * (minus whatever bits it's missing) as a valid authority.
+ * Return 0 on success or filtering out by type,
* or -1 if the line isn't well-formed or if we can't add it. */
static int
parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
@@ -5268,14 +5417,6 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
fingerprint, (int)strlen(fingerprint));
goto err;
}
- if (!strcmp(fingerprint, "E623F7625FBE0C87820F11EC5F6D5377ED816294")) {
- /* a known bad fingerprint. refuse to use it. We can remove this
- * clause once Tor 0.1.2.17 is obsolete. */
- log_warn(LD_CONFIG, "Dangerous dirserver line. To correct, erase your "
- "torrc file (%s), or reinstall Tor and use the default torrc.",
- get_torrc_fname(0));
- goto err;
- }
if (base16_decode(digest, DIGEST_LEN, fingerprint, HEX_DIGEST_LEN)<0) {
log_warn(LD_CONFIG, "Unable to decode DirAuthority key digest.");
goto err;
@@ -5405,12 +5546,13 @@ parse_dir_fallback_line(const char *line,
/** Allocate and return a new port_cfg_t with reasonable defaults. */
static port_cfg_t *
-port_cfg_new(void)
+port_cfg_new(size_t namelen)
{
- port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
- cfg->ipv4_traffic = 1;
- cfg->cache_ipv4_answers = 1;
- cfg->prefer_ipv6_virtaddr = 1;
+ tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1);
+ port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t) + namelen + 1);
+ cfg->entry_cfg.ipv4_traffic = 1;
+ cfg->entry_cfg.cache_ipv4_answers = 1;
+ cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
return cfg;
}
@@ -5517,6 +5659,56 @@ warn_nonlocal_controller_ports(smartlist_t *ports, unsigned forbid)
#define CL_PORT_SERVER_OPTIONS (1u<<3)
#define CL_PORT_FORBID_NONLOCAL (1u<<4)
#define CL_PORT_TAKES_HOSTNAMES (1u<<5)
+#define CL_PORT_IS_UNIXSOCKET (1u<<6)
+
+#ifdef HAVE_SYS_UN_H
+
+/** Parse the given <b>addrport</b> and set <b>path_out</b> if a Unix socket
+ * path is found. Return 0 on success. On error, a negative value is
+ * returned, -ENOENT if no Unix statement found, -EINVAL if the socket path
+ * is empty and -ENOSYS if AF_UNIX is not supported (see function in the
+ * #else statement below). */
+
+int
+config_parse_unix_port(const char *addrport, char **path_out)
+{
+ tor_assert(path_out);
+ tor_assert(addrport);
+
+ if (strcmpstart(addrport, unix_socket_prefix)) {
+ /* Not a Unix socket path. */
+ return -ENOENT;
+ }
+
+ if (strlen(addrport + strlen(unix_socket_prefix)) == 0) {
+ /* Empty socket path, not very usable. */
+ return -EINVAL;
+ }
+
+ *path_out = tor_strdup(addrport + strlen(unix_socket_prefix));
+ return 0;
+}
+
+#else /* defined(HAVE_SYS_UN_H) */
+
+int
+config_parse_unix_port(const char *addrport, char **path_out)
+{
+ tor_assert(path_out);
+ tor_assert(addrport);
+
+ if (strcmpstart(addrport, unix_socket_prefix)) {
+ /* Not a Unix socket path. */
+ return -ENOENT;
+ }
+
+ log_warn(LD_CONFIG,
+ "Port configuration %s is for an AF_UNIX socket, but we have no"
+ "support available on this platform",
+ escaped(addrport));
+ return -ENOSYS;
+}
+#endif /* defined(HAVE_SYS_UN_H) */
/**
* Parse port configuration for a single port type.
@@ -5564,7 +5756,7 @@ parse_port_config(smartlist_t *out,
int listener_type,
const char *defaultaddr,
int defaultport,
- unsigned flags)
+ const unsigned flags)
{
smartlist_t *elts;
int retval = -1;
@@ -5577,7 +5769,9 @@ parse_port_config(smartlist_t *out,
const unsigned allow_spurious_listenaddr =
flags & CL_PORT_ALLOW_EXTRA_LISTENADDR;
const unsigned takes_hostnames = flags & CL_PORT_TAKES_HOSTNAMES;
+ const unsigned is_unix_socket = flags & CL_PORT_IS_UNIXSOCKET;
int got_zero_port=0, got_nonzero_port=0;
+ char *unix_socket_path = NULL;
/* FooListenAddress is deprecated; let's make it work like it used to work,
* though. */
@@ -5613,14 +5807,14 @@ parse_port_config(smartlist_t *out,
if (use_server_options && out) {
/* Add a no_listen port. */
- port_cfg_t *cfg = port_cfg_new();
+ port_cfg_t *cfg = port_cfg_new(0);
cfg->type = listener_type;
cfg->port = mainport;
tor_addr_make_unspec(&cfg->addr); /* Server ports default to 0.0.0.0 */
- cfg->no_listen = 1;
- cfg->bind_ipv4_only = 1;
- cfg->ipv4_traffic = 1;
- cfg->prefer_ipv6_virtaddr = 1;
+ cfg->server_cfg.no_listen = 1;
+ cfg->server_cfg.bind_ipv4_only = 1;
+ cfg->entry_cfg.ipv4_traffic = 1;
+ cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
smartlist_add(out, cfg);
}
@@ -5633,13 +5827,13 @@ parse_port_config(smartlist_t *out,
return -1;
}
if (out) {
- port_cfg_t *cfg = port_cfg_new();
+ port_cfg_t *cfg = port_cfg_new(0);
cfg->type = listener_type;
cfg->port = port ? port : mainport;
tor_addr_copy(&cfg->addr, &addr);
- cfg->session_group = SESSION_GROUP_UNSET;
- cfg->isolation_flags = ISO_DEFAULT;
- cfg->no_advertise = 1;
+ cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
+ cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
+ cfg->server_cfg.no_advertise = 1;
smartlist_add(out, cfg);
}
}
@@ -5658,13 +5852,19 @@ parse_port_config(smartlist_t *out,
/* No ListenAddress lines. If there's no FooPort, then maybe make a default
* one. */
if (! ports) {
- if (defaultport && out) {
- port_cfg_t *cfg = port_cfg_new();
+ if (defaultport && defaultaddr && out) {
+ port_cfg_t *cfg = port_cfg_new(is_unix_socket ? strlen(defaultaddr) : 0);
cfg->type = listener_type;
- cfg->port = defaultport;
- tor_addr_parse(&cfg->addr, defaultaddr);
- cfg->session_group = SESSION_GROUP_UNSET;
- cfg->isolation_flags = ISO_DEFAULT;
+ if (is_unix_socket) {
+ tor_addr_make_unspec(&cfg->addr);
+ memcpy(cfg->unix_addr, defaultaddr, strlen(defaultaddr) + 1);
+ cfg->is_unix_addr = 1;
+ } else {
+ cfg->port = defaultport;
+ tor_addr_parse(&cfg->addr, defaultaddr);
+ }
+ cfg->entry_cfg.session_group = SESSION_GROUP_UNSET;
+ cfg->entry_cfg.isolation_flags = ISO_DEFAULT;
smartlist_add(out, cfg);
}
return 0;
@@ -5676,7 +5876,7 @@ parse_port_config(smartlist_t *out,
for (; ports; ports = ports->next) {
tor_addr_t addr;
- int port;
+ int port, ret;
int sessiongroup = SESSION_GROUP_UNSET;
unsigned isolation = ISO_DEFAULT;
int prefer_no_auth = 0;
@@ -5705,7 +5905,31 @@ parse_port_config(smartlist_t *out,
/* Now parse the addr/port value */
addrport = smartlist_get(elts, 0);
- if (!strcmp(addrport, "auto")) {
+
+ /* Let's start to check if it's a Unix socket path. */
+ ret = config_parse_unix_port(addrport, &unix_socket_path);
+ if (ret < 0 && ret != -ENOENT) {
+ if (ret == -EINVAL) {
+ log_warn(LD_CONFIG, "Empty Unix socket path.");
+ }
+ goto err;
+ }
+
+ if (unix_socket_path &&
+ ! conn_listener_type_supports_af_unix(listener_type)) {
+ log_warn(LD_CONFIG, "%sPort does not support unix sockets", portname);
+ goto err;
+ }
+
+ if (unix_socket_path) {
+ port = 1;
+ } else if (is_unix_socket) {
+ unix_socket_path = tor_strdup(addrport);
+ if (!strcmp(addrport, "0"))
+ port = 0;
+ else
+ port = 1;
+ } else if (!strcmp(addrport, "auto")) {
port = CFG_AUTO_PORT;
tor_addr_parse(&addr, defaultaddr);
} else if (!strcasecmpend(addrport, ":auto")) {
@@ -5890,28 +6114,36 @@ parse_port_config(smartlist_t *out,
}
if (out && port) {
- port_cfg_t *cfg = port_cfg_new();
- tor_addr_copy(&cfg->addr, &addr);
- cfg->port = port;
+ size_t namelen = unix_socket_path ? strlen(unix_socket_path) : 0;
+ port_cfg_t *cfg = port_cfg_new(namelen);
+ if (unix_socket_path) {
+ tor_addr_make_unspec(&cfg->addr);
+ memcpy(cfg->unix_addr, unix_socket_path, namelen + 1);
+ cfg->is_unix_addr = 1;
+ tor_free(unix_socket_path);
+ } else {
+ tor_addr_copy(&cfg->addr, &addr);
+ cfg->port = port;
+ }
cfg->type = listener_type;
- cfg->isolation_flags = isolation;
- cfg->session_group = sessiongroup;
- cfg->no_advertise = no_advertise;
- cfg->no_listen = no_listen;
- cfg->all_addrs = all_addrs;
- cfg->bind_ipv4_only = bind_ipv4_only;
- cfg->bind_ipv6_only = bind_ipv6_only;
- cfg->ipv4_traffic = ipv4_traffic;
- cfg->ipv6_traffic = ipv6_traffic;
- cfg->prefer_ipv6 = prefer_ipv6;
- cfg->cache_ipv4_answers = cache_ipv4;
- cfg->cache_ipv6_answers = cache_ipv6;
- cfg->use_cached_ipv4_answers = use_cached_ipv4;
- cfg->use_cached_ipv6_answers = use_cached_ipv6;
- cfg->prefer_ipv6_virtaddr = prefer_ipv6_automap;
- cfg->socks_prefer_no_auth = prefer_no_auth;
+ cfg->entry_cfg.isolation_flags = isolation;
+ cfg->entry_cfg.session_group = sessiongroup;
+ cfg->server_cfg.no_advertise = no_advertise;
+ cfg->server_cfg.no_listen = no_listen;
+ cfg->server_cfg.all_addrs = all_addrs;
+ cfg->server_cfg.bind_ipv4_only = bind_ipv4_only;
+ cfg->server_cfg.bind_ipv6_only = bind_ipv6_only;
+ cfg->entry_cfg.ipv4_traffic = ipv4_traffic;
+ cfg->entry_cfg.ipv6_traffic = ipv6_traffic;
+ cfg->entry_cfg.prefer_ipv6 = prefer_ipv6;
+ cfg->entry_cfg.cache_ipv4_answers = cache_ipv4;
+ cfg->entry_cfg.cache_ipv6_answers = cache_ipv6;
+ cfg->entry_cfg.use_cached_ipv4_answers = use_cached_ipv4;
+ cfg->entry_cfg.use_cached_ipv6_answers = use_cached_ipv6;
+ cfg->entry_cfg.prefer_ipv6_virtaddr = prefer_ipv6_automap;
+ cfg->entry_cfg.socks_prefer_no_auth = prefer_no_auth;
if (! (isolation & ISO_SOCKSAUTH))
- cfg->socks_prefer_no_auth = 1;
+ cfg->entry_cfg.socks_prefer_no_auth = 1;
smartlist_add(out, cfg);
}
@@ -5939,32 +6171,10 @@ parse_port_config(smartlist_t *out,
err:
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts);
+ tor_free(unix_socket_path);
return retval;
}
-/** Parse a list of config_line_t for an AF_UNIX unix socket listener option
- * from <b>cfg</b> and add them to <b>out</b>. No fancy options are
- * supported: the line contains nothing but the path to the AF_UNIX socket. */
-static int
-parse_unix_socket_config(smartlist_t *out, const config_line_t *cfg,
- int listener_type)
-{
-
- if (!out)
- return 0;
-
- for ( ; cfg; cfg = cfg->next) {
- size_t len = strlen(cfg->value);
- port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1);
- port->is_unix_addr = 1;
- memcpy(port->unix_addr, cfg->value, len+1);
- port->type = listener_type;
- smartlist_add(out, port);
- }
-
- return 0;
-}
-
/** Return the number of ports which are actually going to listen with type
* <b>listenertype</b>. Do not count no_listen ports. Do not count unix
* sockets. */
@@ -5973,7 +6183,7 @@ count_real_listeners(const smartlist_t *ports, int listenertype)
{
int n = 0;
SMARTLIST_FOREACH_BEGIN(ports, port_cfg_t *, port) {
- if (port->no_listen || port->is_unix_addr)
+ if (port->server_cfg.no_listen || port->is_unix_addr)
continue;
if (port->type != listenertype)
continue;
@@ -6053,9 +6263,11 @@ parse_ports(or_options_t *options, int validate_only,
"configuration");
goto err;
}
- if (parse_unix_socket_config(ports,
- options->ControlSocket,
- CONN_TYPE_CONTROL_LISTENER) < 0) {
+
+ if (parse_port_config(ports, options->ControlSocket, NULL,
+ "ControlSocket",
+ CONN_TYPE_CONTROL_LISTENER, NULL, 0,
+ control_port_flags | CL_PORT_IS_UNIXSOCKET) < 0) {
*msg = tor_strdup("Invalid ControlSocket configuration");
goto err;
}
@@ -6149,25 +6361,25 @@ check_server_ports(const smartlist_t *ports,
SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
if (port->type == CONN_TYPE_DIR_LISTENER) {
- if (! port->no_advertise)
+ if (! port->server_cfg.no_advertise)
++n_dirport_advertised;
- if (! port->no_listen)
+ if (! port->server_cfg.no_listen)
++n_dirport_listeners;
} else if (port->type == CONN_TYPE_OR_LISTENER) {
- if (! port->no_advertise) {
+ if (! port->server_cfg.no_advertise) {
++n_orport_advertised;
if (tor_addr_family(&port->addr) == AF_INET ||
(tor_addr_family(&port->addr) == AF_UNSPEC &&
- !port->bind_ipv6_only))
+ !port->server_cfg.bind_ipv6_only))
++n_orport_advertised_ipv4;
}
- if (! port->no_listen)
+ if (! port->server_cfg.no_listen)
++n_orport_listeners;
} else {
continue;
}
#ifndef _WIN32
- if (!port->no_listen && port->port < 1024)
+ if (!port->server_cfg.no_listen && port->port < 1024)
++n_low_port;
#endif
} SMARTLIST_FOREACH_END(port);
@@ -6245,7 +6457,7 @@ get_first_listener_addrport_string(int listener_type)
return NULL;
SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) {
- if (cfg->no_listen)
+ if (cfg->server_cfg.no_listen)
continue;
if (cfg->type == listener_type &&
@@ -6292,12 +6504,12 @@ get_first_advertised_port_by_type_af(int listener_type, int address_family)
return 0;
SMARTLIST_FOREACH_BEGIN(configured_ports, const port_cfg_t *, cfg) {
if (cfg->type == listener_type &&
- !cfg->no_advertise &&
+ !cfg->server_cfg.no_advertise &&
(tor_addr_family(&cfg->addr) == address_family ||
tor_addr_family(&cfg->addr) == AF_UNSPEC)) {
if (tor_addr_family(&cfg->addr) != AF_UNSPEC ||
- (address_family == AF_INET && !cfg->bind_ipv6_only) ||
- (address_family == AF_INET6 && !cfg->bind_ipv4_only)) {
+ (address_family == AF_INET && !cfg->server_cfg.bind_ipv6_only) ||
+ (address_family == AF_INET6 && !cfg->server_cfg.bind_ipv4_only)) {
return cfg->port;
}
}
@@ -6381,10 +6593,13 @@ write_configuration_file(const char *fname, const or_options_t *options)
char *old_val=NULL, *new_val=NULL, *new_conf=NULL;
int rename_old = 0, r;
- tor_assert(fname);
+ if (!fname)
+ return -1;
switch (file_status(fname)) {
+ /* create backups of old config files, even if they're empty */
case FN_FILE:
+ case FN_EMPTY:
old_val = read_file_to_str(fname, 0, NULL);
if (!old_val || strcmpstart(old_val, GENERATED_FILE_PREFIX)) {
rename_old = 1;
diff --git a/src/or/config.h b/src/or/config.h
index 8a1919c2ed..b064f05321 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,10 +29,11 @@ setopt_err_t options_trial_assign(config_line_t *list, int use_defaults,
int clear_first, char **msg);
uint32_t get_last_resolved_addr(void);
+void reset_last_resolved_addr(void);
int resolve_my_address(int warn_severity, const or_options_t *options,
uint32_t *addr_out,
const char **method_out, char **hostname_out);
-int is_local_addr(const tor_addr_t *addr);
+MOCK_DECL(int, is_local_addr, (const tor_addr_t *addr));
void options_init(or_options_t *options);
#define OPTIONS_DUMP_MINIMAL 1
@@ -112,6 +113,7 @@ int addressmap_register_auto(const char *from, const char *to,
time_t expires,
addressmap_entry_source_t addrmap_source,
const char **msg);
+int config_parse_unix_port(const char *addrport, char **path_out);
/** Represents the information stored in a torrc Bridge line. */
typedef struct bridge_line_t {
@@ -140,6 +142,9 @@ STATIC int options_validate(or_options_t *old_options,
or_options_t *options,
or_options_t *default_options,
int from_setconf, char **msg);
+STATIC int parse_transport_line(const or_options_t *options,
+ const char *line, int validate_only,
+ int server);
#endif
#endif
diff --git a/src/or/confparse.c b/src/or/confparse.c
index c5400a6512..ac21df25cb 100644
--- a/src/or/confparse.c
+++ b/src/or/confparse.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/or/confparse.h b/src/or/confparse.h
index 2cd6c49a2a..83c0f75b52 100644
--- a/src/or/confparse.h
+++ b/src/or/confparse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_CONFPARSE_H
diff --git a/src/or/connection.c b/src/or/connection.c
index 276dca2818..721ee20d27 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,7 +29,6 @@
#include "connection_edge.h"
#include "connection_or.h"
#include "control.h"
-#include "cpuworker.h"
#include "directory.h"
#include "dirserv.h"
#include "dns.h"
@@ -57,6 +56,11 @@
#include <pwd.h>
#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
static connection_t *connection_listener_new(
const struct sockaddr *listensockaddr,
socklen_t listensocklen, int type,
@@ -130,7 +134,6 @@ conn_type_to_string(int type)
case CONN_TYPE_AP: return "Socks";
case CONN_TYPE_DIR_LISTENER: return "Directory listener";
case CONN_TYPE_DIR: return "Directory";
- case CONN_TYPE_CPUWORKER: return "CPU worker";
case CONN_TYPE_CONTROL_LISTENER: return "Control listener";
case CONN_TYPE_CONTROL: return "Control";
case CONN_TYPE_EXT_OR: return "Extended OR";
@@ -213,12 +216,6 @@ conn_state_to_string(int type, int state)
case DIR_CONN_STATE_SERVER_WRITING: return "writing";
}
break;
- case CONN_TYPE_CPUWORKER:
- switch (state) {
- case CPUWORKER_STATE_IDLE: return "idle";
- case CPUWORKER_STATE_BUSY_ONION: return "busy with onion";
- }
- break;
case CONN_TYPE_CONTROL:
switch (state) {
case CONTROL_CONN_STATE_OPEN: return "open (protocol v1)";
@@ -248,7 +245,6 @@ connection_type_uses_bufferevent(connection_t *conn)
case CONN_TYPE_CONTROL:
case CONN_TYPE_OR:
case CONN_TYPE_EXT_OR:
- case CONN_TYPE_CPUWORKER:
return 1;
default:
return 0;
@@ -305,9 +301,11 @@ entry_connection_new(int type, int socket_family)
* in a little while. Otherwise, we're doing this as a linked connection
* of some kind, and we should set it up here based on the socket family */
if (socket_family == AF_INET)
- entry_conn->ipv4_traffic_ok = 1;
+ entry_conn->entry_cfg.ipv4_traffic = 1;
else if (socket_family == AF_INET6)
- entry_conn->ipv6_traffic_ok = 1;
+ entry_conn->entry_cfg.ipv6_traffic = 1;
+ else if (socket_family == AF_UNIX)
+ entry_conn->is_socks_socket = 1;
return entry_conn;
}
@@ -451,6 +449,22 @@ connection_link_connections(connection_t *conn_a, connection_t *conn_b)
conn_b->linked_conn = conn_a;
}
+/** Return true iff the provided connection listener type supports AF_UNIX
+ * sockets. */
+int
+conn_listener_type_supports_af_unix(int type)
+{
+ /* For now only control ports or SOCKS ports can be Unix domain sockets
+ * and listeners at the same time */
+ switch (type) {
+ case CONN_TYPE_CONTROL_LISTENER:
+ case CONN_TYPE_AP_LISTENER:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
/** Deallocate memory used by <b>conn</b>. Deallocate its buffers if
* necessary, close its socket if necessary, and mark the directory as dirty
* if <b>conn</b> is an OR or OP connection.
@@ -516,9 +530,9 @@ connection_free_(connection_t *conn)
buf_free(conn->outbuf);
} else {
if (conn->socket_family == AF_UNIX) {
- /* For now only control ports can be Unix domain sockets
+ /* For now only control and SOCKS ports can be Unix domain sockets
* and listeners at the same time */
- tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
+ tor_assert(conn_listener_type_supports_af_unix(conn->type));
if (unlink(conn->address) < 0 && errno != ENOENT) {
log_warn(LD_NET, "Could not unlink %s: %s", conn->address,
@@ -544,8 +558,7 @@ connection_free_(connection_t *conn)
or_conn, TLS_CHAN_TO_BASE(or_conn->chan),
U64_PRINTF_ARG(
TLS_CHAN_TO_BASE(or_conn->chan)->global_identifier));
- if (!(TLS_CHAN_TO_BASE(or_conn->chan)->state == CHANNEL_STATE_CLOSED ||
- TLS_CHAN_TO_BASE(or_conn->chan)->state == CHANNEL_STATE_ERROR)) {
+ if (!CHANNEL_FINISHED(TLS_CHAN_TO_BASE(or_conn->chan))) {
channel_close_for_error(TLS_CHAN_TO_BASE(or_conn->chan));
}
@@ -575,8 +588,10 @@ connection_free_(connection_t *conn)
tor_free(control_conn->incoming_cmd);
}
- tor_free(conn->read_event); /* Probably already freed by connection_free. */
- tor_free(conn->write_event); /* Probably already freed by connection_free. */
+ /* Probably already freed by connection_free. */
+ tor_event_free(conn->read_event);
+ tor_event_free(conn->write_event);
+ conn->read_event = conn->write_event = NULL;
IF_HAS_BUFFEREVENT(conn, {
/* This was a workaround to handle bugs in some old versions of libevent
* where callbacks can occur after calling bufferevent_free(). Setting
@@ -894,9 +909,9 @@ create_unix_sockaddr(const char *listenaddress, char **readable_address,
}
#endif /* HAVE_SYS_UN_H */
-/** Warn that an accept or a connect has failed because we're running up
- * against our ulimit. Rate-limit these warnings so that we don't spam
- * the log. */
+/** Warn that an accept or a connect has failed because we're running out of
+ * TCP sockets we can use on current system. Rate-limit these warnings so
+ * that we don't spam the log. */
static void
warn_too_many_conns(void)
{
@@ -906,7 +921,7 @@ warn_too_many_conns(void)
if ((m = rate_limit_log(&last_warned, approx_time()))) {
int n_conns = get_n_open_sockets();
log_warn(LD_NET,"Failing because we have %d connections already. Please "
- "raise your ulimit -n.%s", n_conns, m);
+ "read doc/TUNING for guidance.%s", n_conns, m);
tor_free(m);
control_event_general_status(LOG_WARN, "TOO_MANY_CONNECTIONS CURRENT=%d",
n_conns);
@@ -914,13 +929,57 @@ warn_too_many_conns(void)
}
#ifdef HAVE_SYS_UN_H
+
+#define UNIX_SOCKET_PURPOSE_CONTROL_SOCKET 0
+#define UNIX_SOCKET_PURPOSE_SOCKS_SOCKET 1
+
+/** Check if the purpose isn't one of the ones we know what to do with */
+
+static int
+is_valid_unix_socket_purpose(int purpose)
+{
+ int valid = 0;
+
+ switch (purpose) {
+ case UNIX_SOCKET_PURPOSE_CONTROL_SOCKET:
+ case UNIX_SOCKET_PURPOSE_SOCKS_SOCKET:
+ valid = 1;
+ break;
+ }
+
+ return valid;
+}
+
+/** Return a string description of a unix socket purpose */
+static const char *
+unix_socket_purpose_to_string(int purpose)
+{
+ const char *s = "unknown-purpose socket";
+
+ switch (purpose) {
+ case UNIX_SOCKET_PURPOSE_CONTROL_SOCKET:
+ s = "control socket";
+ break;
+ case UNIX_SOCKET_PURPOSE_SOCKS_SOCKET:
+ s = "SOCKS socket";
+ break;
+ }
+
+ return s;
+}
+
/** Check whether we should be willing to open an AF_UNIX socket in
* <b>path</b>. Return 0 if we should go ahead and -1 if we shouldn't. */
static int
-check_location_for_unix_socket(const or_options_t *options, const char *path)
+check_location_for_unix_socket(const or_options_t *options, const char *path,
+ int purpose)
{
int r = -1;
- char *p = tor_strdup(path);
+ char *p = NULL;
+
+ tor_assert(is_valid_unix_socket_purpose(purpose));
+
+ p = tor_strdup(path);
cpd_check_t flags = CPD_CHECK_MODE_ONLY;
if (get_parent_directory(p)<0 || p[0] != '/') {
log_warn(LD_GENERAL, "Bad unix socket address '%s'. Tor does not support "
@@ -928,18 +987,23 @@ check_location_for_unix_socket(const or_options_t *options, const char *path)
goto done;
}
- if (options->ControlSocketsGroupWritable)
+ if ((purpose == UNIX_SOCKET_PURPOSE_CONTROL_SOCKET &&
+ options->ControlSocketsGroupWritable) ||
+ (purpose == UNIX_SOCKET_PURPOSE_SOCKS_SOCKET &&
+ options->SocksSocketsGroupWritable)) {
flags |= CPD_GROUP_OK;
+ }
if (check_private_dir(p, flags, options->User) < 0) {
char *escpath, *escdir;
escpath = esc_for_log(path);
escdir = esc_for_log(p);
- log_warn(LD_GENERAL, "Before Tor can create a control socket in %s, the "
- "directory %s needs to exist, and to be accessible only by the "
- "user%s account that is running Tor. (On some Unix systems, "
- "anybody who can list a socket can connect to it, so Tor is "
- "being careful.)", escpath, escdir,
+ log_warn(LD_GENERAL, "Before Tor can create a %s in %s, the directory "
+ "%s needs to exist, and to be accessible only by the user%s "
+ "account that is running Tor. (On some Unix systems, anybody "
+ "who can list a socket can connect to it, so Tor is being "
+ "careful.)",
+ unix_socket_purpose_to_string(purpose), escpath, escdir,
options->ControlSocketsGroupWritable ? " and group" : "");
tor_free(escpath);
tor_free(escdir);
@@ -1022,15 +1086,15 @@ connection_listener_new(const struct sockaddr *listensockaddr,
static int global_next_session_group = SESSION_GROUP_FIRST_AUTO;
tor_addr_t addr;
- if (get_n_open_sockets() >= get_options()->ConnLimit_-1) {
+ if (get_n_open_sockets() >= options->ConnLimit_-1) {
warn_too_many_conns();
return NULL;
}
if (listensockaddr->sa_family == AF_INET ||
listensockaddr->sa_family == AF_INET6) {
- int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
- if (is_tcp)
+ int is_stream = (type != CONN_TYPE_AP_DNS_LISTENER);
+ if (is_stream)
start_reading = 1;
tor_addr_from_sockaddr(&addr, listensockaddr, &usePort);
@@ -1039,10 +1103,10 @@ connection_listener_new(const struct sockaddr *listensockaddr,
conn_type_to_string(type), fmt_addrport(&addr, usePort));
s = tor_open_socket_nonblocking(tor_addr_family(&addr),
- is_tcp ? SOCK_STREAM : SOCK_DGRAM,
- is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
+ is_stream ? SOCK_STREAM : SOCK_DGRAM,
+ is_stream ? IPPROTO_TCP: IPPROTO_UDP);
if (!SOCKET_OK(s)) {
- log_warn(LD_NET,"Socket creation failed: %s",
+ log_warn(LD_NET, "Socket creation failed: %s",
tor_socket_strerror(tor_socket_errno(-1)));
goto err;
}
@@ -1099,7 +1163,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
goto err;
}
- if (is_tcp) {
+ if (is_stream) {
if (tor_listen(s) < 0) {
log_warn(LD_NET, "Could not listen on %s:%u: %s", address, usePort,
tor_socket_strerror(tor_socket_errno(s)));
@@ -1122,15 +1186,21 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_addr_from_sockaddr(&addr2, (struct sockaddr*)&ss, &gotPort);
}
#ifdef HAVE_SYS_UN_H
+ /*
+ * AF_UNIX generic setup stuff
+ */
} else if (listensockaddr->sa_family == AF_UNIX) {
+ /* We want to start reading for both AF_UNIX cases */
start_reading = 1;
- /* For now only control ports can be Unix domain sockets
- * and listeners at the same time */
- tor_assert(type == CONN_TYPE_CONTROL_LISTENER);
+ tor_assert(conn_listener_type_supports_af_unix(type));
- if (check_location_for_unix_socket(options, address) < 0)
- goto err;
+ if (check_location_for_unix_socket(options, address,
+ (type == CONN_TYPE_CONTROL_LISTENER) ?
+ UNIX_SOCKET_PURPOSE_CONTROL_SOCKET :
+ UNIX_SOCKET_PURPOSE_SOCKS_SOCKET) < 0) {
+ goto err;
+ }
log_notice(LD_NET, "Opening %s on %s",
conn_type_to_string(type), address);
@@ -1142,17 +1212,20 @@ connection_listener_new(const struct sockaddr *listensockaddr,
strerror(errno));
goto err;
}
+
s = tor_open_socket_nonblocking(AF_UNIX, SOCK_STREAM, 0);
if (! SOCKET_OK(s)) {
log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno));
goto err;
}
- if (bind(s, listensockaddr, (socklen_t)sizeof(struct sockaddr_un)) == -1) {
+ if (bind(s, listensockaddr,
+ (socklen_t)sizeof(struct sockaddr_un)) == -1) {
log_warn(LD_NET,"Bind to %s failed: %s.", address,
tor_socket_strerror(tor_socket_errno(s)));
goto err;
}
+
#ifdef HAVE_PWD_H
if (options->User) {
pw = tor_getpwnam(options->User);
@@ -1167,13 +1240,27 @@ connection_listener_new(const struct sockaddr *listensockaddr,
}
}
#endif
- if (options->ControlSocketsGroupWritable) {
+
+ if ((type == CONN_TYPE_CONTROL_LISTENER &&
+ options->ControlSocketsGroupWritable) ||
+ (type == CONN_TYPE_AP_LISTENER &&
+ options->SocksSocketsGroupWritable)) {
/* We need to use chmod; fchmod doesn't work on sockets on all
* platforms. */
if (chmod(address, 0660) < 0) {
log_warn(LD_FS,"Unable to make %s group-writable.", address);
goto err;
}
+ } else if ((type == CONN_TYPE_CONTROL_LISTENER &&
+ !(options->ControlSocketsGroupWritable)) ||
+ (type == CONN_TYPE_AP_LISTENER &&
+ !(options->SocksSocketsGroupWritable))) {
+ /* We need to use chmod; fchmod doesn't work on sockets on all
+ * platforms. */
+ if (chmod(address, 0600) < 0) {
+ log_warn(LD_FS,"Unable to make %s group-writable.", address);
+ goto err;
+ }
}
if (listen(s, SOMAXCONN) < 0) {
@@ -1181,8 +1268,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_socket_strerror(tor_socket_errno(s)));
goto err;
}
-#else
- (void)options;
#endif /* HAVE_SYS_UN_H */
} else {
log_err(LD_BUG, "Got unexpected address family %d.",
@@ -1199,10 +1284,12 @@ connection_listener_new(const struct sockaddr *listensockaddr,
conn->port = gotPort;
tor_addr_copy(&conn->addr, &addr);
- if (port_cfg->isolation_flags) {
- lis_conn->isolation_flags = port_cfg->isolation_flags;
- if (port_cfg->session_group >= 0) {
- lis_conn->session_group = port_cfg->session_group;
+ memcpy(&lis_conn->entry_cfg, &port_cfg->entry_cfg, sizeof(entry_port_cfg_t));
+
+ if (port_cfg->entry_cfg.isolation_flags) {
+ lis_conn->entry_cfg.isolation_flags = port_cfg->entry_cfg.isolation_flags;
+ if (port_cfg->entry_cfg.session_group >= 0) {
+ lis_conn->entry_cfg.session_group = port_cfg->entry_cfg.session_group;
} else {
/* This can wrap after around INT_MAX listeners are opened. But I don't
* believe that matters, since you would need to open a ridiculous
@@ -1210,23 +1297,15 @@ connection_listener_new(const struct sockaddr *listensockaddr,
* hit this. An OR with a dozen ports open, for example, would have to
* close and re-open its listeners every second for 4 years nonstop.
*/
- lis_conn->session_group = global_next_session_group--;
+ lis_conn->entry_cfg.session_group = global_next_session_group--;
}
}
- if (type == CONN_TYPE_AP_LISTENER) {
- lis_conn->socks_ipv4_traffic = port_cfg->ipv4_traffic;
- lis_conn->socks_ipv6_traffic = port_cfg->ipv6_traffic;
- lis_conn->socks_prefer_ipv6 = port_cfg->prefer_ipv6;
- } else {
- lis_conn->socks_ipv4_traffic = 1;
- lis_conn->socks_ipv6_traffic = 1;
+
+ if (type != CONN_TYPE_AP_LISTENER) {
+ lis_conn->entry_cfg.ipv4_traffic = 1;
+ lis_conn->entry_cfg.ipv6_traffic = 1;
+ lis_conn->entry_cfg.prefer_ipv6 = 0;
}
- lis_conn->cache_ipv4_answers = port_cfg->cache_ipv4_answers;
- lis_conn->cache_ipv6_answers = port_cfg->cache_ipv6_answers;
- lis_conn->use_cached_ipv4_answers = port_cfg->use_cached_ipv4_answers;
- lis_conn->use_cached_ipv6_answers = port_cfg->use_cached_ipv6_answers;
- lis_conn->prefer_ipv6_virtaddr = port_cfg->prefer_ipv6_virtaddr;
- lis_conn->socks_prefer_no_auth = port_cfg->socks_prefer_no_auth;
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
@@ -1293,6 +1372,8 @@ check_sockaddr(const struct sockaddr *sa, int len, int level)
"Address for new connection has address/port equal to zero.");
ok = 0;
}
+ } else if (sa->sa_family == AF_UNIX) {
+ ok = 1;
} else {
ok = 0;
}
@@ -1377,7 +1458,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
return 0;
}
- if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6) {
+ if (conn->socket_family == AF_INET || conn->socket_family == AF_INET6 ||
+ (conn->socket_family == AF_UNIX && new_type == CONN_TYPE_AP)) {
tor_addr_t addr;
uint16_t port;
if (check_sockaddr(remote, remotelen, LOG_INFO)<0) {
@@ -1418,18 +1500,21 @@ connection_handle_listener_read(connection_t *conn, int new_type)
newconn->port = port;
newconn->address = tor_dup_addr(&addr);
- if (new_type == CONN_TYPE_AP) {
- TO_ENTRY_CONN(newconn)->socks_request->socks_prefer_no_auth =
- TO_LISTENER_CONN(conn)->socks_prefer_no_auth;
+ if (new_type == CONN_TYPE_AP && conn->socket_family != AF_UNIX) {
+ log_info(LD_NET, "New SOCKS connection opened from %s.",
+ fmt_and_decorate_addr(&addr));
+ }
+ if (new_type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
+ newconn->port = 0;
+ newconn->address = tor_strdup(conn->address);
+ log_info(LD_NET, "New SOCKS AF_UNIX connection opened");
}
if (new_type == CONN_TYPE_CONTROL) {
log_notice(LD_CONTROL, "New control connection opened from %s.",
fmt_and_decorate_addr(&addr));
}
- } else if (conn->socket_family == AF_UNIX) {
- /* For now only control ports can be Unix domain sockets
- * and listeners at the same time */
+ } else if (conn->socket_family == AF_UNIX && conn->type != CONN_TYPE_AP) {
tor_assert(conn->type == CONN_TYPE_CONTROL_LISTENER);
tor_assert(new_type == CONN_TYPE_CONTROL);
log_notice(LD_CONTROL, "New control connection opened.");
@@ -1484,25 +1569,16 @@ connection_init_accepted_conn(connection_t *conn,
return rv;
break;
case CONN_TYPE_AP:
- TO_ENTRY_CONN(conn)->isolation_flags = listener->isolation_flags;
- TO_ENTRY_CONN(conn)->session_group = listener->session_group;
+ memcpy(&TO_ENTRY_CONN(conn)->entry_cfg, &listener->entry_cfg,
+ sizeof(entry_port_cfg_t));
TO_ENTRY_CONN(conn)->nym_epoch = get_signewnym_epoch();
TO_ENTRY_CONN(conn)->socks_request->listener_type = listener->base_.type;
- TO_ENTRY_CONN(conn)->ipv4_traffic_ok = listener->socks_ipv4_traffic;
- TO_ENTRY_CONN(conn)->ipv6_traffic_ok = listener->socks_ipv6_traffic;
- TO_ENTRY_CONN(conn)->prefer_ipv6_traffic = listener->socks_prefer_ipv6;
- TO_ENTRY_CONN(conn)->cache_ipv4_answers = listener->cache_ipv4_answers;
- TO_ENTRY_CONN(conn)->cache_ipv6_answers = listener->cache_ipv6_answers;
- TO_ENTRY_CONN(conn)->use_cached_ipv4_answers =
- listener->use_cached_ipv4_answers;
- TO_ENTRY_CONN(conn)->use_cached_ipv6_answers =
- listener->use_cached_ipv6_answers;
- TO_ENTRY_CONN(conn)->prefer_ipv6_virtaddr =
- listener->prefer_ipv6_virtaddr;
switch (TO_CONN(listener)->type) {
case CONN_TYPE_AP_LISTENER:
conn->state = AP_CONN_STATE_SOCKS_WAIT;
+ TO_ENTRY_CONN(conn)->socks_request->socks_prefer_no_auth =
+ listener->entry_cfg.socks_prefer_no_auth;
break;
case CONN_TYPE_AP_TRANS_LISTENER:
TO_ENTRY_CONN(conn)->is_transparent_ap = 1;
@@ -1525,26 +1601,21 @@ connection_init_accepted_conn(connection_t *conn,
return 0;
}
-/** Take conn, make a nonblocking socket; try to connect to
- * addr:port (they arrive in *host order*). If fail, return -1 and if
- * applicable put your best guess about errno into *<b>socket_error</b>.
- * Else assign s to conn-\>s: if connected return 1, if EAGAIN return 0.
- *
- * address is used to make the logs useful.
- *
- * On success, add conn to the list of polled connections.
- */
-int
-connection_connect(connection_t *conn, const char *address,
- const tor_addr_t *addr, uint16_t port, int *socket_error)
+static int
+connection_connect_sockaddr(connection_t *conn,
+ const struct sockaddr *sa,
+ socklen_t sa_len,
+ const struct sockaddr *bindaddr,
+ socklen_t bindaddr_len,
+ int *socket_error)
{
tor_socket_t s;
int inprogress = 0;
- struct sockaddr_storage addrbuf;
- struct sockaddr *dest_addr;
- int dest_addr_len;
const or_options_t *options = get_options();
- int protocol_family;
+
+ tor_assert(conn);
+ tor_assert(sa);
+ tor_assert(socket_error);
if (get_n_open_sockets() >= get_options()->ConnLimit_-1) {
warn_too_many_conns();
@@ -1552,11 +1623,6 @@ connection_connect(connection_t *conn, const char *address,
return -1;
}
- if (tor_addr_family(addr) == AF_INET6)
- protocol_family = PF_INET6;
- else
- protocol_family = PF_INET;
-
if (get_options()->DisableNetwork) {
/* We should never even try to connect anyplace if DisableNetwork is set.
* Warn if we do, and refuse to make the connection. */
@@ -1568,7 +1634,11 @@ connection_connect(connection_t *conn, const char *address,
return -1;
}
- s = tor_open_socket_nonblocking(protocol_family,SOCK_STREAM,IPPROTO_TCP);
+ const int protocol_family = sa->sa_family;
+ const int proto = (sa->sa_family == AF_INET6 ||
+ sa->sa_family == AF_INET) ? IPPROTO_TCP : 0;
+
+ s = tor_open_socket_nonblocking(protocol_family, SOCK_STREAM, proto);
if (! SOCKET_OK(s)) {
*socket_error = tor_socket_errno(-1);
log_warn(LD_NET,"Error creating network socket: %s",
@@ -1581,6 +1651,73 @@ connection_connect(connection_t *conn, const char *address,
tor_socket_strerror(errno));
}
+ if (bindaddr && bind(s, bindaddr, bindaddr_len) < 0) {
+ *socket_error = tor_socket_errno(s);
+ log_warn(LD_NET,"Error binding network socket: %s",
+ tor_socket_strerror(*socket_error));
+ tor_close_socket(s);
+ return -1;
+ }
+
+ tor_assert(options);
+ if (options->ConstrainedSockets)
+ set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
+
+ if (connect(s, sa, sa_len) < 0) {
+ int e = tor_socket_errno(s);
+ if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
+ /* yuck. kill it. */
+ *socket_error = e;
+ log_info(LD_NET,
+ "connect() to socket failed: %s",
+ tor_socket_strerror(e));
+ tor_close_socket(s);
+ return -1;
+ } else {
+ inprogress = 1;
+ }
+ }
+
+ /* it succeeded. we're connected. */
+ log_fn(inprogress ? LOG_DEBUG : LOG_INFO, LD_NET,
+ "Connection to socket %s (sock "TOR_SOCKET_T_FORMAT").",
+ inprogress ? "in progress" : "established", s);
+ conn->s = s;
+ if (connection_add_connecting(conn) < 0) {
+ /* no space, forget it */
+ *socket_error = SOCK_ERRNO(ENOBUFS);
+ return -1;
+ }
+
+ return inprogress ? 0 : 1;
+}
+
+/** Take conn, make a nonblocking socket; try to connect to
+ * addr:port (they arrive in *host order*). If fail, return -1 and if
+ * applicable put your best guess about errno into *<b>socket_error</b>.
+ * Else assign s to conn-\>s: if connected return 1, if EAGAIN return 0.
+ *
+ * address is used to make the logs useful.
+ *
+ * On success, add conn to the list of polled connections.
+ */
+int
+connection_connect(connection_t *conn, const char *address,
+ const tor_addr_t *addr, uint16_t port, int *socket_error)
+{
+ struct sockaddr_storage addrbuf;
+ struct sockaddr_storage bind_addr_ss;
+ struct sockaddr *bind_addr = NULL;
+ struct sockaddr *dest_addr;
+ int dest_addr_len, bind_addr_len = 0;
+ const or_options_t *options = get_options();
+ int protocol_family;
+
+ if (tor_addr_family(addr) == AF_INET6)
+ protocol_family = PF_INET6;
+ else
+ protocol_family = PF_INET;
+
if (!tor_addr_is_loopback(addr)) {
const tor_addr_t *ext_addr = NULL;
if (protocol_family == AF_INET &&
@@ -1590,33 +1727,20 @@ connection_connect(connection_t *conn, const char *address,
!tor_addr_is_null(&options->OutboundBindAddressIPv6_))
ext_addr = &options->OutboundBindAddressIPv6_;
if (ext_addr) {
- struct sockaddr_storage ext_addr_sa;
- socklen_t ext_addr_len = 0;
- memset(&ext_addr_sa, 0, sizeof(ext_addr_sa));
- ext_addr_len = tor_addr_to_sockaddr(ext_addr, 0,
- (struct sockaddr *) &ext_addr_sa,
- sizeof(ext_addr_sa));
- if (ext_addr_len == 0) {
+ memset(&bind_addr_ss, 0, sizeof(bind_addr_ss));
+ bind_addr_len = tor_addr_to_sockaddr(ext_addr, 0,
+ (struct sockaddr *) &bind_addr_ss,
+ sizeof(bind_addr_ss));
+ if (bind_addr_len == 0) {
log_warn(LD_NET,
"Error converting OutboundBindAddress %s into sockaddr. "
"Ignoring.", fmt_and_decorate_addr(ext_addr));
} else {
- if (bind(s, (struct sockaddr *) &ext_addr_sa, ext_addr_len) < 0) {
- *socket_error = tor_socket_errno(s);
- log_warn(LD_NET,"Error binding network socket to %s: %s",
- fmt_and_decorate_addr(ext_addr),
- tor_socket_strerror(*socket_error));
- tor_close_socket(s);
- return -1;
- }
+ bind_addr = (struct sockaddr *)&bind_addr_ss;
}
}
}
- tor_assert(options);
- if (options->ConstrainedSockets)
- set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
-
memset(&addrbuf,0,sizeof(addrbuf));
dest_addr = (struct sockaddr*) &addrbuf;
dest_addr_len = tor_addr_to_sockaddr(addr, port, dest_addr, sizeof(addrbuf));
@@ -1625,36 +1749,51 @@ connection_connect(connection_t *conn, const char *address,
log_debug(LD_NET, "Connecting to %s:%u.",
escaped_safe_str_client(address), port);
- if (connect(s, dest_addr, (socklen_t)dest_addr_len) < 0) {
- int e = tor_socket_errno(s);
- if (!ERRNO_IS_CONN_EINPROGRESS(e)) {
- /* yuck. kill it. */
- *socket_error = e;
- log_info(LD_NET,
- "connect() to %s:%u failed: %s",
- escaped_safe_str_client(address),
- port, tor_socket_strerror(e));
- tor_close_socket(s);
- return -1;
- } else {
- inprogress = 1;
- }
- }
+ return connection_connect_sockaddr(conn, dest_addr, dest_addr_len,
+ bind_addr, bind_addr_len, socket_error);
+}
- /* it succeeded. we're connected. */
- log_fn(inprogress?LOG_DEBUG:LOG_INFO, LD_NET,
- "Connection to %s:%u %s (sock "TOR_SOCKET_T_FORMAT").",
- escaped_safe_str_client(address),
- port, inprogress?"in progress":"established", s);
- conn->s = s;
- if (connection_add_connecting(conn) < 0) {
- /* no space, forget it */
- *socket_error = SOCK_ERRNO(ENOBUFS);
+#ifdef HAVE_SYS_UN_H
+
+/** Take conn, make a nonblocking socket; try to connect to
+ * an AF_UNIX socket at socket_path. If fail, return -1 and if applicable
+ * put your best guess about errno into *<b>socket_error</b>. Else assign s
+ * to conn-\>s: if connected return 1, if EAGAIN return 0.
+ *
+ * On success, add conn to the list of polled connections.
+ */
+int
+connection_connect_unix(connection_t *conn, const char *socket_path,
+ int *socket_error)
+{
+ struct sockaddr_un dest_addr;
+
+ tor_assert(socket_path);
+
+ /* Check that we'll be able to fit it into dest_addr later */
+ if (strlen(socket_path) + 1 > sizeof(dest_addr.sun_path)) {
+ log_warn(LD_NET,
+ "Path %s is too long for an AF_UNIX socket\n",
+ escaped_safe_str_client(socket_path));
+ *socket_error = SOCK_ERRNO(ENAMETOOLONG);
return -1;
}
- return inprogress ? 0 : 1;
+
+ memset(&dest_addr, 0, sizeof(dest_addr));
+ dest_addr.sun_family = AF_UNIX;
+ strlcpy(dest_addr.sun_path, socket_path, sizeof(dest_addr.sun_path));
+
+ log_debug(LD_NET,
+ "Connecting to AF_UNIX socket at %s.",
+ escaped_safe_str_client(socket_path));
+
+ return connection_connect_sockaddr(conn,
+ (struct sockaddr *)&dest_addr, sizeof(dest_addr),
+ NULL, 0, socket_error);
}
+#endif /* defined(HAVE_SYS_UN_H) */
+
/** Convert state number to string representation for logging purposes.
*/
static const char *
@@ -1688,14 +1827,14 @@ get_proxy_type(void)
{
const or_options_t *options = get_options();
- if (options->HTTPSProxy)
+ if (options->ClientTransportPlugin)
+ return PROXY_PLUGGABLE;
+ else if (options->HTTPSProxy)
return PROXY_CONNECT;
else if (options->Socks4Proxy)
return PROXY_SOCKS4;
else if (options->Socks5Proxy)
return PROXY_SOCKS5;
- else if (options->ClientTransportPlugin)
- return PROXY_PLUGGABLE;
else
return PROXY_NONE;
}
@@ -2185,7 +2324,7 @@ retry_listener_ports(smartlist_t *old_conns,
(conn->socket_family == AF_UNIX && ! wanted->is_unix_addr))
continue;
- if (wanted->no_listen)
+ if (wanted->server_cfg.no_listen)
continue; /* We don't want to open a listener for this one */
if (wanted->is_unix_addr) {
@@ -2226,7 +2365,7 @@ retry_listener_ports(smartlist_t *old_conns,
connection_t *conn;
int real_port = port->port == CFG_AUTO_PORT ? 0 : port->port;
tor_assert(real_port <= UINT16_MAX);
- if (port->no_listen)
+ if (port->server_cfg.no_listen)
continue;
if (port->is_unix_addr) {
@@ -2348,7 +2487,6 @@ connection_mark_all_noncontrol_connections(void)
if (conn->marked_for_close)
continue;
switch (conn->type) {
- case CONN_TYPE_CPUWORKER:
case CONN_TYPE_CONTROL_LISTENER:
case CONN_TYPE_CONTROL:
break;
@@ -2391,6 +2529,7 @@ connection_is_rate_limited(connection_t *conn)
return 0; /* Internal connection */
else if (! options->CountPrivateBandwidth &&
(tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */
+ tor_addr_family(&conn->addr) == AF_UNIX || /* no address */
tor_addr_is_internal(&conn->addr, 0)))
return 0; /* Internal address */
else
@@ -3716,9 +3855,15 @@ connection_handle_write_impl(connection_t *conn, int force)
if (connection_state_is_connecting(conn)) {
if (getsockopt(conn->s, SOL_SOCKET, SO_ERROR, (void*)&e, &len) < 0) {
log_warn(LD_BUG, "getsockopt() syscall failed");
- if (CONN_IS_EDGE(conn))
- connection_edge_end_errno(TO_EDGE_CONN(conn));
- connection_mark_for_close(conn);
+ if (conn->type == CONN_TYPE_OR) {
+ or_connection_t *orconn = TO_OR_CONN(conn);
+ connection_or_close_for_error(orconn, 0);
+ } else {
+ if (CONN_IS_EDGE(conn)) {
+ connection_edge_end_errno(TO_EDGE_CONN(conn));
+ }
+ connection_mark_for_close(conn);
+ }
return -1;
}
if (e) {
@@ -3833,6 +3978,8 @@ connection_handle_write_impl(connection_t *conn, int force)
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);
+ or_conn->bytes_xmitted += result;
+ or_conn->bytes_xmitted_by_tls += n_written;
/* So we notice bytes were written even on error */
/* XXXX024 This cast is safe since we can never write INT_MAX bytes in a
* single set of TLS operations. But it looks kinda ugly. If we refactor
@@ -4380,6 +4527,8 @@ client_check_address_changed(tor_socket_t sock)
SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t*, a_ptr, tor_free(a_ptr));
smartlist_clear(outgoing_addrs);
smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t)));
+ /* We'll need to resolve ourselves again. */
+ reset_last_resolved_addr();
/* Okay, now change our keys. */
ip_address_changed(1);
}
@@ -4431,8 +4580,6 @@ connection_process_inbuf(connection_t *conn, int package_partial)
package_partial);
case CONN_TYPE_DIR:
return connection_dir_process_inbuf(TO_DIR_CONN(conn));
- case CONN_TYPE_CPUWORKER:
- return connection_cpu_process_inbuf(conn);
case CONN_TYPE_CONTROL:
return connection_control_process_inbuf(TO_CONTROL_CONN(conn));
default:
@@ -4492,8 +4639,6 @@ connection_finished_flushing(connection_t *conn)
return connection_edge_finished_flushing(TO_EDGE_CONN(conn));
case CONN_TYPE_DIR:
return connection_dir_finished_flushing(TO_DIR_CONN(conn));
- case CONN_TYPE_CPUWORKER:
- return connection_cpu_finished_flushing(conn);
case CONN_TYPE_CONTROL:
return connection_control_finished_flushing(TO_CONTROL_CONN(conn));
default:
@@ -4549,8 +4694,6 @@ connection_reached_eof(connection_t *conn)
return connection_edge_reached_eof(TO_EDGE_CONN(conn));
case CONN_TYPE_DIR:
return connection_dir_reached_eof(TO_DIR_CONN(conn));
- case CONN_TYPE_CPUWORKER:
- return connection_cpu_reached_eof(conn);
case CONN_TYPE_CONTROL:
return connection_control_reached_eof(TO_CONTROL_CONN(conn));
default:
@@ -4756,10 +4899,6 @@ assert_connection_ok(connection_t *conn, time_t now)
tor_assert(conn->purpose >= DIR_PURPOSE_MIN_);
tor_assert(conn->purpose <= DIR_PURPOSE_MAX_);
break;
- case CONN_TYPE_CPUWORKER:
- tor_assert(conn->state >= CPUWORKER_STATE_MIN_);
- tor_assert(conn->state <= CPUWORKER_STATE_MAX_);
- break;
case CONN_TYPE_CONTROL:
tor_assert(conn->state >= CONTROL_CONN_STATE_MIN_);
tor_assert(conn->state <= CONTROL_CONN_STATE_MAX_);
@@ -4781,6 +4920,27 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
{
const or_options_t *options = get_options();
+ /* Client Transport Plugins can use another proxy, but that should be hidden
+ * from the rest of tor (as the plugin is responsible for dealing with the
+ * proxy), check it first, then check the rest of the proxy types to allow
+ * the config to have unused ClientTransportPlugin entries.
+ */
+ if (options->ClientTransportPlugin) {
+ const transport_t *transport = NULL;
+ int r;
+ r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport);
+ if (r<0)
+ return -1;
+ if (transport) { /* transport found */
+ tor_addr_copy(addr, &transport->addr);
+ *port = transport->port;
+ *proxy_type = transport->socks_version;
+ return 0;
+ }
+
+ /* Unused ClientTransportPlugin. */
+ }
+
if (options->HTTPSProxy) {
tor_addr_copy(addr, &options->HTTPSProxyAddr);
*port = options->HTTPSProxyPort;
@@ -4796,19 +4956,6 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
*port = options->Socks5ProxyPort;
*proxy_type = PROXY_SOCKS5;
return 0;
- } else if (options->ClientTransportPlugin ||
- options->Bridges) {
- const transport_t *transport = NULL;
- int r;
- r = get_transport_by_bridge_addrport(&conn->addr, conn->port, &transport);
- if (r<0)
- return -1;
- if (transport) { /* transport found */
- tor_addr_copy(addr, &transport->addr);
- *port = transport->port;
- *proxy_type = transport->socks_version;
- return 0;
- }
}
tor_addr_make_unspec(addr);
@@ -4832,7 +4979,7 @@ log_failed_proxy_connection(connection_t *conn)
log_warn(LD_NET,
"The connection to the %s proxy server at %s just failed. "
"Make sure that the proxy server is up and running.",
- proxy_type_to_string(get_proxy_type()),
+ proxy_type_to_string(proxy_type),
fmt_addrport(&proxy_addr, proxy_port));
}
@@ -4852,9 +4999,7 @@ proxy_type_to_string(int proxy_type)
}
/** Call connection_free_() on every connection in our array, and release all
- * storage held by connection.c. This is used by cpuworkers and dnsworkers
- * when they fork, so they don't keep resources held open (especially
- * sockets).
+ * storage held by connection.c.
*
* Don't do the checks in connection_free(), because they will
* fail.
diff --git a/src/or/connection.h b/src/or/connection.h
index 13dcbcd919..d0a34ece5c 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -17,6 +17,7 @@
const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
+int conn_listener_type_supports_af_unix(int type);
dir_connection_t *dir_connection_new(int socket_family);
or_connection_t *or_connection_new(int type, int socket_family);
@@ -89,6 +90,13 @@ int connection_connect(connection_t *conn, const char *address,
const tor_addr_t *addr,
uint16_t port, int *socket_error);
+#ifdef HAVE_SYS_UN_H
+
+int connection_connect_unix(connection_t *conn, const char *socket_path,
+ int *socket_error);
+
+#endif /* defined(HAVE_SYS_UN_H) */
+
/** Maximum size of information that we can fit into SOCKS5 username
or password fields. */
#define MAX_SOCKS5_AUTH_FIELD_SIZE 255
@@ -189,7 +197,8 @@ dir_connection_t *connection_dir_get_by_purpose_and_resource(
int any_other_active_or_conns(const or_connection_t *this_conn);
-#define connection_speaks_cells(conn) ((conn)->type == CONN_TYPE_OR)
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
+#define connection_speaks_cells(conn) (((conn)->type == CONN_TYPE_OR) || 0)
int connection_is_listener(connection_t *conn);
int connection_state_is_open(connection_t *conn);
int connection_state_is_connecting(connection_t *conn);
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index d210f93fa1..2a1a2f0fd2 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -46,6 +46,19 @@
#ifdef HAVE_LINUX_NETFILTER_IPV4_H
#include <linux/netfilter_ipv4.h>
#define TRANS_NETFILTER
+#define TRANS_NETFILTER_IPV4
+#endif
+
+#ifdef HAVE_LINUX_IF_H
+#include <linux/if.h>
+#endif
+
+#ifdef HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#if defined(IP6T_SO_ORIGINAL_DST)
+#define TRANS_NETFILTER
+#define TRANS_NETFILTER_IPV6
+#endif
#endif
#if defined(HAVE_NET_IF_H) && defined(HAVE_NET_PFVAR_H)
@@ -54,6 +67,10 @@
#define TRANS_PF
#endif
+#ifdef IP_TRANSPARENT
+#define TRANS_TPROXY
+#endif
+
#define SOCKS4_GRANTED 90
#define SOCKS4_REJECT 91
@@ -744,8 +761,9 @@ connection_ap_fail_onehop(const char *failed_digest,
/* we don't know the digest; have to compare addr:port */
tor_addr_t addr;
if (!build_state || !build_state->chosen_exit ||
- !entry_conn->socks_request)
+ !entry_conn->socks_request) {
continue;
+ }
if (tor_addr_parse(&addr, entry_conn->socks_request->address)<0 ||
!tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
build_state->chosen_exit->port != entry_conn->socks_request->port)
@@ -894,78 +912,102 @@ connection_ap_rewrite_and_attach_if_allowed(entry_connection_t *conn,
return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath);
}
-/** Connection <b>conn</b> just finished its socks handshake, or the
- * controller asked us to take care of it. If <b>circ</b> is defined,
- * then that's where we'll want to attach it. Otherwise we have to
- * figure it out ourselves.
- *
- * First, parse whether it's a .exit address, remap it, and so on. Then
- * if it's for a general circuit, try to attach it to a circuit (or launch
- * one as needed), else if it's for a rendezvous circuit, fetch a
- * rendezvous descriptor first (or attach/launch a circuit if the
- * rendezvous descriptor is already here and fresh enough).
- *
- * The stream will exit from the hop
- * indicated by <b>cpath</b>, or from the last hop in circ's cpath if
- * <b>cpath</b> is NULL.
+/* Try to perform any map-based rewriting of the target address in
+ * <b>conn</b>, filling in the fields of <b>out</b> as we go, and modifying
+ * conn->socks_request.address as appropriate.
*/
-int
-connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
- origin_circuit_t *circ,
- crypt_path_t *cpath)
+STATIC void
+connection_ap_handshake_rewrite(entry_connection_t *conn,
+ rewrite_result_t *out)
{
socks_request_t *socks = conn->socks_request;
- hostname_type_t addresstype;
const or_options_t *options = get_options();
tor_addr_t addr_tmp;
- /* We set this to true if this is an address we should automatically
- * remap to a local address in VirtualAddrNetwork */
- int automap = 0;
- char orig_address[MAX_SOCKS_ADDR_LEN];
- time_t map_expires = TIME_MAX;
- time_t now = time(NULL);
- connection_t *base_conn = ENTRY_TO_CONN(conn);
- addressmap_entry_source_t exit_source = ADDRMAPSRC_NONE;
- tor_strlower(socks->address); /* normalize it */
- strlcpy(orig_address, socks->address, sizeof(orig_address));
+ /* Initialize all the fields of 'out' to reasonable defaults */
+ out->automap = 0;
+ out->exit_source = ADDRMAPSRC_NONE;
+ out->map_expires = TIME_MAX;
+ out->end_reason = 0;
+ out->should_close = 0;
+ out->orig_address[0] = 0;
+
+ /* We convert all incoming addresses to lowercase. */
+ tor_strlower(socks->address);
+ /* Remember the original address. */
+ strlcpy(out->orig_address, socks->address, sizeof(out->orig_address));
log_debug(LD_APP,"Client asked for %s:%d",
safe_str_client(socks->address),
socks->port);
+ /* Check for whether this is a .exit address. By default, those are
+ * disallowed when they're coming straight from the client, but you're
+ * allowed to have them in MapAddress commands and so forth. */
if (!strcmpend(socks->address, ".exit") && !options->AllowDotExit) {
log_warn(LD_APP, "The \".exit\" notation is disabled in Tor due to "
"security risks. Set AllowDotExit in your torrc to enable "
"it (at your own risk).");
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
- connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
- return -1;
+ out->end_reason = END_STREAM_REASON_TORPROTOCOL;
+ out->should_close = 1;
+ return;
}
- if (! conn->original_dest_address)
+ /* Remember the original address so we can tell the user about what
+ * they actually said, not just what it turned into. */
+ if (! conn->original_dest_address) {
+ /* Is the 'if' necessary here? XXXX */
conn->original_dest_address = tor_strdup(conn->socks_request->address);
+ }
+ /* First, apply MapAddress and MAPADDRESS mappings. We need to do
+ * these only for non-reverse lookups, since they don't exist for those.
+ * We need to do this before we consider automapping, since we might
+ * e.g. resolve irc.oftc.net into irconionaddress.onion, at which point
+ * we'd need to automap it. */
+ if (socks->command != SOCKS_COMMAND_RESOLVE_PTR) {
+ const unsigned rewrite_flags = AMR_FLAG_USE_MAPADDRESS;
+ if (addressmap_rewrite(socks->address, sizeof(socks->address),
+ rewrite_flags, &out->map_expires, &out->exit_source)) {
+ control_event_stream_status(conn, STREAM_EVENT_REMAP,
+ REMAP_STREAM_SOURCE_CACHE);
+ }
+ }
+
+ /* Now, handle automapping. Automapping happens when we're asked to
+ * resolve a hostname, and AutomapHostsOnResolve is set, and
+ * the hostname has a suffix listed in AutomapHostsSuffixes.
+ */
if (socks->command == SOCKS_COMMAND_RESOLVE &&
tor_addr_parse(&addr_tmp, socks->address)<0 &&
options->AutomapHostsOnResolve) {
- automap = addressmap_address_should_automap(socks->address, options);
- if (automap) {
+ /* Check the suffix... */
+ out->automap = addressmap_address_should_automap(socks->address, options);
+ if (out->automap) {
+ /* If we get here, then we should apply an automapping for this. */
const char *new_addr;
+ /* We return an IPv4 address by default, or an IPv6 address if we
+ * are allowed to do so. */
int addr_type = RESOLVED_TYPE_IPV4;
if (conn->socks_request->socks_version != 4) {
- if (!conn->ipv4_traffic_ok ||
- (conn->ipv6_traffic_ok && conn->prefer_ipv6_traffic) ||
- conn->prefer_ipv6_virtaddr)
+ if (!conn->entry_cfg.ipv4_traffic ||
+ (conn->entry_cfg.ipv6_traffic && conn->entry_cfg.prefer_ipv6) ||
+ conn->entry_cfg.prefer_ipv6_virtaddr)
addr_type = RESOLVED_TYPE_IPV6;
}
+ /* Okay, register the target address as automapped, and find the new
+ * address we're supposed to give as a resolve answer. (Return a cached
+ * value if we've looked up this address before.
+ */
new_addr = addressmap_register_virtual_address(
addr_type, tor_strdup(socks->address));
if (! new_addr) {
log_warn(LD_APP, "Unable to automap address %s",
escaped_safe_str(socks->address));
- connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL);
- return -1;
+ out->end_reason = END_STREAM_REASON_INTERNAL;
+ out->should_close = 1;
+ return;
}
log_info(LD_APP, "Automapping %s to %s",
escaped_safe_str_client(socks->address),
@@ -974,28 +1016,35 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
}
+ /* Now handle reverse lookups, if they're in the cache. This doesn't
+ * happen too often, since client-side DNS caching is off by default. */
if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) {
unsigned rewrite_flags = 0;
- if (conn->use_cached_ipv4_answers)
+ if (conn->entry_cfg.use_cached_ipv4_answers)
rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
- if (conn->use_cached_ipv6_answers)
+ if (conn->entry_cfg.use_cached_ipv6_answers)
rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address),
- rewrite_flags, &map_expires)) {
+ rewrite_flags, &out->map_expires)) {
char *result = tor_strdup(socks->address);
/* remember _what_ is supposed to have been resolved. */
tor_snprintf(socks->address, sizeof(socks->address), "REVERSE[%s]",
- orig_address);
+ out->orig_address);
connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_HOSTNAME,
strlen(result), (uint8_t*)result,
-1,
- map_expires);
- connection_mark_unattached_ap(conn,
- END_STREAM_REASON_DONE |
- END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
- return 0;
+ out->map_expires);
+ tor_free(result);
+ out->end_reason = END_STREAM_REASON_DONE |
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED;
+ out->should_close = 1;
+ return;
}
+
+ /* Hang on, did we find an answer saying that this is a reverse lookup for
+ * an internal address? If so, we should reject it if we're condigured to
+ * do so. */
if (options->ClientDNSRejectInternalAddresses) {
/* Don't let people try to do a reverse lookup on 10.0.0.1. */
tor_addr_t addr;
@@ -1005,43 +1054,108 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
if (ok == 1 && tor_addr_is_internal(&addr, 0)) {
connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_ERROR,
0, NULL, -1, TIME_MAX);
- connection_mark_unattached_ap(conn,
- END_STREAM_REASON_SOCKSPROTOCOL |
- END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
- return -1;
+ out->end_reason = END_STREAM_REASON_SOCKSPROTOCOL |
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED;
+ out->should_close = 1;
+ return;
}
}
- } else if (!automap) {
- /* For address map controls, remap the address. */
- unsigned rewrite_flags = 0;
- if (conn->use_cached_ipv4_answers)
+ }
+
+ /* If we didn't automap it before, then this is still the address
+ * that came straight from the user, mapped according to any
+ * MapAddress/MAPADDRESS commands. Now other mappings, including
+ * previously registered Automap entries, TrackHostExits entries,
+ * and client-side DNS cache entries (not recommended).
+ */
+ if (socks->command != SOCKS_COMMAND_RESOLVE_PTR &&
+ !out->automap) {
+ unsigned rewrite_flags = AMR_FLAG_USE_AUTOMAP | AMR_FLAG_USE_TRACKEXIT;
+ addressmap_entry_source_t exit_source2;
+ if (conn->entry_cfg.use_cached_ipv4_answers)
rewrite_flags |= AMR_FLAG_USE_IPV4_DNS;
- if (conn->use_cached_ipv6_answers)
+ if (conn->entry_cfg.use_cached_ipv6_answers)
rewrite_flags |= AMR_FLAG_USE_IPV6_DNS;
if (addressmap_rewrite(socks->address, sizeof(socks->address),
- rewrite_flags, &map_expires, &exit_source)) {
+ rewrite_flags, &out->map_expires, &exit_source2)) {
control_event_stream_status(conn, STREAM_EVENT_REMAP,
REMAP_STREAM_SOURCE_CACHE);
}
+ if (out->exit_source == ADDRMAPSRC_NONE) {
+ /* If it wasn't a .exit before, maybe it turned into a .exit. Remember
+ * the original source of a .exit. */
+ out->exit_source = exit_source2;
+ }
}
- if (!automap && address_is_in_virtual_range(socks->address)) {
- /* This address was probably handed out by client_dns_get_unmapped_address,
- * but the mapping was discarded for some reason. We *don't* want to send
- * the address through Tor; that's likely to fail, and may leak
- * information.
+ /* Check to see whether we're about to use an address in the virtual
+ * range without actually having gotten it from an Automap. */
+ if (!out->automap && address_is_in_virtual_range(socks->address)) {
+ /* This address was probably handed out by
+ * client_dns_get_unmapped_address, but the mapping was discarded for some
+ * reason. Or the user typed in a virtual address range manually. We
+ * *don't* want to send the address through Tor; that's likely to fail,
+ * and may leak information.
*/
log_warn(LD_APP,"Missing mapping for virtual address '%s'. Refusing.",
safe_str_client(socks->address));
- connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL);
- return -1;
+ out->end_reason = END_STREAM_REASON_INTERNAL;
+ out->should_close = 1;
+ return;
+ }
+}
+
+/** Connection <b>conn</b> just finished its socks handshake, or the
+ * controller asked us to take care of it. If <b>circ</b> is defined,
+ * then that's where we'll want to attach it. Otherwise we have to
+ * figure it out ourselves.
+ *
+ * First, parse whether it's a .exit address, remap it, and so on. Then
+ * if it's for a general circuit, try to attach it to a circuit (or launch
+ * one as needed), else if it's for a rendezvous circuit, fetch a
+ * rendezvous descriptor first (or attach/launch a circuit if the
+ * rendezvous descriptor is already here and fresh enough).
+ *
+ * The stream will exit from the hop
+ * indicated by <b>cpath</b>, or from the last hop in circ's cpath if
+ * <b>cpath</b> is NULL.
+ */
+int
+connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
+ origin_circuit_t *circ,
+ crypt_path_t *cpath)
+{
+ socks_request_t *socks = conn->socks_request;
+ const or_options_t *options = get_options();
+ connection_t *base_conn = ENTRY_TO_CONN(conn);
+ time_t now = time(NULL);
+ rewrite_result_t rr;
+
+ memset(&rr, 0, sizeof(rr));
+ connection_ap_handshake_rewrite(conn,&rr);
+
+ if (rr.should_close) {
+ /* connection_ap_handshake_rewrite told us to close the connection,
+ * either because it sent back an answer, or because it sent back an
+ * error */
+ connection_mark_unattached_ap(conn, rr.end_reason);
+ if (END_STREAM_REASON_DONE == (rr.end_reason & END_STREAM_REASON_MASK))
+ return 0;
+ else
+ return -1;
}
+ const time_t map_expires = rr.map_expires;
+ const int automap = rr.automap;
+ const addressmap_entry_source_t exit_source = rr.exit_source;
+
/* Parse the address provided by SOCKS. Modify it in-place if it
* specifies a hidden-service (.onion) or particular exit node (.exit).
*/
- addresstype = parse_extended_hostname(socks->address);
+ const hostname_type_t addresstype = parse_extended_hostname(socks->address);
+ /* Now see whether the hostname is bogus. This could happen because of an
+ * onion hostname whose format we don't recognize. */
if (addresstype == BAD_HOSTNAME) {
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
@@ -1049,16 +1163,21 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
return -1;
}
+ /* If this is a .exit hostname, strip off the .name.exit part, and
+ * see whether we're going to connect there, and otherwise handle it.
+ * (The ".exit" part got stripped off by "parse_extended_hostname").
+ *
+ * We'll set chosen_exit_name and/or close the connection as appropriate.
+ */
if (addresstype == EXIT_HOSTNAME) {
- /* foo.exit -- modify conn->chosen_exit_node to specify the exit
- * node, and conn->address to hold only the address portion. */
- char *s = strrchr(socks->address,'.');
-
- /* If StrictNodes is not set, then .exit overrides ExcludeNodes. */
+ /* If StrictNodes is not set, then .exit overrides ExcludeNodes but
+ * not ExcludeExitNodes. */
routerset_t *excludeset = options->StrictNodes ?
options->ExcludeExitNodesUnion_ : options->ExcludeExitNodes;
- const node_t *node;
+ const node_t *node = NULL;
+ /* If this .exit was added by an AUTOMAP, then it came straight from
+ * a user. Make sure that options->AllowDotExit permits that. */
if (exit_source == ADDRMAPSRC_AUTOMAP && !options->AllowDotExit) {
/* Whoops; this one is stale. It must have gotten added earlier,
* when AllowDotExit was on. */
@@ -1071,6 +1190,8 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
return -1;
}
+ /* Double-check to make sure there are no .exits coming from
+ * impossible/weird sources. */
if (exit_source == ADDRMAPSRC_DNS ||
(exit_source == ADDRMAPSRC_NONE && !options->AllowDotExit)) {
/* It shouldn't be possible to get a .exit address from any of these
@@ -1085,9 +1206,12 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
tor_assert(!automap);
+ /* Now, find the character before the .(name) part. */
+ char *s = strrchr(socks->address,'.');
if (s) {
/* The address was of the form "(stuff).(name).exit */
if (s[1] != '\0') {
+ /* Looks like a real .exit one. */
conn->chosen_exit_name = tor_strdup(s+1);
node = node_get_by_nickname(conn->chosen_exit_name, 1);
@@ -1106,7 +1230,8 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
return -1;
}
} else {
- /* It looks like they just asked for "foo.exit". */
+ /* It looks like they just asked for "foo.exit". That's a special
+ * form that means (foo's address).foo.exit. */
conn->chosen_exit_name = tor_strdup(socks->address);
node = node_get_by_nickname(conn->chosen_exit_name, 1);
@@ -1115,6 +1240,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
node_get_address_string(node, socks->address, sizeof(socks->address));
}
}
+
/* Now make sure that the chosen exit exists... */
if (!node) {
log_warn(LD_APP,
@@ -1136,8 +1262,12 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
implies no. */
}
+ /* Now, handle everything that isn't a .onion address. */
if (addresstype != ONION_HOSTNAME) {
- /* not a hidden-service request (i.e. normal or .exit) */
+ /* Not a hidden-service request. It's either a hostname or an IP,
+ * possibly with a .exit that we stripped off. */
+
+ /* Check for funny characters in the address. */
if (address_is_invalid_destination(socks->address, 1)) {
control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
escaped(socks->address));
@@ -1148,6 +1278,9 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
return -1;
}
+#ifdef ENABLE_TOR2WEB_MODE
+ /* If we're running in Tor2webMode, we don't allow anything BUT .onion
+ * addresses. */
if (options->Tor2webMode) {
log_warn(LD_APP, "Refusing to connect to non-hidden-service hostname %s "
"because tor2web mode is enabled.",
@@ -1155,13 +1288,17 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
return -1;
}
+#endif
+ /* See if this is a hostname lookup that we can answer immediately.
+ * (For example, an attempt to look up the IP address for an IP address.)
+ */
if (socks->command == SOCKS_COMMAND_RESOLVE) {
tor_addr_t answer;
/* Reply to resolves immediately if we can. */
if (tor_addr_parse(&answer, socks->address) >= 0) {/* is it an IP? */
/* remember _what_ is supposed to have been resolved. */
- strlcpy(socks->address, orig_address, sizeof(socks->address));
+ strlcpy(socks->address, rr.orig_address, sizeof(socks->address));
connection_ap_handshake_socks_resolved_addr(conn, &answer, -1,
map_expires);
connection_mark_unattached_ap(conn,
@@ -1172,14 +1309,22 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
tor_assert(!automap);
rep_hist_note_used_resolve(now); /* help predict this next time */
} else if (socks->command == SOCKS_COMMAND_CONNECT) {
+ /* Special handling for attempts to connect */
tor_assert(!automap);
+ /* Don't allow connections to port 0. */
if (socks->port == 0) {
log_notice(LD_APP,"Application asked to connect to port 0. Refusing.");
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return -1;
}
+ /* You can't make connections to internal addresses, by default.
+ * Exceptions are begindir requests (where the address is meaningless,
+ * or cases where you've hand-configured a particular exit, thereby
+ * making the local address meaningful. */
if (options->ClientRejectInternalAddresses &&
!conn->use_begindir && !conn->chosen_exit_name && !circ) {
+ /* If we reach this point then we don't want to allow internal
+ * addresses. Check if we got one. */
tor_addr_t addr;
if (tor_addr_hostname_is_local(socks->address) ||
(tor_addr_parse(&addr, socks->address) >= 0 &&
@@ -1214,39 +1359,58 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
connection_mark_unattached_ap(conn, END_STREAM_REASON_PRIVATE_ADDR);
return -1;
}
- }
+ } /* end "if we should check for internal addresses" */
+ /* Okay. We're still doing a CONNECT, and it wasn't a private
+ * address. Do special handling for literal IP addresses */
{
tor_addr_t addr;
/* XXX Duplicate call to tor_addr_parse. */
if (tor_addr_parse(&addr, socks->address) >= 0) {
+ /* If we reach this point, it's an IPv4 or an IPv6 address. */
sa_family_t family = tor_addr_family(&addr);
- if ((family == AF_INET && ! conn->ipv4_traffic_ok) ||
- (family == AF_INET6 && ! conn->ipv4_traffic_ok)) {
+
+ if ((family == AF_INET && ! conn->entry_cfg.ipv4_traffic) ||
+ (family == AF_INET6 && ! conn->entry_cfg.ipv6_traffic)) {
+ /* You can't do an IPv4 address on a v6-only socks listener,
+ * or vice versa. */
log_warn(LD_NET, "Rejecting SOCKS request for an IP address "
"family that this listener does not support.");
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
return -1;
} else if (family == AF_INET6 && socks->socks_version == 4) {
+ /* You can't make a socks4 request to an IPv6 address. Socks4
+ * doesn't support that. */
log_warn(LD_NET, "Rejecting SOCKS4 request for an IPv6 address.");
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
return -1;
- } else if (socks->socks_version == 4 && !conn->ipv4_traffic_ok) {
+ } else if (socks->socks_version == 4 &&
+ !conn->entry_cfg.ipv4_traffic) {
+ /* You can't do any kind of Socks4 request when IPv4 is forbidden.
+ *
+ * XXX raise this check outside the enclosing block? */
log_warn(LD_NET, "Rejecting SOCKS4 request on a listener with "
"no IPv4 traffic supported.");
connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
return -1;
} else if (family == AF_INET6) {
- conn->ipv4_traffic_ok = 0;
+ /* Tell the exit: we won't accept any ipv4 connection to an IPv6
+ * address. */
+ conn->entry_cfg.ipv4_traffic = 0;
} else if (family == AF_INET) {
- conn->ipv6_traffic_ok = 0;
+ /* Tell the exit: we won't accept any ipv6 connection to an IPv4
+ * address. */
+ conn->entry_cfg.ipv6_traffic = 0;
}
}
}
if (socks->socks_version == 4)
- conn->ipv6_traffic_ok = 0;
+ conn->entry_cfg.ipv6_traffic = 0;
+ /* Still handling CONNECT. Now, check for exit enclaves. (Which we
+ * don't do on BEGINDIR, or there is a chosen exit.)
+ */
if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
/* see if we can find a suitable enclave exit */
const node_t *r =
@@ -1263,11 +1427,13 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
}
- /* warn or reject if it's using a dangerous port */
+ /* Still handling CONNECT: warn or reject if it's using a dangerous
+ * port. */
if (!conn->use_begindir && !conn->chosen_exit_name && !circ)
if (consider_plaintext_ports(conn, socks->port) < 0)
return -1;
+ /* Remember the port so that we do predicted requests there. */
if (!conn->use_begindir) {
/* help predict this next time */
rep_hist_note_used_port(now, socks->port);
@@ -1276,25 +1442,41 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
rep_hist_note_used_resolve(now); /* help predict this next time */
/* no extra processing needed */
} else {
+ /* We should only be doing CONNECT or RESOLVE! */
tor_fragile_assert();
}
+
+ /* Okay. At this point we've set chosen_exit_name if needed, rewritten the
+ * address, and decided not to reject it for any number of reasons. Now
+ * mark the connection as waiting for a circuit, and try to attach it!
+ */
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
- if ((circ && connection_ap_handshake_attach_chosen_circuit(
- conn, circ, cpath) < 0) ||
- (!circ &&
- connection_ap_handshake_attach_circuit(conn) < 0)) {
+
+ /* If we were given a circuit to attach to, try to attach. Otherwise,
+ * try to find a good one and attach to that. */
+ int rv;
+ if (circ)
+ rv = connection_ap_handshake_attach_chosen_circuit(conn, circ, cpath);
+ else
+ rv = connection_ap_handshake_attach_circuit(conn);
+
+ /* If the above function returned 0 then we're waiting for a circuit.
+ * if it returned 1, we're attached. Both are okay. But if it returned
+ * -1, there was an error, so make sure the connection is marked, and
+ * return -1. */
+ if (rv < 0) {
if (!base_conn->marked_for_close)
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
return -1;
}
+
return 0;
} else {
- /* it's a hidden-service request */
- rend_cache_entry_t *entry;
- int r;
- rend_service_authorization_t *client_auth;
- rend_data_t *rend_data;
+ /* If we get here, it's a request for a .onion address! */
tor_assert(!automap);
+
+ /* Check whether it's RESOLVE or RESOLVE_PTR. We don't handle those
+ * for hidden service addresses. */
if (SOCKS_COMMAND_IS_RESOLVE(socks->command)) {
/* if it's a resolve request, fail it right now, rather than
* building all the circuits and then realizing it won't work. */
@@ -1308,6 +1490,8 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
return -1;
}
+ /* If we were passed a circuit, then we need to fail. .onion addresses
+ * only work when we launch our own circuits for now. */
if (circ) {
log_warn(LD_CONTROL, "Attachstream to a circuit is not "
"supported for .onion addresses currently. Failing.");
@@ -1315,15 +1499,22 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
return -1;
}
- ENTRY_TO_EDGE_CONN(conn)->rend_data = rend_data =
+ /* Fill in the rend_data field so we can start doing a connection to
+ * a hidden service. */
+ rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data =
tor_malloc_zero(sizeof(rend_data_t));
strlcpy(rend_data->onion_address, socks->address,
sizeof(rend_data->onion_address));
log_info(LD_REND,"Got a hidden service request for ID '%s'",
safe_str_client(rend_data->onion_address));
- /* see if we already have it cached */
- r = rend_cache_lookup_entry(rend_data->onion_address, -1, &entry);
- if (r<0) {
+
+ /* see if we already have a hidden service descriptor cached for this
+ * address. */
+ rend_cache_entry_t *entry = NULL;
+ const int rend_cache_lookup_result =
+ rend_cache_lookup_entry(rend_data->onion_address, -1, &entry);
+ if (rend_cache_lookup_result < 0) {
+ /* We should already have rejected this address! */
log_warn(LD_BUG,"Invalid service name '%s'",
safe_str_client(rend_data->onion_address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
@@ -1334,8 +1525,10 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
* a stable circuit yet, but we know we'll need *something*. */
rep_hist_note_used_internal(now, 0, 1);
- /* Look up if we have client authorization for it. */
- client_auth = rend_client_lookup_service_authorization(
+ /* Look up if we have client authorization configured for this hidden
+ * service. If we do, associate it with the rend_data. */
+ rend_service_authorization_t *client_auth =
+ rend_client_lookup_service_authorization(
rend_data->onion_address);
if (client_auth) {
log_info(LD_REND, "Using previously configured client authorization "
@@ -1344,12 +1537,16 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
client_auth->descriptor_cookie, REND_DESC_COOKIE_LEN);
rend_data->auth_type = client_auth->auth_type;
}
- if (r==0) {
+
+ /* Now, we either launch an attempt to connect to the hidden service,
+ * or we launch an attempt to look up its descriptor, depending on
+ * whether we had the descriptor. */
+ if (rend_cache_lookup_result == 0) {
base_conn->state = AP_CONN_STATE_RENDDESC_WAIT;
log_info(LD_REND, "Unknown descriptor %s. Fetching.",
safe_str_client(rend_data->onion_address));
rend_client_refetch_v2_renddesc(rend_data);
- } else { /* r > 0 */
+ } else { /* rend_cache_lookup_result > 0 */
base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
log_info(LD_REND, "Descriptor is here. Great.");
if (connection_ap_handshake_attach_circuit(conn) < 0) {
@@ -1360,6 +1557,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
}
return 0;
}
+
return 0; /* unreached but keeps the compiler happy */
}
@@ -1391,7 +1589,7 @@ get_pf_socket(void)
}
#endif
-#if defined(TRANS_NETFILTER) || defined(TRANS_PF)
+#if defined(TRANS_NETFILTER) || defined(TRANS_PF) || defined(TRANS_TPROXY)
/** Try fill in the address of <b>req</b> from the socket configured
* with <b>conn</b>. */
static int
@@ -1401,13 +1599,45 @@ destination_from_socket(entry_connection_t *conn, socks_request_t *req)
socklen_t orig_dst_len = sizeof(orig_dst);
tor_addr_t addr;
+#ifdef TRANS_TRPOXY
+ if (options->TransProxyType_parsed == TPT_TPROXY) {
+ if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&orig_dst,
+ &orig_dst_len) < 0) {
+ int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s);
+ log_warn(LD_NET, "getsockname() failed: %s", tor_socket_strerror(e));
+ return -1;
+ }
+ goto done;
+ }
+#endif
+
#ifdef TRANS_NETFILTER
- if (getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IP, SO_ORIGINAL_DST,
- (struct sockaddr*)&orig_dst, &orig_dst_len) < 0) {
+ int rv = -1;
+ switch (ENTRY_TO_CONN(conn)->socket_family) {
+#ifdef TRANS_NETFILTER_IPV4
+ case AF_INET:
+ rv = getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IP, SO_ORIGINAL_DST,
+ (struct sockaddr*)&orig_dst, &orig_dst_len);
+ break;
+#endif
+#ifdef TRANS_NETFILTER_IPV6
+ case AF_INET6:
+ rv = getsockopt(ENTRY_TO_CONN(conn)->s, SOL_IPV6, IP6T_SO_ORIGINAL_DST,
+ (struct sockaddr*)&orig_dst, &orig_dst_len);
+ break;
+#endif
+ default:
+ log_warn(LD_BUG,
+ "Received transparent data from an unsuported socket family %d",
+ ENTRY_TO_CONN(conn)->socket_family);
+ return -1;
+ }
+ if (rv < 0) {
int e = tor_socket_errno(ENTRY_TO_CONN(conn)->s);
log_warn(LD_NET, "getsockopt() failed: %s", tor_socket_strerror(e));
return -1;
}
+ goto done;
#elif defined(TRANS_PF)
if (getsockname(ENTRY_TO_CONN(conn)->s, (struct sockaddr*)&orig_dst,
&orig_dst_len) < 0) {
@@ -1415,6 +1645,7 @@ destination_from_socket(entry_connection_t *conn, socks_request_t *req)
log_warn(LD_NET, "getsockname() failed: %s", tor_socket_strerror(e));
return -1;
}
+ goto done;
#else
(void)conn;
(void)req;
@@ -1422,6 +1653,7 @@ destination_from_socket(entry_connection_t *conn, socks_request_t *req)
return -1;
#endif
+ done:
tor_addr_from_sockaddr(&addr, (struct sockaddr*)&orig_dst, &req->port);
tor_addr_to_str(req->address, &addr, sizeof(req->address), 1);
@@ -1531,7 +1763,8 @@ connection_ap_get_original_destination(entry_connection_t *conn,
if (options->TransProxyType_parsed == TPT_PF_DIVERT)
return destination_from_socket(conn, req);
- if (options->TransProxyType_parsed == TPT_DEFAULT)
+ if (options->TransProxyType_parsed == TPT_DEFAULT ||
+ options->TransProxyType_parsed == TPT_IPFW)
return destination_from_pf(conn, req);
(void)conn;
@@ -1767,7 +2000,8 @@ connection_ap_supports_optimistic_data(const entry_connection_t *conn)
general circuit. */
if (edge_conn->on_circuit == NULL ||
edge_conn->on_circuit->state != CIRCUIT_STATE_OPEN ||
- edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL)
+ (edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL &&
+ edge_conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_REND_JOINED))
return 0;
return conn->may_use_optimistic_data;
@@ -1792,19 +2026,19 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
return 0;
/* If only IPv4 is supported, no flags */
- if (ap_conn->ipv4_traffic_ok && !ap_conn->ipv6_traffic_ok)
+ if (ap_conn->entry_cfg.ipv4_traffic && !ap_conn->entry_cfg.ipv6_traffic)
return 0;
if (! cpath_layer ||
! cpath_layer->extend_info)
return 0;
- if (!ap_conn->ipv4_traffic_ok)
+ if (!ap_conn->entry_cfg.ipv4_traffic)
flags |= BEGIN_FLAG_IPV4_NOT_OK;
exitnode = node_get_by_id(cpath_layer->extend_info->identity_digest);
- if (ap_conn->ipv6_traffic_ok && exitnode) {
+ if (ap_conn->entry_cfg.ipv6_traffic && exitnode) {
tor_addr_t a;
tor_addr_make_null(&a, AF_INET6);
if (compare_tor_addr_to_node_policy(&a, ap_conn->socks_request->port,
@@ -1819,7 +2053,7 @@ connection_ap_get_begincell_flags(entry_connection_t *ap_conn)
if (flags == BEGIN_FLAG_IPV6_OK) {
/* When IPv4 and IPv6 are both allowed, consider whether to say we
* prefer IPv6. Otherwise there's no point in declaring a preference */
- if (ap_conn->prefer_ipv6_traffic)
+ if (ap_conn->entry_cfg.prefer_ipv6)
flags |= BEGIN_FLAG_IPV6_PREFERRED;
}
@@ -2056,8 +2290,8 @@ connection_ap_make_link(connection_t *partner,
/* Populate isolation fields. */
conn->socks_request->listener_type = CONN_TYPE_DIR_LISTENER;
conn->original_dest_address = tor_strdup(address);
- conn->session_group = session_group;
- conn->isolation_flags = isolation_flags;
+ conn->entry_cfg.session_group = session_group;
+ conn->entry_cfg.isolation_flags = isolation_flags;
base_conn->address = tor_strdup("(Tor_internal)");
tor_addr_make_unspec(&base_conn->addr);
@@ -2460,7 +2694,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
relay_header_unpack(&rh, cell->payload);
if (rh.length > RELAY_PAYLOAD_SIZE)
- return -1;
+ return -END_CIRC_REASON_TORPROTOCOL;
/* Note: we have to use relay_send_command_from_edge here, not
* connection_edge_end or connection_edge_send_command, since those require
@@ -2478,7 +2712,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
r = begin_cell_parse(cell, &bcell, &end_reason);
if (r < -1) {
- return -1;
+ return -END_CIRC_REASON_TORPROTOCOL;
} else if (r == -1) {
tor_free(bcell.address);
relay_send_end_cell_from_edge(rh.stream_id, circ, end_reason, NULL);
@@ -2576,15 +2810,31 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
n_stream->rend_data = rend_data_dup(origin_circ->rend_data);
tor_assert(connection_edge_is_rendezvous_stream(n_stream));
assert_circuit_ok(circ);
- if (rend_service_set_connection_addr_port(n_stream, origin_circ) < 0) {
+
+ const int r = rend_service_set_connection_addr_port(n_stream, origin_circ);
+ if (r < 0) {
log_info(LD_REND,"Didn't find rendezvous service (port %d)",
n_stream->base_.port);
+ /* Send back reason DONE because we want to make hidden service port
+ * scanning harder thus instead of returning that the exit policy
+ * didn't match, which makes it obvious that the port is closed,
+ * return DONE and kill the circuit. That way, a user (malicious or
+ * not) needs one circuit per bad port unless it matches the policy of
+ * the hidden service. */
relay_send_end_cell_from_edge(rh.stream_id, circ,
- END_STREAM_REASON_EXITPOLICY,
+ END_STREAM_REASON_DONE,
origin_circ->cpath->prev);
connection_free(TO_CONN(n_stream));
tor_free(address);
- return 0;
+
+ /* Drop the circuit here since it might be someone deliberately
+ * scanning the hidden service ports. Note that this mitigates port
+ * scanning by adding more work on the attacker side to successfully
+ * scan but does not fully solve it. */
+ if (r < -1)
+ return END_CIRC_AT_ORIGIN;
+ else
+ return 0;
}
assert_circuit_ok(circ);
log_debug(LD_REND,"Finished assigning addr/port");
@@ -2712,7 +2962,7 @@ connection_exit_connect(edge_connection_t *edge_conn)
const tor_addr_t *addr;
uint16_t port;
connection_t *conn = TO_CONN(edge_conn);
- int socket_error = 0;
+ int socket_error = 0, result;
if ( (!connection_edge_is_rendezvous_stream(edge_conn) &&
router_compare_to_my_exit_policy(&edge_conn->base_.addr,
@@ -2727,14 +2977,36 @@ connection_exit_connect(edge_connection_t *edge_conn)
return;
}
- addr = &conn->addr;
- port = conn->port;
+#ifdef HAVE_SYS_UN_H
+ if (conn->socket_family != AF_UNIX) {
+#else
+ {
+#endif /* defined(HAVE_SYS_UN_H) */
+ addr = &conn->addr;
+ port = conn->port;
+
+ if (tor_addr_family(addr) == AF_INET6)
+ conn->socket_family = AF_INET6;
+
+ log_debug(LD_EXIT, "about to try connecting");
+ result = connection_connect(conn, conn->address,
+ addr, port, &socket_error);
+#ifdef HAVE_SYS_UN_H
+ } else {
+ /*
+ * In the AF_UNIX case, we expect to have already had conn->port = 1,
+ * tor_addr_make_unspec(conn->addr) (cf. the way we mark in the incoming
+ * case in connection_handle_listener_read()), and conn->address should
+ * have the socket path to connect to.
+ */
+ tor_assert(conn->address && strlen(conn->address) > 0);
- if (tor_addr_family(addr) == AF_INET6)
- conn->socket_family = AF_INET6;
+ log_debug(LD_EXIT, "about to try connecting");
+ result = connection_connect_unix(conn, conn->address, &socket_error);
+#endif /* defined(HAVE_SYS_UN_H) */
+ }
- log_debug(LD_EXIT,"about to try connecting");
- switch (connection_connect(conn, conn->address, addr, port, &socket_error)) {
+ switch (result) {
case -1: {
int reason = errno_to_stream_end_reason(socket_error);
connection_edge_end(edge_conn, reason);
@@ -2764,7 +3036,6 @@ connection_exit_connect(edge_connection_t *edge_conn)
/* also, deliver a 'connected' cell back through the circuit. */
if (connection_edge_is_rendezvous_stream(edge_conn)) {
- /* rendezvous stream */
/* don't send an address back! */
connection_edge_send_command(edge_conn,
RELAY_COMMAND_CONNECTED,
@@ -2903,10 +3174,10 @@ connection_ap_can_use_exit(const entry_connection_t *conn, const node_t *exit)
addr_policy_result_t r;
if (0 == tor_addr_parse(&addr, conn->socks_request->address)) {
addrp = &addr;
- } else if (!conn->ipv4_traffic_ok && conn->ipv6_traffic_ok) {
+ } else if (!conn->entry_cfg.ipv4_traffic && conn->entry_cfg.ipv6_traffic) {
tor_addr_make_null(&addr, AF_INET6);
addrp = &addr;
- } else if (conn->ipv4_traffic_ok && !conn->ipv6_traffic_ok) {
+ } else if (conn->entry_cfg.ipv4_traffic && !conn->entry_cfg.ipv6_traffic) {
tor_addr_make_null(&addr, AF_INET);
addrp = &addr;
}
@@ -3012,7 +3283,7 @@ int
connection_edge_compatible_with_circuit(const entry_connection_t *conn,
const origin_circuit_t *circ)
{
- const uint8_t iso = conn->isolation_flags;
+ const uint8_t iso = conn->entry_cfg.isolation_flags;
const socks_request_t *sr = conn->socks_request;
/* If circ has never been used for an isolated connection, we can
@@ -3061,7 +3332,8 @@ connection_edge_compatible_with_circuit(const entry_connection_t *conn,
if ((iso & ISO_CLIENTADDR) &&
!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr))
return 0;
- if ((iso & ISO_SESSIONGRP) && conn->session_group != circ->session_group)
+ if ((iso & ISO_SESSIONGRP) &&
+ conn->entry_cfg.session_group != circ->session_group)
return 0;
if ((iso & ISO_NYM_EPOCH) && conn->nym_epoch != circ->nym_epoch)
return 0;
@@ -3100,7 +3372,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
circ->client_proto_type = conn->socks_request->listener_type;
circ->client_proto_socksver = conn->socks_request->socks_version;
tor_addr_copy(&circ->client_addr, &ENTRY_TO_CONN(conn)->addr);
- circ->session_group = conn->session_group;
+ circ->session_group = conn->entry_cfg.session_group;
circ->nym_epoch = conn->nym_epoch;
circ->socks_username = sr->username ?
tor_memdup(sr->username, sr->usernamelen) : NULL;
@@ -3127,7 +3399,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
mixed |= ISO_CLIENTPROTO;
if (!tor_addr_eq(&ENTRY_TO_CONN(conn)->addr, &circ->client_addr))
mixed |= ISO_CLIENTADDR;
- if (conn->session_group != circ->session_group)
+ if (conn->entry_cfg.session_group != circ->session_group)
mixed |= ISO_SESSIONGRP;
if (conn->nym_epoch != circ->nym_epoch)
mixed |= ISO_NYM_EPOCH;
@@ -3135,7 +3407,7 @@ connection_edge_update_circuit_isolation(const entry_connection_t *conn,
if (dry_run)
return mixed;
- if ((mixed & conn->isolation_flags) != 0) {
+ if ((mixed & conn->entry_cfg.isolation_flags) != 0) {
log_warn(LD_BUG, "Updating a circuit with seemingly incompatible "
"isolation flags.");
}
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index 3c0e30a973..7c0b9c0767 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -143,6 +143,30 @@ STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
STATIC int connected_cell_format_payload(uint8_t *payload_out,
const tor_addr_t *addr,
uint32_t ttl);
+
+typedef struct {
+ /** Original address, after we lowercased it but before we started
+ * mapping it.
+ */
+ char orig_address[MAX_SOCKS_ADDR_LEN];
+ /** True iff the address has been automatically remapped to a local
+ * address in VirtualAddrNetwork. (Only set true when we do a resolve
+ * and get a virtual address; not when we connect to the address.) */
+ int automap;
+ /** If this connection has a .exit address, who put it there? */
+ addressmap_entry_source_t exit_source;
+ /** If we've rewritten the address, when does this map expire? */
+ time_t map_expires;
+ /** If we should close the connection, this is the end_reason to pass
+ * to connection_mark_unattached_ap */
+ int end_reason;
+ /** True iff we should close the connection, either because of error or
+ * because of successful early RESOLVED reply. */
+ int should_close;
+} rewrite_result_t;
+
+STATIC void connection_ap_handshake_rewrite(entry_connection_t *conn,
+ rewrite_result_t *out);
#endif
#endif
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 8c8094b440..09c9b7c27f 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -38,6 +38,8 @@
#include "router.h"
#include "routerlist.h"
#include "ext_orport.h"
+#include "scheduler.h"
+
#ifdef USE_BUFFEREVENTS
#include <event2/bufferevent_ssl.h>
#endif
@@ -576,48 +578,51 @@ connection_or_process_inbuf(or_connection_t *conn)
return ret;
}
-/** When adding cells to an OR connection's outbuf, keep adding until the
- * outbuf is at least this long, or we run out of cells. */
-#define OR_CONN_HIGHWATER (32*1024)
-
-/** Add cells to an OR connection's outbuf whenever the outbuf's data length
- * drops below this size. */
-#define OR_CONN_LOWWATER (16*1024)
-
/** Called whenever we have flushed some data on an or_conn: add more data
* from active circuits. */
int
connection_or_flushed_some(or_connection_t *conn)
{
- size_t datalen, temp;
- ssize_t n, flushed;
- size_t cell_network_size = get_cell_network_size(conn->wide_circ_ids);
+ size_t datalen;
+
+ /* The channel will want to update its estimated queue size */
+ channel_update_xmit_queue_size(TLS_CHAN_TO_BASE(conn->chan));
/* If we're under the low water mark, add cells until we're just over the
* high water mark. */
datalen = connection_get_outbuf_len(TO_CONN(conn));
if (datalen < OR_CONN_LOWWATER) {
- while ((conn->chan) && channel_tls_more_to_flush(conn->chan)) {
- /* Compute how many more cells we want at most */
- n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, cell_network_size);
- /* Bail out if we don't want any more */
- if (n <= 0) break;
- /* We're still here; try to flush some more cells */
- flushed = channel_tls_flush_some_cells(conn->chan, n);
- /* Bail out if it says it didn't flush anything */
- if (flushed <= 0) break;
- /* How much in the outbuf now? */
- temp = connection_get_outbuf_len(TO_CONN(conn));
- /* Bail out if we didn't actually increase the outbuf size */
- if (temp <= datalen) break;
- /* Update datalen for the next iteration */
- datalen = temp;
- }
+ /* Let the scheduler know */
+ scheduler_channel_wants_writes(TLS_CHAN_TO_BASE(conn->chan));
}
return 0;
}
+/** This is for channeltls.c to ask how many cells we could accept if
+ * they were available. */
+ssize_t
+connection_or_num_cells_writeable(or_connection_t *conn)
+{
+ size_t datalen, cell_network_size;
+ ssize_t n = 0;
+
+ tor_assert(conn);
+
+ /*
+ * If we're under the high water mark, we're potentially
+ * writeable; note this is different from the calculation above
+ * used to trigger when to start writing after we've stopped.
+ */
+ datalen = connection_get_outbuf_len(TO_CONN(conn));
+ if (datalen < OR_CONN_HIGHWATER) {
+ cell_network_size = get_cell_network_size(conn->wide_circ_ids);
+ n = CEIL_DIV(OR_CONN_HIGHWATER - datalen, cell_network_size);
+ }
+
+ return n;
+}
+
/** Connection <b>conn</b> has finished writing and has no bytes left on
* its outbuf.
*
@@ -910,18 +915,11 @@ connection_or_init_conn_from_address(or_connection_t *conn,
tor_free(conn->base_.address);
conn->base_.address = tor_dup_addr(&node_ap.addr);
} else {
- const char *n;
- /* If we're an authoritative directory server, we may know a
- * nickname for this router. */
- n = dirserv_get_nickname_by_digest(id_digest);
- if (n) {
- conn->nickname = tor_strdup(n);
- } else {
- conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
- conn->nickname[0] = '$';
- base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
- conn->identity_digest, DIGEST_LEN);
- }
+ conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
+ conn->nickname[0] = '$';
+ base16_encode(conn->nickname+1, HEX_DIGEST_LEN+1,
+ conn->identity_digest, DIGEST_LEN);
+
tor_free(conn->base_.address);
conn->base_.address = tor_dup_addr(addr);
}
@@ -1153,9 +1151,7 @@ connection_or_notify_error(or_connection_t *conn,
if (conn->chan) {
chan = TLS_CHAN_TO_BASE(conn->chan);
/* Don't transition if we're already in closing, closed or error */
- if (!(chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR)) {
+ if (!CHANNEL_CONDEMNED(chan)) {
channel_close_for_error(chan);
}
}
@@ -1178,10 +1174,10 @@ connection_or_notify_error(or_connection_t *conn,
*
* Return the launched conn, or NULL if it failed.
*/
-or_connection_t *
-connection_or_connect(const tor_addr_t *_addr, uint16_t port,
- const char *id_digest,
- channel_tls_t *chan)
+
+MOCK_IMPL(or_connection_t *,
+connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
+ const char *id_digest, channel_tls_t *chan))
{
or_connection_t *conn;
const or_options_t *options = get_options();
@@ -1314,9 +1310,7 @@ connection_or_close_normally(or_connection_t *orconn, int flush)
if (orconn->chan) {
chan = TLS_CHAN_TO_BASE(orconn->chan);
/* Don't transition if we're already in closing, closed or error */
- if (!(chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR)) {
+ if (!CHANNEL_CONDEMNED(chan)) {
channel_close_from_lower_layer(chan);
}
}
@@ -1337,9 +1331,7 @@ connection_or_close_for_error(or_connection_t *orconn, int flush)
if (orconn->chan) {
chan = TLS_CHAN_TO_BASE(orconn->chan);
/* Don't transition if we're already in closing, closed or error */
- if (!(chan->state == CHANNEL_STATE_CLOSING ||
- chan->state == CHANNEL_STATE_CLOSED ||
- chan->state == CHANNEL_STATE_ERROR)) {
+ if (!CHANNEL_CONDEMNED(chan)) {
channel_close_for_error(chan);
}
}
@@ -1829,6 +1821,7 @@ connection_tls_finish_handshake(or_connection_t *conn)
conn->base_.port, digest_rcvd, 0);
}
tor_tls_block_renegotiation(conn->tls);
+ rep_hist_note_negotiated_link_proto(1, started_here);
return connection_or_set_state_open(conn);
} else {
connection_or_change_state(conn, OR_CONN_STATE_OR_HANDSHAKING_V2);
diff --git a/src/or/connection_or.h b/src/or/connection_or.h
index 143540edd9..fc261c6bac 100644
--- a/src/or/connection_or.h
+++ b/src/or/connection_or.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -24,6 +24,7 @@ void connection_or_set_bad_connections(const char *digest, int force);
void connection_or_block_renegotiation(or_connection_t *conn);
int connection_or_reached_eof(or_connection_t *conn);
int connection_or_process_inbuf(or_connection_t *conn);
+ssize_t connection_or_num_cells_writeable(or_connection_t *conn);
int connection_or_flushed_some(or_connection_t *conn);
int connection_or_finished_flushing(or_connection_t *conn);
int connection_or_finished_connecting(or_connection_t *conn);
@@ -36,9 +37,10 @@ void connection_or_connect_failed(or_connection_t *conn,
int reason, const char *msg);
void connection_or_notify_error(or_connection_t *conn,
int reason, const char *msg);
-or_connection_t *connection_or_connect(const tor_addr_t *addr, uint16_t port,
- const char *id_digest,
- channel_tls_t *chan);
+MOCK_DECL(or_connection_t *,
+ connection_or_connect,
+ (const tor_addr_t *addr, uint16_t port,
+ const char *id_digest, channel_tls_t *chan));
void connection_or_close_normally(or_connection_t *orconn, int flush);
void connection_or_close_for_error(or_connection_t *orconn, int flush);
diff --git a/src/or/control.c b/src/or/control.c
index 2ff1cc8442..e25c3b2954 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -47,6 +47,7 @@
#include <sys/resource.h>
#endif
+#include "crypto_s2k.h"
#include "procmon.h"
/** Yield true iff <b>s</b> is the state of a control_connection_t that has
@@ -194,14 +195,14 @@ log_severity_to_event(int severity)
static void
clear_circ_bw_fields(void)
{
- circuit_t *circ;
origin_circuit_t *ocirc;
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
ocirc = TO_ORIGIN_CIRCUIT(circ);
ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0;
}
+ SMARTLIST_FOREACH_END(circ);
}
/** Set <b>global_event_mask*</b> to the bitwise OR of each live control
@@ -949,7 +950,7 @@ static int
handle_control_setevents(control_connection_t *conn, uint32_t len,
const char *body)
{
- int event_code = -1;
+ int event_code;
event_mask_t event_mask = 0;
smartlist_t *events = smartlist_new();
@@ -963,6 +964,8 @@ handle_control_setevents(control_connection_t *conn, uint32_t len,
continue;
} else {
int i;
+ event_code = -1;
+
for (i = 0; control_event_table[i].event_name != NULL; ++i) {
if (!strcasecmp(ev, control_event_table[i].event_name)) {
event_code = control_event_table[i].event_code;
@@ -993,7 +996,8 @@ handle_control_setevents(control_connection_t *conn, uint32_t len,
/** Decode the hashed, base64'd passwords stored in <b>passwords</b>.
* Return a smartlist of acceptable passwords (unterminated strings of
- * length S2K_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on failure.
+ * length S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) on success, or NULL on
+ * failure.
*/
smartlist_t *
decode_hashed_passwords(config_line_t *passwords)
@@ -1009,16 +1013,17 @@ decode_hashed_passwords(config_line_t *passwords)
if (!strcmpstart(hashed, "16:")) {
if (base16_decode(decoded, sizeof(decoded), hashed+3, strlen(hashed+3))<0
- || strlen(hashed+3) != (S2K_SPECIFIER_LEN+DIGEST_LEN)*2) {
+ || strlen(hashed+3) != (S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN)*2) {
goto err;
}
} else {
if (base64_decode(decoded, sizeof(decoded), hashed, strlen(hashed))
- != S2K_SPECIFIER_LEN+DIGEST_LEN) {
+ != S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN) {
goto err;
}
}
- smartlist_add(sl, tor_memdup(decoded, S2K_SPECIFIER_LEN+DIGEST_LEN));
+ smartlist_add(sl,
+ tor_memdup(decoded, S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN));
}
return sl;
@@ -1039,7 +1044,7 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
{
int used_quoted_string = 0;
const or_options_t *options = get_options();
- const char *errstr = NULL;
+ const char *errstr = "Unknown error";
char *password;
size_t password_len;
const char *cp;
@@ -1160,22 +1165,27 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
}
if (bad) {
if (!also_cookie) {
- log_warn(LD_CONTROL,
+ log_warn(LD_BUG,
"Couldn't decode HashedControlPassword: invalid base16");
errstr="Couldn't decode HashedControlPassword value in configuration.";
+ goto err;
}
bad_password = 1;
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_free(sl);
+ sl = NULL;
} else {
SMARTLIST_FOREACH(sl, char *, expected,
{
- secret_to_key(received,DIGEST_LEN,password,password_len,expected);
- if (tor_memeq(expected+S2K_SPECIFIER_LEN, received, DIGEST_LEN))
+ secret_to_key_rfc2440(received,DIGEST_LEN,
+ password,password_len,expected);
+ if (tor_memeq(expected + S2K_RFC2440_SPECIFIER_LEN,
+ received, DIGEST_LEN))
goto ok;
});
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_free(sl);
+ sl = NULL;
if (used_quoted_string)
errstr = "Password did not match HashedControlPassword value from "
@@ -1198,9 +1208,12 @@ handle_control_authenticate(control_connection_t *conn, uint32_t len,
err:
tor_free(password);
- connection_printf_to_buf(conn, "515 Authentication failed: %s\r\n",
- errstr ? errstr : "Unknown reason.");
+ connection_printf_to_buf(conn, "515 Authentication failed: %s\r\n", errstr);
connection_mark_for_close(TO_CONN(conn));
+ if (sl) { /* clean up */
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+ }
return 0;
ok:
log_info(LD_CONTROL, "Authenticated control connection ("TOR_SOCKET_T_FORMAT
@@ -1250,6 +1263,7 @@ static const struct signal_t signal_table[] = {
{ SIGTERM, "INT" },
{ SIGNEWNYM, "NEWNYM" },
{ SIGCLEARDNSCACHE, "CLEARDNSCACHE"},
+ { SIGHEARTBEAT, "HEARTBEAT"},
{ 0, NULL },
};
@@ -1427,9 +1441,13 @@ getinfo_helper_misc(control_connection_t *conn, const char *question,
} else if (!strcmp(question, "bw-event-cache")) {
*answer = get_bw_samples();
} else if (!strcmp(question, "config-file")) {
- *answer = tor_strdup(get_torrc_fname(0));
+ const char *a = get_torrc_fname(0);
+ if (a)
+ *answer = tor_strdup(a);
} else if (!strcmp(question, "config-defaults-file")) {
- *answer = tor_strdup(get_torrc_fname(1));
+ const char *a = get_torrc_fname(1);
+ if (a)
+ *answer = tor_strdup(a);
} else if (!strcmp(question, "config-text")) {
*answer = options_dump(get_options(), OPTIONS_DUMP_MINIMAL);
} else if (!strcmp(question, "info/names")) {
@@ -1864,6 +1882,22 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
smartlist_add_asprintf(descparts, "TIME_CREATED=%s", tbuf);
}
+ // Show username and/or password if available.
+ if (circ->socks_username_len > 0) {
+ char* socks_username_escaped = esc_for_log_len(circ->socks_username,
+ (size_t) circ->socks_username_len);
+ smartlist_add_asprintf(descparts, "SOCKS_USERNAME=%s",
+ socks_username_escaped);
+ tor_free(socks_username_escaped);
+ }
+ if (circ->socks_password_len > 0) {
+ char* socks_password_escaped = esc_for_log_len(circ->socks_password,
+ (size_t) circ->socks_password_len);
+ smartlist_add_asprintf(descparts, "SOCKS_PASSWORD=%s",
+ socks_password_escaped);
+ tor_free(socks_password_escaped);
+ }
+
rv = smartlist_join_strings(descparts, " ", 0, NULL);
SMARTLIST_FOREACH(descparts, char *, cp, tor_free(cp));
@@ -1881,9 +1915,8 @@ getinfo_helper_events(control_connection_t *control_conn,
{
(void) control_conn;
if (!strcmp(question, "circuit-status")) {
- circuit_t *circ_;
smartlist_t *status = smartlist_new();
- TOR_LIST_FOREACH(circ_, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ_) {
origin_circuit_t *circ;
char *circdesc;
const char *state;
@@ -1905,6 +1938,7 @@ getinfo_helper_events(control_connection_t *control_conn,
state, *circdesc ? " " : "", circdesc);
tor_free(circdesc);
}
+ SMARTLIST_FOREACH_END(circ_);
*answer = smartlist_join_strings(status, "\r\n", 0, NULL);
SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
smartlist_free(status);
@@ -2004,7 +2038,7 @@ getinfo_helper_events(control_connection_t *control_conn,
/* Note that status/ is not a catch-all for events; there's only supposed
* to be a status GETINFO if there's a corresponding STATUS event. */
if (!strcmp(question, "status/circuit-established")) {
- *answer = tor_strdup(can_complete_circuit ? "1" : "0");
+ *answer = tor_strdup(have_completed_a_circuit() ? "1" : "0");
} else if (!strcmp(question, "status/enough-dir-info")) {
*answer = tor_strdup(router_have_minimum_dir_info() ? "1" : "0");
} else if (!strcmp(question, "status/good-server-descriptor") ||
@@ -2151,6 +2185,8 @@ static const getinfo_item_t getinfo_items[] = {
"Brief summary of router status by nickname (v2 directory format)."),
PREFIX("ns/purpose/", networkstatus,
"Brief summary of router status by purpose (v2 directory format)."),
+ PREFIX("consensus/", networkstatus,
+ "Information about and from the ns consensus."),
ITEM("network-status", dir,
"Brief summary of router status (v1 directory format)"),
ITEM("circuit-status", events, "List of current circuits originating here."),
@@ -2454,6 +2490,14 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
goto done;
}
+ if (smartlist_len(args) < 2) {
+ connection_printf_to_buf(conn,
+ "512 syntax error: not enough arguments.\r\n");
+ SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
+ smartlist_free(args);
+ goto done;
+ }
+
smartlist_split_string(router_nicknames, smartlist_get(args,1), ",", 0, 0);
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
@@ -3912,12 +3956,11 @@ control_event_stream_bandwidth_used(void)
int
control_event_circ_bandwidth_used(void)
{
- circuit_t *circ;
origin_circuit_t *ocirc;
if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED))
return 0;
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
ocirc = TO_ORIGIN_CIRCUIT(circ);
@@ -3930,6 +3973,7 @@ control_event_circ_bandwidth_used(void)
(unsigned long)ocirc->n_written_circ_bw);
ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0;
}
+ SMARTLIST_FOREACH_END(circ);
return 0;
}
@@ -4094,14 +4138,13 @@ format_cell_stats(char **event_string, circuit_t *circ,
int
control_event_circuit_cell_stats(void)
{
- circuit_t *circ;
cell_stats_t *cell_stats;
char *event_string;
if (!get_options()->TestingEnableCellStatsEvent ||
!EVENT_IS_INTERESTING(EVENT_CELL_STATS))
return 0;
cell_stats = tor_malloc(sizeof(cell_stats_t));;
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (!circ->testing_cell_stats)
continue;
sum_up_cell_stats_by_command(circ, cell_stats);
@@ -4110,6 +4153,7 @@ control_event_circuit_cell_stats(void)
"650 CELL_STATS %s\r\n", event_string);
tor_free(event_string);
}
+ SMARTLIST_FOREACH_END(circ);
tor_free(cell_stats);
return 0;
}
@@ -4175,12 +4219,12 @@ get_bw_samples(void)
int i;
int idx = (next_measurement_idx + N_BW_EVENTS_TO_CACHE - n_measurements)
% N_BW_EVENTS_TO_CACHE;
- smartlist_t *elements = smartlist_new();
tor_assert(0 <= idx && idx < N_BW_EVENTS_TO_CACHE);
+ smartlist_t *elements = smartlist_new();
+
for (i = 0; i < n_measurements; ++i) {
tor_assert(0 <= idx && idx < N_BW_EVENTS_TO_CACHE);
- {
const struct cached_bw_event_s *bwe = &cached_bw_events[idx];
smartlist_add_asprintf(elements, "%u,%u",
@@ -4188,17 +4232,14 @@ get_bw_samples(void)
(unsigned)bwe->n_written);
idx = (idx + 1) % N_BW_EVENTS_TO_CACHE;
- }
}
- {
char *result = smartlist_join_strings(elements, " ", 0, NULL);
SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
smartlist_free(elements);
return result;
- }
}
/** Called when we are sending a log message to the controllers: suspend
@@ -4494,6 +4535,9 @@ control_event_signal(uintptr_t signal)
case SIGCLEARDNSCACHE:
signal_string = "CLEARDNSCACHE";
break;
+ case SIGHEARTBEAT:
+ signal_string = "HEARTBEAT";
+ break;
default:
log_warn(LD_BUG, "Unrecognized signal %lu in control_event_signal",
(unsigned long)signal);
@@ -4843,23 +4887,43 @@ bootstrap_status_to_string(bootstrap_status_t s, const char **tag,
break;
case BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS:
*tag = "requesting_descriptors";
- *summary = "Asking for relay descriptors";
+ /* XXXX this appears to incorrectly report internal on most loads */
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Asking for relay descriptors for internal paths" :
+ "Asking for relay descriptors";
break;
+ /* If we're sure there are no exits in the consensus,
+ * inform the controller by adding "internal"
+ * to the status summaries.
+ * (We only check this while loading descriptors,
+ * so we may not know in the earlier stages.)
+ * But if there are exits, we can't be sure whether
+ * we're creating internal or exit paths/circuits.
+ * XXXX Or should be use different tags or statuses
+ * for internal and exit/all? */
case BOOTSTRAP_STATUS_LOADING_DESCRIPTORS:
*tag = "loading_descriptors";
- *summary = "Loading relay descriptors";
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Loading relay descriptors for internal paths" :
+ "Loading relay descriptors";
break;
case BOOTSTRAP_STATUS_CONN_OR:
*tag = "conn_or";
- *summary = "Connecting to the Tor network";
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Connecting to the Tor network internally" :
+ "Connecting to the Tor network";
break;
case BOOTSTRAP_STATUS_HANDSHAKE_OR:
*tag = "handshake_or";
- *summary = "Finishing handshake with first hop";
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Finishing handshake with first hop of internal circuit" :
+ "Finishing handshake with first hop";
break;
case BOOTSTRAP_STATUS_CIRCUIT_CREATE:
*tag = "circuit_create";
- *summary = "Establishing a Tor circuit";
+ *summary = router_have_consensus_path() == CONSENSUS_PATH_INTERNAL ?
+ "Establishing an internal Tor circuit" :
+ "Establishing a Tor circuit";
break;
case BOOTSTRAP_STATUS_DONE:
*tag = "done";
@@ -4907,15 +4971,18 @@ static int bootstrap_problems = 0;
*
* <b>status</b> is the new status, that is, what task we will be doing
* next. <b>progress</b> is zero if we just started this task, else it
- * represents progress on the task. */
-void
+ * represents progress on the task.
+ *
+ * Return true if we logged a message at level NOTICE, and false otherwise.
+ */
+int
control_event_bootstrap(bootstrap_status_t status, int progress)
{
const char *tag, *summary;
char buf[BOOTSTRAP_MSG_LEN];
if (bootstrap_percent == BOOTSTRAP_STATUS_DONE)
- return; /* already bootstrapped; nothing to be done here. */
+ return 0; /* already bootstrapped; nothing to be done here. */
/* special case for handshaking status, since our TLS handshaking code
* can't distinguish what the connection is going to be for. */
@@ -4962,7 +5029,10 @@ control_event_bootstrap(bootstrap_status_t status, int progress)
/* Remember that we gave a notice at this level. */
notice_bootstrap_percent = bootstrap_percent;
}
+ return loglevel == LOG_NOTICE;
}
+
+ return 0;
}
/** Called when Tor has failed to make bootstrapping progress in a way
@@ -5016,19 +5086,26 @@ MOCK_IMPL(void,
log_fn(severity,
LD_CONTROL, "Problem bootstrapping. Stuck at %d%%: %s. (%s; %s; "
- "count %d; recommendation %s)",
+ "count %d; recommendation %s; host %s at %s:%d)",
status, summary, warn,
orconn_end_reason_to_control_string(reason),
- bootstrap_problems, recommendation);
+ bootstrap_problems, recommendation,
+ hex_str(or_conn->identity_digest, DIGEST_LEN),
+ or_conn->base_.address,
+ or_conn->base_.port);
connection_or_report_broken_states(severity, LD_HANDSHAKE);
tor_snprintf(buf, sizeof(buf),
"BOOTSTRAP PROGRESS=%d TAG=%s SUMMARY=\"%s\" WARNING=\"%s\" REASON=%s "
- "COUNT=%d RECOMMENDATION=%s",
+ "COUNT=%d RECOMMENDATION=%s HOSTID=\"%s\" HOSTADDR=\"%s:%d\"",
bootstrap_percent, tag, summary, warn,
orconn_end_reason_to_control_string(reason), bootstrap_problems,
- recommendation);
+ recommendation,
+ hex_str(or_conn->identity_digest, DIGEST_LEN),
+ or_conn->base_.address,
+ (int)or_conn->base_.port);
+
tor_snprintf(last_sent_bootstrap_message,
sizeof(last_sent_bootstrap_message),
"WARN %s", buf);
@@ -5136,20 +5213,30 @@ control_event_hs_descriptor_requested(const rend_data_t *rend_query,
void
control_event_hs_descriptor_receive_end(const char *action,
const rend_data_t *rend_query,
- const char *id_digest)
+ const char *id_digest,
+ const char *reason)
{
+ char *reason_field = NULL;
+
if (!action || !rend_query || !id_digest) {
log_warn(LD_BUG, "Called with action==%p, rend_query==%p, "
"id_digest==%p", action, rend_query, id_digest);
return;
}
+ if (reason) {
+ tor_asprintf(&reason_field, " REASON=%s", reason);
+ }
+
send_control_event(EVENT_HS_DESC, ALL_FORMATS,
- "650 HS_DESC %s %s %s %s\r\n",
+ "650 HS_DESC %s %s %s %s%s\r\n",
action,
rend_query->onion_address,
rend_auth_type_to_string(rend_query->auth_type),
- node_describe_longname_by_id(id_digest));
+ node_describe_longname_by_id(id_digest),
+ reason_field ? reason_field : "");
+
+ tor_free(reason_field);
}
/** send HS_DESC RECEIVED event
@@ -5165,23 +5252,27 @@ control_event_hs_descriptor_received(const rend_data_t *rend_query,
rend_query, id_digest);
return;
}
- control_event_hs_descriptor_receive_end("RECEIVED", rend_query, id_digest);
+ control_event_hs_descriptor_receive_end("RECEIVED", rend_query,
+ id_digest, NULL);
}
-/** send HS_DESC FAILED event
- *
- * called when request for hidden service descriptor returned failure.
+/** Send HS_DESC event to inform controller that query <b>rend_query</b>
+ * failed to retrieve hidden service descriptor identified by
+ * <b>id_digest</b>. If <b>reason</b> is not NULL, add it to REASON=
+ * field.
*/
void
control_event_hs_descriptor_failed(const rend_data_t *rend_query,
- const char *id_digest)
+ const char *id_digest,
+ const char *reason)
{
if (!rend_query || !id_digest) {
log_warn(LD_BUG, "Called with rend_query==%p, id_digest==%p",
rend_query, id_digest);
return;
}
- control_event_hs_descriptor_receive_end("FAILED", rend_query, id_digest);
+ control_event_hs_descriptor_receive_end("FAILED", rend_query,
+ id_digest, reason);
}
/** Free any leftover allocated memory of the control.c subsystem. */
diff --git a/src/or/control.h b/src/or/control.h
index 8697262176..47a601817a 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -92,7 +92,7 @@ void enable_control_logging(void);
void monitor_owning_controller_process(const char *process_spec);
-void control_event_bootstrap(bootstrap_status_t status, int progress);
+int control_event_bootstrap(bootstrap_status_t status, int progress);
MOCK_DECL(void, control_event_bootstrap_problem,(const char *warn,
int reason,
or_connection_t *or_conn));
@@ -108,11 +108,13 @@ void control_event_hs_descriptor_requested(const rend_data_t *rend_query,
const char *hs_dir);
void control_event_hs_descriptor_receive_end(const char *action,
const rend_data_t *rend_query,
- const char *hs_dir);
+ const char *hs_dir,
+ const char *reason);
void control_event_hs_descriptor_received(const rend_data_t *rend_query,
const char *hs_dir);
void control_event_hs_descriptor_failed(const rend_data_t *rend_query,
- const char *hs_dir);
+ const char *hs_dir,
+ const char *reason);
void control_free_all(void);
diff --git a/src/or/cpuworker.c b/src/or/cpuworker.c
index 61b2c29b38..d511ecf84c 100644
--- a/src/or/cpuworker.c
+++ b/src/or/cpuworker.c
@@ -1,88 +1,103 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file cpuworker.c
- * \brief Implements a farm of 'CPU worker' processes to perform
- * CPU-intensive tasks in another thread or process, to not
- * interrupt the main thread.
+ * \brief Uses the workqueue/threadpool code to farm CPU-intensive activities
+ * out to subprocesses.
*
* Right now, we only use this for processing onionskins.
**/
#include "or.h"
-#include "buffers.h"
#include "channel.h"
-#include "channeltls.h"
#include "circuitbuild.h"
#include "circuitlist.h"
-#include "config.h"
-#include "connection.h"
#include "connection_or.h"
+#include "config.h"
#include "cpuworker.h"
#include "main.h"
#include "onion.h"
#include "rephist.h"
#include "router.h"
+#include "workqueue.h"
-/** The maximum number of cpuworker processes we will keep around. */
-#define MAX_CPUWORKERS 16
-/** The minimum number of cpuworker processes we will keep around. */
-#define MIN_CPUWORKERS 1
-
-/** The tag specifies which circuit this onionskin was from. */
-#define TAG_LEN 12
-
-/** How many cpuworkers we have running right now. */
-static int num_cpuworkers=0;
-/** How many of the running cpuworkers have an assigned task right now. */
-static int num_cpuworkers_busy=0;
-/** We need to spawn new cpuworkers whenever we rotate the onion keys
- * on platforms where execution contexts==processes. This variable stores
- * the last time we got a key rotation event. */
-static time_t last_rotation_time=0;
-
-static void cpuworker_main(void *data) ATTR_NORETURN;
-static int spawn_cpuworker(void);
-static void spawn_enough_cpuworkers(void);
-static void process_pending_task(connection_t *cpuworker);
-
-/** Initialize the cpuworker subsystem.
- */
-void
-cpu_init(void)
+#ifdef HAVE_EVENT2_EVENT_H
+#include <event2/event.h>
+#else
+#include <event.h>
+#endif
+
+static void queue_pending_tasks(void);
+
+typedef struct worker_state_s {
+ int generation;
+ server_onion_keys_t *onion_keys;
+} worker_state_t;
+
+static void *
+worker_state_new(void *arg)
{
- cpuworkers_rotate();
+ worker_state_t *ws;
+ (void)arg;
+ ws = tor_malloc_zero(sizeof(worker_state_t));
+ ws->onion_keys = server_onion_keys_new();
+ return ws;
}
-
-/** Called when we're done sending a request to a cpuworker. */
-int
-connection_cpu_finished_flushing(connection_t *conn)
+static void
+worker_state_free(void *arg)
{
- tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_CPUWORKER);
- return 0;
+ worker_state_t *ws = arg;
+ server_onion_keys_free(ws->onion_keys);
+ tor_free(ws);
}
-/** Pack global_id and circ_id; set *tag to the result. (See note on
- * cpuworker_main for wire format.) */
+static replyqueue_t *replyqueue = NULL;
+static threadpool_t *threadpool = NULL;
+static struct event *reply_event = NULL;
+
+static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT;
+
+static int total_pending_tasks = 0;
+static int max_pending_tasks = 128;
+
static void
-tag_pack(uint8_t *tag, uint64_t chan_id, circid_t circ_id)
+replyqueue_process_cb(evutil_socket_t sock, short events, void *arg)
{
- /*XXXX RETHINK THIS WHOLE MESS !!!! !NM NM NM NM*/
- /*XXXX DOUBLEPLUSTHIS!!!! AS AS AS AS*/
- set_uint64(tag, chan_id);
- set_uint32(tag+8, circ_id);
+ replyqueue_t *rq = arg;
+ (void) sock;
+ (void) events;
+ replyqueue_process(rq);
}
-/** Unpack <b>tag</b> into addr, port, and circ_id.
+/** Initialize the cpuworker subsystem. It is OK to call this more than once
+ * during Tor's lifetime.
*/
-static void
-tag_unpack(const uint8_t *tag, uint64_t *chan_id, circid_t *circ_id)
+void
+cpu_init(void)
{
- *chan_id = get_uint64(tag);
- *circ_id = get_uint32(tag+8);
+ if (!replyqueue) {
+ replyqueue = replyqueue_new(0);
+ }
+ if (!reply_event) {
+ reply_event = tor_event_new(tor_libevent_get_base(),
+ replyqueue_get_socket(replyqueue),
+ EV_READ|EV_PERSIST,
+ replyqueue_process_cb,
+ replyqueue);
+ event_add(reply_event, NULL);
+ }
+ if (!threadpool) {
+ threadpool = threadpool_new(get_num_cpus(get_options()),
+ replyqueue,
+ worker_state_new,
+ worker_state_free,
+ NULL);
+ }
+ /* Total voodoo. Can we make this more sensible? */
+ max_pending_tasks = get_num_cpus(get_options()) * 64;
+ crypto_seed_weak_rng(&request_sample_rng);
}
/** Magic numbers to make sure our cpuworker_requests don't grow any
@@ -94,10 +109,6 @@ tag_unpack(const uint8_t *tag, uint64_t *chan_id, circid_t *circ_id)
typedef struct cpuworker_request_t {
/** Magic number; must be CPUWORKER_REQUEST_MAGIC. */
uint32_t magic;
- /** Opaque tag to identify the job */
- uint8_t tag[TAG_LEN];
- /** Task code. Must be one of CPUWORKER_TASK_* */
- uint8_t task;
/** Flag: Are we timing this request? */
unsigned timed : 1;
@@ -114,8 +125,7 @@ typedef struct cpuworker_request_t {
typedef struct cpuworker_reply_t {
/** Magic number; must be CPUWORKER_REPLY_MAGIC. */
uint32_t magic;
- /** Opaque tag to identify the job; matches the request's tag.*/
- uint8_t tag[TAG_LEN];
+
/** True iff we got a successful request. */
uint8_t success;
@@ -142,42 +152,45 @@ typedef struct cpuworker_reply_t {
uint8_t rend_auth_material[DIGEST_LEN];
} cpuworker_reply_t;
-/** Called when the onion key has changed and we need to spawn new
- * cpuworkers. Close all currently idle cpuworkers, and mark the last
- * rotation time as now.
- */
-void
-cpuworkers_rotate(void)
+typedef struct cpuworker_job_u {
+ or_circuit_t *circ;
+ union {
+ cpuworker_request_t request;
+ cpuworker_reply_t reply;
+ } u;
+} cpuworker_job_t;
+
+static int
+update_state_threadfn(void *state_, void *work_)
{
- connection_t *cpuworker;
- while ((cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER,
- CPUWORKER_STATE_IDLE))) {
- connection_mark_for_close(cpuworker);
- --num_cpuworkers;
- }
- last_rotation_time = time(NULL);
- if (server_mode(get_options()))
- spawn_enough_cpuworkers();
+ worker_state_t *state = state_;
+ worker_state_t *update = work_;
+ server_onion_keys_free(state->onion_keys);
+ state->onion_keys = update->onion_keys;
+ update->onion_keys = NULL;
+ ++state->generation;
+ return WQ_RPL_REPLY;
}
-/** If the cpuworker closes the connection,
- * mark it as closed and spawn a new one as needed. */
-int
-connection_cpu_reached_eof(connection_t *conn)
+/** Called when the onion key has changed so update all CPU worker(s) with
+ * new function pointers with which a new state will be generated.
+ */
+void
+cpuworkers_rotate_keyinfo(void)
{
- log_warn(LD_GENERAL,"Read eof. CPU worker died unexpectedly.");
- if (conn->state != CPUWORKER_STATE_IDLE) {
- /* the circ associated with this cpuworker will have to wait until
- * it gets culled in run_connection_housekeeping(), since we have
- * no way to find out which circ it was. */
- log_warn(LD_GENERAL,"...and it left a circuit queued; abandoning circ.");
- num_cpuworkers_busy--;
+ if (!threadpool) {
+ /* If we're a client, then we won't have cpuworkers, and we won't need
+ * to tell them to rotate their state.
+ */
+ return;
+ }
+ if (threadpool_queue_update(threadpool,
+ worker_state_new,
+ update_state_threadfn,
+ worker_state_free,
+ NULL)) {
+ log_warn(LD_OR, "Failed to queue key update for worker threads.");
}
- num_cpuworkers--;
- spawn_enough_cpuworkers(); /* try to regrow. hope we don't end up
- spinning. */
- connection_mark_for_close(conn);
- return 0;
}
/** Indexed by handshake type: how many onionskins have we processed and
@@ -197,8 +210,6 @@ static uint64_t onionskins_usec_roundtrip[MAX_ONION_HANDSHAKE_TYPE+1];
* time. (microseconds) */
#define MAX_BELIEVABLE_ONIONSKIN_DELAY (2*1000*1000)
-static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT;
-
/** Return true iff we'd like to measure a handshake of type
* <b>onionskin_type</b>. Call only from the main thread. */
static int
@@ -286,438 +297,275 @@ cpuworker_log_onionskin_overhead(int severity, int onionskin_type,
onionskin_type_name, (unsigned)overhead, relative_overhead*100);
}
-/** Called when we get data from a cpuworker. If the answer is not complete,
- * wait for a complete answer. If the answer is complete,
- * process it as appropriate.
- */
-int
-connection_cpu_process_inbuf(connection_t *conn)
-{
- uint64_t chan_id;
- circid_t circ_id;
- channel_t *p_chan = NULL;
- circuit_t *circ;
-
- tor_assert(conn);
- tor_assert(conn->type == CONN_TYPE_CPUWORKER);
-
- if (!connection_get_inbuf_len(conn))
- return 0;
-
- if (conn->state == CPUWORKER_STATE_BUSY_ONION) {
- cpuworker_reply_t rpl;
- if (connection_get_inbuf_len(conn) < sizeof(cpuworker_reply_t))
- return 0; /* not yet */
- tor_assert(connection_get_inbuf_len(conn) == sizeof(cpuworker_reply_t));
-
- connection_fetch_from_buf((void*)&rpl,sizeof(cpuworker_reply_t),conn);
-
- tor_assert(rpl.magic == CPUWORKER_REPLY_MAGIC);
-
- if (rpl.timed && rpl.success &&
- rpl.handshake_type <= MAX_ONION_HANDSHAKE_TYPE) {
- /* Time how long this request took. The handshake_type check should be
- needless, but let's leave it in to be safe. */
- struct timeval tv_end, tv_diff;
- int64_t usec_roundtrip;
- tor_gettimeofday(&tv_end);
- timersub(&tv_end, &rpl.started_at, &tv_diff);
- usec_roundtrip = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
- if (usec_roundtrip >= 0 &&
- usec_roundtrip < MAX_BELIEVABLE_ONIONSKIN_DELAY) {
- ++onionskins_n_processed[rpl.handshake_type];
- onionskins_usec_internal[rpl.handshake_type] += rpl.n_usec;
- onionskins_usec_roundtrip[rpl.handshake_type] += usec_roundtrip;
- if (onionskins_n_processed[rpl.handshake_type] >= 500000) {
- /* Scale down every 500000 handshakes. On a busy server, that's
- * less impressive than it sounds. */
- onionskins_n_processed[rpl.handshake_type] /= 2;
- onionskins_usec_internal[rpl.handshake_type] /= 2;
- onionskins_usec_roundtrip[rpl.handshake_type] /= 2;
- }
- }
- }
- /* parse out the circ it was talking about */
- tag_unpack(rpl.tag, &chan_id, &circ_id);
- circ = NULL;
- log_debug(LD_OR,
- "Unpacking cpuworker reply, chan_id is " U64_FORMAT
- ", circ_id is %u",
- U64_PRINTF_ARG(chan_id), (unsigned)circ_id);
- p_chan = channel_find_by_global_id(chan_id);
-
- if (p_chan)
- circ = circuit_get_by_circid_channel(circ_id, p_chan);
-
- if (rpl.success == 0) {
- log_debug(LD_OR,
- "decoding onionskin failed. "
- "(Old key or bad software.) Closing.");
- if (circ)
- circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
- goto done_processing;
- }
- if (!circ) {
- /* This happens because somebody sends us a destroy cell and the
- * circuit goes away, while the cpuworker is working. This is also
- * why our tag doesn't include a pointer to the circ, because we'd
- * never know if it's still valid.
- */
- log_debug(LD_OR,"processed onion for a circ that's gone. Dropping.");
- goto done_processing;
- }
- tor_assert(! CIRCUIT_IS_ORIGIN(circ));
- if (onionskin_answer(TO_OR_CIRCUIT(circ),
- &rpl.created_cell,
- (const char*)rpl.keys,
- rpl.rend_auth_material) < 0) {
- log_warn(LD_OR,"onionskin_answer failed. Closing.");
- circuit_mark_for_close(circ, END_CIRC_REASON_INTERNAL);
- goto done_processing;
- }
- log_debug(LD_OR,"onionskin_answer succeeded. Yay.");
- } else {
- tor_assert(0); /* don't ask me to do handshakes yet */
- }
-
- done_processing:
- conn->state = CPUWORKER_STATE_IDLE;
- num_cpuworkers_busy--;
- if (conn->timestamp_created < last_rotation_time) {
- connection_mark_for_close(conn);
- num_cpuworkers--;
- spawn_enough_cpuworkers();
- } else {
- process_pending_task(conn);
- }
- return 0;
-}
-
-/** Implement a cpuworker. 'data' is an fdarray as returned by socketpair.
- * Read and writes from fdarray[1]. Reads requests, writes answers.
- *
- * Request format:
- * cpuworker_request_t.
- * Response format:
- * cpuworker_reply_t
- */
+/** Handle a reply from the worker threads. */
static void
-cpuworker_main(void *data)
+cpuworker_onion_handshake_replyfn(void *work_)
{
- /* For talking to the parent thread/process */
- tor_socket_t *fdarray = data;
- tor_socket_t fd;
-
- /* variables for onion processing */
- server_onion_keys_t onion_keys;
- cpuworker_request_t req;
+ cpuworker_job_t *job = work_;
cpuworker_reply_t rpl;
-
- fd = fdarray[1]; /* this side is ours */
-#ifndef TOR_IS_MULTITHREADED
- tor_close_socket(fdarray[0]); /* this is the side of the socketpair the
- * parent uses */
- tor_free_all(1); /* so the child doesn't hold the parent's fd's open */
- handle_signals(0); /* ignore interrupts from the keyboard, etc */
-#endif
- tor_free(data);
-
- setup_server_onion_keys(&onion_keys);
-
- for (;;) {
- if (read_all(fd, (void *)&req, sizeof(req), 1) != sizeof(req)) {
- log_info(LD_OR, "read request failed. Exiting.");
- goto end;
- }
- tor_assert(req.magic == CPUWORKER_REQUEST_MAGIC);
-
- memset(&rpl, 0, sizeof(rpl));
-
- if (req.task == CPUWORKER_TASK_ONION) {
- const create_cell_t *cc = &req.create_cell;
- created_cell_t *cell_out = &rpl.created_cell;
- struct timeval tv_start = {0,0}, tv_end;
- int n;
- rpl.timed = req.timed;
- rpl.started_at = req.started_at;
- rpl.handshake_type = cc->handshake_type;
- if (req.timed)
- tor_gettimeofday(&tv_start);
- n = onion_skin_server_handshake(cc->handshake_type,
- cc->onionskin, cc->handshake_len,
- &onion_keys,
- cell_out->reply,
- rpl.keys, CPATH_KEY_MATERIAL_LEN,
- rpl.rend_auth_material);
- if (n < 0) {
- /* failure */
- log_debug(LD_OR,"onion_skin_server_handshake failed.");
- memset(&rpl, 0, sizeof(rpl));
- memcpy(rpl.tag, req.tag, TAG_LEN);
- rpl.success = 0;
- } else {
- /* success */
- log_debug(LD_OR,"onion_skin_server_handshake succeeded.");
- memcpy(rpl.tag, req.tag, TAG_LEN);
- cell_out->handshake_len = n;
- switch (cc->cell_type) {
- case CELL_CREATE:
- cell_out->cell_type = CELL_CREATED; break;
- case CELL_CREATE2:
- cell_out->cell_type = CELL_CREATED2; break;
- case CELL_CREATE_FAST:
- cell_out->cell_type = CELL_CREATED_FAST; break;
- default:
- tor_assert(0);
- goto end;
- }
- rpl.success = 1;
- }
- rpl.magic = CPUWORKER_REPLY_MAGIC;
- if (req.timed) {
- struct timeval tv_diff;
- int64_t usec;
- tor_gettimeofday(&tv_end);
- timersub(&tv_end, &tv_start, &tv_diff);
- usec = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
- if (usec < 0 || usec > MAX_BELIEVABLE_ONIONSKIN_DELAY)
- rpl.n_usec = MAX_BELIEVABLE_ONIONSKIN_DELAY;
- else
- rpl.n_usec = (uint32_t) usec;
+ or_circuit_t *circ = NULL;
+
+ tor_assert(total_pending_tasks > 0);
+ --total_pending_tasks;
+
+ /* Could avoid this, but doesn't matter. */
+ memcpy(&rpl, &job->u.reply, sizeof(rpl));
+
+ tor_assert(rpl.magic == CPUWORKER_REPLY_MAGIC);
+
+ if (rpl.timed && rpl.success &&
+ rpl.handshake_type <= MAX_ONION_HANDSHAKE_TYPE) {
+ /* Time how long this request took. The handshake_type check should be
+ needless, but let's leave it in to be safe. */
+ struct timeval tv_end, tv_diff;
+ int64_t usec_roundtrip;
+ tor_gettimeofday(&tv_end);
+ timersub(&tv_end, &rpl.started_at, &tv_diff);
+ usec_roundtrip = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
+ if (usec_roundtrip >= 0 &&
+ usec_roundtrip < MAX_BELIEVABLE_ONIONSKIN_DELAY) {
+ ++onionskins_n_processed[rpl.handshake_type];
+ onionskins_usec_internal[rpl.handshake_type] += rpl.n_usec;
+ onionskins_usec_roundtrip[rpl.handshake_type] += usec_roundtrip;
+ if (onionskins_n_processed[rpl.handshake_type] >= 500000) {
+ /* Scale down every 500000 handshakes. On a busy server, that's
+ * less impressive than it sounds. */
+ onionskins_n_processed[rpl.handshake_type] /= 2;
+ onionskins_usec_internal[rpl.handshake_type] /= 2;
+ onionskins_usec_roundtrip[rpl.handshake_type] /= 2;
}
- if (write_all(fd, (void*)&rpl, sizeof(rpl), 1) != sizeof(rpl)) {
- log_err(LD_BUG,"writing response buf failed. Exiting.");
- goto end;
- }
- log_debug(LD_OR,"finished writing response.");
- } else if (req.task == CPUWORKER_TASK_SHUTDOWN) {
- log_info(LD_OR,"Clean shutdown: exiting");
- goto end;
}
- memwipe(&req, 0, sizeof(req));
- memwipe(&rpl, 0, sizeof(req));
}
- end:
- memwipe(&req, 0, sizeof(req));
- memwipe(&rpl, 0, sizeof(req));
- release_server_onion_keys(&onion_keys);
- tor_close_socket(fd);
- crypto_thread_cleanup();
- spawn_exit();
-}
-/** Launch a new cpuworker. Return 0 if we're happy, -1 if we failed.
- */
-static int
-spawn_cpuworker(void)
-{
- tor_socket_t *fdarray;
- tor_socket_t fd;
- connection_t *conn;
- int err;
-
- fdarray = tor_malloc(sizeof(tor_socket_t)*2);
- if ((err = tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fdarray)) < 0) {
- log_warn(LD_NET, "Couldn't construct socketpair for cpuworker: %s",
- tor_socket_strerror(-err));
- tor_free(fdarray);
- return -1;
- }
+ circ = job->circ;
- tor_assert(SOCKET_OK(fdarray[0]));
- tor_assert(SOCKET_OK(fdarray[1]));
+ log_debug(LD_OR,
+ "Unpacking cpuworker reply %p, circ=%p, success=%d",
+ job, circ, rpl.success);
- fd = fdarray[0];
- if (spawn_func(cpuworker_main, (void*)fdarray) < 0) {
- tor_close_socket(fdarray[0]);
- tor_close_socket(fdarray[1]);
- tor_free(fdarray);
- return -1;
+ if (circ->base_.magic == DEAD_CIRCUIT_MAGIC) {
+ /* The circuit was supposed to get freed while the reply was
+ * pending. Instead, it got left for us to free so that we wouldn't freak
+ * out when the job->circ field wound up pointing to nothing. */
+ log_debug(LD_OR, "Circuit died while reply was pending. Freeing memory.");
+ circ->base_.magic = 0;
+ tor_free(circ);
+ goto done_processing;
}
- log_debug(LD_OR,"just spawned a cpu worker.");
-#ifndef TOR_IS_MULTITHREADED
- tor_close_socket(fdarray[1]); /* don't need the worker's side of the pipe */
- tor_free(fdarray);
-#endif
-
- conn = connection_new(CONN_TYPE_CPUWORKER, AF_UNIX);
- /* set up conn so it's got all the data we need to remember */
- conn->s = fd;
- conn->address = tor_strdup("localhost");
- tor_addr_make_unspec(&conn->addr);
+ circ->workqueue_entry = NULL;
- if (set_socket_nonblocking(fd) == -1) {
- connection_free(conn); /* this closes fd */
- return -1;
+ if (TO_CIRCUIT(circ)->marked_for_close) {
+ /* We already marked this circuit; we can't call it open. */
+ log_debug(LD_OR,"circuit is already marked.");
+ goto done_processing;
}
- if (connection_add(conn) < 0) { /* no space, forget it */
- log_warn(LD_NET,"connection_add for cpuworker failed. Giving up.");
- connection_free(conn); /* this closes fd */
- return -1;
+ if (rpl.success == 0) {
+ log_debug(LD_OR,
+ "decoding onionskin failed. "
+ "(Old key or bad software.) Closing.");
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
+ goto done_processing;
}
- conn->state = CPUWORKER_STATE_IDLE;
- connection_start_reading(conn);
+ if (onionskin_answer(circ,
+ &rpl.created_cell,
+ (const char*)rpl.keys,
+ rpl.rend_auth_material) < 0) {
+ log_warn(LD_OR,"onionskin_answer failed. Closing.");
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
+ goto done_processing;
+ }
+ log_debug(LD_OR,"onionskin_answer succeeded. Yay.");
- return 0; /* success */
+ done_processing:
+ memwipe(&rpl, 0, sizeof(rpl));
+ memwipe(job, 0, sizeof(*job));
+ tor_free(job);
+ queue_pending_tasks();
}
-/** If we have too few or too many active cpuworkers, try to spawn new ones
- * or kill idle ones.
- */
-static void
-spawn_enough_cpuworkers(void)
+/** Implementation function for onion handshake requests. */
+static int
+cpuworker_onion_handshake_threadfn(void *state_, void *work_)
{
- int num_cpuworkers_needed = get_num_cpus(get_options());
- int reseed = 0;
+ worker_state_t *state = state_;
+ cpuworker_job_t *job = work_;
- if (num_cpuworkers_needed < MIN_CPUWORKERS)
- num_cpuworkers_needed = MIN_CPUWORKERS;
- if (num_cpuworkers_needed > MAX_CPUWORKERS)
- num_cpuworkers_needed = MAX_CPUWORKERS;
+ /* variables for onion processing */
+ server_onion_keys_t *onion_keys = state->onion_keys;
+ cpuworker_request_t req;
+ cpuworker_reply_t rpl;
- while (num_cpuworkers < num_cpuworkers_needed) {
- if (spawn_cpuworker() < 0) {
- log_warn(LD_GENERAL,"Cpuworker spawn failed. Will try again later.");
- return;
+ memcpy(&req, &job->u.request, sizeof(req));
+
+ tor_assert(req.magic == CPUWORKER_REQUEST_MAGIC);
+ memset(&rpl, 0, sizeof(rpl));
+
+ const create_cell_t *cc = &req.create_cell;
+ created_cell_t *cell_out = &rpl.created_cell;
+ struct timeval tv_start = {0,0}, tv_end;
+ int n;
+ rpl.timed = req.timed;
+ rpl.started_at = req.started_at;
+ rpl.handshake_type = cc->handshake_type;
+ if (req.timed)
+ tor_gettimeofday(&tv_start);
+ n = onion_skin_server_handshake(cc->handshake_type,
+ cc->onionskin, cc->handshake_len,
+ onion_keys,
+ cell_out->reply,
+ rpl.keys, CPATH_KEY_MATERIAL_LEN,
+ rpl.rend_auth_material);
+ if (n < 0) {
+ /* failure */
+ log_debug(LD_OR,"onion_skin_server_handshake failed.");
+ memset(&rpl, 0, sizeof(rpl));
+ rpl.success = 0;
+ } else {
+ /* success */
+ log_debug(LD_OR,"onion_skin_server_handshake succeeded.");
+ cell_out->handshake_len = n;
+ switch (cc->cell_type) {
+ case CELL_CREATE:
+ cell_out->cell_type = CELL_CREATED; break;
+ case CELL_CREATE2:
+ cell_out->cell_type = CELL_CREATED2; break;
+ case CELL_CREATE_FAST:
+ cell_out->cell_type = CELL_CREATED_FAST; break;
+ default:
+ tor_assert(0);
+ return WQ_RPL_SHUTDOWN;
}
- num_cpuworkers++;
- reseed++;
+ rpl.success = 1;
+ }
+ rpl.magic = CPUWORKER_REPLY_MAGIC;
+ if (req.timed) {
+ struct timeval tv_diff;
+ int64_t usec;
+ tor_gettimeofday(&tv_end);
+ timersub(&tv_end, &tv_start, &tv_diff);
+ usec = ((int64_t)tv_diff.tv_sec)*1000000 + tv_diff.tv_usec;
+ if (usec < 0 || usec > MAX_BELIEVABLE_ONIONSKIN_DELAY)
+ rpl.n_usec = MAX_BELIEVABLE_ONIONSKIN_DELAY;
+ else
+ rpl.n_usec = (uint32_t) usec;
}
- if (reseed)
- crypto_seed_weak_rng(&request_sample_rng);
+ memcpy(&job->u.reply, &rpl, sizeof(rpl));
+
+ memwipe(&req, 0, sizeof(req));
+ memwipe(&rpl, 0, sizeof(req));
+ return WQ_RPL_REPLY;
}
-/** Take a pending task from the queue and assign it to 'cpuworker'. */
+/** Take pending tasks from the queue and assign them to cpuworkers. */
static void
-process_pending_task(connection_t *cpuworker)
+queue_pending_tasks(void)
{
or_circuit_t *circ;
create_cell_t *onionskin = NULL;
- tor_assert(cpuworker);
-
- /* for now only process onion tasks */
-
- circ = onion_next_task(&onionskin);
- if (!circ)
- return;
- if (assign_onionskin_to_cpuworker(cpuworker, circ, onionskin))
- log_warn(LD_OR,"assign_to_cpuworker failed. Ignoring.");
-}
+ while (total_pending_tasks < max_pending_tasks) {
+ circ = onion_next_task(&onionskin);
-/** How long should we let a cpuworker stay busy before we give
- * up on it and decide that we have a bug or infinite loop?
- * This value is high because some servers with low memory/cpu
- * sometimes spend an hour or more swapping, and Tor starves. */
-#define CPUWORKER_BUSY_TIMEOUT (60*60*12)
+ if (!circ)
+ return;
-/** We have a bug that I can't find. Sometimes, very rarely, cpuworkers get
- * stuck in the 'busy' state, even though the cpuworker process thinks of
- * itself as idle. I don't know why. But here's a workaround to kill any
- * cpuworker that's been busy for more than CPUWORKER_BUSY_TIMEOUT.
- */
-static void
-cull_wedged_cpuworkers(void)
-{
- time_t now = time(NULL);
- smartlist_t *conns = get_connection_array();
- SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
- if (!conn->marked_for_close &&
- conn->type == CONN_TYPE_CPUWORKER &&
- conn->state == CPUWORKER_STATE_BUSY_ONION &&
- conn->timestamp_lastwritten + CPUWORKER_BUSY_TIMEOUT < now) {
- log_notice(LD_BUG,
- "closing wedged cpuworker. Can somebody find the bug?");
- num_cpuworkers_busy--;
- num_cpuworkers--;
- connection_mark_for_close(conn);
- }
- } SMARTLIST_FOREACH_END(conn);
+ if (assign_onionskin_to_cpuworker(circ, onionskin))
+ log_warn(LD_OR,"assign_to_cpuworker failed. Ignoring.");
+ }
}
/** Try to tell a cpuworker to perform the public key operations necessary to
* respond to <b>onionskin</b> for the circuit <b>circ</b>.
*
- * If <b>cpuworker</b> is defined, assert that he's idle, and use him. Else,
- * look for an idle cpuworker and use him. If none idle, queue task onto the
- * pending onion list and return. Return 0 if we successfully assign the
- * task, or -1 on failure.
+ * Return 0 if we successfully assign the task, or -1 on failure.
*/
int
-assign_onionskin_to_cpuworker(connection_t *cpuworker,
- or_circuit_t *circ,
+assign_onionskin_to_cpuworker(or_circuit_t *circ,
create_cell_t *onionskin)
{
+ workqueue_entry_t *queue_entry;
+ cpuworker_job_t *job;
cpuworker_request_t req;
- time_t now = approx_time();
- static time_t last_culled_cpuworkers = 0;
int should_time;
- /* Checking for wedged cpuworkers requires a linear search over all
- * connections, so let's do it only once a minute.
- */
-#define CULL_CPUWORKERS_INTERVAL 60
+ tor_assert(threadpool);
- if (last_culled_cpuworkers + CULL_CPUWORKERS_INTERVAL <= now) {
- cull_wedged_cpuworkers();
- spawn_enough_cpuworkers();
- last_culled_cpuworkers = now;
+ if (!circ->p_chan) {
+ log_info(LD_OR,"circ->p_chan gone. Failing circ.");
+ tor_free(onionskin);
+ return -1;
}
- if (1) {
- if (num_cpuworkers_busy == num_cpuworkers) {
- log_debug(LD_OR,"No idle cpuworkers. Queuing.");
- if (onion_pending_add(circ, onionskin) < 0) {
- tor_free(onionskin);
- return -1;
- }
- return 0;
- }
-
- if (!cpuworker)
- cpuworker = connection_get_by_type_state(CONN_TYPE_CPUWORKER,
- CPUWORKER_STATE_IDLE);
-
- tor_assert(cpuworker);
-
- if (!circ->p_chan) {
- log_info(LD_OR,"circ->p_chan gone. Failing circ.");
+ if (total_pending_tasks >= max_pending_tasks) {
+ log_debug(LD_OR,"No idle cpuworkers. Queuing.");
+ if (onion_pending_add(circ, onionskin) < 0) {
tor_free(onionskin);
return -1;
}
+ return 0;
+ }
- if (connection_or_digest_is_known_relay(circ->p_chan->identity_digest))
- rep_hist_note_circuit_handshake_assigned(onionskin->handshake_type);
+ if (connection_or_digest_is_known_relay(circ->p_chan->identity_digest))
+ rep_hist_note_circuit_handshake_assigned(onionskin->handshake_type);
- should_time = should_time_request(onionskin->handshake_type);
- memset(&req, 0, sizeof(req));
- req.magic = CPUWORKER_REQUEST_MAGIC;
- tag_pack(req.tag, circ->p_chan->global_identifier,
- circ->p_circ_id);
- req.timed = should_time;
+ should_time = should_time_request(onionskin->handshake_type);
+ memset(&req, 0, sizeof(req));
+ req.magic = CPUWORKER_REQUEST_MAGIC;
+ req.timed = should_time;
- cpuworker->state = CPUWORKER_STATE_BUSY_ONION;
- /* touch the lastwritten timestamp, since that's how we check to
- * see how long it's been since we asked the question, and sometimes
- * we check before the first call to connection_handle_write(). */
- cpuworker->timestamp_lastwritten = now;
- num_cpuworkers_busy++;
+ memcpy(&req.create_cell, onionskin, sizeof(create_cell_t));
- req.task = CPUWORKER_TASK_ONION;
- memcpy(&req.create_cell, onionskin, sizeof(create_cell_t));
+ tor_free(onionskin);
- tor_free(onionskin);
+ if (should_time)
+ tor_gettimeofday(&req.started_at);
- if (should_time)
- tor_gettimeofday(&req.started_at);
+ job = tor_malloc_zero(sizeof(cpuworker_job_t));
+ job->circ = circ;
+ memcpy(&job->u.request, &req, sizeof(req));
+ memwipe(&req, 0, sizeof(req));
- connection_write_to_buf((void*)&req, sizeof(req), cpuworker);
- memwipe(&req, 0, sizeof(req));
+ ++total_pending_tasks;
+ queue_entry = threadpool_queue_work(threadpool,
+ cpuworker_onion_handshake_threadfn,
+ cpuworker_onion_handshake_replyfn,
+ job);
+ if (!queue_entry) {
+ log_warn(LD_BUG, "Couldn't queue work on threadpool");
+ tor_free(job);
+ return -1;
}
+
+ log_debug(LD_OR, "Queued task %p (qe=%p, circ=%p)",
+ job, queue_entry, job->circ);
+
+ circ->workqueue_entry = queue_entry;
+
return 0;
}
+/** If <b>circ</b> has a pending handshake that hasn't been processed yet,
+ * remove it from the worker queue. */
+void
+cpuworker_cancel_circ_handshake(or_circuit_t *circ)
+{
+ cpuworker_job_t *job;
+ if (circ->workqueue_entry == NULL)
+ return;
+
+ job = workqueue_entry_cancel(circ->workqueue_entry);
+ if (job) {
+ /* It successfully cancelled. */
+ memwipe(job, 0xe0, sizeof(*job));
+ tor_free(job);
+ tor_assert(total_pending_tasks > 0);
+ --total_pending_tasks;
+ /* if (!job), this is done in cpuworker_onion_handshake_replyfn. */
+ circ->workqueue_entry = NULL;
+ }
+}
+
diff --git a/src/or/cpuworker.h b/src/or/cpuworker.h
index 317cef43ba..70a595e472 100644
--- a/src/or/cpuworker.h
+++ b/src/or/cpuworker.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,19 +13,17 @@
#define TOR_CPUWORKER_H
void cpu_init(void);
-void cpuworkers_rotate(void);
-int connection_cpu_finished_flushing(connection_t *conn);
-int connection_cpu_reached_eof(connection_t *conn);
-int connection_cpu_process_inbuf(connection_t *conn);
+void cpuworkers_rotate_keyinfo(void);
+
struct create_cell_t;
-int assign_onionskin_to_cpuworker(connection_t *cpuworker,
- or_circuit_t *circ,
+int assign_onionskin_to_cpuworker(or_circuit_t *circ,
struct create_cell_t *onionskin);
uint64_t estimated_usec_for_onionskins(uint32_t n_requests,
uint16_t onionskin_type);
void cpuworker_log_onionskin_overhead(int severity, int onionskin_type,
const char *onionskin_type_name);
+void cpuworker_cancel_circ_handshake(or_circuit_t *circ);
#endif
diff --git a/src/or/directory.c b/src/or/directory.c
index 50863d0c7e..d2b6b86f6d 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -20,6 +20,7 @@
#include "networkstatus.h"
#include "nodelist.h"
#include "policies.h"
+#include "relay.h"
#include "rendclient.h"
#include "rendcommon.h"
#include "rephist.h"
@@ -63,8 +64,6 @@ static void directory_send_command(dir_connection_t *conn,
time_t if_modified_since);
static int directory_handle_command(dir_connection_t *conn);
static int body_is_plausible(const char *body, size_t body_len, int purpose);
-static int purpose_needs_anonymity(uint8_t dir_purpose,
- uint8_t router_purpose);
static char *http_get_header(const char *headers, const char *which);
static void http_set_address_origin(const char *headers, connection_t *conn);
static void connection_dir_download_routerdesc_failed(dir_connection_t *conn);
@@ -119,7 +118,7 @@ static void directory_initiate_command_rend(const tor_addr_t *addr,
/** Return true iff the directory purpose <b>dir_purpose</b> (and if it's
* fetching descriptors, it's fetching them for <b>router_purpose</b>)
* must use an anonymous connection to a directory. */
-static int
+STATIC int
purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose)
{
if (get_options()->AllDirActionsPrivate)
@@ -197,9 +196,49 @@ dir_conn_purpose_to_string(int purpose)
return "(unknown)";
}
-/** Return true iff <b>identity_digest</b> is the digest of a router we
- * believe to support extrainfo downloads. (If <b>is_authority</b> we do
- * additional checking that's only valid for authorities.) */
+/** Return the requisite directory information types. */
+STATIC dirinfo_type_t
+dir_fetch_type(int dir_purpose, int router_purpose, const char *resource)
+{
+ dirinfo_type_t type;
+ switch (dir_purpose) {
+ case DIR_PURPOSE_FETCH_EXTRAINFO:
+ type = EXTRAINFO_DIRINFO;
+ if (router_purpose == ROUTER_PURPOSE_BRIDGE)
+ type |= BRIDGE_DIRINFO;
+ else
+ type |= V3_DIRINFO;
+ break;
+ case DIR_PURPOSE_FETCH_SERVERDESC:
+ if (router_purpose == ROUTER_PURPOSE_BRIDGE)
+ type = BRIDGE_DIRINFO;
+ else
+ type = V3_DIRINFO;
+ break;
+ case DIR_PURPOSE_FETCH_STATUS_VOTE:
+ case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
+ case DIR_PURPOSE_FETCH_CERTIFICATE:
+ type = V3_DIRINFO;
+ break;
+ case DIR_PURPOSE_FETCH_CONSENSUS:
+ type = V3_DIRINFO;
+ if (resource && !strcmp(resource, "microdesc"))
+ type |= MICRODESC_DIRINFO;
+ break;
+ case DIR_PURPOSE_FETCH_MICRODESC:
+ type = MICRODESC_DIRINFO;
+ break;
+ default:
+ log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
+ type = NO_DIRINFO;
+ break;
+ }
+ return type;
+}
+
+/** Return true iff <b>identity_digest</b> is the digest of a router which
+ * says that it caches extrainfos. (If <b>is_authority</b> we always
+ * believe that to be true.) */
int
router_supports_extrainfo(const char *identity_digest, int is_authority)
{
@@ -385,47 +424,21 @@ directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags,
* Use <b>pds_flags</b> as arguments to router_pick_directory_server()
* or router_pick_trusteddirserver().
*/
-void
-directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
- const char *resource, int pds_flags)
+MOCK_IMPL(void, directory_get_from_dirserver, (uint8_t dir_purpose,
+ uint8_t router_purpose,
+ const char *resource,
+ int pds_flags))
{
const routerstatus_t *rs = NULL;
const or_options_t *options = get_options();
int prefer_authority = directory_fetches_from_authorities(options);
int require_authority = 0;
int get_via_tor = purpose_needs_anonymity(dir_purpose, router_purpose);
- dirinfo_type_t type;
+ dirinfo_type_t type = dir_fetch_type(dir_purpose, router_purpose, resource);
time_t if_modified_since = 0;
- /* FFFF we could break this switch into its own function, and call
- * it elsewhere in directory.c. -RD */
- switch (dir_purpose) {
- case DIR_PURPOSE_FETCH_EXTRAINFO:
- type = EXTRAINFO_DIRINFO |
- (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO :
- V3_DIRINFO);
- break;
- case DIR_PURPOSE_FETCH_SERVERDESC:
- type = (router_purpose == ROUTER_PURPOSE_BRIDGE ? BRIDGE_DIRINFO :
- V3_DIRINFO);
- break;
- case DIR_PURPOSE_FETCH_STATUS_VOTE:
- case DIR_PURPOSE_FETCH_DETACHED_SIGNATURES:
- case DIR_PURPOSE_FETCH_CERTIFICATE:
- type = V3_DIRINFO;
- break;
- case DIR_PURPOSE_FETCH_CONSENSUS:
- type = V3_DIRINFO;
- if (resource && !strcmp(resource,"microdesc"))
- type |= MICRODESC_DIRINFO;
- break;
- case DIR_PURPOSE_FETCH_MICRODESC:
- type = MICRODESC_DIRINFO;
- break;
- default:
- log_warn(LD_BUG, "Unexpected purpose %d", (int)dir_purpose);
- return;
- }
+ if (type == NO_DIRINFO)
+ return;
if (dir_purpose == DIR_PURPOSE_FETCH_CONSENSUS) {
int flav = FLAV_NS;
@@ -433,18 +446,33 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
if (resource)
flav = networkstatus_parse_flavor_name(resource);
+ /* DEFAULT_IF_MODIFIED_SINCE_DELAY is 1/20 of the default consensus
+ * period of 1 hour.
+ */
+#define DEFAULT_IF_MODIFIED_SINCE_DELAY (180)
if (flav != -1) {
/* IF we have a parsed consensus of this type, we can do an
* if-modified-time based on it. */
v = networkstatus_get_latest_consensus_by_flavor(flav);
- if (v)
- if_modified_since = v->valid_after + 180;
+ if (v) {
+ /* In networks with particularly short V3AuthVotingIntervals,
+ * ask for the consensus if it's been modified since half the
+ * V3AuthVotingInterval of the most recent consensus. */
+ time_t ims_delay = DEFAULT_IF_MODIFIED_SINCE_DELAY;
+ if (v->fresh_until > v->valid_after
+ && ims_delay > (v->fresh_until - v->valid_after)/2) {
+ ims_delay = (v->fresh_until - v->valid_after)/2;
+ }
+ if_modified_since = v->valid_after + ims_delay;
+ }
} else {
/* Otherwise it might be a consensus we don't parse, but which we
* do cache. Look at the cached copy, perhaps. */
cached_dir_t *cd = dirserv_get_consensus(resource);
+ /* We have no method of determining the voting interval from an
+ * unparsed consensus, so we use the default. */
if (cd)
- if_modified_since = cd->published + 180;
+ if_modified_since = cd->published + DEFAULT_IF_MODIFIED_SINCE_DELAY;
}
}
@@ -452,7 +480,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
return;
if (!get_via_tor) {
- if (options->UseBridges && type != BRIDGE_DIRINFO) {
+ if (options->UseBridges && !(type & BRIDGE_DIRINFO)) {
/* We want to ask a running bridge for which we have a descriptor.
*
* When we ask choose_random_entry() for a bridge, we specify what
@@ -479,7 +507,7 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
"nodes are available yet.");
return;
} else {
- if (prefer_authority || type == BRIDGE_DIRINFO) {
+ if (prefer_authority || (type & BRIDGE_DIRINFO)) {
/* only ask authdirservers, and don't ask myself */
rs = router_pick_trusteddirserver(type, pds_flags);
if (rs == NULL && (pds_flags & (PDS_NO_EXISTING_SERVERDESC_FETCH|
@@ -506,29 +534,25 @@ directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
return;
}
}
- if (!rs && type != BRIDGE_DIRINFO) {
+ if (!rs && !(type & BRIDGE_DIRINFO)) {
/* */
rs = directory_pick_generic_dirserver(type, pds_flags,
dir_purpose);
- if (!rs) {
- /*XXXX024 I'm pretty sure this can never do any good, since
- * rs isn't set. */
+ if (!rs)
get_via_tor = 1; /* last resort: try routing it via Tor */
- }
}
}
- } else { /* get_via_tor */
+ }
+
+ if (get_via_tor) {
/* Never use fascistfirewall; we're going via Tor. */
- if (1) {
- /* anybody with a non-zero dirport will do. Disregard firewalls. */
- pds_flags |= PDS_IGNORE_FASCISTFIREWALL;
- rs = router_pick_directory_server(type, pds_flags);
- /* If we have any hope of building an indirect conn, we know some router
- * descriptors. If (rs==NULL), we can't build circuits anyway, so
- * there's no point in falling back to the authorities in this case. */
- }
+ pds_flags |= PDS_IGNORE_FASCISTFIREWALL;
+ rs = router_pick_directory_server(type, pds_flags);
}
+ /* If we have any hope of building an indirect conn, we know some router
+ * descriptors. If (rs==NULL), we can't build circuits anyway, so
+ * there's no point in falling back to the authorities in this case. */
if (rs) {
const dir_indirection_t indirection =
get_via_tor ? DIRIND_ANONYMOUS : DIRIND_ONEHOP;
@@ -1255,7 +1279,8 @@ directory_send_command(dir_connection_t *conn,
return;
}
- if (strlen(proxystring) + strlen(url) >= 4096) {
+ /* warn in the non-tunneled case */
+ if (direct && (strlen(proxystring) + strlen(url) >= 4096)) {
log_warn(LD_BUG,
"Squid does not like URLs longer than 4095 bytes, and this "
"one is %d bytes long: %s%s",
@@ -2073,23 +2098,25 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
}
if (conn->base_.purpose == DIR_PURPOSE_FETCH_RENDDESC_V2) {
- #define SEND_HS_DESC_FAILED_EVENT() ( \
+ #define SEND_HS_DESC_FAILED_EVENT(reason) ( \
control_event_hs_descriptor_failed(conn->rend_data, \
- conn->identity_digest) )
+ conn->identity_digest, \
+ reason) )
tor_assert(conn->rend_data);
log_info(LD_REND,"Received rendezvous descriptor (size %d, status %d "
"(%s))",
(int)body_len, status_code, escaped(reason));
switch (status_code) {
case 200:
- switch (rend_cache_store_v2_desc_as_client(body, conn->rend_data)) {
+ switch (rend_cache_store_v2_desc_as_client(body,
+ conn->requested_resource, conn->rend_data)) {
case RCS_BADDESC:
case RCS_NOTDIR: /* Impossible */
log_warn(LD_REND,"Fetching v2 rendezvous descriptor failed. "
"Retrying at another directory.");
/* We'll retry when connection_about_to_close_connection()
* cleans this dir conn up. */
- SEND_HS_DESC_FAILED_EVENT();
+ SEND_HS_DESC_FAILED_EVENT("BAD_DESC");
break;
case RCS_OKAY:
default:
@@ -2108,14 +2135,14 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
* connection_about_to_close_connection() cleans this conn up. */
log_info(LD_REND,"Fetching v2 rendezvous descriptor failed: "
"Retrying at another directory.");
- SEND_HS_DESC_FAILED_EVENT();
+ SEND_HS_DESC_FAILED_EVENT("NOT_FOUND");
break;
case 400:
log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
"http status 400 (%s). Dirserver didn't like our "
"v2 rendezvous query? Retrying at another directory.",
escaped(reason));
- SEND_HS_DESC_FAILED_EVENT();
+ SEND_HS_DESC_FAILED_EVENT("QUERY_REJECTED");
break;
default:
log_warn(LD_REND, "Fetching v2 rendezvous descriptor failed: "
@@ -2124,7 +2151,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
"Retrying at another directory.",
status_code, escaped(reason), conn->base_.address,
conn->base_.port);
- SEND_HS_DESC_FAILED_EVENT();
+ SEND_HS_DESC_FAILED_EVENT("UNEXPECTED");
break;
}
}
@@ -2215,8 +2242,10 @@ connection_dir_process_inbuf(dir_connection_t *conn)
MAX_VOTE_DL_SIZE : MAX_DIRECTORY_OBJECT_SIZE;
if (connection_get_inbuf_len(TO_CONN(conn)) > max_size) {
- log_warn(LD_HTTP, "Too much data received from directory connection: "
- "denial of service attempt, or you need to upgrade?");
+ log_warn(LD_HTTP,
+ "Too much data received from directory connection (%s): "
+ "denial of service attempt, or you need to upgrade?",
+ conn->base_.address);
connection_mark_for_close(TO_CONN(conn));
return -1;
}
@@ -2261,6 +2290,7 @@ write_http_status_line(dir_connection_t *conn, int status,
log_warn(LD_BUG,"status line too long.");
return;
}
+ log_debug(LD_DIRSERV,"Wrote status 'HTTP/1.0 %d %s'", status, reason_phrase);
connection_write_to_buf(buf, strlen(buf), TO_CONN(conn));
}
@@ -2526,6 +2556,24 @@ client_likes_consensus(networkstatus_t *v, const char *want_url)
return (have >= need_at_least);
}
+/** Return the compression level we should use for sending a compressed
+ * response of size <b>n_bytes</b>. */
+static zlib_compression_level_t
+choose_compression_level(ssize_t n_bytes)
+{
+ if (! have_been_under_memory_pressure()) {
+ return HIGH_COMPRESSION; /* we have plenty of RAM. */
+ } else if (n_bytes < 0) {
+ return HIGH_COMPRESSION; /* unknown; might be big. */
+ } else if (n_bytes < 1024) {
+ return LOW_COMPRESSION;
+ } else if (n_bytes < 2048) {
+ return MEDIUM_COMPRESSION;
+ } else {
+ return HIGH_COMPRESSION;
+ }
+}
+
/** Helper function: called when a dirserver gets a complete HTTP GET
* request. Look for a request for a directory or for a rendezvous
* service descriptor. On finding one, write a response into
@@ -2557,8 +2605,11 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
if ((header = http_get_header(headers, "If-Modified-Since: "))) {
struct tm tm;
if (parse_http_time(header, &tm) == 0) {
- if (tor_timegm(&tm, &if_modified_since)<0)
+ if (tor_timegm(&tm, &if_modified_since)<0) {
if_modified_since = 0;
+ } else {
+ log_debug(LD_DIRSERV, "If-Modified-Since is '%s'.", escaped(header));
+ }
}
/* The correct behavior on a malformed If-Modified-Since header is to
* act as if no If-Modified-Since header had been given. */
@@ -2708,7 +2759,7 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
smartlist_len(dir_fps) == 1 ? lifetime : 0);
conn->fingerprint_stack = dir_fps;
if (! compressed)
- conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
+ conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD, HIGH_COMPRESSION);
/* Prime the connection with some data. */
conn->dir_spool_src = DIR_SPOOL_NETWORKSTATUS;
@@ -2796,7 +2847,8 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
if (smartlist_len(items)) {
if (compressed) {
- conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
+ conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD,
+ choose_compression_level(estimated_len));
SMARTLIST_FOREACH(items, const char *, c,
connection_write_to_buf_zlib(c, strlen(c), conn, 0));
connection_write_to_buf_zlib("", 0, conn, 1);
@@ -2845,7 +2897,8 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
conn->fingerprint_stack = fps;
if (compressed)
- conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
+ conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD,
+ choose_compression_level(dlen));
connection_dirserv_flushed_some(conn);
goto done;
@@ -2913,7 +2966,8 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
}
write_http_response_header(conn, -1, compressed, cache_lifetime);
if (compressed)
- conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
+ conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD,
+ choose_compression_level(dlen));
/* Prime the connection with some data. */
connection_dirserv_flushed_some(conn);
}
@@ -2988,7 +3042,8 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
write_http_response_header(conn, compressed?-1:len, compressed, 60*60);
if (compressed) {
- conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD);
+ conn->zlib_state = tor_zlib_new(1, ZLIB_METHOD,
+ choose_compression_level(len));
SMARTLIST_FOREACH(certs, authority_cert_t *, c,
connection_write_to_buf_zlib(c->cache_info.signed_descriptor_body,
c->cache_info.signed_descriptor_len,
@@ -3449,6 +3504,9 @@ download_status_increment_failure(download_status_t *dls, int status_code,
void
download_status_reset(download_status_t *dls)
{
+ if (dls->n_download_failures == IMPOSSIBLE_TO_DOWNLOAD)
+ return; /* Don't reset this. */
+
const smartlist_t *schedule = find_dl_schedule_and_len(
dls, get_options()->DirPort_set);
diff --git a/src/or/directory.h b/src/or/directory.h
index bc200797d4..4899eb5c8c 100644
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,9 +16,10 @@ int directories_have_accepted_server_descriptor(void);
void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose,
dirinfo_type_t type, const char *payload,
size_t payload_len, size_t extrainfo_len);
-void directory_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
- const char *resource,
- int pds_flags);
+MOCK_DECL(void, directory_get_from_dirserver, (uint8_t dir_purpose,
+ uint8_t router_purpose,
+ const char *resource,
+ int pds_flags));
void directory_get_from_all_authorities(uint8_t dir_purpose,
uint8_t router_purpose,
const char *resource);
@@ -120,7 +121,12 @@ int download_status_get_n_failures(const download_status_t *dls);
#ifdef TOR_UNIT_TESTS
/* Used only by directory.c and test_dir.c */
+
STATIC int parse_http_url(const char *headers, char **url);
+STATIC int purpose_needs_anonymity(uint8_t dir_purpose,
+ uint8_t router_purpose);
+STATIC dirinfo_type_t dir_fetch_type(int dir_purpose, int router_purpose,
+ const char *resource);
#endif
#endif
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 03b32cb2f3..65bfafba6c 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DIRSERV_PRIVATE
@@ -56,13 +56,11 @@ static int routers_with_measured_bw = 0;
static void directory_remove_invalid(void);
static char *format_versions_list(config_line_t *ln);
struct authdir_config_t;
-static int add_fingerprint_to_dir(const char *nickname, const char *fp,
- struct authdir_config_t *list);
static uint32_t
dirserv_get_status_impl(const char *fp, const char *nickname,
uint32_t addr, uint16_t or_port,
- const char *platform, const char *contact,
- const char **msg, int should_log);
+ const char *platform, const char **msg,
+ int should_log);
static void clear_cached_dir(cached_dir_t *d);
static const signed_descriptor_t *get_signed_descriptor_by_fp(
const char *fp,
@@ -75,19 +73,19 @@ static uint32_t dirserv_get_credible_bandwidth_kb(const routerinfo_t *ri);
/************** Fingerprint handling code ************/
-#define FP_NAMED 1 /**< Listed in fingerprint file. */
+/* 1 Historically used to indicate Named */
#define FP_INVALID 2 /**< Believed invalid. */
#define FP_REJECT 4 /**< We will not publish this router. */
-#define FP_BADDIR 8 /**< We'll tell clients to avoid using this as a dir. */
+/* 8 Historically used to avoid using this as a dir. */
#define FP_BADEXIT 16 /**< We'll tell clients not to use this as an exit. */
-#define FP_UNNAMED 32 /**< Another router has this name in fingerprint file. */
+/* 32 Historically used to indicade Unnamed */
-/** Encapsulate a nickname and an FP_* status; target of status_by_digest
- * map. */
-typedef struct router_status_t {
- char nickname[MAX_NICKNAME_LEN+1];
- uint32_t status;
-} router_status_t;
+/** Target of status_by_digest map. */
+typedef uint32_t router_status_t;
+
+static void add_fingerprint_to_dir(const char *fp,
+ struct authdir_config_t *list,
+ router_status_t add_status);
/** List of nickname-\>identity fingerprint mappings for all the routers
* that we name. Used to prevent router impersonation. */
@@ -109,18 +107,17 @@ authdir_config_new(void)
return list;
}
-/** Add the fingerprint <b>fp</b> for <b>nickname</b> to
- * the smartlist of fingerprint_entry_t's <b>list</b>. Return 0 if it's
- * new, or 1 if we replaced the old value.
+/** Add the fingerprint <b>fp</b> to the smartlist of fingerprint_entry_t's
+ * <b>list</b>, or-ing the currently set status flags with
+ * <b>add_status</b>.
*/
-/* static */ int
-add_fingerprint_to_dir(const char *nickname, const char *fp,
- authdir_config_t *list)
+/* static */ void
+add_fingerprint_to_dir(const char *fp, authdir_config_t *list,
+ router_status_t add_status)
{
char *fingerprint;
char d[DIGEST_LEN];
router_status_t *status;
- tor_assert(nickname);
tor_assert(fp);
tor_assert(list);
@@ -130,14 +127,7 @@ add_fingerprint_to_dir(const char *nickname, const char *fp,
log_warn(LD_DIRSERV, "Couldn't decode fingerprint \"%s\"",
escaped(fp));
tor_free(fingerprint);
- return 0;
- }
-
- if (!strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) {
- log_warn(LD_DIRSERV, "Tried to add a mapping for reserved nickname %s",
- UNNAMED_ROUTER_NICKNAME);
- tor_free(fingerprint);
- return 0;
+ return;
}
status = digestmap_get(list->status_by_digest, d);
@@ -146,35 +136,15 @@ add_fingerprint_to_dir(const char *nickname, const char *fp,
digestmap_set(list->status_by_digest, d, status);
}
- if (nickname[0] != '!') {
- char *old_fp = strmap_get_lc(list->fp_by_name, nickname);
- if (old_fp && !strcasecmp(fingerprint, old_fp)) {
- tor_free(fingerprint);
- } else {
- tor_free(old_fp);
- strmap_set_lc(list->fp_by_name, nickname, fingerprint);
- }
- status->status |= FP_NAMED;
- strlcpy(status->nickname, nickname, sizeof(status->nickname));
- } else {
- tor_free(fingerprint);
- if (!strcasecmp(nickname, "!reject")) {
- status->status |= FP_REJECT;
- } else if (!strcasecmp(nickname, "!invalid")) {
- status->status |= FP_INVALID;
- } else if (!strcasecmp(nickname, "!baddir")) {
- status->status |= FP_BADDIR;
- } else if (!strcasecmp(nickname, "!badexit")) {
- status->status |= FP_BADEXIT;
- }
- }
- return 0;
+ tor_free(fingerprint);
+ *status |= add_status;
+ return;
}
-/** Add the nickname and fingerprint for this OR to the
- * global list of recognized identity key fingerprints. */
+/** Add the fingerprint for this OR to the global list of recognized
+ * identity key fingerprints. */
int
-dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk)
+dirserv_add_own_fingerprint(crypto_pk_t *pk)
{
char fp[FINGERPRINT_LEN+1];
if (crypto_pk_get_fingerprint(pk, fp, 0)<0) {
@@ -183,7 +153,7 @@ dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk)
}
if (!fingerprint_list)
fingerprint_list = authdir_config_new();
- add_fingerprint_to_dir(nickname, fp, fingerprint_list);
+ add_fingerprint_to_dir(fp, fingerprint_list, 0);
return 0;
}
@@ -201,7 +171,6 @@ dirserv_load_fingerprint_file(void)
authdir_config_t *fingerprint_list_new;
int result;
config_line_t *front=NULL, *list;
- const or_options_t *options = get_options();
fname = get_datadir_fname("approved-routers");
log_info(LD_GENERAL,
@@ -209,15 +178,9 @@ dirserv_load_fingerprint_file(void)
cf = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
if (!cf) {
- if (options->NamingAuthoritativeDir) {
- log_warn(LD_FS, "Cannot open fingerprint file '%s'. Failing.", fname);
- tor_free(fname);
- return -1;
- } else {
- log_info(LD_FS, "Cannot open fingerprint file '%s'. That's ok.", fname);
- tor_free(fname);
- return 0;
- }
+ log_warn(LD_FS, "Cannot open fingerprint file '%s'. That's ok.", fname);
+ tor_free(fname);
+ return 0;
}
tor_free(fname);
@@ -232,22 +195,8 @@ dirserv_load_fingerprint_file(void)
for (list=front; list; list=list->next) {
char digest_tmp[DIGEST_LEN];
+ router_status_t add_status = 0;
nickname = list->key; fingerprint = list->value;
- if (strlen(nickname) > MAX_NICKNAME_LEN) {
- log_notice(LD_CONFIG,
- "Nickname '%s' too long in fingerprint file. Skipping.",
- nickname);
- continue;
- }
- if (!is_legal_nickname(nickname) &&
- strcasecmp(nickname, "!reject") &&
- strcasecmp(nickname, "!invalid") &&
- strcasecmp(nickname, "!badexit")) {
- log_notice(LD_CONFIG,
- "Invalid nickname '%s' in fingerprint file. Skipping.",
- nickname);
- continue;
- }
tor_strstrip(fingerprint, " "); /* remove spaces */
if (strlen(fingerprint) != HEX_DIGEST_LEN ||
base16_decode(digest_tmp, sizeof(digest_tmp),
@@ -258,26 +207,14 @@ dirserv_load_fingerprint_file(void)
nickname, fingerprint);
continue;
}
- if (0==strcasecmp(nickname, DEFAULT_CLIENT_NICKNAME)) {
- /* If you approved an OR called "client", then clients who use
- * the default nickname could all be rejected. That's no good. */
- log_notice(LD_CONFIG,
- "Authorizing nickname '%s' would break "
- "many clients; skipping.",
- DEFAULT_CLIENT_NICKNAME);
- continue;
- }
- if (0==strcasecmp(nickname, UNNAMED_ROUTER_NICKNAME)) {
- /* If you approved an OR called "unnamed", then clients will be
- * confused. */
- log_notice(LD_CONFIG,
- "Authorizing nickname '%s' is not allowed; skipping.",
- UNNAMED_ROUTER_NICKNAME);
- continue;
+ if (!strcasecmp(nickname, "!reject")) {
+ add_status = FP_REJECT;
+ } else if (!strcasecmp(nickname, "!badexit")) {
+ add_status = FP_BADEXIT;
+ } else if (!strcasecmp(nickname, "!invalid")) {
+ add_status = FP_INVALID;
}
- if (add_fingerprint_to_dir(nickname, fingerprint, fingerprint_list_new)
- != 0)
- log_notice(LD_CONFIG, "Duplicate nickname '%s'.", nickname);
+ add_fingerprint_to_dir(fingerprint, fingerprint_list_new, add_status);
}
config_free_lines(front);
@@ -308,8 +245,7 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg)
return dirserv_get_status_impl(d, router->nickname,
router->addr, router->or_port,
- router->platform, router->contact_info,
- msg, 1);
+ router->platform, msg, 1);
}
/** Return true if there is no point in downloading the router described by
@@ -321,37 +257,14 @@ dirserv_would_reject_router(const routerstatus_t *rs)
res = dirserv_get_status_impl(rs->identity_digest, rs->nickname,
rs->addr, rs->or_port,
- NULL, NULL,
- NULL, 0);
+ NULL, NULL, 0);
return (res & FP_REJECT) != 0;
}
-/** Helper: Based only on the ID/Nickname combination,
- * return FP_UNNAMED (unnamed), FP_NAMED (named), or 0 (neither).
- */
-static uint32_t
-dirserv_get_name_status(const char *id_digest, const char *nickname)
-{
- char fp[HEX_DIGEST_LEN+1];
- char *fp_by_name;
-
- base16_encode(fp, sizeof(fp), id_digest, DIGEST_LEN);
-
- if ((fp_by_name =
- strmap_get_lc(fingerprint_list->fp_by_name, nickname))) {
- if (!strcasecmp(fp, fp_by_name)) {
- return FP_NAMED;
- } else {
- return FP_UNNAMED; /* Wrong fingerprint. */
- }
- }
- return 0;
-}
-
/** Helper: As dirserv_router_get_status, but takes the router fingerprint
* (hex, no spaces), nickname, address (used for logging only), IP address, OR
- * port, platform (logging only) and contact info (logging only) as arguments.
+ * port and platform (logging only) as arguments.
*
* If should_log is false, do not log messages. (There's not much point in
* logging that we're rejecting servers we'll not download.)
@@ -359,11 +272,9 @@ dirserv_get_name_status(const char *id_digest, const char *nickname)
static uint32_t
dirserv_get_status_impl(const char *id_digest, const char *nickname,
uint32_t addr, uint16_t or_port,
- const char *platform, const char *contact,
- const char **msg, int should_log)
+ const char *platform, const char **msg, int should_log)
{
- int reject_unlisted = get_options()->AuthDirRejectUnlisted;
- uint32_t result;
+ uint32_t result = 0;
router_status_t *status_by_digest;
if (!fingerprint_list)
@@ -374,50 +285,18 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
strmap_size(fingerprint_list->fp_by_name),
digestmap_size(fingerprint_list->status_by_digest));
- /* Versions before Tor 0.2.3.16-alpha are too old to support, and are
+ /* Versions before Tor 0.2.4.18-rc are too old to support, and are
* missing some important security fixes too. Disable them. */
- if (platform && !tor_version_as_new_as(platform,"0.2.3.16-alpha")) {
+ if (platform && !tor_version_as_new_as(platform,"0.2.4.18-rc")) {
if (msg)
*msg = "Tor version is insecure or unsupported. Please upgrade!";
return FP_REJECT;
}
-#if 0
- else if (platform && tor_version_as_new_as(platform,"0.2.3.0-alpha")) {
- /* Versions from 0.2.3-alpha...0.2.3.9-alpha have known security
- * issues that make them unusable for the current network */
- if (!tor_version_as_new_as(platform, "0.2.3.10-alpha")) {
- if (msg)
- *msg = "Tor version is insecure or unsupported. Please upgrade!";
- return FP_REJECT;
- }
- }
-#endif
-
- result = dirserv_get_name_status(id_digest, nickname);
- if (result & FP_NAMED) {
- if (should_log)
- log_debug(LD_DIRSERV,"Good fingerprint for '%s'",nickname);
- }
- if (result & FP_UNNAMED) {
- if (should_log) {
- char *esc_contact = esc_for_log(contact);
- log_info(LD_DIRSERV,
- "Mismatched fingerprint for '%s'. "
- "ContactInfo '%s', platform '%s'.)",
- nickname,
- esc_contact,
- platform ? escaped(platform) : "");
- tor_free(esc_contact);
- }
- if (msg)
- *msg = "Rejected: There is already a named server with this nickname "
- "and a different fingerprint.";
- }
status_by_digest = digestmap_get(fingerprint_list->status_by_digest,
id_digest);
if (status_by_digest)
- result |= (status_by_digest->status & ~FP_NAMED);
+ result |= *status_by_digest;
if (result & FP_REJECT) {
if (msg)
@@ -428,14 +307,6 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
*msg = "Fingerprint is marked invalid";
}
- if (authdir_policy_baddir_address(addr, or_port)) {
- if (should_log)
- log_info(LD_DIRSERV,
- "Marking '%s' as bad directory because of address '%s'",
- nickname, fmt_addr32(addr));
- result |= FP_BADDIR;
- }
-
if (authdir_policy_badexit_address(addr, or_port)) {
if (should_log)
log_info(LD_DIRSERV, "Marking '%s' as bad exit because of address '%s'",
@@ -443,46 +314,24 @@ dirserv_get_status_impl(const char *id_digest, const char *nickname,
result |= FP_BADEXIT;
}
- if (!(result & FP_NAMED)) {
- if (!authdir_policy_permits_address(addr, or_port)) {
- if (should_log)
- log_info(LD_DIRSERV, "Rejecting '%s' because of address '%s'",
- nickname, fmt_addr32(addr));
- if (msg)
- *msg = "Authdir is rejecting routers in this range.";
- return FP_REJECT;
- }
- if (!authdir_policy_valid_address(addr, or_port)) {
- if (should_log)
- log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'",
- nickname, fmt_addr32(addr));
- result |= FP_INVALID;
- }
- if (reject_unlisted) {
- if (msg)
- *msg = "Authdir rejects unknown routers.";
- return FP_REJECT;
- }
+ if (!authdir_policy_permits_address(addr, or_port)) {
+ if (should_log)
+ log_info(LD_DIRSERV, "Rejecting '%s' because of address '%s'",
+ nickname, fmt_addr32(addr));
+ if (msg)
+ *msg = "Authdir is rejecting routers in this range.";
+ return FP_REJECT;
+ }
+ if (!authdir_policy_valid_address(addr, or_port)) {
+ if (should_log)
+ log_info(LD_DIRSERV, "Not marking '%s' valid because of address '%s'",
+ nickname, fmt_addr32(addr));
+ result |= FP_INVALID;
}
return result;
}
-/** If we are an authoritative dirserver, and the list of approved
- * servers contains one whose identity key digest is <b>digest</b>,
- * return that router's nickname. Otherwise return NULL. */
-const char *
-dirserv_get_nickname_by_digest(const char *digest)
-{
- router_status_t *status;
- if (!fingerprint_list)
- return NULL;
- tor_assert(digest);
-
- status = digestmap_get(fingerprint_list->status_by_digest, digest);
- return status ? status->nickname : NULL;
-}
-
/** Clear the current fingerprint list. */
void
dirserv_free_fingerprint_list(void)
@@ -519,7 +368,7 @@ dirserv_router_has_valid_address(routerinfo_t *ri)
}
/** Check whether we, as a directory server, want to accept <b>ri</b>. If so,
- * set its is_valid,named,running fields and return 0. Otherwise, return -1.
+ * set its is_valid,running fields and return 0. Otherwise, return -1.
*
* If the router is rejected, set *<b>msg</b> to an explanation of why.
*
@@ -584,7 +433,6 @@ dirserv_set_node_flags_from_authoritative_status(node_t *node,
uint32_t authstatus)
{
node->is_valid = (authstatus & FP_INVALID) ? 0 : 1;
- node->is_bad_directory = (authstatus & FP_BADDIR) ? 1 : 0;
node->is_bad_exit = (authstatus & FP_BADEXIT) ? 1 : 0;
}
@@ -630,7 +478,7 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
s = desc;
list = smartlist_new();
if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 0, 0,
- annotation_buf)) {
+ annotation_buf, NULL)) {
SMARTLIST_FOREACH(list, routerinfo_t *, ri, {
msg_out = NULL;
tor_assert(ri->purpose == purpose);
@@ -646,7 +494,7 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
s = desc;
if (!router_parse_list_from_string(&s, NULL, list, SAVED_NOWHERE, 1, 0,
- NULL)) {
+ NULL, NULL)) {
SMARTLIST_FOREACH(list, extrainfo_t *, ei, {
msg_out = NULL;
@@ -664,7 +512,7 @@ dirserv_add_multiple_descriptors(const char *desc, uint8_t purpose,
if (!n_parsed) {
*msg = "No descriptors found in your POST.";
if (WRA_WAS_ADDED(r))
- r = ROUTER_WAS_NOT_NEW;
+ r = ROUTER_IS_ALREADY_KNOWN;
} else {
*msg = "(no message)";
}
@@ -689,7 +537,8 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
was_router_added_t r;
routerinfo_t *ri_old;
char *desc, *nickname;
- size_t desclen = 0;
+ const size_t desclen = ri->cache_info.signed_descriptor_len +
+ ri->cache_info.annotations_len;
*msg = NULL;
/* If it's too big, refuse it now. Otherwise we'll cache it all over the
@@ -703,7 +552,7 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
*msg = "Router descriptor was too large.";
control_event_or_authdir_new_descriptor("REJECTED",
ri->cache_info.signed_descriptor_body,
- ri->cache_info.signed_descriptor_len, *msg);
+ desclen, *msg);
routerinfo_free(ri);
return ROUTER_AUTHDIR_REJECTS;
}
@@ -724,14 +573,13 @@ dirserv_add_descriptor(routerinfo_t *ri, const char **msg, const char *source)
"the last one with this identity.";
control_event_or_authdir_new_descriptor("DROPPED",
ri->cache_info.signed_descriptor_body,
- ri->cache_info.signed_descriptor_len, *msg);
+ desclen, *msg);
routerinfo_free(ri);
- return ROUTER_WAS_NOT_NEW;
+ return ROUTER_IS_ALREADY_KNOWN;
}
/* Make a copy of desc, since router_add_to_routerlist might free
* ri and its associated signed_descriptor_t. */
- desclen = ri->cache_info.signed_descriptor_len;
desc = tor_strndup(ri->cache_info.signed_descriptor_body, desclen);
nickname = tor_strdup(ri->nickname);
@@ -798,7 +646,7 @@ dirserv_add_extrainfo(extrainfo_t *ei, const char **msg)
if ((r = routerinfo_incompatible_with_extrainfo(ri, ei, NULL, msg))) {
extrainfo_free(ei);
- return r < 0 ? ROUTER_WAS_NOT_NEW : ROUTER_BAD_EI;
+ return r < 0 ? ROUTER_IS_ALREADY_KNOWN : ROUTER_BAD_EI;
}
router_add_extrainfo_to_routerlist(ei, msg, 0, 0);
return ROUTER_ADDED_SUCCESSFULLY;
@@ -816,7 +664,7 @@ directory_remove_invalid(void)
smartlist_add_all(nodes, nodelist_get_list());
SMARTLIST_FOREACH_BEGIN(nodes, node_t *, node) {
- const char *msg;
+ const char *msg = NULL;
routerinfo_t *ent = node->ri;
char description[NODE_DESC_BUF_LEN];
uint32_t r;
@@ -830,30 +678,11 @@ directory_remove_invalid(void)
routerlist_remove(rl, ent, 0, time(NULL));
continue;
}
-#if 0
- if (bool_neq((r & FP_NAMED), ent->auth_says_is_named)) {
- log_info(LD_DIRSERV,
- "Router %s is now %snamed.", description,
- (r&FP_NAMED)?"":"un");
- ent->is_named = (r&FP_NAMED)?1:0;
- }
- if (bool_neq((r & FP_UNNAMED), ent->auth_says_is_unnamed)) {
- log_info(LD_DIRSERV,
- "Router '%s' is now %snamed. (FP_UNNAMED)", description,
- (r&FP_NAMED)?"":"un");
- ent->is_named = (r&FP_NUNAMED)?0:1;
- }
-#endif
if (bool_neq((r & FP_INVALID), !node->is_valid)) {
log_info(LD_DIRSERV, "Router '%s' is now %svalid.", description,
(r&FP_INVALID) ? "in" : "");
node->is_valid = (r&FP_INVALID)?0:1;
}
- if (bool_neq((r & FP_BADDIR), node->is_bad_directory)) {
- log_info(LD_DIRSERV, "Router '%s' is now a %s directory", description,
- (r & FP_BADDIR) ? "bad" : "good");
- node->is_bad_directory = (r&FP_BADDIR) ? 1: 0;
- }
if (bool_neq((r & FP_BADEXIT), node->is_bad_exit)) {
log_info(LD_DIRSERV, "Router '%s' is now a %s exit", description,
(r & FP_BADEXIT) ? "bad" : "good");
@@ -904,7 +733,7 @@ running_long_enough_to_decide_unreachable(void)
}
/** Each server needs to have passed a reachability test no more
- * than this number of seconds ago, or he is listed as down in
+ * than this number of seconds ago, or it is listed as down in
* the directory. */
#define REACHABLE_TIMEOUT (45*60)
@@ -1051,16 +880,33 @@ format_versions_list(config_line_t *ln)
}
/** Return 1 if <b>ri</b>'s descriptor is "active" -- running, valid,
- * not hibernating, and not too old. Else return 0.
+ * not hibernating, having observed bw greater 0, and not too old. Else
+ * return 0.
*/
static int
router_is_active(const routerinfo_t *ri, const node_t *node, time_t now)
{
time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
- if (ri->cache_info.published_on < cutoff)
+ if (ri->cache_info.published_on < cutoff) {
return 0;
- if (!node->is_running || !node->is_valid || ri->is_hibernating)
+ }
+ if (!node->is_running || !node->is_valid || ri->is_hibernating) {
return 0;
+ }
+ /* Only require bandwith capacity in non-test networks, or
+ * if TestingTorNetwork, and TestingMinExitFlagThreshold is non-zero */
+ if (!ri->bandwidthcapacity) {
+ if (get_options()->TestingTorNetwork) {
+ if (get_options()->TestingMinExitFlagThreshold > 0) {
+ /* If we're in a TestingTorNetwork, and TestingMinExitFlagThreshold is,
+ * then require bandwidthcapacity */
+ return 0;
+ }
+ } else {
+ /* If we're not in a TestingTorNetwork, then require bandwidthcapacity */
+ return 0;
+ }
+ }
return 1;
}
@@ -1205,7 +1051,7 @@ directory_fetches_dir_info_later(const or_options_t *options)
}
/** Return true iff we want to fetch and keep certificates for authorities
- * that we don't acknowledge as aurthorities ourself.
+ * that we don't acknowledge as authorities ourself.
*/
int
directory_caches_unknown_auth_certs(const or_options_t *options)
@@ -1432,8 +1278,9 @@ dirserv_thinks_router_is_unreliable(time_t now,
}
/** Return true iff <b>router</b> should be assigned the "HSDir" flag.
- * Right now this means it advertises support for it, it has a high
- * uptime, it has a DirPort open, and it's currently considered Running.
+ * Right now this means it advertises support for it, it has a high uptime,
+ * it has a DirPort open, it has the Stable flag and it's currently
+ * considered Running.
*
* This function needs to be called after router-\>is_running has
* been set.
@@ -1459,16 +1306,10 @@ dirserv_thinks_router_is_hs_dir(const routerinfo_t *router,
else
uptime = real_uptime(router, now);
- /* XXX We shouldn't need to check dir_port, but we do because of
- * bug 1693. In the future, once relays set wants_to_be_hs_dir
- * correctly, we can revert to only checking dir_port if router's
- * version is too old. */
- /* XXX Unfortunately, we need to keep checking dir_port until all
- * *clients* suffering from bug 2722 are obsolete. The first version
- * to fix the bug was 0.2.2.25-alpha. */
return (router->wants_to_be_hs_dir && router->dir_port &&
+ node->is_stable &&
uptime >= get_options()->MinUptimeHidServDirectoryV2 &&
- node->is_running);
+ router_is_active(router, node, now));
}
/** Don't consider routers with less bandwidth than this when computing
@@ -1537,18 +1378,18 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
* sort them and use that to compute thresholds. */
n_active = n_active_nonexit = 0;
/* Uptime for every active router. */
- uptimes = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
+ uptimes = tor_calloc(smartlist_len(rl->routers), sizeof(uint32_t));
/* Bandwidth for every active router. */
- bandwidths_kb = tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
+ bandwidths_kb = tor_calloc(smartlist_len(rl->routers), sizeof(uint32_t));
/* Bandwidth for every active non-exit router. */
bandwidths_excluding_exits_kb =
- tor_malloc(sizeof(uint32_t)*smartlist_len(rl->routers));
+ tor_calloc(smartlist_len(rl->routers), sizeof(uint32_t));
/* Weighted mean time between failure for each active router. */
- mtbfs = tor_malloc(sizeof(double)*smartlist_len(rl->routers));
+ mtbfs = tor_calloc(smartlist_len(rl->routers), sizeof(double));
/* Time-known for each active router. */
- tks = tor_malloc(sizeof(long)*smartlist_len(rl->routers));
+ tks = tor_calloc(smartlist_len(rl->routers), sizeof(long));
/* Weighted fractional uptime for each active router. */
- wfus = tor_malloc(sizeof(double)*smartlist_len(rl->routers));
+ wfus = tor_calloc(smartlist_len(rl->routers), sizeof(double));
nodelist_assert_ok();
@@ -1563,6 +1404,8 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
routerinfo_t *ri = node->ri;
const char *id = node->identity;
uint32_t bw_kb;
+ /* resolve spurious clang shallow analysis null pointer errors */
+ tor_assert(ri);
node->is_exit = (!router_exit_policy_rejects_all(ri) &&
exit_policy_is_general_exit(ri->exit_policy));
uptimes[n_active] = (uint32_t)real_uptime(ri, now);
@@ -1586,9 +1429,10 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
/* The 12.5th percentile bandwidth is fast. */
fast_bandwidth_kb = find_nth_uint32(bandwidths_kb, n_active, n_active/8);
/* (Now bandwidths is sorted.) */
- if (fast_bandwidth_kb < ROUTER_REQUIRED_MIN_BANDWIDTH/(2 * 1000))
+ if (fast_bandwidth_kb < RELAY_REQUIRED_MIN_BANDWIDTH/(2 * 1000))
fast_bandwidth_kb = bandwidths_kb[n_active/4];
- guard_bandwidth_including_exits_kb = bandwidths_kb[n_active*3/4];
+ guard_bandwidth_including_exits_kb =
+ third_quartile_uint32(bandwidths_kb, n_active);
guard_tk = find_nth_long(tks, n_active, n_active/8);
}
@@ -1663,7 +1507,7 @@ dirserv_compute_performance_thresholds(routerlist_t *rl,
(unsigned long)guard_tk,
(unsigned long)guard_bandwidth_including_exits_kb,
(unsigned long)guard_bandwidth_excluding_exits_kb,
- enough_mtbf_info ? "" : " don't ");
+ enough_mtbf_info ? "" : " don't");
tor_free(uptimes);
tor_free(mtbfs);
@@ -1959,13 +1803,12 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
char published[ISO_TIME_LEN+1];
char identity64[BASE64_DIGEST_LEN+1];
char digest64[BASE64_DIGEST_LEN+1];
- smartlist_t *chunks = NULL;
+ smartlist_t *chunks = smartlist_new();
format_iso_time(published, rs->published_on);
digest_to_base64(identity64, rs->identity_digest);
digest_to_base64(digest64, rs->descriptor_digest);
- chunks = smartlist_new();
smartlist_add_asprintf(chunks,
"r %s %s %s%s%s %s %d %d\n",
rs->nickname,
@@ -1996,19 +1839,16 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
goto done;
smartlist_add_asprintf(chunks,
- "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ "s%s%s%s%s%s%s%s%s%s%s\n",
/* These must stay in alphabetical order. */
rs->is_authority?" Authority":"",
- rs->is_bad_directory?" BadDirectory":"",
rs->is_bad_exit?" BadExit":"",
rs->is_exit?" Exit":"",
rs->is_fast?" Fast":"",
rs->is_possible_guard?" Guard":"",
rs->is_hs_dir?" HSDir":"",
- rs->is_named?" Named":"",
rs->is_flagged_running?" Running":"",
rs->is_stable?" Stable":"",
- rs->is_unnamed?" Unnamed":"",
(rs->dir_port!=0)?" V2Dir":"",
rs->is_valid?" Valid":"");
@@ -2077,6 +1917,13 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
smartlist_add_asprintf(chunks,
" Measured=%d", vrs->measured_bw_kb);
}
+ /* Write down guardfraction information if we have it. */
+ if (format == NS_V3_VOTE && vrs && vrs->status.has_guardfraction) {
+ smartlist_add_asprintf(chunks,
+ " GuardFraction=%d",
+ vrs->status.guardfraction_percentage);
+ }
+
smartlist_add(chunks, tor_strdup("\n"));
if (desc) {
@@ -2090,10 +1937,8 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
result = smartlist_join_strings(chunks, "", 0, NULL);
err:
- if (chunks) {
- SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
- smartlist_free(chunks);
- }
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
return result;
}
@@ -2199,78 +2044,8 @@ get_possible_sybil_list(const smartlist_t *routers)
return omit_as_sybil;
}
-/** Return non-zero iff a relay running the Tor version specified in
- * <b>platform</b> is suitable for use as a potential entry guard. */
-static int
-is_router_version_good_for_possible_guard(const char *platform)
-{
- static int parsed_versions_initialized = 0;
- static tor_version_t first_good_0_2_1_guard_version;
- static tor_version_t first_good_0_2_2_guard_version;
- static tor_version_t first_good_later_guard_version;
-
- tor_version_t router_version;
-
- /* XXX024 This block should be extracted into its own function. */
- /* XXXX Begin code copied from tor_version_as_new_as (in routerparse.c) */
- {
- char *s, *s2, *start;
- char tmp[128];
-
- tor_assert(platform);
-
- /* nonstandard Tor; be safe and say yes */
- if (strcmpstart(platform,"Tor "))
- return 1;
-
- start = (char *)eat_whitespace(platform+3);
- if (!*start) return 0;
- s = (char *)find_whitespace(start); /* also finds '\0', which is fine */
- s2 = (char*)eat_whitespace(s);
- if (!strcmpstart(s2, "(r") || !strcmpstart(s2, "(git-"))
- s = (char*)find_whitespace(s2);
-
- if ((size_t)(s-start+1) >= sizeof(tmp)) /* too big, no */
- return 0;
- strlcpy(tmp, start, s-start+1);
-
- if (tor_version_parse(tmp, &router_version)<0) {
- log_info(LD_DIR,"Router version '%s' unparseable.",tmp);
- return 1; /* be safe and say yes */
- }
- }
- /* XXXX End code copied from tor_version_as_new_as (in routerparse.c) */
-
- if (!parsed_versions_initialized) {
- /* CVE-2011-2769 was fixed on the relay side in Tor versions
- * 0.2.1.31, 0.2.2.34, and 0.2.3.6-alpha. */
- tor_assert(tor_version_parse("0.2.1.31",
- &first_good_0_2_1_guard_version)>=0);
- tor_assert(tor_version_parse("0.2.2.34",
- &first_good_0_2_2_guard_version)>=0);
- tor_assert(tor_version_parse("0.2.3.6-alpha",
- &first_good_later_guard_version)>=0);
-
- /* Don't parse these constant version strings once for every relay
- * for every vote. */
- parsed_versions_initialized = 1;
- }
-
- return ((tor_version_same_series(&first_good_0_2_1_guard_version,
- &router_version) &&
- tor_version_compare(&first_good_0_2_1_guard_version,
- &router_version) <= 0) ||
- (tor_version_same_series(&first_good_0_2_2_guard_version,
- &router_version) &&
- tor_version_compare(&first_good_0_2_2_guard_version,
- &router_version) <= 0) ||
- (tor_version_compare(&first_good_later_guard_version,
- &router_version) <= 0));
-}
-
/** Extract status information from <b>ri</b> and from other authority
- * functions and store it in <b>rs</b>>. If <b>naming</b>, consider setting
- * the named flag in <b>rs</b>.
+ * functions and store it in <b>rs</b>>.
*
* We assume that ri-\>is_running has already been set, e.g. by
* dirserv_set_router_is_running(ri, now);
@@ -2280,8 +2055,8 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
node_t *node,
routerinfo_t *ri,
time_t now,
- int naming, int listbadexits,
- int listbaddirs, int vote_on_hsdirs)
+ int listbadexits,
+ int vote_on_hsdirs)
{
const or_options_t *options = get_options();
uint32_t routerbw_kb = dirserv_get_credible_bandwidth_kb(ri);
@@ -2301,20 +2076,13 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
!dirserv_thinks_router_is_unreliable(now, ri, 0, 1);
rs->is_flagged_running = node->is_running; /* computed above */
- if (naming) {
- uint32_t name_status = dirserv_get_name_status(
- node->identity, ri->nickname);
- rs->is_named = (naming && (name_status & FP_NAMED)) ? 1 : 0;
- rs->is_unnamed = (naming && (name_status & FP_UNNAMED)) ? 1 : 0;
- }
rs->is_valid = node->is_valid;
if (node->is_fast &&
((options->AuthDirGuardBWGuarantee &&
routerbw_kb >= options->AuthDirGuardBWGuarantee/1000) ||
routerbw_kb >= MIN(guard_bandwidth_including_exits_kb,
- guard_bandwidth_excluding_exits_kb)) &&
- is_router_version_good_for_possible_guard(ri->platform)) {
+ guard_bandwidth_excluding_exits_kb))) {
long tk = rep_hist_get_weighted_time_known(
node->identity, now);
double wfu = rep_hist_get_weighted_fractional_uptime(
@@ -2323,19 +2091,12 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
} else {
rs->is_possible_guard = 0;
}
- if (options->TestingTorNetwork &&
- routerset_contains_routerstatus(options->TestingDirAuthVoteGuard,
- rs, 0)) {
- rs->is_possible_guard = 1;
- }
- rs->is_bad_directory = listbaddirs && node->is_bad_directory;
rs->is_bad_exit = listbadexits && node->is_bad_exit;
node->is_hs_dir = dirserv_thinks_router_is_hs_dir(ri, node, now);
rs->is_hs_dir = vote_on_hsdirs && node->is_hs_dir;
- if (!strcasecmp(ri->nickname, UNNAMED_ROUTER_NICKNAME))
- rs->is_named = rs->is_unnamed = 0;
+ rs->is_named = rs->is_unnamed = 0;
rs->published_on = ri->cache_info.published_on;
memcpy(rs->identity_digest, node->identity, DIGEST_LEN);
@@ -2353,6 +2114,28 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr);
rs->ipv6_orport = ri->ipv6_orport;
}
+
+ /* Iff we are in a testing network, use TestingDirAuthVoteExit,
+ TestingDirAuthVoteGuard, and TestingDirAuthVoteHSDir to
+ give out the Exit, Guard, and HSDir flags, respectively.
+ But don't set the corresponding node flags. */
+ if (options->TestingTorNetwork) {
+ if (routerset_contains_routerstatus(options->TestingDirAuthVoteExit,
+ rs, 0)) {
+ rs->is_exit = 1;
+ }
+
+ if (routerset_contains_routerstatus(options->TestingDirAuthVoteGuard,
+ rs, 0)) {
+ rs->is_possible_guard = 1;
+ }
+
+ if (routerset_contains_routerstatus(options->TestingDirAuthVoteHSDir,
+ rs, 0)) {
+ /* TestingDirAuthVoteHSDir respects VoteOnHidServDirectoriesV2 */
+ rs->is_hs_dir = vote_on_hsdirs;
+ }
+ }
}
/** Routerstatus <b>rs</b> is part of a group of routers that are on
@@ -2364,13 +2147,325 @@ clear_status_flags_on_sybil(routerstatus_t *rs)
{
rs->is_authority = rs->is_exit = rs->is_stable = rs->is_fast =
rs->is_flagged_running = rs->is_named = rs->is_valid =
- rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit =
- rs->is_bad_directory = 0;
+ rs->is_hs_dir = rs->is_possible_guard = rs->is_bad_exit = 0;
/* FFFF we might want some mechanism to check later on if we
* missed zeroing any flags: it's easy to add a new flag but
* forget to add it to this clause. */
}
+/** The guardfraction of the guard with identity fingerprint <b>guard_id</b>
+ * is <b>guardfraction_percentage</b>. See if we have a vote routerstatus for
+ * this guard in <b>vote_routerstatuses</b>, and if we do, register the
+ * information to it.
+ *
+ * Return 1 if we applied the information and 0 if we couldn't find a
+ * matching guard.
+ *
+ * Requires that <b>vote_routerstatuses</b> be sorted.
+ */
+static int
+guardfraction_line_apply(const char *guard_id,
+ uint32_t guardfraction_percentage,
+ smartlist_t *vote_routerstatuses)
+{
+ vote_routerstatus_t *vrs = NULL;
+
+ tor_assert(vote_routerstatuses);
+
+ vrs = smartlist_bsearch(vote_routerstatuses, guard_id,
+ compare_digest_to_vote_routerstatus_entry);
+
+ if (!vrs) {
+ return 0;
+ }
+
+ vrs->status.has_guardfraction = 1;
+ vrs->status.guardfraction_percentage = guardfraction_percentage;
+
+ return 1;
+}
+
+/* Given a guard line from a guardfraction file, parse it and register
+ * its information to <b>vote_routerstatuses</b>.
+ *
+ * Return:
+ * * 1 if the line was proper and its information got registered.
+ * * 0 if the line was proper but no currently active guard was found
+ * to register the guardfraction information to.
+ * * -1 if the line could not be parsed and set <b>err_msg</b> to a
+ newly allocated string containing the error message.
+ */
+static int
+guardfraction_file_parse_guard_line(const char *guard_line,
+ smartlist_t *vote_routerstatuses,
+ char **err_msg)
+{
+ char guard_id[DIGEST_LEN];
+ uint32_t guardfraction;
+ char *inputs_tmp = NULL;
+ int num_ok = 1;
+
+ smartlist_t *sl = smartlist_new();
+ int retval = -1;
+
+ tor_assert(err_msg);
+
+ /* guard_line should contain something like this:
+ <hex digest> <guardfraction> <appearances> */
+ smartlist_split_string(sl, guard_line, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
+ if (smartlist_len(sl) < 3) {
+ tor_asprintf(err_msg, "bad line '%s'", guard_line);
+ goto done;
+ }
+
+ inputs_tmp = smartlist_get(sl, 0);
+ if (strlen(inputs_tmp) != HEX_DIGEST_LEN ||
+ base16_decode(guard_id, DIGEST_LEN, inputs_tmp, HEX_DIGEST_LEN)) {
+ tor_asprintf(err_msg, "bad digest '%s'", inputs_tmp);
+ goto done;
+ }
+
+ inputs_tmp = smartlist_get(sl, 1);
+ /* Guardfraction is an integer in [0, 100]. */
+ guardfraction =
+ (uint32_t) tor_parse_long(inputs_tmp, 10, 0, 100, &num_ok, NULL);
+ if (!num_ok) {
+ tor_asprintf(err_msg, "wrong percentage '%s'", inputs_tmp);
+ goto done;
+ }
+
+ /* If routerstatuses were provided, apply this info to actual routers. */
+ if (vote_routerstatuses) {
+ retval = guardfraction_line_apply(guard_id, guardfraction,
+ vote_routerstatuses);
+ } else {
+ retval = 0; /* If we got this far, line was correctly formatted. */
+ }
+
+ done:
+
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+
+ return retval;
+}
+
+/** Given an inputs line from a guardfraction file, parse it and
+ * register its information to <b>total_consensuses</b> and
+ * <b>total_days</b>.
+ *
+ * Return 0 if it parsed well. Return -1 if there was an error, and
+ * set <b>err_msg</b> to a newly allocated string containing the
+ * error message.
+ */
+static int
+guardfraction_file_parse_inputs_line(const char *inputs_line,
+ int *total_consensuses,
+ int *total_days,
+ char **err_msg)
+{
+ int retval = -1;
+ char *inputs_tmp = NULL;
+ int num_ok = 1;
+ smartlist_t *sl = smartlist_new();
+
+ tor_assert(err_msg);
+
+ /* Second line is inputs information:
+ * n-inputs <total_consensuses> <total_days>. */
+ smartlist_split_string(sl, inputs_line, " ",
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 3);
+ if (smartlist_len(sl) < 2) {
+ tor_asprintf(err_msg, "incomplete line '%s'", inputs_line);
+ goto done;
+ }
+
+ inputs_tmp = smartlist_get(sl, 0);
+ *total_consensuses =
+ (int) tor_parse_long(inputs_tmp, 10, 0, INT_MAX, &num_ok, NULL);
+ if (!num_ok) {
+ tor_asprintf(err_msg, "unparseable consensus '%s'", inputs_tmp);
+ goto done;
+ }
+
+ inputs_tmp = smartlist_get(sl, 1);
+ *total_days =
+ (int) tor_parse_long(inputs_tmp, 10, 0, INT_MAX, &num_ok, NULL);
+ if (!num_ok) {
+ tor_asprintf(err_msg, "unparseable days '%s'", inputs_tmp);
+ goto done;
+ }
+
+ retval = 0;
+
+ done:
+ SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
+ smartlist_free(sl);
+
+ return retval;
+}
+
+/* Maximum age of a guardfraction file that we are willing to accept. */
+#define MAX_GUARDFRACTION_FILE_AGE (7*24*60*60) /* approx a week */
+
+/** Static strings of guardfraction files. */
+#define GUARDFRACTION_DATE_STR "written-at"
+#define GUARDFRACTION_INPUTS "n-inputs"
+#define GUARDFRACTION_GUARD "guard-seen"
+#define GUARDFRACTION_VERSION "guardfraction-file-version"
+
+/** Given a guardfraction file in a string, parse it and register the
+ * guardfraction information to the provided vote routerstatuses.
+ *
+ * This is the rough format of the guardfraction file:
+ *
+ * guardfraction-file-version 1
+ * written-at <date and time>
+ * n-inputs <number of consesuses parsed> <number of days considered>
+ *
+ * guard-seen <fpr 1> <guardfraction percentage> <consensus appearances>
+ * guard-seen <fpr 2> <guardfraction percentage> <consensus appearances>
+ * guard-seen <fpr 3> <guardfraction percentage> <consensus appearances>
+ * guard-seen <fpr 4> <guardfraction percentage> <consensus appearances>
+ * guard-seen <fpr 5> <guardfraction percentage> <consensus appearances>
+ * ...
+ *
+ * Return -1 if the parsing failed and 0 if it went smoothly. Parsing
+ * should tolerate errors in all lines but the written-at header.
+ */
+STATIC int
+dirserv_read_guardfraction_file_from_str(const char *guardfraction_file_str,
+ smartlist_t *vote_routerstatuses)
+{
+ config_line_t *front=NULL, *line;
+ int ret_tmp;
+ int retval = -1;
+ int current_line_n = 0; /* line counter for better log messages */
+
+ /* Guardfraction info to be parsed */
+ int total_consensuses = 0;
+ int total_days = 0;
+
+ /* Stats */
+ int guards_read_n = 0;
+ int guards_applied_n = 0;
+
+ /* Parse file and split it in lines */
+ ret_tmp = config_get_lines(guardfraction_file_str, &front, 0);
+ if (ret_tmp < 0) {
+ log_warn(LD_CONFIG, "Error reading from guardfraction file");
+ goto done;
+ }
+
+ /* Sort routerstatuses (needed later when applying guardfraction info) */
+ if (vote_routerstatuses)
+ smartlist_sort(vote_routerstatuses, compare_vote_routerstatus_entries);
+
+ for (line = front; line; line=line->next) {
+ current_line_n++;
+
+ if (!strcmp(line->key, GUARDFRACTION_VERSION)) {
+ int num_ok = 1;
+ unsigned int version;
+
+ version =
+ (unsigned int) tor_parse_long(line->value,
+ 10, 0, INT_MAX, &num_ok, NULL);
+
+ if (!num_ok || version != 1) {
+ log_warn(LD_GENERAL, "Got unknown guardfraction version %d.", version);
+ goto done;
+ }
+ } else if (!strcmp(line->key, GUARDFRACTION_DATE_STR)) {
+ time_t file_written_at;
+ time_t now = time(NULL);
+
+ /* First line is 'written-at <date>' */
+ if (parse_iso_time(line->value, &file_written_at) < 0) {
+ log_warn(LD_CONFIG, "Guardfraction:%d: Bad date '%s'. Ignoring",
+ current_line_n, line->value);
+ goto done; /* don't tolerate failure here. */
+ }
+ if (file_written_at < now - MAX_GUARDFRACTION_FILE_AGE) {
+ log_warn(LD_CONFIG, "Guardfraction:%d: was written very long ago '%s'",
+ current_line_n, line->value);
+ goto done; /* don't tolerate failure here. */
+ }
+ } else if (!strcmp(line->key, GUARDFRACTION_INPUTS)) {
+ char *err_msg = NULL;
+
+ if (guardfraction_file_parse_inputs_line(line->value,
+ &total_consensuses,
+ &total_days,
+ &err_msg) < 0) {
+ log_warn(LD_CONFIG, "Guardfraction:%d: %s",
+ current_line_n, err_msg);
+ tor_free(err_msg);
+ continue;
+ }
+
+ } else if (!strcmp(line->key, GUARDFRACTION_GUARD)) {
+ char *err_msg = NULL;
+
+ ret_tmp = guardfraction_file_parse_guard_line(line->value,
+ vote_routerstatuses,
+ &err_msg);
+ if (ret_tmp < 0) { /* failed while parsing the guard line */
+ log_warn(LD_CONFIG, "Guardfraction:%d: %s",
+ current_line_n, err_msg);
+ tor_free(err_msg);
+ continue;
+ }
+
+ /* Successfully parsed guard line. Check if it was applied properly. */
+ guards_read_n++;
+ if (ret_tmp > 0) {
+ guards_applied_n++;
+ }
+ } else {
+ log_warn(LD_CONFIG, "Unknown guardfraction line %d (%s %s)",
+ current_line_n, line->key, line->value);
+ }
+ }
+
+ retval = 0;
+
+ log_info(LD_CONFIG,
+ "Successfully parsed guardfraction file with %d consensuses over "
+ "%d days. Parsed %d nodes and applied %d of them%s.",
+ total_consensuses, total_days, guards_read_n, guards_applied_n,
+ vote_routerstatuses ? "" : " (no routerstatus provided)" );
+
+ done:
+ config_free_lines(front);
+
+ if (retval < 0) {
+ return retval;
+ } else {
+ return guards_read_n;
+ }
+}
+
+/** Read a guardfraction file at <b>fname</b> and load all its
+ * information to <b>vote_routerstatuses</b>. */
+int
+dirserv_read_guardfraction_file(const char *fname,
+ smartlist_t *vote_routerstatuses)
+{
+ char *guardfraction_file_str;
+
+ /* Read file to a string */
+ guardfraction_file_str = read_file_to_str(fname, RFTS_IGNORE_MISSING, NULL);
+ if (!guardfraction_file_str) {
+ log_warn(LD_FS, "Cannot open guardfraction file '%s'. Failing.", fname);
+ return -1;
+ }
+
+ return dirserv_read_guardfraction_file_from_str(guardfraction_file_str,
+ vote_routerstatuses);
+}
+
/**
* Helper function to parse out a line in the measured bandwidth file
* into a measured_bw_line_t output structure. Returns -1 on failure
@@ -2563,9 +2658,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
smartlist_t *routers, *routerstatuses;
char identity_digest[DIGEST_LEN];
char signing_key_digest[DIGEST_LEN];
- int naming = options->NamingAuthoritativeDir;
int listbadexits = options->AuthDirListBadExits;
- int listbaddirs = options->AuthDirListBadDirs;
int vote_on_hsdirs = options->VoteOnHidServDirectoriesV2;
routerlist_t *rl = router_get_routerlist();
time_t now = time(NULL);
@@ -2657,7 +2750,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
rs = &vrs->status;
set_routerstatus_from_routerinfo(rs, node, ri, now,
- naming, listbadexits, listbaddirs,
+ listbadexits,
vote_on_hsdirs);
if (digestmap_get(omit_as_sybil, ri->cache_info.identity_digest))
@@ -2685,6 +2778,12 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
smartlist_free(routers);
digestmap_free(omit_as_sybil, NULL);
+ /* Apply guardfraction information to routerstatuses. */
+ if (options->GuardfractionFile) {
+ dirserv_read_guardfraction_file(options->GuardfractionFile,
+ routerstatuses);
+ }
+
/* This pass through applies the measured bw lines to the routerstatuses */
if (options->V3BandwidthsFile) {
dirserv_read_measured_bandwidths(options->V3BandwidthsFile,
@@ -2733,20 +2832,23 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
v3_out->client_versions = client_versions;
v3_out->server_versions = server_versions;
+ v3_out->package_lines = smartlist_new();
+ {
+ config_line_t *cl;
+ for (cl = get_options()->RecommendedPackages; cl; cl = cl->next) {
+ if (validate_recommended_package_line(cl->value))
+ smartlist_add(v3_out->package_lines, tor_strdup(cl->value));
+ }
+ }
+
v3_out->known_flags = smartlist_new();
smartlist_split_string(v3_out->known_flags,
"Authority Exit Fast Guard Stable V2Dir Valid",
0, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (vote_on_reachability)
smartlist_add(v3_out->known_flags, tor_strdup("Running"));
- if (listbaddirs)
- smartlist_add(v3_out->known_flags, tor_strdup("BadDirectory"));
if (listbadexits)
smartlist_add(v3_out->known_flags, tor_strdup("BadExit"));
- if (naming) {
- smartlist_add(v3_out->known_flags, tor_strdup("Named"));
- smartlist_add(v3_out->known_flags, tor_strdup("Unnamed"));
- }
if (vote_on_hsdirs)
smartlist_add(v3_out->known_flags, tor_strdup("HSDir"));
smartlist_sort_strings(v3_out->known_flags);
@@ -3431,7 +3533,7 @@ connection_dirserv_add_networkstatus_bytes_to_outbuf(dir_connection_t *conn)
if (uncompressing && ! conn->zlib_state &&
conn->fingerprint_stack &&
smartlist_len(conn->fingerprint_stack)) {
- conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD);
+ conn->zlib_state = tor_zlib_new(0, ZLIB_METHOD, HIGH_COMPRESSION);
}
}
if (r) return r;
@@ -3484,6 +3586,80 @@ connection_dirserv_flushed_some(dir_connection_t *conn)
}
}
+/** Return true iff <b>line</b> is a valid RecommendedPackages line.
+ */
+/*
+ The grammar is:
+
+ "package" SP PACKAGENAME SP VERSION SP URL SP DIGESTS NL
+
+ PACKAGENAME = NONSPACE
+ VERSION = NONSPACE
+ URL = NONSPACE
+ DIGESTS = DIGEST | DIGESTS SP DIGEST
+ DIGEST = DIGESTTYPE "=" DIGESTVAL
+
+ NONSPACE = one or more non-space printing characters
+
+ DIGESTVAL = DIGESTTYPE = one or more non-=, non-" " characters.
+
+ SP = " "
+ NL = a newline
+
+ */
+int
+validate_recommended_package_line(const char *line)
+{
+ const char *cp = line;
+
+#define WORD() \
+ do { \
+ if (*cp == ' ') \
+ return 0; \
+ cp = strchr(cp, ' '); \
+ if (!cp) \
+ return 0; \
+ } while (0)
+
+ WORD(); /* skip packagename */
+ ++cp;
+ WORD(); /* skip version */
+ ++cp;
+ WORD(); /* Skip URL */
+ ++cp;
+
+ /* Skip digesttype=digestval + */
+ int n_entries = 0;
+ while (1) {
+ const char *start_of_word = cp;
+ const char *end_of_word = strchr(cp, ' ');
+ if (! end_of_word)
+ end_of_word = cp + strlen(cp);
+
+ if (start_of_word == end_of_word)
+ return 0;
+
+ const char *eq = memchr(start_of_word, '=', end_of_word - start_of_word);
+
+ if (!eq)
+ return 0;
+ if (eq == start_of_word)
+ return 0;
+ if (eq == end_of_word - 1)
+ return 0;
+ if (memchr(eq+1, '=', end_of_word - (eq+1)))
+ return 0;
+
+ ++n_entries;
+ if (0 == *end_of_word)
+ break;
+
+ cp = end_of_word + 1;
+ }
+
+ return (n_entries == 0) ? 0 : 1;
+}
+
/** Release all storage used by the directory server. */
void
dirserv_free_all(void)
diff --git a/src/or/dirserv.h b/src/or/dirserv.h
index 858e6e3a07..311a513dbe 100644
--- a/src/or/dirserv.h
+++ b/src/or/dirserv.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -34,10 +34,9 @@
int connection_dirserv_flushed_some(dir_connection_t *conn);
-int dirserv_add_own_fingerprint(const char *nickname, crypto_pk_t *pk);
+int dirserv_add_own_fingerprint(crypto_pk_t *pk);
int dirserv_load_fingerprint_file(void);
void dirserv_free_fingerprint_list(void);
-const char *dirserv_get_nickname_by_digest(const char *digest);
enum was_router_added_t dirserv_add_multiple_descriptors(
const char *desc, uint8_t purpose,
const char *source,
@@ -105,6 +104,8 @@ void dirserv_free_all(void);
void cached_dir_decref(cached_dir_t *d);
cached_dir_t *new_cached_dir(char *s, time_t published);
+int validate_recommended_package_line(const char *line);
+
#ifdef DIRSERV_PRIVATE
/* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */
@@ -124,10 +125,17 @@ STATIC int dirserv_query_measured_bw_cache_kb(const char *node_id,
long *bw_out,
time_t *as_of_out);
STATIC int dirserv_has_measured_bw(const char *node_id);
+
+STATIC int
+dirserv_read_guardfraction_file_from_str(const char *guardfraction_file_str,
+ smartlist_t *vote_routerstatuses);
#endif
int dirserv_read_measured_bandwidths(const char *from_file,
smartlist_t *routerstatuses);
+int dirserv_read_guardfraction_file(const char *fname,
+ smartlist_t *vote_routerstatuses);
+
#endif
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 137d6c1a8c..7a5154dae5 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define DIRVOTE_PRIVATE
@@ -16,6 +16,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "entrynodes.h" /* needed for guardfraction methods */
/**
* \file dirvote.c
@@ -64,8 +65,9 @@ STATIC char *
format_networkstatus_vote(crypto_pk_t *private_signing_key,
networkstatus_t *v3_ns)
{
- smartlist_t *chunks;
+ smartlist_t *chunks = smartlist_new();
const char *client_versions = NULL, *server_versions = NULL;
+ char *packages = NULL;
char fingerprint[FINGERPRINT_LEN+1];
char digest[DIGEST_LEN];
uint32_t addr;
@@ -98,7 +100,18 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
server_versions_line = tor_strdup("");
}
- chunks = smartlist_new();
+ if (v3_ns->package_lines) {
+ smartlist_t *tmp = smartlist_new();
+ SMARTLIST_FOREACH(v3_ns->package_lines, const char *, p,
+ if (validate_recommended_package_line(p))
+ smartlist_add_asprintf(tmp, "package %s\n", p));
+ packages = smartlist_join_strings(tmp, "", 0, NULL);
+ SMARTLIST_FOREACH(tmp, char *, cp, tor_free(cp));
+ smartlist_free(tmp);
+ } else {
+ packages = tor_strdup("");
+ }
+
{
char published[ISO_TIME_LEN+1];
char va[ISO_TIME_LEN+1];
@@ -110,7 +123,8 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
char *params;
authority_cert_t *cert = v3_ns->cert;
char *methods =
- make_consensus_method_list(1, MAX_SUPPORTED_CONSENSUS_METHOD, " ");
+ make_consensus_method_list(MIN_SUPPORTED_CONSENSUS_METHOD,
+ MAX_SUPPORTED_CONSENSUS_METHOD, " ");
format_iso_time(published, v3_ns->published);
format_iso_time(va, v3_ns->valid_after);
format_iso_time(fu, v3_ns->fresh_until);
@@ -132,6 +146,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
"valid-until %s\n"
"voting-delay %d %d\n"
"%s%s" /* versions */
+ "%s" /* packages */
"known-flags %s\n"
"flag-thresholds %s\n"
"params %s\n"
@@ -143,6 +158,7 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
v3_ns->vote_seconds, v3_ns->dist_seconds,
client_versions_line,
server_versions_line,
+ packages,
flags,
flag_thresholds,
params,
@@ -230,10 +246,10 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
done:
tor_free(client_versions_line);
tor_free(server_versions_line);
- if (chunks) {
- SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
- smartlist_free(chunks);
- }
+ tor_free(packages);
+
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
return status;
}
@@ -458,8 +474,7 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
smartlist_free(alt_orports);
}
- if (consensus_method >= MIN_METHOD_FOR_MICRODESC &&
- microdesc_digest256_out) {
+ if (microdesc_digest256_out) {
smartlist_t *digests = smartlist_new();
const char *best_microdesc_digest;
SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
@@ -541,7 +556,8 @@ compute_consensus_method(smartlist_t *votes)
static int
consensus_method_is_supported(int method)
{
- return (method >= 1) && (method <= MAX_SUPPORTED_CONSENSUS_METHOD);
+ return (method >= MIN_SUPPORTED_CONSENSUS_METHOD) &&
+ (method <= MAX_SUPPORTED_CONSENSUS_METHOD);
}
/** Return a newly allocated string holding the numbers between low and high
@@ -605,13 +621,14 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
const int n_votes = smartlist_len(votes);
smartlist_t *output;
smartlist_t *param_list = smartlist_new();
+ (void) method;
/* We require that the parameter lists in the votes are well-formed: that
is, that their keywords are unique and sorted, and that their values are
between INT32_MIN and INT32_MAX inclusive. This should be guaranteed by
the parsing code. */
- vals = tor_malloc(sizeof(int)*n_votes);
+ vals = tor_calloc(n_votes, sizeof(int));
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
if (!v->net_params)
@@ -647,12 +664,13 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
next_param = NULL;
else
next_param = smartlist_get(param_list, param_sl_idx+1);
+ /* resolve spurious clang shallow analysis null pointer errors */
+ tor_assert(param);
if (!next_param || strncmp(next_param, param, cur_param_len)) {
/* We've reached the end of a series. */
/* Make sure enough authorities voted on this param, unless the
* the consensus method we use is too old for that. */
- if (method < MIN_METHOD_FOR_MAJORITY_PARAMS ||
- i > total_authorities/2 ||
+ if (i > total_authorities/2 ||
i >= MIN_VOTES_FOR_PARAM) {
int32_t median = median_int32(vals, i);
char *out_string = tor_malloc(64+cur_param_len);
@@ -1005,299 +1023,87 @@ networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G,
I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
return 1;
}
-/**
- * This function computes the bandwidth weights for consensus method 9.
- *
- * It has been obsoleted in favor of consensus method 10.
- */
+
+/** Update total bandwidth weights (G/M/E/D/T) with the bandwidth of
+ * the router in <b>rs</b>. */
static void
-networkstatus_compute_bw_weights_v9(smartlist_t *chunks, int64_t G, int64_t M,
- int64_t E, int64_t D, int64_t T,
- int64_t weight_scale)
+update_total_bandwidth_weights(const routerstatus_t *rs,
+ int is_exit, int is_guard,
+ int64_t *G, int64_t *M, int64_t *E, int64_t *D,
+ int64_t *T)
{
- int64_t Wgg = -1, Wgd = -1;
- int64_t Wmg = -1, Wme = -1, Wmd = -1;
- int64_t Wed = -1, Wee = -1;
- const char *casename;
+ int default_bandwidth = rs->bandwidth_kb;
+ int guardfraction_bandwidth = 0;
- if (G <= 0 || M <= 0 || E <= 0 || D <= 0) {
- log_warn(LD_DIR, "Consensus with empty bandwidth: "
- "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
- " D="I64_FORMAT" T="I64_FORMAT,
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+ if (!rs->has_bandwidth) {
+ log_info(LD_BUG, "Missing consensus bandwidth for router %s",
+ rs->nickname);
return;
}
- /*
- * Computed from cases in 3.4.3 of dir-spec.txt
+ /* If this routerstatus represents a guard that we have
+ * guardfraction information on, use it to calculate its actual
+ * bandwidth. From proposal236:
*
- * 1. Neither are scarce
- * 2. Both Guard and Exit are scarce
- * a. R+D <= S
- * b. R+D > S
- * 3. One of Guard or Exit is scarce
- * a. S+D < T/3
- * b. S+D >= T/3
+ * Similarly, when calculating the bandwidth-weights line as in
+ * section 3.8.3 of dir-spec.txt, directory authorities should treat N
+ * as if fraction F of its bandwidth has the guard flag and (1-F) does
+ * not. So when computing the totals G,M,E,D, each relay N with guard
+ * visibility fraction F and bandwidth B should be added as follows:
+ *
+ * G' = G + F*B, if N does not have the exit flag
+ * M' = M + (1-F)*B, if N does not have the exit flag
+ *
+ * or
+ *
+ * D' = D + F*B, if N has the exit flag
+ * E' = E + (1-F)*B, if N has the exit flag
+ *
+ * In this block of code, we prepare the bandwidth values by setting
+ * the default_bandwidth to F*B and guardfraction_bandwidth to (1-F)*B.
*/
- if (3*E >= T && 3*G >= T) { // E >= T/3 && G >= T/3
- bw_weights_error_t berr = 0;
- /* Case 1: Neither are scarce.
- *
- * Attempt to ensure that we have a large amount of exit bandwidth
- * in the middle position.
- */
- casename = "Case 1 (Wme*E = Wmd*D)";
- Wgg = (weight_scale*(D+E+G+M))/(3*G);
- if (D==0) Wmd = 0;
- else Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D);
- Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E);
- Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E);
- Wgd = 0;
- Wmg = weight_scale - Wgg;
- Wed = weight_scale - Wmd;
+ if (rs->has_guardfraction) {
+ guardfraction_bandwidth_t guardfraction_bw;
- berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed,
- weight_scale, G, M, E, D, T, 10, 1);
+ tor_assert(is_guard);
- if (berr) {
- log_warn(LD_DIR, "Bw Weights error %d for case %s. "
- "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
- " D="I64_FORMAT" T="I64_FORMAT,
- berr, casename,
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
- }
- } else if (3*E < T && 3*G < T) { // E < T/3 && G < T/3
- int64_t R = MIN(E, G);
- int64_t S = MAX(E, G);
- /*
- * Case 2: Both Guards and Exits are scarce
- * Balance D between E and G, depending upon
- * D capacity and scarcity.
- */
- if (R+D < S) { // Subcase a
- Wgg = weight_scale;
- Wee = weight_scale;
- Wmg = 0;
- Wme = 0;
- Wmd = 0;
- if (E < G) {
- casename = "Case 2a (E scarce)";
- Wed = weight_scale;
- Wgd = 0;
- } else { /* E >= G */
- casename = "Case 2a (G scarce)";
- Wed = 0;
- Wgd = weight_scale;
- }
- } else { // Subcase b: R+D > S
- bw_weights_error_t berr = 0;
- casename = "Case 2b (Wme*E == Wmd*D)";
- if (D != 0) {
- Wgg = weight_scale;
- Wgd = (weight_scale*(D + E - 2*G + M))/(3*D); // T/3 >= G (Ok)
- Wmd = (weight_scale*(D + E + G - 2*M))/(6*D); // T/3 >= M
- Wme = (weight_scale*(D + E + G - 2*M))/(6*E);
- Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E); // 2E+M >= T/3
- Wmg = 0;
- Wed = weight_scale - Wgd - Wmd;
+ guard_get_guardfraction_bandwidth(&guardfraction_bw,
+ rs->bandwidth_kb,
+ rs->guardfraction_percentage);
- berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed,
- weight_scale, G, M, E, D, T, 10, 1);
- }
+ default_bandwidth = guardfraction_bw.guard_bw;
+ guardfraction_bandwidth = guardfraction_bw.non_guard_bw;
+ }
- if (D == 0 || berr) { // Can happen if M > T/3
- casename = "Case 2b (E=G)";
- Wgg = weight_scale;
- Wee = weight_scale;
- Wmg = 0;
- Wme = 0;
- Wmd = 0;
- if (D == 0) Wgd = 0;
- else Wgd = (weight_scale*(D+E-G))/(2*D);
- Wed = weight_scale - Wgd;
- berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
- Wed, weight_scale, G, M, E, D, T, 10, 1);
- }
- if (berr != BW_WEIGHTS_NO_ERROR &&
- berr != BW_WEIGHTS_BALANCE_MID_ERROR) {
- log_warn(LD_DIR, "Bw Weights error %d for case %s. "
- "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT
- " D="I64_FORMAT" T="I64_FORMAT,
- berr, casename,
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
- }
- }
- } else { // if (E < T/3 || G < T/3) {
- int64_t S = MIN(E, G);
- // Case 3: Exactly one of Guard or Exit is scarce
- if (!(3*E < T || 3*G < T) || !(3*G >= T || 3*E >= T)) {
- log_warn(LD_BUG,
- "Bw-Weights Case 3 but with G="I64_FORMAT" M="
- I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT,
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+ /* Now calculate the total bandwidth weights with or without
+ * guardfraction. Depending on the flags of the relay, add its
+ * bandwidth to the appropriate weight pool. If it's a guard and
+ * guardfraction is enabled, add its bandwidth to both pools as
+ * indicated by the previous comment.
+ */
+ *T += default_bandwidth;
+ if (is_exit && is_guard) {
+
+ *D += default_bandwidth;
+ if (rs->has_guardfraction) {
+ *E += guardfraction_bandwidth;
}
- if (3*(S+D) < T) { // Subcase a: S+D < T/3
- if (G < E) {
- casename = "Case 3a (G scarce)";
- Wgg = Wgd = weight_scale;
- Wmd = Wed = Wmg = 0;
- // Minor subcase, if E is more scarce than M,
- // keep its bandwidth in place.
- if (E < M) Wme = 0;
- else Wme = (weight_scale*(E-M))/(2*E);
- Wee = weight_scale-Wme;
- } else { // G >= E
- casename = "Case 3a (E scarce)";
- Wee = Wed = weight_scale;
- Wmd = Wgd = Wme = 0;
- // Minor subcase, if G is more scarce than M,
- // keep its bandwidth in place.
- if (G < M) Wmg = 0;
- else Wmg = (weight_scale*(G-M))/(2*G);
- Wgg = weight_scale-Wmg;
- }
- } else { // Subcase b: S+D >= T/3
- bw_weights_error_t berr = 0;
- // D != 0 because S+D >= T/3
- if (G < E) {
- casename = "Case 3b (G scarce, Wme*E == Wmd*D)";
- Wgd = (weight_scale*(D + E - 2*G + M))/(3*D);
- Wmd = (weight_scale*(D + E + G - 2*M))/(6*D);
- Wme = (weight_scale*(D + E + G - 2*M))/(6*E);
- Wee = (weight_scale*(-D + 5*E - G + 2*M))/(6*E);
- Wgg = weight_scale;
- Wmg = 0;
- Wed = weight_scale - Wgd - Wmd;
+ } else if (is_exit) {
- berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
- Wed, weight_scale, G, M, E, D, T, 10, 1);
- } else { // G >= E
- casename = "Case 3b (E scarce, Wme*E == Wmd*D)";
- Wgg = (weight_scale*(D + E + G + M))/(3*G);
- Wmd = (weight_scale*(2*D + 2*E - G - M))/(6*D);
- Wme = (weight_scale*(2*D + 2*E - G - M))/(6*E);
- Wee = (weight_scale*(-2*D + 4*E + G + M))/(6*E);
- Wgd = 0;
- Wmg = weight_scale - Wgg;
- Wed = weight_scale - Wmd;
+ *E += default_bandwidth;
- berr = networkstatus_check_weights(Wgg, Wgd, Wmg, Wme, Wmd, Wee,
- Wed, weight_scale, G, M, E, D, T, 10, 1);
- }
- if (berr) {
- log_warn(LD_DIR, "Bw Weights error %d for case %s. "
- "G="I64_FORMAT" M="I64_FORMAT
- " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT,
- berr, casename,
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
- }
- }
- }
+ } else if (is_guard) {
- /* We cast down the weights to 32 bit ints on the assumption that
- * weight_scale is ~= 10000. We need to ensure a rogue authority
- * doesn't break this assumption to rig our weights */
- tor_assert(0 < weight_scale && weight_scale <= INT32_MAX);
+ *G += default_bandwidth;
+ if (rs->has_guardfraction) {
+ *M += guardfraction_bandwidth;
+ }
- if (Wgg < 0 || Wgg > weight_scale) {
- log_warn(LD_DIR, "Bw %s: Wgg="I64_FORMAT"! G="I64_FORMAT
- " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
- " T="I64_FORMAT,
- casename, I64_PRINTF_ARG(Wgg),
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
+ } else {
- Wgg = MAX(MIN(Wgg, weight_scale), 0);
- }
- if (Wgd < 0 || Wgd > weight_scale) {
- log_warn(LD_DIR, "Bw %s: Wgd="I64_FORMAT"! G="I64_FORMAT
- " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
- " T="I64_FORMAT,
- casename, I64_PRINTF_ARG(Wgd),
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
- Wgd = MAX(MIN(Wgd, weight_scale), 0);
- }
- if (Wmg < 0 || Wmg > weight_scale) {
- log_warn(LD_DIR, "Bw %s: Wmg="I64_FORMAT"! G="I64_FORMAT
- " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
- " T="I64_FORMAT,
- casename, I64_PRINTF_ARG(Wmg),
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
- Wmg = MAX(MIN(Wmg, weight_scale), 0);
- }
- if (Wme < 0 || Wme > weight_scale) {
- log_warn(LD_DIR, "Bw %s: Wme="I64_FORMAT"! G="I64_FORMAT
- " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
- " T="I64_FORMAT,
- casename, I64_PRINTF_ARG(Wme),
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
- Wme = MAX(MIN(Wme, weight_scale), 0);
+ *M += default_bandwidth;
}
- if (Wmd < 0 || Wmd > weight_scale) {
- log_warn(LD_DIR, "Bw %s: Wmd="I64_FORMAT"! G="I64_FORMAT
- " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
- " T="I64_FORMAT,
- casename, I64_PRINTF_ARG(Wmd),
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
- Wmd = MAX(MIN(Wmd, weight_scale), 0);
- }
- if (Wee < 0 || Wee > weight_scale) {
- log_warn(LD_DIR, "Bw %s: Wee="I64_FORMAT"! G="I64_FORMAT
- " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
- " T="I64_FORMAT,
- casename, I64_PRINTF_ARG(Wee),
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
- Wee = MAX(MIN(Wee, weight_scale), 0);
- }
- if (Wed < 0 || Wed > weight_scale) {
- log_warn(LD_DIR, "Bw %s: Wed="I64_FORMAT"! G="I64_FORMAT
- " M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
- " T="I64_FORMAT,
- casename, I64_PRINTF_ARG(Wed),
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
- Wed = MAX(MIN(Wed, weight_scale), 0);
- }
-
- // Add consensus weight keywords
- smartlist_add(chunks, tor_strdup("bandwidth-weights "));
- /*
- * Provide Wgm=Wgg, Wmm=1, Wem=Wee, Weg=Wed. May later determine
- * that middle nodes need different bandwidth weights for dirport traffic,
- * or that weird exit policies need special weight, or that bridges
- * need special weight.
- *
- * NOTE: This list is sorted.
- */
- smartlist_add_asprintf(chunks,
- "Wbd=%d Wbe=%d Wbg=%d Wbm=%d "
- "Wdb=%d "
- "Web=%d Wed=%d Wee=%d Weg=%d Wem=%d "
- "Wgb=%d Wgd=%d Wgg=%d Wgm=%d "
- "Wmb=%d Wmd=%d Wme=%d Wmg=%d Wmm=%d\n",
- (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale,
- (int)weight_scale,
- (int)weight_scale, (int)Wed, (int)Wee, (int)Wed, (int)Wee,
- (int)weight_scale, (int)Wgd, (int)Wgg, (int)Wgg,
- (int)weight_scale, (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale);
-
- log_notice(LD_CIRC, "Computed bandwidth weights for %s with v9: "
- "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT
- " T="I64_FORMAT,
- casename,
- I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E),
- I64_PRINTF_ARG(D), I64_PRINTF_ARG(T));
}
/** Given a list of vote networkstatus_t in <b>votes</b>, our public
@@ -1330,6 +1136,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
const routerstatus_format_type_t rs_format =
flavor == FLAV_NS ? NS_V3_CONSENSUS : NS_V3_CONSENSUS_MICRODESC;
char *params = NULL;
+ char *packages = NULL;
int added_weights = 0;
tor_assert(flavor == FLAV_NS || flavor == FLAV_MICRODESC);
tor_assert(total_authorities >= smartlist_len(votes));
@@ -1350,18 +1157,18 @@ networkstatus_compute_consensus(smartlist_t *votes,
log_warn(LD_DIR, "The other authorities will use consensus method %d, "
"which I don't support. Maybe I should upgrade!",
consensus_method);
- consensus_method = 1;
+ consensus_method = MAX_SUPPORTED_CONSENSUS_METHOD;
}
/* Compute medians of time-related things, and figure out how many
* routers we might need to talk about. */
{
int n_votes = smartlist_len(votes);
- time_t *va_times = tor_malloc(n_votes * sizeof(time_t));
- time_t *fu_times = tor_malloc(n_votes * sizeof(time_t));
- time_t *vu_times = tor_malloc(n_votes * sizeof(time_t));
- int *votesec_list = tor_malloc(n_votes * sizeof(int));
- int *distsec_list = tor_malloc(n_votes * sizeof(int));
+ time_t *va_times = tor_calloc(n_votes, sizeof(time_t));
+ time_t *fu_times = tor_calloc(n_votes, sizeof(time_t));
+ time_t *vu_times = tor_calloc(n_votes, sizeof(time_t));
+ int *votesec_list = tor_calloc(n_votes, sizeof(int));
+ int *distsec_list = tor_calloc(n_votes, sizeof(int));
int n_versioning_clients = 0, n_versioning_servers = 0;
smartlist_t *combined_client_versions = smartlist_new();
smartlist_t *combined_server_versions = smartlist_new();
@@ -1400,8 +1207,12 @@ networkstatus_compute_consensus(smartlist_t *votes,
vote_seconds = median_int(votesec_list, n_votes);
dist_seconds = median_int(distsec_list, n_votes);
- tor_assert(valid_after+MIN_VOTE_INTERVAL <= fresh_until);
- tor_assert(fresh_until+MIN_VOTE_INTERVAL <= valid_until);
+ tor_assert(valid_after +
+ (get_options()->TestingTorNetwork ?
+ MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL) <= fresh_until);
+ tor_assert(fresh_until +
+ (get_options()->TestingTorNetwork ?
+ MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL) <= valid_until);
tor_assert(vote_seconds >= MIN_VOTE_SECONDS);
tor_assert(dist_seconds >= MIN_DIST_SECONDS);
@@ -1409,6 +1220,11 @@ networkstatus_compute_consensus(smartlist_t *votes,
n_versioning_servers);
client_versions = compute_consensus_versions_list(combined_client_versions,
n_versioning_clients);
+ if (consensus_method >= MIN_METHOD_FOR_PACKAGE_LINES) {
+ packages = compute_consensus_package_lines(votes);
+ } else {
+ packages = tor_strdup("");
+ }
SMARTLIST_FOREACH(combined_server_versions, char *, cp, tor_free(cp));
SMARTLIST_FOREACH(combined_client_versions, char *, cp, tor_free(cp));
@@ -1441,10 +1257,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
flavor == FLAV_NS ? "" : " ",
flavor == FLAV_NS ? "" : flavor_name);
- if (consensus_method >= 2) {
- smartlist_add_asprintf(chunks, "consensus-method %d\n",
- consensus_method);
- }
+ smartlist_add_asprintf(chunks, "consensus-method %d\n",
+ consensus_method);
smartlist_add_asprintf(chunks,
"valid-after %s\n"
@@ -1453,22 +1267,23 @@ networkstatus_compute_consensus(smartlist_t *votes,
"voting-delay %d %d\n"
"client-versions %s\n"
"server-versions %s\n"
+ "%s" /* packages */
"known-flags %s\n",
va_buf, fu_buf, vu_buf,
vote_seconds, dist_seconds,
- client_versions, server_versions, flaglist);
+ client_versions, server_versions,
+ packages,
+ flaglist);
tor_free(flaglist);
}
- if (consensus_method >= MIN_METHOD_FOR_PARAMS) {
- params = dirvote_compute_params(votes, consensus_method,
- total_authorities);
- if (params) {
- smartlist_add(chunks, tor_strdup("params "));
- smartlist_add(chunks, params);
- smartlist_add(chunks, tor_strdup("\n"));
- }
+ params = dirvote_compute_params(votes, consensus_method,
+ total_authorities);
+ if (params) {
+ smartlist_add(chunks, tor_strdup("params "));
+ smartlist_add(chunks, params);
+ smartlist_add(chunks, tor_strdup("\n"));
}
/* Sort the votes. */
@@ -1482,8 +1297,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
e->digest = get_voter(v)->identity_digest;
e->is_legacy = 0;
smartlist_add(dir_sources, e);
- if (consensus_method >= 3 &&
- !tor_digest_is_zero(get_voter(v)->legacy_id_digest)) {
+ if (!tor_digest_is_zero(get_voter(v)->legacy_id_digest)) {
dir_src_ent_t *e_legacy = tor_malloc_zero(sizeof(dir_src_ent_t));
e_legacy->v = v;
e_legacy->digest = get_voter(v)->legacy_id_digest;
@@ -1499,9 +1313,6 @@ networkstatus_compute_consensus(smartlist_t *votes,
networkstatus_t *v = e->v;
networkstatus_voter_info_t *voter = get_voter(v);
- if (e->is_legacy)
- tor_assert(consensus_method >= 2);
-
base16_encode(fingerprint, sizeof(fingerprint), e->digest, DIGEST_LEN);
base16_encode(votedigest, sizeof(votedigest), voter->vote_digest,
DIGEST_LEN);
@@ -1559,12 +1370,15 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_t *chosen_flags = smartlist_new();
smartlist_t *versions = smartlist_new();
smartlist_t *exitsummaries = smartlist_new();
- uint32_t *bandwidths_kb = tor_malloc(sizeof(uint32_t) *
- smartlist_len(votes));
- uint32_t *measured_bws_kb = tor_malloc(sizeof(uint32_t) *
- smartlist_len(votes));
+ uint32_t *bandwidths_kb = tor_calloc(smartlist_len(votes),
+ sizeof(uint32_t));
+ uint32_t *measured_bws_kb = tor_calloc(smartlist_len(votes),
+ sizeof(uint32_t));
+ uint32_t *measured_guardfraction = tor_calloc(smartlist_len(votes),
+ sizeof(uint32_t));
int num_bandwidths;
int num_mbws;
+ int num_guardfraction_inputs;
int *n_voter_flags; /* n_voter_flags[j] is the number of flags that
* votes[j] knows about. */
@@ -1574,7 +1388,6 @@ networkstatus_compute_consensus(smartlist_t *votes,
* is the same flag as votes[j]->known_flags[b]. */
int *named_flag; /* Index of the flag "Named" for votes[j] */
int *unnamed_flag; /* Index of the flag "Unnamed" for votes[j] */
- int chosen_named_idx;
int n_authorities_measuring_bandwidth;
strmap_t *name_to_id_map = strmap_new();
@@ -1583,16 +1396,15 @@ networkstatus_compute_consensus(smartlist_t *votes,
memset(conflict, 0, sizeof(conflict));
memset(unknown, 0xff, sizeof(conflict));
- index = tor_malloc_zero(sizeof(int)*smartlist_len(votes));
- size = tor_malloc_zero(sizeof(int)*smartlist_len(votes));
- n_voter_flags = tor_malloc_zero(sizeof(int) * smartlist_len(votes));
- n_flag_voters = tor_malloc_zero(sizeof(int) * smartlist_len(flags));
- flag_map = tor_malloc_zero(sizeof(int*) * smartlist_len(votes));
- named_flag = tor_malloc_zero(sizeof(int) * smartlist_len(votes));
- unnamed_flag = tor_malloc_zero(sizeof(int) * smartlist_len(votes));
+ index = tor_calloc(smartlist_len(votes), sizeof(int));
+ size = tor_calloc(smartlist_len(votes), sizeof(int));
+ n_voter_flags = tor_calloc(smartlist_len(votes), sizeof(int));
+ n_flag_voters = tor_calloc(smartlist_len(flags), sizeof(int));
+ flag_map = tor_calloc(smartlist_len(votes), sizeof(int *));
+ named_flag = tor_calloc(smartlist_len(votes), sizeof(int));
+ unnamed_flag = tor_calloc(smartlist_len(votes), sizeof(int));
for (i = 0; i < smartlist_len(votes); ++i)
unnamed_flag[i] = named_flag[i] = -1;
- chosen_named_idx = smartlist_string_pos(flags, "Named");
/* Build the flag indexes. Note that no vote can have more than 64 members
* for known_flags, so no value will be greater than 63, so it's safe to
@@ -1601,8 +1413,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
* that they're actually set before doing U64_LITERAL(1) << index with
* them.*/
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
- flag_map[v_sl_idx] = tor_malloc_zero(
- sizeof(int)*smartlist_len(v->known_flags));
+ flag_map[v_sl_idx] = tor_calloc(smartlist_len(v->known_flags),
+ sizeof(int));
if (smartlist_len(v->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) {
log_warn(LD_BUG, "Somehow, a vote has %d entries in known_flags",
smartlist_len(v->known_flags));
@@ -1622,7 +1434,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
} SMARTLIST_FOREACH_END(v);
/* Named and Unnamed get treated specially */
- if (consensus_method >= 2) {
+ {
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
uint64_t nf;
if (named_flag[v_sl_idx]<0)
@@ -1675,14 +1487,14 @@ networkstatus_compute_consensus(smartlist_t *votes,
/* We need to know how many votes measure bandwidth. */
n_authorities_measuring_bandwidth = 0;
- SMARTLIST_FOREACH(votes, networkstatus_t *, v,
+ SMARTLIST_FOREACH(votes, const networkstatus_t *, v,
if (v->has_measured_bws) {
++n_authorities_measuring_bandwidth;
}
);
/* Now go through all the votes */
- flag_counts = tor_malloc(sizeof(int) * smartlist_len(flags));
+ flag_counts = tor_calloc(smartlist_len(flags), sizeof(int));
while (1) {
vote_routerstatus_t *rs;
routerstatus_t rs_out;
@@ -1717,6 +1529,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_clear(versions);
num_bandwidths = 0;
num_mbws = 0;
+ num_guardfraction_inputs = 0;
/* Okay, go through all the entries for this digest. */
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
@@ -1750,6 +1563,12 @@ networkstatus_compute_consensus(smartlist_t *votes,
chosen_name = rs->status.nickname;
}
+ /* Count guardfraction votes and note down the values. */
+ if (rs->status.has_guardfraction) {
+ measured_guardfraction[num_guardfraction_inputs++] =
+ rs->status.guardfraction_percentage;
+ }
+
/* count bandwidths */
if (rs->has_measured_bw)
measured_bws_kb[num_mbws++] = rs->measured_bw_kb;
@@ -1791,10 +1610,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
strlcpy(rs_out.nickname, rs->status.nickname, sizeof(rs_out.nickname));
}
- if (consensus_method == 1) {
- is_named = chosen_named_idx >= 0 &&
- (!naming_conflict && flag_counts[chosen_named_idx]);
- } else {
+ {
const char *d = strmap_get_lc(name_to_id_map, rs_out.nickname);
if (!d) {
is_named = is_unnamed = 0;
@@ -1811,7 +1627,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
if (!strcmp(fl, "Named")) {
if (is_named)
smartlist_add(chosen_flags, (char*)fl);
- } else if (!strcmp(fl, "Unnamed") && consensus_method >= 2) {
+ } else if (!strcmp(fl, "Unnamed")) {
if (is_unnamed)
smartlist_add(chosen_flags, (char*)fl);
} else {
@@ -1831,7 +1647,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
/* Starting with consensus method 4 we do not list servers
* that are not running in a consensus. See Proposal 138 */
- if (consensus_method >= 4 && !is_running)
+ if (!is_running)
continue;
/* Pick the version. */
@@ -1842,12 +1658,23 @@ networkstatus_compute_consensus(smartlist_t *votes,
chosen_version = NULL;
}
+ /* If it's a guard and we have enough guardfraction votes,
+ calculate its consensus guardfraction value. */
+ if (is_guard && num_guardfraction_inputs > 2 &&
+ consensus_method >= MIN_METHOD_FOR_GUARDFRACTION) {
+ rs_out.has_guardfraction = 1;
+ rs_out.guardfraction_percentage = median_uint32(measured_guardfraction,
+ num_guardfraction_inputs);
+ /* final value should be an integer percentage! */
+ tor_assert(rs_out.guardfraction_percentage <= 100);
+ }
+
/* Pick a bandwidth */
- if (consensus_method >= 6 && num_mbws > 2) {
+ if (num_mbws > 2) {
rs_out.has_bandwidth = 1;
rs_out.bw_is_unmeasured = 0;
rs_out.bandwidth_kb = median_uint32(measured_bws_kb, num_mbws);
- } else if (consensus_method >= 5 && num_bandwidths > 0) {
+ } else if (num_bandwidths > 0) {
rs_out.has_bandwidth = 1;
rs_out.bw_is_unmeasured = 1;
rs_out.bandwidth_kb = median_uint32(bandwidths_kb, num_bandwidths);
@@ -1861,25 +1688,13 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
/* Fix bug 2203: Do not count BadExit nodes as Exits for bw weights */
- if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) {
- is_exit = is_exit && !is_bad_exit;
- }
+ is_exit = is_exit && !is_bad_exit;
- if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
- if (rs_out.has_bandwidth) {
- T += rs_out.bandwidth_kb;
- if (is_exit && is_guard)
- D += rs_out.bandwidth_kb;
- else if (is_exit)
- E += rs_out.bandwidth_kb;
- else if (is_guard)
- G += rs_out.bandwidth_kb;
- else
- M += rs_out.bandwidth_kb;
- } else {
- log_warn(LD_BUG, "Missing consensus bandwidth for router %s",
- rs_out.nickname);
- }
+ /* Update total bandwidth weights with the bandwidths of this router. */
+ {
+ update_total_bandwidth_weights(&rs_out,
+ is_exit, is_guard,
+ &G, &M, &E, &D, &T);
}
/* Ok, we already picked a descriptor digest we want to list
@@ -1896,7 +1711,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
* the policy that was most often listed in votes, again breaking
* ties like in the previous case.
*/
- if (consensus_method >= 5) {
+ {
/* Okay, go through all the votes for this router. We prepared
* that list previously */
const char *chosen_exitsummary = NULL;
@@ -1967,7 +1782,6 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
if (flavor == FLAV_MICRODESC &&
- consensus_method >= MIN_METHOD_FOR_MANDATORY_MICRODESC &&
tor_digest256_is_zero(microdesc_digest)) {
/* With no microdescriptor digest, we omit the entry entirely. */
continue;
@@ -1999,11 +1813,21 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_add(chunks, tor_strdup("\n"));
/* Now the weight line. */
if (rs_out.has_bandwidth) {
+ char *guardfraction_str = NULL;
int unmeasured = rs_out.bw_is_unmeasured &&
consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW;
- smartlist_add_asprintf(chunks, "w Bandwidth=%d%s\n",
+
+ /* If we have guardfraction info, include it in the 'w' line. */
+ if (rs_out.has_guardfraction) {
+ tor_asprintf(&guardfraction_str,
+ " GuardFraction=%u", rs_out.guardfraction_percentage);
+ }
+ smartlist_add_asprintf(chunks, "w Bandwidth=%d%s%s\n",
rs_out.bandwidth_kb,
- unmeasured?" Unmeasured=1":"");
+ unmeasured?" Unmeasured=1":"",
+ guardfraction_str ? guardfraction_str : "");
+
+ tor_free(guardfraction_str);
}
/* Now the exitpolicy summary line. */
@@ -2031,15 +1855,13 @@ networkstatus_compute_consensus(smartlist_t *votes,
smartlist_free(exitsummaries);
tor_free(bandwidths_kb);
tor_free(measured_bws_kb);
+ tor_free(measured_guardfraction);
}
- if (consensus_method >= MIN_METHOD_FOR_FOOTER) {
- /* Starting with consensus method 9, we clearly mark the directory
- * footer region */
- smartlist_add(chunks, tor_strdup("directory-footer\n"));
- }
+ /* Mark the directory footer region */
+ smartlist_add(chunks, tor_strdup("directory-footer\n"));
- if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS) {
+ {
int64_t weight_scale = BW_WEIGHT_SCALE;
char *bw_weight_param = NULL;
@@ -2072,13 +1894,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
}
- if (consensus_method < 10) {
- networkstatus_compute_bw_weights_v9(chunks, G, M, E, D, T, weight_scale);
- added_weights = 1;
- } else {
- added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D,
- T, weight_scale);
- }
+ added_weights = networkstatus_compute_bw_weights_v10(chunks, G, M, E, D,
+ T, weight_scale);
}
/* Add a signature. */
@@ -2119,7 +1936,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
}
smartlist_add(chunks, signature);
- if (legacy_id_key_digest && legacy_signing_key && consensus_method >= 3) {
+ if (legacy_id_key_digest && legacy_signing_key) {
smartlist_add(chunks, tor_strdup("directory-signature "));
base16_encode(fingerprint, sizeof(fingerprint),
legacy_id_key_digest, DIGEST_LEN);
@@ -2155,7 +1972,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
goto done;
}
// Verify balancing parameters
- if (consensus_method >= MIN_METHOD_FOR_BW_WEIGHTS && added_weights) {
+ if (added_weights) {
networkstatus_verify_bw_weights(c, consensus_method);
}
networkstatus_vote_free(c);
@@ -2165,6 +1982,7 @@ networkstatus_compute_consensus(smartlist_t *votes,
tor_free(client_versions);
tor_free(server_versions);
+ tor_free(packages);
SMARTLIST_FOREACH(flags, char *, cp, tor_free(cp));
smartlist_free(flags);
SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
@@ -2173,6 +1991,78 @@ networkstatus_compute_consensus(smartlist_t *votes,
return result;
}
+/** Given a list of networkstatus_t for each vote, return a newly allocated
+ * string containing the "package" lines for the vote. */
+STATIC char *
+compute_consensus_package_lines(smartlist_t *votes)
+{
+ const int n_votes = smartlist_len(votes);
+
+ /* This will be a map from "packagename version" strings to arrays
+ * of const char *, with the i'th member of the array corresponding to the
+ * package line from the i'th vote.
+ */
+ strmap_t *package_status = strmap_new();
+
+ SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
+ if (! v->package_lines)
+ continue;
+ SMARTLIST_FOREACH_BEGIN(v->package_lines, const char *, line) {
+ if (! validate_recommended_package_line(line))
+ continue;
+
+ /* Skip 'cp' to the second space in the line. */
+ const char *cp = strchr(line, ' ');
+ if (!cp) continue;
+ ++cp;
+ cp = strchr(cp, ' ');
+ if (!cp) continue;
+
+ char *key = tor_strndup(line, cp - line);
+
+ const char **status = strmap_get(package_status, key);
+ if (!status) {
+ status = tor_calloc(n_votes, sizeof(const char *));
+ strmap_set(package_status, key, status);
+ }
+ status[v_sl_idx] = line; /* overwrite old value */
+ tor_free(key);
+ } SMARTLIST_FOREACH_END(line);
+ } SMARTLIST_FOREACH_END(v);
+
+ smartlist_t *entries = smartlist_new(); /* temporary */
+ smartlist_t *result_list = smartlist_new(); /* output */
+ STRMAP_FOREACH(package_status, key, const char **, values) {
+ int i, count=-1;
+ for (i = 0; i < n_votes; ++i) {
+ if (values[i])
+ smartlist_add(entries, (void*) values[i]);
+ }
+ smartlist_sort_strings(entries);
+ int n_voting_for_entry = smartlist_len(entries);
+ const char *most_frequent =
+ smartlist_get_most_frequent_string_(entries, &count);
+
+ if (n_voting_for_entry >= 3 && count > n_voting_for_entry / 2) {
+ smartlist_add_asprintf(result_list, "package %s\n", most_frequent);
+ }
+
+ smartlist_clear(entries);
+
+ } STRMAP_FOREACH_END;
+
+ smartlist_sort_strings(result_list);
+
+ char *result = smartlist_join_strings(result_list, "", 0, NULL);
+
+ SMARTLIST_FOREACH(result_list, char *, cp, tor_free(cp));
+ smartlist_free(result_list);
+ smartlist_free(entries);
+ strmap_free(package_status, tor_free_);
+
+ return result;
+}
+
/** Given a consensus vote <b>target</b> and a set of detached signatures in
* <b>sigs</b> that correspond to the same consensus, check whether there are
* any new signatures in <b>src_voter_list</b> that should be added to
@@ -2279,8 +2169,11 @@ networkstatus_add_detached_signatures(networkstatus_t *target,
if (!sig->good_signature && !sig->bad_signature) {
cert = authority_cert_get_by_digests(sig->identity_digest,
sig->signing_key_digest);
- if (cert)
- networkstatus_check_document_signature(target, sig, cert);
+ if (cert) {
+ /* Not checking the return value here, since we are going to look
+ * at the status of sig->good_signature in a moment. */
+ (void) networkstatus_check_document_signature(target, sig, cert);
+ }
}
/* If this signature is good, or we don't have any signature yet,
@@ -3020,7 +2913,7 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out)
goto discard;
} else if (v->vote->published < vote->published) {
log_notice(LD_DIR, "Replacing an older pending vote from this "
- "directory.");
+ "directory (%s)", vi->address);
cached_dir_decref(v->vote_body);
networkstatus_vote_free(v->vote);
v->vote_body = new_cached_dir(tor_strndup(vote_body,
@@ -3602,8 +3495,8 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
{
smartlist_t *lst = microdescs_parse_from_string(output,
- output+strlen(output), 0,
- SAVED_NOWHERE);
+ output+strlen(output), 0,
+ SAVED_NOWHERE, NULL);
if (smartlist_len(lst) != 1) {
log_warn(LD_DIR, "We generated a microdescriptor we couldn't parse.");
SMARTLIST_FOREACH(lst, microdesc_t *, md, microdesc_free(md));
@@ -3664,7 +3557,7 @@ static const struct consensus_method_range_t {
int low;
int high;
} microdesc_consensus_methods[] = {
- {MIN_METHOD_FOR_MICRODESC, MIN_METHOD_FOR_A_LINES - 1},
+ {MIN_SUPPORTED_CONSENSUS_METHOD, MIN_METHOD_FOR_A_LINES - 1},
{MIN_METHOD_FOR_A_LINES, MIN_METHOD_FOR_P6_LINES - 1},
{MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1},
{MIN_METHOD_FOR_NTOR_KEY, MIN_METHOD_FOR_ID_HASH_IN_MD - 1},
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index 4c57e43661..542563b708 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,34 +14,48 @@
#include "testsupport.h"
+/*
+ * Ideally, assuming synced clocks, we should only need 1 second for each of:
+ * - Vote
+ * - Distribute
+ * - Consensus Publication
+ * As we can gather descriptors continuously.
+ * (Could we even go as far as publishing the previous consensus,
+ * in the same second that we vote for the next one?)
+ * But we're not there yet: these are the lowest working values at this time.
+ */
+
/** Lowest allowable value for VoteSeconds. */
#define MIN_VOTE_SECONDS 2
+/** Lowest allowable value for VoteSeconds when TestingTorNetwork is 1 */
+#define MIN_VOTE_SECONDS_TESTING 2
+
/** Lowest allowable value for DistSeconds. */
#define MIN_DIST_SECONDS 2
-/** Smallest allowable voting interval. */
+/** Lowest allowable value for DistSeconds when TestingTorNetwork is 1 */
+#define MIN_DIST_SECONDS_TESTING 2
+
+/** Lowest allowable voting interval. */
#define MIN_VOTE_INTERVAL 300
+/** Lowest allowable voting interval when TestingTorNetwork is 1:
+ * Voting Interval can be:
+ * 10, 12, 15, 18, 20, 24, 25, 30, 36, 40, 45, 50, 60, ...
+ * Testing Initial Voting Interval can be:
+ * 5, 6, 8, 9, or any of the possible values for Voting Interval,
+ * as they both need to evenly divide 30 minutes.
+ * If clock desynchronisation is an issue, use an interval of at least:
+ * 18 * drift in seconds, to allow for a clock slop factor */
+#define MIN_VOTE_INTERVAL_TESTING \
+ (((MIN_VOTE_SECONDS_TESTING)+(MIN_DIST_SECONDS_TESTING)+1)*2)
+
+#define MIN_VOTE_INTERVAL_TESTING_INITIAL \
+ ((MIN_VOTE_SECONDS_TESTING)+(MIN_DIST_SECONDS_TESTING)+1)
+
+/** The lowest consensus method that we currently support. */
+#define MIN_SUPPORTED_CONSENSUS_METHOD 13
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 18
-
-/** Lowest consensus method that contains a 'directory-footer' marker */
-#define MIN_METHOD_FOR_FOOTER 9
-
-/** Lowest consensus method that contains bandwidth weights */
-#define MIN_METHOD_FOR_BW_WEIGHTS 9
-
-/** Lowest consensus method that contains consensus params */
-#define MIN_METHOD_FOR_PARAMS 7
-
-/** Lowest consensus method that generates microdescriptors */
-#define MIN_METHOD_FOR_MICRODESC 8
-
-/** Lowest consensus method that doesn't count bad exits as exits for weight */
-#define MIN_METHOD_TO_CUT_BADEXIT_WEIGHT 11
-
-/** Lowest consensus method that ensures a majority of authorities voted
- * for a param. */
-#define MIN_METHOD_FOR_MAJORITY_PARAMS 12
+#define MAX_SUPPORTED_CONSENSUS_METHOD 20
/** Lowest consensus method where microdesc consensuses omit any entry
* with no microdesc. */
@@ -65,8 +79,16 @@
* microdescriptors. */
#define MIN_METHOD_FOR_ID_HASH_IN_MD 18
+/** Lowest consensus method where we include "package" lines*/
+#define MIN_METHOD_FOR_PACKAGE_LINES 19
+
+/** Lowest consensus method where authorities may include
+ * GuardFraction information in microdescriptors. */
+#define MIN_METHOD_FOR_GUARDFRACTION 20
+
/** Default bandwidth to clip unmeasured bandwidths to using method >=
- * MIN_METHOD_TO_CLIP_UNMEASURED_BW */
+ * MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
+ * get confused with the above macros.) */
#define DEFAULT_MAX_UNMEASURED_BW_KB 20
void dirvote_free_all(void);
@@ -116,8 +138,8 @@ const cached_dir_t *dirvote_get_vote(const char *fp, int flags);
void set_routerstatus_from_routerinfo(routerstatus_t *rs,
node_t *node,
routerinfo_t *ri, time_t now,
- int naming, int listbadexits,
- int listbaddirs, int vote_on_hsdirs);
+ int listbadexits,
+ int vote_on_hsdirs);
networkstatus_t *
dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
authority_cert_t *cert);
@@ -146,6 +168,7 @@ STATIC char *format_networkstatus_vote(crypto_pk_t *private_key,
networkstatus_t *v3_ns);
STATIC char *dirvote_compute_params(smartlist_t *votes, int method,
int total_authorities);
+STATIC char *compute_consensus_package_lines(smartlist_t *votes);
#endif
#endif
diff --git a/src/or/dns.c b/src/or/dns.c
index b55bf7384e..cc4a169422 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -244,8 +244,8 @@ cached_resolve_hash(cached_resolve_t *a)
HT_PROTOTYPE(cache_map, cached_resolve_t, node, cached_resolve_hash,
cached_resolves_eq)
-HT_GENERATE(cache_map, cached_resolve_t, node, cached_resolve_hash,
- cached_resolves_eq, 0.6, malloc, realloc, free)
+HT_GENERATE2(cache_map, cached_resolve_t, node, cached_resolve_hash,
+ cached_resolves_eq, 0.6, tor_reallocarray_, tor_free_)
/** Initialize the DNS cache. */
static void
diff --git a/src/or/dns.h b/src/or/dns.h
index 022cd4ac63..b13ab0f890 100644
--- a/src/or/dns.h
+++ b/src/or/dns.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/dnsserv.c b/src/or/dnsserv.c
index 9b0368dd09..f3618cc2c5 100644
--- a/src/or/dnsserv.c
+++ b/src/or/dnsserv.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -139,13 +139,13 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
}
if (q->type == EVDNS_TYPE_A || q->type == EVDNS_QTYPE_ALL) {
- entry_conn->ipv4_traffic_ok = 1;
- entry_conn->ipv6_traffic_ok = 0;
- entry_conn->prefer_ipv6_traffic = 0;
+ entry_conn->entry_cfg.ipv4_traffic = 1;
+ entry_conn->entry_cfg.ipv6_traffic = 0;
+ entry_conn->entry_cfg.prefer_ipv6 = 0;
} else if (q->type == EVDNS_TYPE_AAAA) {
- entry_conn->ipv4_traffic_ok = 0;
- entry_conn->ipv6_traffic_ok = 1;
- entry_conn->prefer_ipv6_traffic = 1;
+ entry_conn->entry_cfg.ipv4_traffic = 0;
+ entry_conn->entry_cfg.ipv6_traffic = 1;
+ entry_conn->entry_cfg.prefer_ipv6 = 1;
}
strlcpy(entry_conn->socks_request->address, q->name,
@@ -153,8 +153,8 @@ evdns_server_callback(struct evdns_server_request *req, void *data_)
entry_conn->socks_request->listener_type = listener->base_.type;
entry_conn->dns_server_request = req;
- entry_conn->isolation_flags = listener->isolation_flags;
- entry_conn->session_group = listener->session_group;
+ entry_conn->entry_cfg.isolation_flags = listener->entry_cfg.isolation_flags;
+ entry_conn->entry_cfg.session_group = listener->entry_cfg.session_group;
entry_conn->nym_epoch = get_signewnym_epoch();
if (connection_add(ENTRY_TO_CONN(entry_conn)) < 0) {
@@ -230,9 +230,9 @@ dnsserv_launch_request(const char *name, int reverse,
entry_conn->socks_request->listener_type = CONN_TYPE_CONTROL_LISTENER;
entry_conn->original_dest_address = tor_strdup(name);
- entry_conn->session_group = SESSION_GROUP_CONTROL_RESOLVE;
+ entry_conn->entry_cfg.session_group = SESSION_GROUP_CONTROL_RESOLVE;
entry_conn->nym_epoch = get_signewnym_epoch();
- entry_conn->isolation_flags = ISO_DEFAULT;
+ entry_conn->entry_cfg.isolation_flags = ISO_DEFAULT;
if (connection_add(TO_CONN(conn))<0) {
log_warn(LD_APP, "Couldn't register dummy connection for RESOLVE request");
diff --git a/src/or/dnsserv.h b/src/or/dnsserv.h
index 687a77e59e..09ad5d7759 100644
--- a/src/or/dnsserv.h
+++ b/src/or/dnsserv.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 66b7201187..30108b6041 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,6 +12,8 @@
* circumvention).
**/
+#define ENTRYNODES_PRIVATE
+
#include "or.h"
#include "circpathbias.h"
#include "circuitbuild.h"
@@ -154,21 +156,41 @@ entry_guard_set_status(entry_guard_t *e, const node_t *node,
/** Return true iff enough time has passed since we last tried to connect
* to the unreachable guard <b>e</b> that we're willing to try again. */
-static int
-entry_is_time_to_retry(entry_guard_t *e, time_t now)
+STATIC int
+entry_is_time_to_retry(const entry_guard_t *e, time_t now)
{
- long diff;
+ struct guard_retry_period_s {
+ time_t period_duration;
+ time_t interval_during_period;
+ };
+
+ struct guard_retry_period_s periods[] = {
+ { 6*60*60, 60*60 }, /* For first 6 hrs., retry hourly; */
+ { 3*24*60*60, 4*60*60 }, /* Then retry every 4 hrs. until the
+ 3-day mark; */
+ { 7*24*60*60, 18*60*60 }, /* After 3 days, retry every 18 hours until
+ 1 week mark. */
+ { TIME_MAX, 36*60*60 } /* After 1 week, retry every 36 hours. */
+ };
+
+ time_t ith_deadline_for_retry;
+ time_t unreachable_for;
+ unsigned i;
+
if (e->last_attempted < e->unreachable_since)
return 1;
- diff = now - e->unreachable_since;
- if (diff < 6*60*60)
- return now > (e->last_attempted + 60*60);
- else if (diff < 3*24*60*60)
- return now > (e->last_attempted + 4*60*60);
- else if (diff < 7*24*60*60)
- return now > (e->last_attempted + 18*60*60);
- else
- return now > (e->last_attempted + 36*60*60);
+
+ unreachable_for = now - e->unreachable_since;
+
+ for (i = 0; i < ARRAY_LENGTH(periods); i++) {
+ if (unreachable_for <= periods[i].period_duration) {
+ ith_deadline_for_retry = e->last_attempted +
+ periods[i].interval_during_period;
+
+ return (now > ith_deadline_for_retry);
+ }
+ }
+ return 0;
}
/** Return the node corresponding to <b>e</b>, if <b>e</b> is
@@ -188,12 +210,17 @@ entry_is_time_to_retry(entry_guard_t *e, time_t now)
* If need_descriptor is true, only return the node if we currently have
* a descriptor (routerinfo or microdesc) for it.
*/
-static INLINE const node_t *
-entry_is_live(entry_guard_t *e, int need_uptime, int need_capacity,
- int assume_reachable, int need_descriptor, const char **msg)
+STATIC const node_t *
+entry_is_live(const entry_guard_t *e, entry_is_live_flags_t flags,
+ const char **msg)
{
const node_t *node;
const or_options_t *options = get_options();
+ int need_uptime = (flags & ENTRY_NEED_UPTIME) != 0;
+ int need_capacity = (flags & ENTRY_NEED_CAPACITY) != 0;
+ const int assume_reachable = (flags & ENTRY_ASSUME_REACHABLE) != 0;
+ const int need_descriptor = (flags & ENTRY_NEED_DESCRIPTOR) != 0;
+
tor_assert(msg);
if (e->path_bias_disabled) {
@@ -255,12 +282,18 @@ num_live_entry_guards(int for_directory)
{
int n = 0;
const char *msg;
+ /* Set the entry node attributes we are interested in. */
+ entry_is_live_flags_t entry_flags = ENTRY_NEED_CAPACITY;
+ if (!for_directory) {
+ entry_flags |= ENTRY_NEED_DESCRIPTOR;
+ }
+
if (! entry_guards)
return 0;
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
if (for_directory && !entry->is_dir_cache)
continue;
- if (entry_is_live(entry, 0, 1, 0, !for_directory, &msg))
+ if (entry_is_live(entry, entry_flags, &msg))
++n;
} SMARTLIST_FOREACH_END(entry);
return n;
@@ -289,7 +322,7 @@ log_entry_guards(int severity)
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e)
{
const char *msg = NULL;
- if (entry_is_live(e, 0, 1, 0, 0, &msg))
+ if (entry_is_live(e, ENTRY_NEED_CAPACITY, &msg))
smartlist_add_asprintf(elements, "%s [%s] (up %s)",
e->nickname,
hex_str(e->identity, DIGEST_LEN),
@@ -350,7 +383,7 @@ control_event_guard_deferred(void)
* If <b>chosen</b> is defined, use that one, and if it's not
* already in our entry_guards list, put it at the *beginning*.
* Else, put the one we pick at the end of the list. */
-static const node_t *
+STATIC const node_t *
add_an_entry_guard(const node_t *chosen, int reset_status, int prepend,
int for_discovery, int for_directory)
{
@@ -437,7 +470,7 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend,
/** Choose how many entry guards or directory guards we'll use. If
* <b>for_directory</b> is true, we return how many directory guards to
* use; else we return how many entry guards to use. */
-static int
+STATIC int
decide_num_guards(const or_options_t *options, int for_directory)
{
if (for_directory) {
@@ -676,7 +709,7 @@ entry_guards_compute_status(const or_options_t *options, time_t now)
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
const char *reason = digestmap_get(reasons, entry->identity);
const char *live_msg = "";
- const node_t *r = entry_is_live(entry, 0, 1, 0, 0, &live_msg);
+ const node_t *r = entry_is_live(entry, ENTRY_NEED_CAPACITY, &live_msg);
log_info(LD_CIRC, "Summary: Entry %s [%s] is %s, %s%s%s, and %s%s.",
entry->nickname,
hex_str(entry->identity, DIGEST_LEN),
@@ -794,7 +827,9 @@ entry_guard_register_connect_status(const char *digest, int succeeded,
break;
if (e->made_contact) {
const char *msg;
- const node_t *r = entry_is_live(e, 0, 1, 1, 0, &msg);
+ const node_t *r = entry_is_live(e,
+ ENTRY_NEED_CAPACITY | ENTRY_ASSUME_REACHABLE,
+ &msg);
if (r && e->unreachable_since) {
refuse_conn = 1;
e->can_retry = 1;
@@ -847,7 +882,7 @@ update_node_guard_status(void)
/** Adjust the entry guards list so that it only contains entries from
* EntryNodes, adding new entries from EntryNodes to the list as needed. */
-static void
+STATIC void
entry_guards_set_from_config(const or_options_t *options)
{
smartlist_t *entry_nodes, *worse_entry_nodes, *entry_fps;
@@ -968,7 +1003,8 @@ node_understands_microdescriptors(const node_t *node)
}
/** Return true iff <b>node</b> is able to answer directory questions
- * of type <b>dirinfo</b>. */
+ * of type <b>dirinfo</b>. Always returns true if <b>dirinfo</b> is
+ * NO_DIRINFO (zero). */
static int
node_can_handle_dirinfo(const node_t *node, dirinfo_type_t dirinfo)
{
@@ -990,13 +1026,13 @@ node_can_handle_dirinfo(const node_t *node, dirinfo_type_t dirinfo)
* <b>state</b> is non-NULL, this is for a specific circuit --
* make sure not to pick this circuit's exit or any node in the
* exit's family. If <b>state</b> is NULL, we're looking for a random
- * guard (likely a bridge). If <b>dirinfo</b> is not NO_DIRINFO, then
- * only select from nodes that know how to answer directory questions
+ * guard (likely a bridge). If <b>dirinfo</b> is not NO_DIRINFO (zero),
+ * then only select from nodes that know how to answer directory questions
* of that type. */
const node_t *
choose_random_entry(cpath_build_state_t *state)
{
- return choose_random_entry_impl(state, 0, 0, NULL);
+ return choose_random_entry_impl(state, 0, NO_DIRINFO, NULL);
}
/** Pick a live (up and listed) directory guard from entry_guards for
@@ -1007,47 +1043,61 @@ choose_random_dirguard(dirinfo_type_t type)
return choose_random_entry_impl(NULL, 1, type, NULL);
}
-/** Helper for choose_random{entry,dirguard}. */
-static const node_t *
-choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
- dirinfo_type_t dirinfo_type, int *n_options_out)
+/** Filter <b>all_entry_guards</b> for usable entry guards and put them
+ * in <b>live_entry_guards</b>. We filter based on whether the node is
+ * currently alive, and on whether it satisfies the restrictions
+ * imposed by the other arguments of this function.
+ *
+ * We don't place more guards than NumEntryGuards in <b>live_entry_guards</b>.
+ *
+ * If <b>chosen_exit</b> is set, it contains the exit node of this
+ * circuit. Make sure to not use it or its family as an entry guard.
+ *
+ * If <b>need_uptime</b> is set, we are looking for a stable entry guard.
+ * if <b>need_capacity</b> is set, we are looking for a fast entry guard.
+ *
+ * The rest of the arguments are the same as in choose_random_entry_impl().
+ *
+ * Return 1 if we should choose a guard right away. Return 0 if we
+ * should try to add more nodes to our list before deciding on a
+ * guard.
+ */
+STATIC int
+populate_live_entry_guards(smartlist_t *live_entry_guards,
+ const smartlist_t *all_entry_guards,
+ const node_t *chosen_exit,
+ dirinfo_type_t dirinfo_type,
+ int for_directory,
+ int need_uptime, int need_capacity)
{
const or_options_t *options = get_options();
- smartlist_t *live_entry_guards = smartlist_new();
- smartlist_t *exit_family = smartlist_new();
- const node_t *chosen_exit =
- state?build_state_get_exit_node(state) : NULL;
const node_t *node = NULL;
- int need_uptime = state ? state->need_uptime : 0;
- int need_capacity = state ? state->need_capacity : 0;
- int preferred_min, consider_exit_family = 0;
- int need_descriptor = !for_directory;
const int num_needed = decide_num_guards(options, for_directory);
+ smartlist_t *exit_family = smartlist_new();
+ int retval = 0;
+ entry_is_live_flags_t entry_flags = 0;
- if (n_options_out)
- *n_options_out = 0;
+ { /* Set the flags we want our entry node to have */
+ if (need_uptime) {
+ entry_flags |= ENTRY_NEED_UPTIME;
+ }
+ if (need_capacity) {
+ entry_flags |= ENTRY_NEED_CAPACITY;
+ }
+ if (!for_directory) {
+ entry_flags |= ENTRY_NEED_DESCRIPTOR;
+ }
+ }
+
+ tor_assert(all_entry_guards);
if (chosen_exit) {
nodelist_add_node_and_family(exit_family, chosen_exit);
- consider_exit_family = 1;
}
- if (!entry_guards)
- entry_guards = smartlist_new();
-
- if (should_add_entry_nodes)
- entry_guards_set_from_config(options);
-
- if (!entry_list_is_constrained(options) &&
- smartlist_len(entry_guards) < num_needed)
- pick_entry_guards(options, for_directory);
-
- retry:
- smartlist_clear(live_entry_guards);
- SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, entry) {
+ SMARTLIST_FOREACH_BEGIN(all_entry_guards, const entry_guard_t *, entry) {
const char *msg;
- node = entry_is_live(entry, need_uptime, need_capacity, 0,
- need_descriptor, &msg);
+ node = entry_is_live(entry, entry_flags, &msg);
if (!node)
continue; /* down, no point */
if (for_directory) {
@@ -1056,39 +1106,96 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
}
if (node == chosen_exit)
continue; /* don't pick the same node for entry and exit */
- if (consider_exit_family && smartlist_contains(exit_family, node))
+ if (smartlist_contains(exit_family, node))
continue; /* avoid relays that are family members of our exit */
if (dirinfo_type != NO_DIRINFO &&
!node_can_handle_dirinfo(node, dirinfo_type))
continue; /* this node won't be able to answer our dir questions */
-#if 0 /* since EntryNodes is always strict now, this clause is moot */
- if (options->EntryNodes &&
- !routerset_contains_node(options->EntryNodes, node)) {
- /* We've come to the end of our preferred entry nodes. */
- if (smartlist_len(live_entry_guards))
- goto choose_and_finish; /* only choose from the ones we like */
- if (options->StrictNodes) {
- /* in theory this case should never happen, since
- * entry_guards_set_from_config() drops unwanted relays */
- tor_fragile_assert();
- } else {
- log_info(LD_CIRC,
- "No relays from EntryNodes available. Using others.");
- }
- }
-#endif
smartlist_add(live_entry_guards, (void*)node);
if (!entry->made_contact) {
/* Always start with the first not-yet-contacted entry
* guard. Otherwise we might add several new ones, pick
* the second new one, and now we've expanded our entry
* guard list without needing to. */
- goto choose_and_finish;
+ retval = 1;
+ goto done;
+ }
+ if (smartlist_len(live_entry_guards) >= num_needed) {
+ retval = 1;
+ goto done; /* We picked enough entry guards. Done! */
}
- if (smartlist_len(live_entry_guards) >= num_needed)
- goto choose_and_finish; /* we have enough */
} SMARTLIST_FOREACH_END(entry);
+ done:
+ smartlist_free(exit_family);
+
+ return retval;
+}
+
+/** Pick a node to be used as the entry guard of a circuit.
+ *
+ * If <b>state</b> is set, it contains the information we know about
+ * the upcoming circuit.
+ *
+ * If <b>for_directory</b> is set, we are looking for a directory guard.
+ *
+ * <b>dirinfo_type</b> contains the kind of directory information we
+ * are looking for in our node, or NO_DIRINFO (zero) if we are not
+ * looking for any particular directory information (when set to
+ * NO_DIRINFO, the <b>dirinfo_type</b> filter is ignored).
+ *
+ * If <b>n_options_out</b> is set, we set it to the number of
+ * candidate guard nodes we had before picking a specific guard node.
+ *
+ * On success, return the node that should be used as the entry guard
+ * of the circuit. Return NULL if no such node could be found.
+ *
+ * Helper for choose_random{entry,dirguard}.
+*/
+static const node_t *
+choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
+ dirinfo_type_t dirinfo_type, int *n_options_out)
+{
+ const or_options_t *options = get_options();
+ smartlist_t *live_entry_guards = smartlist_new();
+ const node_t *chosen_exit =
+ state?build_state_get_exit_node(state) : NULL;
+ const node_t *node = NULL;
+ int need_uptime = state ? state->need_uptime : 0;
+ int need_capacity = state ? state->need_capacity : 0;
+ int preferred_min = 0;
+ const int num_needed = decide_num_guards(options, for_directory);
+ int retval = 0;
+
+ if (n_options_out)
+ *n_options_out = 0;
+
+ if (!entry_guards)
+ entry_guards = smartlist_new();
+
+ if (should_add_entry_nodes)
+ entry_guards_set_from_config(options);
+
+ if (!entry_list_is_constrained(options) &&
+ smartlist_len(entry_guards) < num_needed)
+ pick_entry_guards(options, for_directory);
+
+ retry:
+ smartlist_clear(live_entry_guards);
+
+ /* Populate the list of live entry guards so that we pick one of
+ them. */
+ retval = populate_live_entry_guards(live_entry_guards,
+ entry_guards,
+ chosen_exit,
+ dirinfo_type,
+ for_directory,
+ need_uptime, need_capacity);
+
+ if (retval == 1) { /* We should choose a guard right now. */
+ goto choose_and_finish;
+ }
+
if (entry_list_is_constrained(options)) {
/* If we prefer the entry nodes we've got, and we have at least
* one choice, that's great. Use it. */
@@ -1127,18 +1234,7 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
need_capacity = 0;
goto retry;
}
-#if 0
- /* Removing this retry logic: if we only allow one exit, and it is in the
- same family as all our entries, then we are just plain not going to win
- here. */
- if (!node && entry_list_is_constrained(options) && consider_exit_family) {
- /* still no? if we're using bridges or have strictentrynodes
- * set, and our chosen exit is in the same family as all our
- * bridges/entry guards, then be flexible about families. */
- consider_exit_family = 0;
- goto retry;
- }
-#endif
+
/* live_entry_guards may be empty below. Oh well, we tried. */
}
@@ -1156,7 +1252,6 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
if (n_options_out)
*n_options_out = smartlist_len(live_entry_guards);
smartlist_free(live_entry_guards);
- smartlist_free(exit_family);
return node;
}
@@ -1224,7 +1319,7 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
"EntryGuardDownSince/UnlistedSince without EntryGuard");
break;
}
- if (parse_iso_time(line->value, &when)<0) {
+ if (parse_iso_time_(line->value, &when, 0)<0) {
*msg = tor_strdup("Unable to parse entry nodes: "
"Bad time in EntryGuardDownSince/UnlistedSince");
break;
@@ -1428,6 +1523,13 @@ entry_guards_parse_state(or_state_t *state, int set, char **msg)
return *msg ? -1 : 0;
}
+/** How long will we let a change in our guard nodes stay un-saved
+ * when we are trying to avoid disk writes? */
+#define SLOW_GUARD_STATE_FLUSH_TIME 600
+/** How long will we let a change in our guard nodes stay un-saved
+ * when we are not trying to avoid disk writes? */
+#define FAST_GUARD_STATE_FLUSH_TIME 30
+
/** Our list of entry guards has changed, or some element of one
* of our entry guards has changed. Write the changes to disk within
* the next few minutes.
@@ -1438,8 +1540,12 @@ entry_guards_changed(void)
time_t when;
entry_guards_dirty = 1;
+ if (get_options()->AvoidDiskWrites)
+ when = time(NULL) + SLOW_GUARD_STATE_FLUSH_TIME;
+ else
+ when = time(NULL) + FAST_GUARD_STATE_FLUSH_TIME;
+
/* or_state_save() will call entry_guards_update_state(). */
- when = get_options()->AvoidDiskWrites ? time(NULL) + 3600 : time(NULL)+600;
or_state_mark_dirty(get_or_state(), when);
}
@@ -1560,6 +1666,9 @@ getinfo_helper_entry_guards(control_connection_t *conn,
} else if (e->bad_since) {
when = e->bad_since;
status = "unusable";
+ } else if (e->unreachable_since) {
+ when = e->unreachable_since;
+ status = "down";
} else {
status = "up";
}
@@ -1588,6 +1697,63 @@ getinfo_helper_entry_guards(control_connection_t *conn,
return 0;
}
+/** Return 0 if we should apply guardfraction information found in the
+ * consensus. A specific consensus can be specified with the
+ * <b>ns</b> argument, if NULL the most recent one will be picked.*/
+int
+should_apply_guardfraction(const networkstatus_t *ns)
+{
+ /* We need to check the corresponding torrc option and the consensus
+ * parameter if we need to. */
+ const or_options_t *options = get_options();
+
+ /* If UseGuardFraction is 'auto' then check the same-named consensus
+ * parameter. If the consensus parameter is not present, default to
+ * "off". */
+ if (options->UseGuardFraction == -1) {
+ return networkstatus_get_param(ns, "UseGuardFraction",
+ 0, /* default to "off" */
+ 0, 1);
+ }
+
+ return options->UseGuardFraction;
+}
+
+/* Given the original bandwidth of a guard and its guardfraction,
+ * calculate how much bandwidth the guard should have as a guard and
+ * as a non-guard.
+ *
+ * Quoting from proposal236:
+ *
+ * Let Wpf denote the weight from the 'bandwidth-weights' line a
+ * client would apply to N for position p if it had the guard
+ * flag, Wpn the weight if it did not have the guard flag, and B the
+ * measured bandwidth of N in the consensus. Then instead of choosing
+ * N for position p proportionally to Wpf*B or Wpn*B, clients should
+ * choose N proportionally to F*Wpf*B + (1-F)*Wpn*B.
+ *
+ * This function fills the <b>guardfraction_bw</b> structure. It sets
+ * <b>guard_bw</b> to F*B and <b>non_guard_bw</b> to (1-F)*B.
+ */
+void
+guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw,
+ int orig_bandwidth,
+ uint32_t guardfraction_percentage)
+{
+ double guardfraction_fraction;
+
+ /* Turn the percentage into a fraction. */
+ tor_assert(guardfraction_percentage <= 100);
+ guardfraction_fraction = guardfraction_percentage / 100.0;
+
+ long guard_bw = tor_lround(guardfraction_fraction * orig_bandwidth);
+ tor_assert(guard_bw <= INT_MAX);
+
+ guardfraction_bw->guard_bw = (int) guard_bw;
+
+ guardfraction_bw->non_guard_bw = orig_bandwidth - (int) guard_bw;
+}
+
/** A list of configured bridges. Whenever we actually get a descriptor
* for one, we add it as an entry guard. Note that the order of bridges
* in this list does not necessarily correspond to the order of bridges
@@ -1824,8 +1990,8 @@ bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
/** Return True if we have a bridge that uses a transport with name
* <b>transport_name</b>. */
-int
-transport_is_needed(const char *transport_name)
+MOCK_IMPL(int,
+transport_is_needed, (const char *transport_name))
{
if (!bridge_list)
return 0;
@@ -2199,6 +2365,13 @@ learned_bridge_descriptor(routerinfo_t *ri, int from_cache)
node = node_get_mutable_by_id(ri->cache_info.identity_digest);
tor_assert(node);
rewrite_node_address_for_bridge(bridge, node);
+ if (tor_digest_is_zero(bridge->identity)) {
+ memcpy(bridge->identity,ri->cache_info.identity_digest, DIGEST_LEN);
+ log_notice(LD_DIR, "Learned identity %s for bridge at %s:%d",
+ hex_str(bridge->identity, DIGEST_LEN),
+ fmt_and_decorate_addr(&bridge->addr),
+ (int) bridge->port);
+ }
add_an_entry_guard(node, 1, 1, 0, 0);
log_notice(LD_DIR, "new bridge descriptor '%s' (%s): %s", ri->nickname,
@@ -2255,7 +2428,9 @@ entries_retry_helper(const or_options_t *options, int act)
SMARTLIST_FOREACH_BEGIN(entry_guards, entry_guard_t *, e) {
node = node_get_by_id(e->identity);
if (node && node_has_descriptor(node) &&
- node_is_bridge(node) == need_bridges) {
+ node_is_bridge(node) == need_bridges &&
+ (!need_bridges || (!e->bad_since &&
+ node_is_a_configured_bridge(node)))) {
any_known = 1;
if (node->is_running)
any_running = 1; /* some entry is both known and running */
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index e229f3b79a..107a562506 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -77,6 +77,38 @@ int num_live_entry_guards(int for_directory);
#endif
+#ifdef ENTRYNODES_PRIVATE
+STATIC const node_t *add_an_entry_guard(const node_t *chosen,
+ int reset_status, int prepend,
+ int for_discovery, int for_directory);
+
+STATIC int populate_live_entry_guards(smartlist_t *live_entry_guards,
+ const smartlist_t *all_entry_guards,
+ const node_t *chosen_exit,
+ dirinfo_type_t dirinfo_type,
+ int for_directory,
+ int need_uptime, int need_capacity);
+STATIC int decide_num_guards(const or_options_t *options, int for_directory);
+
+STATIC void entry_guards_set_from_config(const or_options_t *options);
+
+/** Flags to be passed to entry_is_live() to indicate what kind of
+ * entry nodes we are looking for. */
+typedef enum {
+ ENTRY_NEED_UPTIME = 1<<0,
+ ENTRY_NEED_CAPACITY = 1<<1,
+ ENTRY_ASSUME_REACHABLE = 1<<2,
+ ENTRY_NEED_DESCRIPTOR = 1<<3,
+} entry_is_live_flags_t;
+
+STATIC const node_t *entry_is_live(const entry_guard_t *e,
+ entry_is_live_flags_t flags,
+ const char **msg);
+
+STATIC int entry_is_time_to_retry(const entry_guard_t *e, time_t now);
+
+#endif
+
void remove_all_entry_guards(void);
void entry_guards_compute_status(const or_options_t *options, time_t now);
@@ -122,11 +154,27 @@ struct transport_t;
int get_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
const struct transport_t **transport);
-int transport_is_needed(const char *transport_name);
+MOCK_DECL(int, transport_is_needed, (const char *transport_name));
int validate_pluggable_transports_config(void);
double pathbias_get_close_success_count(entry_guard_t *guard);
double pathbias_get_use_success_count(entry_guard_t *guard);
+/** Contains the bandwidth of a relay as a guard and as a non-guard
+ * after the guardfraction has been considered. */
+typedef struct guardfraction_bandwidth_t {
+ /** Bandwidth as a guard after guardfraction has been considered. */
+ int guard_bw;
+ /** Bandwidth as a non-guard after guardfraction has been considered. */
+ int non_guard_bw;
+} guardfraction_bandwidth_t;
+
+int should_apply_guardfraction(const networkstatus_t *ns);
+
+void
+guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw,
+ int orig_bandwidth,
+ uint32_t guardfraction_percentage);
+
#endif
diff --git a/src/or/eventdns_tor.h b/src/or/eventdns_tor.h
index 69662281bc..9d51f0960e 100644
--- a/src/or/eventdns_tor.h
+++ b/src/or/eventdns_tor.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_EVENTDNS_TOR_H
diff --git a/src/or/ext_orport.c b/src/or/ext_orport.c
index 9b550ee90e..e8c8aa60a4 100644
--- a/src/or/ext_orport.c
+++ b/src/or/ext_orport.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/ext_orport.h b/src/or/ext_orport.h
index ce45e5f418..8b2542f937 100644
--- a/src/or/ext_orport.h
+++ b/src/or/ext_orport.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef EXT_ORPORT_H
diff --git a/src/or/fp_pair.c b/src/or/fp_pair.c
index 55e4c89a42..42bebcd847 100644
--- a/src/or/fp_pair.c
+++ b/src/or/fp_pair.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -42,9 +42,9 @@ fp_pair_map_entry_hash(const fp_pair_map_entry_t *a)
HT_PROTOTYPE(fp_pair_map_impl, fp_pair_map_entry_s, node,
fp_pair_map_entry_hash, fp_pair_map_entries_eq)
-HT_GENERATE(fp_pair_map_impl, fp_pair_map_entry_s, node,
- fp_pair_map_entry_hash, fp_pair_map_entries_eq,
- 0.6, tor_malloc, tor_realloc, tor_free)
+HT_GENERATE2(fp_pair_map_impl, fp_pair_map_entry_s, node,
+ fp_pair_map_entry_hash, fp_pair_map_entries_eq,
+ 0.6, tor_reallocarray_, tor_free_)
/** Constructor to create a new empty map from fp_pair_t to void *
*/
diff --git a/src/or/fp_pair.h b/src/or/fp_pair.h
index 89f664a813..0830ab1f36 100644
--- a/src/or/fp_pair.h
+++ b/src/or/fp_pair.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 68db5b9580..82e28b9c1a 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,8 +58,8 @@ static char geoip6_digest[DIGEST_LEN];
/** Return the index of the <b>country</b>'s entry in the GeoIP
* country list if it is a valid 2-letter country code, otherwise
* return -1. */
-country_t
-geoip_get_country(const char *country)
+MOCK_IMPL(country_t,
+geoip_get_country,(const char *country))
{
void *idxplus1_;
intptr_t idx;
@@ -126,7 +126,6 @@ geoip_parse_entry(const char *line, sa_family_t family)
tor_addr_t low_addr, high_addr;
char c[3];
char *country = NULL;
- char buf[512];
if (!geoip_countries)
init_geoip_countries();
@@ -146,6 +145,7 @@ geoip_parse_entry(const char *line, sa_family_t family)
if (*line == '#')
return 0;
+ char buf[512];
if (family == AF_INET) {
unsigned int low, high;
if (tor_sscanf(line,"%u,%u,%2s", &low, &high, c) == 3 ||
@@ -396,8 +396,8 @@ geoip_get_country_by_ipv6(const struct in6_addr *addr)
* the 'unknown country'. The return value will always be less than
* geoip_get_n_countries(). To decode it, call geoip_get_country_name().
*/
-int
-geoip_get_country_by_addr(const tor_addr_t *addr)
+MOCK_IMPL(int,
+geoip_get_country_by_addr,(const tor_addr_t *addr))
{
if (tor_addr_family(addr) == AF_INET) {
return geoip_get_country_by_ipv4(tor_addr_to_ipv4h(addr));
@@ -409,8 +409,8 @@ geoip_get_country_by_addr(const tor_addr_t *addr)
}
/** Return the number of countries recognized by the GeoIP country list. */
-int
-geoip_get_n_countries(void)
+MOCK_IMPL(int,
+geoip_get_n_countries,(void))
{
if (!geoip_countries)
init_geoip_countries();
@@ -430,8 +430,8 @@ geoip_get_country_name(country_t num)
}
/** Return true iff we have loaded a GeoIP database.*/
-int
-geoip_is_loaded(sa_family_t family)
+MOCK_IMPL(int,
+geoip_is_loaded,(sa_family_t family))
{
tor_assert(family == AF_INET || family == AF_INET6);
if (geoip_countries == NULL)
@@ -506,8 +506,8 @@ clientmap_entries_eq(const clientmap_entry_t *a, const clientmap_entry_t *b)
HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
clientmap_entries_eq);
-HT_GENERATE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
- clientmap_entries_eq, 0.6, malloc, realloc, free);
+HT_GENERATE2(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
+ clientmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
/** Free all storage held by <b>ent</b>. */
static void
@@ -720,8 +720,8 @@ dirreq_map_ent_hash(const dirreq_map_entry_t *entry)
HT_PROTOTYPE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash,
dirreq_map_ent_eq);
-HT_GENERATE(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash,
- dirreq_map_ent_eq, 0.6, malloc, realloc, free);
+HT_GENERATE2(dirreqmap, dirreq_map_entry_t, node, dirreq_map_ent_hash,
+ dirreq_map_ent_eq, 0.6, tor_reallocarray_, tor_free_)
/** Helper: Put <b>entry</b> into map of directory requests using
* <b>type</b> and <b>dirreq_id</b> as key parts. If there is
@@ -963,7 +963,7 @@ geoip_get_dirreq_history(dirreq_type_t type)
/* We may have rounded 'completed' up. Here we want to use the
* real value. */
complete = smartlist_len(dirreq_completed);
- dltimes = tor_malloc_zero(sizeof(uint32_t) * complete);
+ dltimes = tor_calloc(complete, sizeof(uint32_t));
SMARTLIST_FOREACH_BEGIN(dirreq_completed, dirreq_map_entry_t *, ent) {
uint32_t bytes_per_second;
uint32_t time_diff = (uint32_t) tv_mdiff(&ent->request_time,
@@ -1033,7 +1033,7 @@ geoip_get_client_history(geoip_client_action_t action,
if (!geoip_is_loaded(AF_INET) && !geoip_is_loaded(AF_INET6))
return -1;
- counts = tor_malloc_zero(sizeof(unsigned)*n_countries);
+ counts = tor_calloc(n_countries, sizeof(unsigned));
HT_FOREACH(ent, clientmap, &client_history) {
int country;
if ((*ent)->action != (int)action)
@@ -1436,6 +1436,39 @@ format_bridge_stats_controller(time_t now)
return out;
}
+/** Return a newly allocated string holding our bridge usage stats by
+ * country in a format suitable for inclusion in our heartbeat
+ * message. Return NULL on failure. */
+char *
+format_client_stats_heartbeat(time_t now)
+{
+ const int n_hours = 6;
+ char *out = NULL;
+ int n_clients = 0;
+ clientmap_entry_t **ent;
+ unsigned cutoff = (unsigned)( (now-n_hours*3600)/60 );
+
+ if (!start_of_bridge_stats_interval)
+ return NULL; /* Not initialized. */
+
+ /* count unique IPs */
+ HT_FOREACH(ent, clientmap, &client_history) {
+ /* only count directly connecting clients */
+ if ((*ent)->action != GEOIP_CLIENT_CONNECT)
+ continue;
+ if ((*ent)->last_seen_in_minutes < cutoff)
+ continue;
+ n_clients++;
+ }
+
+ tor_asprintf(&out, "Heartbeat: "
+ "In the last %d hours, I have seen %d unique clients.",
+ n_hours,
+ n_clients);
+
+ return out;
+}
+
/** Write bridge statistics to $DATADIR/stats/bridge-stats and return
* when we should next try to write statistics. */
time_t
diff --git a/src/or/geoip.h b/src/or/geoip.h
index b9b53c3006..8a3486c7ac 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -21,12 +21,12 @@ STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr);
#endif
int should_record_bridge_info(const or_options_t *options);
int geoip_load_file(sa_family_t family, const char *filename);
-int geoip_get_country_by_addr(const tor_addr_t *addr);
-int geoip_get_n_countries(void);
+MOCK_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+MOCK_DECL(int, geoip_get_n_countries, (void));
const char *geoip_get_country_name(country_t num);
-int geoip_is_loaded(sa_family_t family);
+MOCK_DECL(int, geoip_is_loaded, (sa_family_t family));
const char *geoip_db_digest(sa_family_t family);
-country_t geoip_get_country(const char *countrycode);
+MOCK_DECL(country_t, geoip_get_country, (const char *countrycode));
void geoip_note_client_seen(geoip_client_action_t action,
const tor_addr_t *addr, const char *transport_name,
@@ -64,6 +64,7 @@ time_t geoip_bridge_stats_write(time_t now);
void geoip_bridge_stats_term(void);
const char *geoip_get_bridge_stats_extrainfo(time_t);
char *geoip_get_bridge_stats_controller(time_t);
+char *format_client_stats_heartbeat(time_t now);
#endif
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index c433ac1be9..356e11f6ec 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -410,6 +410,17 @@ configure_accounting(time_t now)
accounting_set_wakeup_time();
}
+/** Return the relevant number of bytes sent/received this interval
+ * based on the set AccountingRule */
+static uint64_t
+get_accounting_bytes(void)
+{
+ if (get_options()->AccountingRule == ACCT_SUM)
+ return n_bytes_read_in_interval+n_bytes_written_in_interval;
+ else
+ return MAX(n_bytes_read_in_interval, n_bytes_written_in_interval);
+}
+
/** Set expected_bandwidth_usage based on how much we sent/received
* per minute last interval (if we were up for at least 30 minutes),
* or based on our declared bandwidth otherwise. */
@@ -421,6 +432,11 @@ update_expected_bandwidth(void)
uint64_t max_configured = (options->RelayBandwidthRate > 0 ?
options->RelayBandwidthRate :
options->BandwidthRate) * 60;
+ /* max_configured is the larger of bytes read and bytes written
+ * If we are accounting based on sum, worst case is both are
+ * at max, doubling the expected sum of bandwidth */
+ if (get_options()->AccountingRule == ACCT_SUM)
+ max_configured *= 2;
#define MIN_TIME_FOR_MEASUREMENT (1800)
@@ -439,8 +455,7 @@ update_expected_bandwidth(void)
* doesn't know to store soft-limit info. Just take rate at which
* we were reading/writing in the last interval as our expected rate.
*/
- uint64_t used = MAX(n_bytes_written_in_interval,
- n_bytes_read_in_interval);
+ uint64_t used = get_accounting_bytes();
expected = used / (n_seconds_active_in_interval / 60);
} else {
/* If we haven't gotten enough data last interval, set 'expected'
@@ -715,8 +730,7 @@ hibernate_hard_limit_reached(void)
uint64_t hard_limit = get_options()->AccountingMax;
if (!hard_limit)
return 0;
- return n_bytes_read_in_interval >= hard_limit
- || n_bytes_written_in_interval >= hard_limit;
+ return get_accounting_bytes() >= hard_limit;
}
/** Return true iff we have sent/received almost all the bytes we are willing
@@ -747,8 +761,7 @@ hibernate_soft_limit_reached(void)
if (!soft_limit)
return 0;
- return n_bytes_read_in_interval >= soft_limit
- || n_bytes_written_in_interval >= soft_limit;
+ return get_accounting_bytes() >= soft_limit;
}
/** Called when we get a SIGINT, or when bandwidth soft limit is
@@ -772,8 +785,7 @@ hibernate_begin(hibernate_state_t new_state, time_t now)
hibernate_state == HIBERNATE_STATE_LIVE) {
soft_limit_hit_at = now;
n_seconds_to_hit_soft_limit = n_seconds_active_in_interval;
- n_bytes_at_soft_limit = MAX(n_bytes_read_in_interval,
- n_bytes_written_in_interval);
+ n_bytes_at_soft_limit = get_accounting_bytes();
}
/* close listeners. leave control listener(s). */
@@ -1003,13 +1015,22 @@ getinfo_helper_accounting(control_connection_t *conn,
U64_PRINTF_ARG(n_bytes_written_in_interval));
} else if (!strcmp(question, "accounting/bytes-left")) {
uint64_t limit = get_options()->AccountingMax;
- uint64_t read_left = 0, write_left = 0;
- if (n_bytes_read_in_interval < limit)
- read_left = limit - n_bytes_read_in_interval;
- if (n_bytes_written_in_interval < limit)
- write_left = limit - n_bytes_written_in_interval;
- tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
- U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left));
+ if (get_options()->AccountingRule == ACCT_SUM) {
+ uint64_t total_left = 0;
+ uint64_t total_bytes = get_accounting_bytes();
+ if (total_bytes < limit)
+ total_left = limit - total_bytes;
+ tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
+ U64_PRINTF_ARG(total_left), U64_PRINTF_ARG(total_left));
+ } else {
+ uint64_t read_left = 0, write_left = 0;
+ if (n_bytes_read_in_interval < limit)
+ read_left = limit - n_bytes_read_in_interval;
+ if (n_bytes_written_in_interval < limit)
+ write_left = limit - n_bytes_written_in_interval;
+ tor_asprintf(answer, U64_FORMAT" "U64_FORMAT,
+ U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left));
+ }
} else if (!strcmp(question, "accounting/interval-start")) {
*answer = tor_malloc(ISO_TIME_LEN+1);
format_iso_time(*answer, interval_start_time);
diff --git a/src/or/hibernate.h b/src/or/hibernate.h
index 38ecb75129..b9e619c5ad 100644
--- a/src/or/hibernate.h
+++ b/src/or/hibernate.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,6 +28,7 @@ void consider_hibernation(time_t now);
int getinfo_helper_accounting(control_connection_t *conn,
const char *question, char **answer,
const char **errmsg);
+uint64_t get_accounting_max_total(void);
#ifdef HIBERNATE_PRIVATE
/** Possible values of hibernate_state */
diff --git a/src/or/include.am b/src/or/include.am
index 47bdd09901..b44e1099dc 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -23,12 +23,6 @@ else
evdns_source=src/ext/eventdns.c
endif
-if CURVE25519_ENABLED
-onion_ntor_source=src/or/onion_ntor.c
-else
-onion_ntor_source=
-endif
-
LIBTOR_A_SOURCES = \
src/or/addressmap.c \
src/or/buffers.c \
@@ -80,11 +74,12 @@ LIBTOR_A_SOURCES = \
src/or/routerlist.c \
src/or/routerparse.c \
src/or/routerset.c \
+ src/or/scheduler.c \
src/or/statefile.c \
src/or/status.c \
+ src/or/onion_ntor.c \
$(evdns_source) \
$(tor_platform_source) \
- $(onion_ntor_source) \
src/or/config_codedigest.c
src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES)
@@ -116,7 +111,7 @@ src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \
src/common/libor-crypto.a $(LIBDONNA) \
src/common/libor-event.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@
if COVERAGE_ENABLED
src_or_tor_cov_SOURCES = src/or/tor_main.c
@@ -127,7 +122,10 @@ src_or_tor_cov_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
src/common/libor-crypto-testing.a $(LIBDONNA) \
src/common/libor-event-testing.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
- @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@
+TESTING_TOR_BINARY = ./src/or/tor-cov
+else
+TESTING_TOR_BINARY = ./src/or/tor
endif
ORHEADERS = \
@@ -185,6 +183,7 @@ ORHEADERS = \
src/or/routerlist.h \
src/or/routerset.h \
src/or/routerparse.h \
+ src/or/scheduler.h \
src/or/statefile.h \
src/or/status.h
diff --git a/src/or/main.c b/src/or/main.c
index 31fbdcd433..8badd7d382 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,6 +28,7 @@
#include "connection_or.h"
#include "control.h"
#include "cpuworker.h"
+#include "crypto_s2k.h"
#include "directory.h"
#include "dirserv.h"
#include "dirvote.h"
@@ -52,6 +53,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "scheduler.h"
#include "statefile.h"
#include "status.h"
#include "util_process.h"
@@ -73,6 +75,16 @@
#include <event2/bufferevent.h>
#endif
+#ifdef HAVE_SYSTEMD
+# if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__)
+/* Systemd's use of gcc's __INCLUDE_LEVEL__ extension macro appears to confuse
+ * Coverity. Here's a kludge to unconfuse it.
+ */
+# define __INCLUDE_LEVEL__ 2
+# endif
+#include <systemd/sd-daemon.h>
+#endif
+
void evdns_shutdown(int);
/********* PROTOTYPES **********/
@@ -85,6 +97,7 @@ static void second_elapsed_callback(periodic_timer_t *timer, void *args);
static int conn_close_if_marked(int i);
static void connection_start_reading_from_linked_conn(connection_t *conn);
static int connection_should_read_from_linked_conn(connection_t *conn);
+static int run_main_loop_until_done(void);
/********* START VARIABLES **********/
@@ -149,7 +162,7 @@ static int called_loop_once = 0;
* any longer (a big time jump happened, when we notice our directory is
* heinously out-of-date, etc.
*/
-int can_complete_circuit=0;
+static int can_complete_circuits = 0;
/** How often do we check for router descriptors that we should download
* when we have too little directory info? */
@@ -170,11 +183,11 @@ int quiet_level = 0;
/********* END VARIABLES ************/
/****************************************************************************
-*
-* This section contains accessors and other methods on the connection_array
-* variables (which are global within this file and unavailable outside it).
-*
-****************************************************************************/
+ *
+ * This section contains accessors and other methods on the connection_array
+ * variables (which are global within this file and unavailable outside it).
+ *
+ ****************************************************************************/
#if 0 && defined(USE_BUFFEREVENTS)
static void
@@ -222,6 +235,31 @@ set_buffer_lengths_to_zero(tor_socket_t s)
}
#endif
+/** Return 1 if we have successfully built a circuit, and nothing has changed
+ * to make us think that maybe we can't.
+ */
+int
+have_completed_a_circuit(void)
+{
+ return can_complete_circuits;
+}
+
+/** Note that we have successfully built a circuit, so that reachability
+ * testing and introduction points and so on may be attempted. */
+void
+note_that_we_completed_a_circuit(void)
+{
+ can_complete_circuits = 1;
+}
+
+/** Note that something has happened (like a clock jump, or DisableNetwork) to
+ * make us think that maybe we can't complete circuits. */
+void
+note_that_we_maybe_cant_complete_circuits(void)
+{
+ can_complete_circuits = 0;
+}
+
/** Add <b>conn</b> to the array of connections that we can poll on. The
* connection's socket must be set; the connection starts out
* non-reading and non-writing.
@@ -354,6 +392,10 @@ connection_remove(connection_t *conn)
(int)conn->s, conn_type_to_string(conn->type),
smartlist_len(connection_array));
+ if (conn->type == CONN_TYPE_AP && conn->socket_family == AF_UNIX) {
+ log_info(LD_NET, "Closing SOCKS SocksSocket connection");
+ }
+
control_event_conn_bandwidth(conn);
tor_assert(conn->conn_array_index >= 0);
@@ -1045,7 +1087,7 @@ directory_info_has_arrived(time_t now, int from_cache)
}
if (server_mode(options) && !net_is_disabled() && !from_cache &&
- (can_complete_circuit || !any_predicted_circuits(now)))
+ (have_completed_a_circuit() || !any_predicted_circuits(now)))
consider_testing_reachability(1, 1);
}
@@ -1229,7 +1271,6 @@ run_scheduled_events(time_t now)
static time_t time_to_check_v3_certificate = 0;
static time_t time_to_check_listeners = 0;
static time_t time_to_download_networkstatus = 0;
- static time_t time_to_shrink_memory = 0;
static time_t time_to_try_getting_descriptors = 0;
static time_t time_to_reset_descriptor_failures = 0;
static time_t time_to_add_entropy = 0;
@@ -1277,7 +1318,7 @@ run_scheduled_events(time_t now)
get_onion_key_set_at()+MIN_ONION_KEY_LIFETIME < now) {
log_info(LD_GENERAL,"Rotating onion key.");
rotate_onion_key();
- cpuworkers_rotate();
+ cpuworkers_rotate_keyinfo();
if (router_rebuild_descriptor(1)<0) {
log_info(LD_CONFIG, "Couldn't rebuild router descriptor");
}
@@ -1404,6 +1445,11 @@ run_scheduled_events(time_t now)
if (next_write && next_write < next_time_to_write_stats_files)
next_time_to_write_stats_files = next_write;
}
+ if (options->HiddenServiceStatistics) {
+ time_t next_write = rep_hist_hs_stats_write(time_to_write_stats_files);
+ if (next_write && next_write < next_time_to_write_stats_files)
+ next_time_to_write_stats_files = next_write;
+ }
if (options->ExitPortStatistics) {
time_t next_write = rep_hist_exit_stats_write(time_to_write_stats_files);
if (next_write && next_write < next_time_to_write_stats_files)
@@ -1448,7 +1494,7 @@ run_scheduled_events(time_t now)
if (time_to_clean_caches < now) {
rep_history_clean(now - options->RephistTrackTime);
rend_cache_clean(now);
- rend_cache_clean_v2_descs_as_dir(now);
+ rend_cache_clean_v2_descs_as_dir(now, 0);
microdesc_cache_rebuild(NULL, 0);
#define CLEAN_CACHES_INTERVAL (30*60)
time_to_clean_caches = now + CLEAN_CACHES_INTERVAL;
@@ -1482,7 +1528,7 @@ run_scheduled_events(time_t now)
/* also, check religiously for reachability, if it's within the first
* 20 minutes of our uptime. */
if (is_server &&
- (can_complete_circuit || !any_predicted_circuits(now)) &&
+ (have_completed_a_circuit() || !any_predicted_circuits(now)) &&
!we_are_hibernating()) {
if (stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
consider_testing_reachability(1, dirport_reachability_count==0);
@@ -1574,28 +1620,12 @@ run_scheduled_events(time_t now)
for (i=0;i<smartlist_len(connection_array);i++) {
run_connection_housekeeping(i, now);
}
- if (time_to_shrink_memory < now) {
- SMARTLIST_FOREACH(connection_array, connection_t *, conn, {
- if (conn->outbuf)
- buf_shrink(conn->outbuf);
- if (conn->inbuf)
- buf_shrink(conn->inbuf);
- });
-#ifdef ENABLE_MEMPOOL
- clean_cell_pool();
-#endif /* ENABLE_MEMPOOL */
- buf_shrink_freelists(0);
-/** How often do we check buffers and pools for empty space that can be
- * deallocated? */
-#define MEM_SHRINK_INTERVAL (60)
- time_to_shrink_memory = now + MEM_SHRINK_INTERVAL;
- }
/* 6. And remove any marked circuits... */
circuit_close_all_marked();
/* 7. And upload service descriptors if necessary. */
- if (can_complete_circuit && !net_is_disabled()) {
+ if (have_completed_a_circuit() && !net_is_disabled()) {
rend_consider_services_upload(now);
rend_consider_descriptor_republication();
}
@@ -1726,7 +1756,7 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
if (server_mode(options) &&
!net_is_disabled() &&
seconds_elapsed > 0 &&
- can_complete_circuit &&
+ have_completed_a_circuit() &&
stats_n_seconds_working / TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT !=
(stats_n_seconds_working+seconds_elapsed) /
TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
@@ -1774,6 +1804,19 @@ second_elapsed_callback(periodic_timer_t *timer, void *arg)
current_second = now; /* remember which second it is, for next time */
}
+#ifdef HAVE_SYSTEMD_209
+static periodic_timer_t *systemd_watchdog_timer = NULL;
+
+/** Libevent callback: invoked to reset systemd watchdog. */
+static void
+systemd_watchdog_callback(periodic_timer_t *timer, void *arg)
+{
+ (void)timer;
+ (void)arg;
+ sd_notify(0, "WATCHDOG=1");
+}
+#endif
+
#ifndef USE_BUFFEREVENTS
/** Timer: used to invoke refill_callback(). */
static periodic_timer_t *refill_timer = NULL;
@@ -1908,6 +1951,10 @@ do_hup(void)
return -1;
}
options = get_options(); /* they have changed now */
+ /* Logs are only truncated the first time they are opened, but were
+ probably intended to be cleaned up on signal. */
+ if (options->TruncateLogFile)
+ truncate_logs();
} else {
char *msg = NULL;
log_notice(LD_GENERAL, "Not reloading config file: the controller told "
@@ -1944,9 +1991,9 @@ do_hup(void)
* force a retry there. */
if (server_mode(options)) {
- /* Restart cpuworker and dnsworker processes, so they get up-to-date
+ /* Update cpuworker and dnsworker processes, so they get up-to-date
* configuration options. */
- cpuworkers_rotate();
+ cpuworkers_rotate_keyinfo();
dns_reset();
}
return 0;
@@ -1956,7 +2003,6 @@ do_hup(void)
int
do_main_loop(void)
{
- int loop_result;
time_t now;
/* initialize dns resolve map, spawn workers if needed */
@@ -1988,11 +2034,6 @@ do_main_loop(void)
}
}
-#ifdef ENABLE_MEMPOOLS
- /* Set up the packed_cell_t memory pool. */
- init_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
-
/* Set up our buckets */
connection_bucket_init();
#ifndef USE_BUFFEREVENTS
@@ -2038,6 +2079,28 @@ do_main_loop(void)
tor_assert(second_timer);
}
+#ifdef HAVE_SYSTEMD_209
+ uint64_t watchdog_delay;
+ /* set up systemd watchdog notification. */
+ if (sd_watchdog_enabled(1, &watchdog_delay) > 0) {
+ if (! systemd_watchdog_timer) {
+ struct timeval watchdog;
+ /* The manager will "act on" us if we don't send them a notification
+ * every 'watchdog_delay' microseconds. So, send notifications twice
+ * that often. */
+ watchdog_delay /= 2;
+ watchdog.tv_sec = watchdog_delay / 1000000;
+ watchdog.tv_usec = watchdog_delay % 1000000;
+
+ systemd_watchdog_timer = periodic_timer_new(tor_libevent_get_base(),
+ &watchdog,
+ systemd_watchdog_callback,
+ NULL);
+ tor_assert(systemd_watchdog_timer);
+ }
+ }
+#endif
+
#ifndef USE_BUFFEREVENTS
if (!refill_timer) {
struct timeval refill_interval;
@@ -2054,51 +2117,92 @@ do_main_loop(void)
}
#endif
- for (;;) {
- if (nt_service_is_stopping())
- return 0;
+#ifdef HAVE_SYSTEMD
+ {
+ const int r = sd_notify(0, "READY=1");
+ if (r < 0) {
+ log_warn(LD_GENERAL, "Unable to send readiness to systemd: %s",
+ strerror(r));
+ } else if (r > 0) {
+ log_notice(LD_GENERAL, "Signaled readiness to systemd");
+ } else {
+ log_info(LD_GENERAL, "Systemd NOTIFY_SOCKET not present.");
+ }
+ }
+#endif
+
+ return run_main_loop_until_done();
+}
+
+/**
+ * Run the main loop a single time. Return 0 for "exit"; -1 for "exit with
+ * error", and 1 for "run this again."
+ */
+static int
+run_main_loop_once(void)
+{
+ int loop_result;
+
+ if (nt_service_is_stopping())
+ return 0;
#ifndef _WIN32
- /* Make it easier to tell whether libevent failure is our fault or not. */
- errno = 0;
+ /* Make it easier to tell whether libevent failure is our fault or not. */
+ errno = 0;
#endif
- /* All active linked conns should get their read events activated. */
- SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn,
- event_active(conn->read_event, EV_READ, 1));
- called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0;
-
- update_approx_time(time(NULL));
-
- /* poll until we have an event, or the second ends, or until we have
- * some active linked connections to trigger events for. */
- loop_result = event_base_loop(tor_libevent_get_base(),
- called_loop_once ? EVLOOP_ONCE : 0);
-
- /* let catch() handle things like ^c, and otherwise don't worry about it */
- if (loop_result < 0) {
- int e = tor_socket_errno(-1);
- /* let the program survive things like ^z */
- if (e != EINTR && !ERRNO_IS_EINPROGRESS(e)) {
- log_err(LD_NET,"libevent call with %s failed: %s [%d]",
- tor_libevent_get_method(), tor_socket_strerror(e), e);
- return -1;
+ /* All active linked conns should get their read events activated. */
+ SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn,
+ event_active(conn->read_event, EV_READ, 1));
+ called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0;
+
+ update_approx_time(time(NULL));
+
+ /* poll until we have an event, or the second ends, or until we have
+ * some active linked connections to trigger events for. */
+ loop_result = event_base_loop(tor_libevent_get_base(),
+ called_loop_once ? EVLOOP_ONCE : 0);
+
+ /* let catch() handle things like ^c, and otherwise don't worry about it */
+ if (loop_result < 0) {
+ int e = tor_socket_errno(-1);
+ /* let the program survive things like ^z */
+ if (e != EINTR && !ERRNO_IS_EINPROGRESS(e)) {
+ log_err(LD_NET,"libevent call with %s failed: %s [%d]",
+ tor_libevent_get_method(), tor_socket_strerror(e), e);
+ return -1;
#ifndef _WIN32
- } else if (e == EINVAL) {
- log_warn(LD_NET, "EINVAL from libevent: should you upgrade libevent?");
- if (got_libevent_error())
- return -1;
+ } else if (e == EINVAL) {
+ log_warn(LD_NET, "EINVAL from libevent: should you upgrade libevent?");
+ if (got_libevent_error())
+ return -1;
#endif
- } else {
- if (ERRNO_IS_EINPROGRESS(e))
- log_warn(LD_BUG,
- "libevent call returned EINPROGRESS? Please report.");
- log_debug(LD_NET,"libevent call interrupted.");
- /* You can't trust the results of this poll(). Go back to the
- * top of the big for loop. */
- continue;
- }
+ } else {
+ if (ERRNO_IS_EINPROGRESS(e))
+ log_warn(LD_BUG,
+ "libevent call returned EINPROGRESS? Please report.");
+ log_debug(LD_NET,"libevent call interrupted.");
+ /* You can't trust the results of this poll(). Go back to the
+ * top of the big for loop. */
+ return 1;
}
}
+
+ return 1;
+}
+
+/** Run the run_main_loop_once() function until it declares itself done,
+ * and return its final return value.
+ *
+ * Shadow won't invoke this function, so don't fill it up with things.
+ */
+static int
+run_main_loop_until_done(void)
+{
+ int loop_result = 1;
+ do {
+ loop_result = run_main_loop_once();
+ } while (loop_result == 1);
+ return loop_result;
}
#ifndef _WIN32 /* Only called when we're willing to use signals */
@@ -2132,6 +2236,9 @@ process_signal(uintptr_t sig)
tor_cleanup();
exit(0);
}
+#ifdef HAVE_SYSTEMD
+ sd_notify(0, "STOPPING=1");
+#endif
hibernate_begin_shutdown();
break;
#ifdef SIGPIPE
@@ -2151,11 +2258,17 @@ process_signal(uintptr_t sig)
control_event_signal(sig);
break;
case SIGHUP:
+#ifdef HAVE_SYSTEMD
+ sd_notify(0, "RELOADING=1");
+#endif
if (do_hup() < 0) {
log_warn(LD_CONFIG,"Restart failed (config error?). Exiting.");
tor_cleanup();
exit(1);
}
+#ifdef HAVE_SYSTEMD
+ sd_notify(0, "READY=1");
+#endif
control_event_signal(sig);
break;
#ifdef SIGCHLD
@@ -2179,6 +2292,10 @@ process_signal(uintptr_t sig)
addressmap_clear_transient();
control_event_signal(sig);
break;
+ case SIGHEARTBEAT:
+ log_heartbeat(time(NULL));
+ control_event_signal(sig);
+ break;
}
}
@@ -2204,7 +2321,6 @@ dumpmemusage(int severity)
dump_routerlist_mem_usage(severity);
dump_cell_pool_usage(severity);
dump_dns_mem_usage(severity);
- buf_dump_freelist_sizes(severity);
tor_log_mallinfo(severity);
}
@@ -2595,7 +2711,7 @@ tor_free_all(int postfork)
channel_tls_free_all();
channel_free_all();
connection_free_all();
- buf_shrink_freelists(1);
+ scheduler_free_all();
memarea_clear_freelist();
nodelist_free_all();
microdesc_free_all();
@@ -2608,9 +2724,6 @@ tor_free_all(int postfork)
router_free_all();
policies_free_all();
}
-#ifdef ENABLE_MEMPOOLS
- free_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
if (!postfork) {
tor_tls_free_all();
#ifndef _WIN32
@@ -2717,11 +2830,11 @@ do_hash_password(void)
{
char output[256];
- char key[S2K_SPECIFIER_LEN+DIGEST_LEN];
+ char key[S2K_RFC2440_SPECIFIER_LEN+DIGEST_LEN];
- crypto_rand(key, S2K_SPECIFIER_LEN-1);
- key[S2K_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */
- secret_to_key(key+S2K_SPECIFIER_LEN, DIGEST_LEN,
+ crypto_rand(key, S2K_RFC2440_SPECIFIER_LEN-1);
+ key[S2K_RFC2440_SPECIFIER_LEN-1] = (uint8_t)96; /* Hash 64 K of data. */
+ secret_to_key_rfc2440(key+S2K_RFC2440_SPECIFIER_LEN, DIGEST_LEN,
get_options()->command_arg, strlen(get_options()->command_arg),
key);
base16_encode(output, sizeof(output), key, sizeof(key));
@@ -2756,31 +2869,6 @@ do_dump_config(void)
return 0;
}
-#if defined (WINCE)
-int
-find_flashcard_path(PWCHAR path, size_t size)
-{
- WIN32_FIND_DATA d = {0};
- HANDLE h = NULL;
-
- if (!path)
- return -1;
-
- h = FindFirstFlashCard(&d);
- if (h == INVALID_HANDLE_VALUE)
- return -1;
-
- if (wcslen(d.cFileName) == 0) {
- FindClose(h);
- return -1;
- }
-
- wcsncpy(path,d.cFileName,size);
- FindClose(h);
- return 0;
-}
-#endif
-
static void
init_addrinfo(void)
{
@@ -2801,43 +2889,47 @@ sandbox_init_filter(void)
sandbox_cfg_allow_openat_filename(&cfg,
get_datadir_fname("cached-status"));
- sandbox_cfg_allow_open_filename_array(&cfg,
- get_datadir_fname("cached-certs"),
- get_datadir_fname("cached-certs.tmp"),
- get_datadir_fname("cached-consensus"),
- get_datadir_fname("cached-consensus.tmp"),
- get_datadir_fname("unverified-consensus"),
- get_datadir_fname("unverified-consensus.tmp"),
- get_datadir_fname("unverified-microdesc-consensus"),
- get_datadir_fname("unverified-microdesc-consensus.tmp"),
- get_datadir_fname("cached-microdesc-consensus"),
- get_datadir_fname("cached-microdesc-consensus.tmp"),
- get_datadir_fname("cached-microdescs"),
- get_datadir_fname("cached-microdescs.tmp"),
- get_datadir_fname("cached-microdescs.new"),
- get_datadir_fname("cached-microdescs.new.tmp"),
- get_datadir_fname("cached-descriptors"),
- get_datadir_fname("cached-descriptors.new"),
- get_datadir_fname("cached-descriptors.tmp"),
- get_datadir_fname("cached-descriptors.new.tmp"),
- get_datadir_fname("cached-descriptors.tmp.tmp"),
- get_datadir_fname("cached-extrainfo"),
- get_datadir_fname("cached-extrainfo.new"),
- get_datadir_fname("cached-extrainfo.tmp"),
- get_datadir_fname("cached-extrainfo.new.tmp"),
- get_datadir_fname("cached-extrainfo.tmp.tmp"),
- get_datadir_fname("state.tmp"),
- get_datadir_fname("unparseable-desc.tmp"),
- get_datadir_fname("unparseable-desc"),
- get_datadir_fname("v3-status-votes"),
- get_datadir_fname("v3-status-votes.tmp"),
- tor_strdup("/dev/srandom"),
- tor_strdup("/dev/urandom"),
- tor_strdup("/dev/random"),
- tor_strdup("/etc/hosts"),
- tor_strdup("/proc/meminfo"),
- NULL, 0
- );
+#define OPEN(name) \
+ sandbox_cfg_allow_open_filename(&cfg, tor_strdup(name))
+
+#define OPEN_DATADIR(name) \
+ sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname(name))
+
+#define OPEN_DATADIR2(name, name2) \
+ sandbox_cfg_allow_open_filename(&cfg, get_datadir_fname2((name), (name2)))
+
+#define OPEN_DATADIR_SUFFIX(name, suffix) do { \
+ OPEN_DATADIR(name); \
+ OPEN_DATADIR(name suffix); \
+ } while (0)
+
+#define OPEN_DATADIR2_SUFFIX(name, name2, suffix) do { \
+ OPEN_DATADIR2(name, name2); \
+ OPEN_DATADIR2(name, name2 suffix); \
+ } while (0)
+
+ OPEN_DATADIR_SUFFIX("cached-certs", ".tmp");
+ OPEN_DATADIR_SUFFIX("cached-consensus", ".tmp");
+ OPEN_DATADIR_SUFFIX("unverified-consensus", ".tmp");
+ OPEN_DATADIR_SUFFIX("unverified-microdesc-consensus", ".tmp");
+ OPEN_DATADIR_SUFFIX("cached-microdesc-consensus", ".tmp");
+ OPEN_DATADIR_SUFFIX("cached-microdescs", ".tmp");
+ OPEN_DATADIR_SUFFIX("cached-microdescs.new", ".tmp");
+ OPEN_DATADIR_SUFFIX("cached-descriptors", ".tmp");
+ OPEN_DATADIR_SUFFIX("cached-descriptors.new", ".tmp");
+ OPEN_DATADIR("cached-descriptors.tmp.tmp");
+ OPEN_DATADIR_SUFFIX("cached-extrainfo", ".tmp");
+ OPEN_DATADIR_SUFFIX("cached-extrainfo.new", ".tmp");
+ OPEN_DATADIR("cached-extrainfo.tmp.tmp");
+ OPEN_DATADIR_SUFFIX("state", ".tmp");
+ OPEN_DATADIR_SUFFIX("unparseable-desc", ".tmp");
+ OPEN_DATADIR_SUFFIX("v3-status-votes", ".tmp");
+ OPEN("/dev/srandom");
+ OPEN("/dev/urandom");
+ OPEN("/dev/random");
+ OPEN("/etc/hosts");
+ OPEN("/proc/meminfo");
+
if (options->ServerDNSResolvConfFile)
sandbox_cfg_allow_open_filename(&cfg,
tor_strdup(options->ServerDNSResolvConfFile));
@@ -2878,14 +2970,17 @@ sandbox_init_filter(void)
RENAME_SUFFIX("unparseable-desc", ".tmp");
RENAME_SUFFIX("v3-status-votes", ".tmp");
- sandbox_cfg_allow_stat_filename_array(&cfg,
- get_datadir_fname(NULL),
- get_datadir_fname("lock"),
- get_datadir_fname("state"),
- get_datadir_fname("router-stability"),
- get_datadir_fname("cached-extrainfo.new"),
- NULL, 0
- );
+#define STAT_DATADIR(name) \
+ sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname(name))
+
+#define STAT_DATADIR2(name, name2) \
+ sandbox_cfg_allow_stat_filename(&cfg, get_datadir_fname2((name), (name2)))
+
+ STAT_DATADIR(NULL);
+ STAT_DATADIR("lock");
+ STAT_DATADIR("state");
+ STAT_DATADIR("router-stability");
+ STAT_DATADIR("cached-extrainfo.new");
{
smartlist_t *files = smartlist_new();
@@ -2907,7 +3002,8 @@ sandbox_init_filter(void)
sandbox_cfg_allow_rename(&cfg,
tor_strdup(tmp_name), tor_strdup(file_name));
/* steals references */
- sandbox_cfg_allow_open_filename_array(&cfg, file_name, tmp_name, NULL);
+ sandbox_cfg_allow_open_filename(&cfg, file_name);
+ sandbox_cfg_allow_open_filename(&cfg, tmp_name);
});
SMARTLIST_FOREACH(dirs, char *, dir, {
/* steals reference */
@@ -2934,38 +3030,28 @@ sandbox_init_filter(void)
// orport
if (server_mode(get_options())) {
- sandbox_cfg_allow_open_filename_array(&cfg,
- get_datadir_fname2("keys", "secret_id_key"),
- get_datadir_fname2("keys", "secret_onion_key"),
- get_datadir_fname2("keys", "secret_onion_key_ntor"),
- get_datadir_fname2("keys", "secret_onion_key_ntor.tmp"),
- get_datadir_fname2("keys", "secret_id_key.old"),
- get_datadir_fname2("keys", "secret_onion_key.old"),
- get_datadir_fname2("keys", "secret_onion_key_ntor.old"),
- get_datadir_fname2("keys", "secret_onion_key.tmp"),
- get_datadir_fname2("keys", "secret_id_key.tmp"),
- get_datadir_fname2("stats", "bridge-stats"),
- get_datadir_fname2("stats", "bridge-stats.tmp"),
- get_datadir_fname2("stats", "dirreq-stats"),
- get_datadir_fname2("stats", "dirreq-stats.tmp"),
- get_datadir_fname2("stats", "entry-stats"),
- get_datadir_fname2("stats", "entry-stats.tmp"),
- get_datadir_fname2("stats", "exit-stats"),
- get_datadir_fname2("stats", "exit-stats.tmp"),
- get_datadir_fname2("stats", "buffer-stats"),
- get_datadir_fname2("stats", "buffer-stats.tmp"),
- get_datadir_fname2("stats", "conn-stats"),
- get_datadir_fname2("stats", "conn-stats.tmp"),
- get_datadir_fname("approved-routers"),
- get_datadir_fname("fingerprint"),
- get_datadir_fname("fingerprint.tmp"),
- get_datadir_fname("hashed-fingerprint"),
- get_datadir_fname("hashed-fingerprint.tmp"),
- get_datadir_fname("router-stability"),
- get_datadir_fname("router-stability.tmp"),
- tor_strdup("/etc/resolv.conf"),
- NULL, 0
- );
+
+ OPEN_DATADIR2_SUFFIX("keys", "secret_id_key", ".tmp");
+ OPEN_DATADIR2_SUFFIX("keys", "secret_onion_key", ".tmp");
+ OPEN_DATADIR2_SUFFIX("keys", "secret_onion_key_ntor", ".tmp");
+ OPEN_DATADIR2("keys", "secret_id_key.old");
+ OPEN_DATADIR2("keys", "secret_onion_key.old");
+ OPEN_DATADIR2("keys", "secret_onion_key_ntor.old");
+
+ OPEN_DATADIR2_SUFFIX("stats", "bridge-stats", ".tmp");
+ OPEN_DATADIR2_SUFFIX("stats", "dirreq-stats", ".tmp");
+
+ OPEN_DATADIR2_SUFFIX("stats", "entry-stats", ".tmp");
+ OPEN_DATADIR2_SUFFIX("stats", "exit-stats", ".tmp");
+ OPEN_DATADIR2_SUFFIX("stats", "buffer-stats", ".tmp");
+ OPEN_DATADIR2_SUFFIX("stats", "conn-stats", ".tmp");
+
+ OPEN_DATADIR("approved-routers");
+ OPEN_DATADIR_SUFFIX("fingerprint", ".tmp");
+ OPEN_DATADIR_SUFFIX("hashed-fingerprint", ".tmp");
+ OPEN_DATADIR_SUFFIX("router-stability", ".tmp");
+
+ OPEN("/etc/resolv.conf");
RENAME_SUFFIX("fingerprint", ".tmp");
RENAME_SUFFIX2("keys", "secret_onion_key_ntor", ".tmp");
@@ -2989,12 +3075,9 @@ sandbox_init_filter(void)
get_datadir_fname2("keys", "secret_onion_key_ntor"),
get_datadir_fname2("keys", "secret_onion_key_ntor.old"));
- sandbox_cfg_allow_stat_filename_array(&cfg,
- get_datadir_fname("keys"),
- get_datadir_fname("stats"),
- get_datadir_fname2("stats", "dirreq-stats"),
- NULL, 0
- );
+ STAT_DATADIR("keys");
+ STAT_DATADIR("stats");
+ STAT_DATADIR2("stats", "dirreq-stats");
}
init_addrinfo();
@@ -3009,31 +3092,6 @@ int
tor_main(int argc, char *argv[])
{
int result = 0;
-#if defined (WINCE)
- WCHAR path [MAX_PATH] = {0};
- WCHAR fullpath [MAX_PATH] = {0};
- PWCHAR p = NULL;
- FILE* redir = NULL;
- FILE* redirdbg = NULL;
-
- // this is to facilitate debugging by opening
- // a file on a folder shared by the wm emulator.
- // if no flashcard (real or emulated) is present,
- // log files will be written in the root folder
- if (find_flashcard_path(path,MAX_PATH) == -1) {
- redir = _wfreopen( L"\\stdout.log", L"w", stdout );
- redirdbg = _wfreopen( L"\\stderr.log", L"w", stderr );
- } else {
- swprintf(fullpath,L"\\%s\\tor",path);
- CreateDirectory(fullpath,NULL);
-
- swprintf(fullpath,L"\\%s\\tor\\stdout.log",path);
- redir = _wfreopen( fullpath, L"w", stdout );
-
- swprintf(fullpath,L"\\%s\\tor\\stderr.log",path);
- redirdbg = _wfreopen( fullpath, L"w", stderr );
- }
-#endif
#ifdef _WIN32
/* Call SetProcessDEPPolicy to permanently enable DEP.
@@ -3052,7 +3110,7 @@ tor_main(int argc, char *argv[])
update_approx_time(time(NULL));
tor_threads_init();
- init_logging();
+ init_logging(0);
#ifdef USE_DMALLOC
{
/* Instruct OpenSSL to use our internal wrappers for malloc,
diff --git a/src/or/main.h b/src/or/main.h
index a3bce3486f..f77b4711c5 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,7 +12,9 @@
#ifndef TOR_MAIN_H
#define TOR_MAIN_H
-extern int can_complete_circuit;
+int have_completed_a_circuit(void);
+void note_that_we_completed_a_circuit(void);
+void note_that_we_maybe_cant_complete_circuits(void);
int connection_add_impl(connection_t *conn, int is_connecting);
#define connection_add(conn) connection_add_impl((conn), 0)
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index fdb549a9ac..0511e870d1 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2013, The Tor Project, Inc. */
+/* Copyright (c) 2009-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -57,9 +57,9 @@ microdesc_eq_(microdesc_t *a, microdesc_t *b)
HT_PROTOTYPE(microdesc_map, microdesc_t, node,
microdesc_hash_, microdesc_eq_);
-HT_GENERATE(microdesc_map, microdesc_t, node,
+HT_GENERATE2(microdesc_map, microdesc_t, node,
microdesc_hash_, microdesc_eq_, 0.6,
- malloc, realloc, free);
+ tor_reallocarray_, tor_free_)
/** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations.
* On success, return the total number of bytes written, and set
@@ -147,39 +147,81 @@ microdescs_add_to_cache(microdesc_cache_t *cache,
int no_save, time_t listed_at,
smartlist_t *requested_digests256)
{
+ void * const DIGEST_REQUESTED = (void*)1;
+ void * const DIGEST_RECEIVED = (void*)2;
+ void * const DIGEST_INVALID = (void*)3;
+
smartlist_t *descriptors, *added;
const int allow_annotations = (where != SAVED_NOWHERE);
+ smartlist_t *invalid_digests = smartlist_new();
descriptors = microdescs_parse_from_string(s, eos,
allow_annotations,
- where);
+ where, invalid_digests);
if (listed_at != (time_t)-1) {
SMARTLIST_FOREACH(descriptors, microdesc_t *, md,
md->last_listed = listed_at);
}
if (requested_digests256) {
- digestmap_t *requested; /* XXXX actually we should just use a
- digest256map */
- requested = digestmap_new();
- SMARTLIST_FOREACH(requested_digests256, const char *, cp,
- digestmap_set(requested, cp, (void*)1));
+ digest256map_t *requested;
+ requested = digest256map_new();
+ /* Set requested[d] to DIGEST_REQUESTED for every md we requested. */
+ SMARTLIST_FOREACH(requested_digests256, const uint8_t *, cp,
+ digest256map_set(requested, cp, DIGEST_REQUESTED));
+ /* Set requested[d] to DIGEST_INVALID for every md we requested which we
+ * will never be able to parse. Remove the ones we didn't request from
+ * invalid_digests.
+ */
+ SMARTLIST_FOREACH_BEGIN(invalid_digests, uint8_t *, cp) {
+ if (digest256map_get(requested, cp)) {
+ digest256map_set(requested, cp, DIGEST_INVALID);
+ } else {
+ tor_free(cp);
+ SMARTLIST_DEL_CURRENT(invalid_digests, cp);
+ }
+ } SMARTLIST_FOREACH_END(cp);
+ /* Update requested[d] to 2 for the mds we asked for and got. Delete the
+ * ones we never requested from the 'descriptors' smartlist.
+ */
SMARTLIST_FOREACH_BEGIN(descriptors, microdesc_t *, md) {
- if (digestmap_get(requested, md->digest)) {
- digestmap_set(requested, md->digest, (void*)2);
+ if (digest256map_get(requested, (const uint8_t*)md->digest)) {
+ digest256map_set(requested, (const uint8_t*)md->digest,
+ DIGEST_RECEIVED);
} else {
log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Received non-requested microdesc");
microdesc_free(md);
SMARTLIST_DEL_CURRENT(descriptors, md);
}
} SMARTLIST_FOREACH_END(md);
- SMARTLIST_FOREACH_BEGIN(requested_digests256, char *, cp) {
- if (digestmap_get(requested, cp) == (void*)2) {
+ /* Remove the ones we got or the invalid ones from requested_digests256.
+ */
+ SMARTLIST_FOREACH_BEGIN(requested_digests256, uint8_t *, cp) {
+ void *status = digest256map_get(requested, cp);
+ if (status == DIGEST_RECEIVED || status == DIGEST_INVALID) {
tor_free(cp);
SMARTLIST_DEL_CURRENT(requested_digests256, cp);
}
} SMARTLIST_FOREACH_END(cp);
- digestmap_free(requested, NULL);
+ digest256map_free(requested, NULL);
+ }
+
+ /* For every requested microdescriptor that was unparseable, mark it
+ * as not to be retried. */
+ if (smartlist_len(invalid_digests)) {
+ networkstatus_t *ns =
+ networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC);
+ if (ns) {
+ SMARTLIST_FOREACH_BEGIN(invalid_digests, char *, d) {
+ routerstatus_t *rs =
+ router_get_mutable_consensus_status_by_descriptor_digest(ns, d);
+ if (rs && tor_memeq(d, rs->descriptor_digest, DIGEST256_LEN)) {
+ download_status_mark_impossible(&rs->dl_status);
+ }
+ } SMARTLIST_FOREACH_END(d);
+ }
}
+ SMARTLIST_FOREACH(invalid_digests, uint8_t *, d, tor_free(d));
+ smartlist_free(invalid_digests);
added = microdescs_add_list_to_cache(cache, descriptors, where, no_save);
smartlist_free(descriptors);
@@ -576,6 +618,7 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force)
microdesc_wipe_body(md);
}
}
+ smartlist_free(wrote);
return -1;
}
@@ -751,7 +794,7 @@ microdesc_average_size(microdesc_cache_t *cache)
* smartlist. Omit all microdescriptors whose digest appear in <b>skip</b>. */
smartlist_t *
microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache,
- int downloadable_only, digestmap_t *skip)
+ int downloadable_only, digest256map_t *skip)
{
smartlist_t *result = smartlist_new();
time_t now = time(NULL);
@@ -763,7 +806,7 @@ microdesc_list_missing_digest256(networkstatus_t *ns, microdesc_cache_t *cache,
!download_status_is_ready(&rs->dl_status, now,
get_options()->TestingMicrodescMaxDownloadTries))
continue;
- if (skip && digestmap_get(skip, rs->descriptor_digest))
+ if (skip && digest256map_get(skip, (const uint8_t*)rs->descriptor_digest))
continue;
if (tor_mem_is_zero(rs->descriptor_digest, DIGEST256_LEN))
continue;
@@ -788,7 +831,7 @@ update_microdesc_downloads(time_t now)
const or_options_t *options = get_options();
networkstatus_t *consensus;
smartlist_t *missing;
- digestmap_t *pending;
+ digest256map_t *pending;
if (should_delay_dir_fetches(options, NULL))
return;
@@ -802,14 +845,14 @@ update_microdesc_downloads(time_t now)
if (!we_fetch_microdescriptors(options))
return;
- pending = digestmap_new();
+ pending = digest256map_new();
list_pending_microdesc_downloads(pending);
missing = microdesc_list_missing_digest256(consensus,
get_microdesc_cache(),
1,
pending);
- digestmap_free(pending, NULL);
+ digest256map_free(pending, NULL);
launch_descriptor_downloads(DIR_PURPOSE_FETCH_MICRODESC,
missing, NULL, now);
diff --git a/src/or/microdesc.h b/src/or/microdesc.h
index 7adb8c68af..08571e4bd5 100644
--- a/src/or/microdesc.h
+++ b/src/or/microdesc.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -37,7 +37,7 @@ size_t microdesc_average_size(microdesc_cache_t *cache);
smartlist_t *microdesc_list_missing_digest256(networkstatus_t *ns,
microdesc_cache_t *cache,
int downloadable_only,
- digestmap_t *skip);
+ digest256map_t *skip);
void microdesc_free_(microdesc_t *md, const char *fname, int line);
#define microdesc_free(md) \
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 890da0ad17..da110fdff6 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -83,7 +83,11 @@ static consensus_waiting_for_certs_t
* before the current consensus becomes invalid. */
static time_t time_to_download_next_consensus[N_CONSENSUS_FLAVORS];
/** Download status for the current consensus networkstatus. */
-static download_status_t consensus_dl_status[N_CONSENSUS_FLAVORS];
+static download_status_t consensus_dl_status[N_CONSENSUS_FLAVORS] =
+ {
+ { 0, 0, DL_SCHED_CONSENSUS },
+ { 0, 0, DL_SCHED_CONSENSUS },
+ };
/** True iff we have logged a warning about this OR's version being older than
* listed by the authorities. */
@@ -253,6 +257,10 @@ networkstatus_vote_free(networkstatus_t *ns)
SMARTLIST_FOREACH(ns->supported_methods, char *, c, tor_free(c));
smartlist_free(ns->supported_methods);
}
+ if (ns->package_lines) {
+ SMARTLIST_FOREACH(ns->package_lines, char *, c, tor_free(c));
+ smartlist_free(ns->package_lines);
+ }
if (ns->voters) {
SMARTLIST_FOREACH_BEGIN(ns->voters, networkstatus_voter_info_t *, voter) {
tor_free(voter->nickname);
@@ -591,10 +599,10 @@ networkstatus_vote_find_entry_idx(networkstatus_t *ns,
/** As router_get_consensus_status_by_descriptor_digest, but does not return
* a const pointer. */
-routerstatus_t *
-router_get_mutable_consensus_status_by_descriptor_digest(
+MOCK_IMPL(routerstatus_t *,
+router_get_mutable_consensus_status_by_descriptor_digest,(
networkstatus_t *consensus,
- const char *digest)
+ const char *digest))
{
if (!consensus)
consensus = current_consensus;
@@ -624,8 +632,8 @@ router_get_consensus_status_by_descriptor_digest(networkstatus_t *consensus,
/** Given the digest of a router descriptor, return its current download
* status, or NULL if the digest is unrecognized. */
-download_status_t *
-router_get_dl_status_by_descriptor_digest(const char *d)
+MOCK_IMPL(download_status_t *,
+router_get_dl_status_by_descriptor_digest,(const char *d))
{
routerstatus_t *rs;
if (!current_ns_consensus)
@@ -754,6 +762,9 @@ update_consensus_networkstatus_downloads(time_t now)
resource = networkstatus_get_flavor_name(i);
+ /* Let's make sure we remembered to update consensus_dl_status */
+ tor_assert(consensus_dl_status[i].schedule == DL_SCHED_CONSENSUS);
+
if (!download_status_is_ready(&consensus_dl_status[i], now,
options->TestingConsensusMaxDownloadTries))
continue; /* We failed downloading a consensus too recently. */
@@ -825,6 +836,10 @@ update_consensus_networkstatus_fetch_time_impl(time_t now, int flav)
a crazy-fast voting interval, though, 2 minutes may be too
much. */
min_sec_before_caching = interval/16;
+ /* make sure we always delay by at least a second before caching */
+ if (min_sec_before_caching == 0) {
+ min_sec_before_caching = 1;
+ }
}
if (directory_fetches_dir_info_early(options)) {
@@ -856,8 +871,17 @@ update_consensus_networkstatus_fetch_time_impl(time_t now, int flav)
dl_interval = (c->valid_until - start) - min_sec_before_caching;
}
}
+ /* catch low dl_interval in crazy-fast networks */
if (dl_interval < 1)
dl_interval = 1;
+ /* catch late start in crazy-fast networks */
+ if (start+dl_interval >= c->valid_until)
+ start = c->valid_until - dl_interval - 1;
+ log_debug(LD_DIR,
+ "fresh_until: %ld start: %ld "
+ "dl_interval: %ld valid_until: %ld ",
+ (long)c->fresh_until, (long)start, dl_interval,
+ (long)c->valid_until);
/* We must not try to replace c while it's still fresh: */
tor_assert(c->fresh_until < start);
/* We must download the next one before c is invalid: */
@@ -988,8 +1012,8 @@ networkstatus_get_latest_consensus(void)
/** Return the latest consensus we have whose flavor matches <b>f</b>, or NULL
* if we don't have one. */
-networkstatus_t *
-networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
+MOCK_IMPL(networkstatus_t *,
+networkstatus_get_latest_consensus_by_flavor,(consensus_flavor_t f))
{
if (f == FLAV_NS)
return current_ns_consensus;
@@ -1055,7 +1079,6 @@ routerstatus_has_changed(const routerstatus_t *a, const routerstatus_t *b)
a->is_valid != b->is_valid ||
a->is_possible_guard != b->is_possible_guard ||
a->is_bad_exit != b->is_bad_exit ||
- a->is_bad_directory != b->is_bad_directory ||
a->is_hs_dir != b->is_hs_dir ||
a->version_known != b->version_known;
}
@@ -1117,7 +1140,7 @@ networkstatus_copy_old_consensus_info(networkstatus_t *new_c,
rs_new->last_dir_503_at = rs_old->last_dir_503_at;
if (tor_memeq(rs_old->descriptor_digest, rs_new->descriptor_digest,
- DIGEST_LEN)) {
+ DIGEST256_LEN)) {
/* And the same descriptor too! */
memcpy(&rs_new->dl_status, &rs_old->dl_status,sizeof(download_status_t));
}
@@ -1655,7 +1678,7 @@ networkstatus_getinfo_by_purpose(const char *purpose_string, time_t now)
if (bridge_auth && ri->purpose == ROUTER_PURPOSE_BRIDGE)
dirserv_set_router_is_running(ri, now);
/* then generate and write out status lines for each of them */
- set_routerstatus_from_routerinfo(&rs, node, ri, now, 0, 0, 0, 0);
+ set_routerstatus_from_routerinfo(&rs, node, ri, now, 0, 0);
smartlist_add(statuses, networkstatus_getinfo_helper_single(&rs));
} SMARTLIST_FOREACH_END(ri);
@@ -1672,17 +1695,22 @@ networkstatus_dump_bridge_status_to_file(time_t now)
char *status = networkstatus_getinfo_by_purpose("bridge", now);
const or_options_t *options = get_options();
char *fname = NULL;
- char *thresholds = NULL, *thresholds_and_status = NULL;
+ char *thresholds = NULL;
+ char *published_thresholds_and_status = NULL;
routerlist_t *rl = router_get_routerlist();
+ char published[ISO_TIME_LEN+1];
+
+ format_iso_time(published, now);
dirserv_compute_bridge_flag_thresholds(rl);
thresholds = dirserv_get_flag_thresholds_line();
- tor_asprintf(&thresholds_and_status, "flag-thresholds %s\n%s",
- thresholds, status);
+ tor_asprintf(&published_thresholds_and_status,
+ "published %s\nflag-thresholds %s\n%s",
+ published, thresholds, status);
tor_asprintf(&fname, "%s"PATH_SEPARATOR"networkstatus-bridges",
options->DataDirectory);
- write_str_to_file(fname,thresholds_and_status,0);
+ write_str_to_file(fname,published_thresholds_and_status,0);
tor_free(thresholds);
- tor_free(thresholds_and_status);
+ tor_free(published_thresholds_and_status);
tor_free(fname);
tor_free(status);
}
@@ -1885,6 +1913,33 @@ getinfo_helper_networkstatus(control_connection_t *conn,
} else if (!strcmpstart(question, "ns/purpose/")) {
*answer = networkstatus_getinfo_by_purpose(question+11, time(NULL));
return *answer ? 0 : -1;
+ } else if (!strcmp(question, "consensus/packages")) {
+ const networkstatus_t *ns = networkstatus_get_latest_consensus();
+ if (ns && ns->package_lines)
+ *answer = smartlist_join_strings(ns->package_lines, "\n", 0, NULL);
+ else
+ *errmsg = "No consensus available";
+ return *answer ? 0 : -1;
+ } else if (!strcmp(question, "consensus/valid-after") ||
+ !strcmp(question, "consensus/fresh-until") ||
+ !strcmp(question, "consensus/valid-until")) {
+ const networkstatus_t *ns = networkstatus_get_latest_consensus();
+ if (ns) {
+ time_t t;
+ if (!strcmp(question, "consensus/valid-after"))
+ t = ns->valid_after;
+ else if (!strcmp(question, "consensus/fresh-until"))
+ t = ns->fresh_until;
+ else
+ t = ns->valid_until;
+
+ char tbuf[ISO_TIME_LEN+1];
+ format_iso_time(tbuf, t);
+ *answer = tor_strdup(tbuf);
+ } else {
+ *errmsg = "No consensus available";
+ }
+ return *answer ? 0 : -1;
} else {
return 0;
}
diff --git a/src/or/networkstatus.h b/src/or/networkstatus.h
index be0a86cdd8..d6e9e37013 100644
--- a/src/or/networkstatus.h
+++ b/src/or/networkstatus.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -12,6 +12,8 @@
#ifndef TOR_NETWORKSTATUS_H
#define TOR_NETWORKSTATUS_H
+#include "testsupport.h"
+
void networkstatus_reset_warnings(void);
void networkstatus_reset_download_failures(void);
int router_reload_consensus_networkstatus(void);
@@ -35,16 +37,19 @@ routerstatus_t *networkstatus_vote_find_mutable_entry(networkstatus_t *ns,
const char *digest);
int networkstatus_vote_find_entry_idx(networkstatus_t *ns,
const char *digest, int *found_out);
-download_status_t *router_get_dl_status_by_descriptor_digest(const char *d);
+
+MOCK_DECL(download_status_t *,router_get_dl_status_by_descriptor_digest,
+ (const char *d));
+
const routerstatus_t *router_get_consensus_status_by_id(const char *digest);
routerstatus_t *router_get_mutable_consensus_status_by_id(
const char *digest);
const routerstatus_t *router_get_consensus_status_by_descriptor_digest(
networkstatus_t *consensus,
const char *digest);
-routerstatus_t *router_get_mutable_consensus_status_by_descriptor_digest(
- networkstatus_t *consensus,
- const char *digest);
+MOCK_DECL(routerstatus_t *,
+ router_get_mutable_consensus_status_by_descriptor_digest,
+ (networkstatus_t *consensus, const char *digest));
const routerstatus_t *router_get_consensus_status_by_nickname(
const char *nickname,
int warn_if_unnamed);
@@ -60,8 +65,8 @@ int consensus_is_waiting_for_certs(void);
int client_would_use_router(const routerstatus_t *rs, time_t now,
const or_options_t *options);
networkstatus_t *networkstatus_get_latest_consensus(void);
-networkstatus_t *networkstatus_get_latest_consensus_by_flavor(
- consensus_flavor_t f);
+MOCK_DECL(networkstatus_t *,networkstatus_get_latest_consensus_by_flavor,
+ (consensus_flavor_t f));
networkstatus_t *networkstatus_get_live_consensus(time_t now);
networkstatus_t *networkstatus_get_reasonably_live_consensus(time_t now,
int flavor);
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index 7b1f338bd4..8f8adb42b5 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -24,6 +24,23 @@
static void nodelist_drop_node(node_t *node, int remove_from_ht);
static void node_free(node_t *node);
+
+/** count_usable_descriptors counts descriptors with these flag(s)
+ */
+typedef enum {
+ /* All descriptors regardless of flags */
+ USABLE_DESCRIPTOR_ALL = 0,
+ /* Only descriptors with the Exit flag */
+ USABLE_DESCRIPTOR_EXIT_ONLY = 1
+} usable_descriptor_t;
+static void count_usable_descriptors(int *num_present,
+ int *num_usable,
+ smartlist_t *descs_out,
+ const networkstatus_t *consensus,
+ const or_options_t *options,
+ time_t now,
+ routerset_t *in_set,
+ usable_descriptor_t exit_only);
static void update_router_have_minimum_dir_info(void);
static double get_frac_paths_needed_for_circs(const or_options_t *options,
const networkstatus_t *ns);
@@ -53,8 +70,8 @@ node_id_eq(const node_t *node1, const node_t *node2)
}
HT_PROTOTYPE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq);
-HT_GENERATE(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq,
- 0.6, malloc, realloc, free);
+HT_GENERATE2(nodelist_map, node_t, ht_ent, node_id_hash, node_id_eq,
+ 0.6, tor_reallocarray_, tor_free_)
/** The global nodelist. */
static nodelist_t *the_nodelist=NULL;
@@ -241,7 +258,6 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_stable = rs->is_stable;
node->is_possible_guard = rs->is_possible_guard;
node->is_exit = rs->is_exit;
- node->is_bad_directory = rs->is_bad_directory;
node->is_bad_exit = rs->is_bad_exit;
node->is_hs_dir = rs->is_hs_dir;
node->ipv6_preferred = 0;
@@ -267,8 +283,7 @@ nodelist_set_consensus(networkstatus_t *ns)
node->is_valid = node->is_running = node->is_hs_dir =
node->is_fast = node->is_stable =
node->is_possible_guard = node->is_exit =
- node->is_bad_exit = node->is_bad_directory =
- node->ipv6_preferred = 0;
+ node->is_bad_exit = node->ipv6_preferred = 0;
}
}
} SMARTLIST_FOREACH_END(node);
@@ -474,8 +489,8 @@ nodelist_assert_ok(void)
/** Return a list of a node_t * for every node we know about. The caller
* MUST NOT modify the list. (You can set and clear flags in the nodes if
* you must, but you must not add or remove nodes.) */
-smartlist_t *
-nodelist_get_list(void)
+MOCK_IMPL(smartlist_t *,
+nodelist_get_list,(void))
{
init_nodelist();
return the_nodelist->nodes;
@@ -517,8 +532,8 @@ node_get_by_hex_id(const char *hex_id)
* the corresponding node_t, or NULL if none exists. Warn the user if
* <b>warn_if_unnamed</b> is set, and they have specified a router by
* nickname, but the Named flag isn't set for that router. */
-const node_t *
-node_get_by_nickname(const char *nickname, int warn_if_unnamed)
+MOCK_IMPL(const node_t *,
+node_get_by_nickname,(const char *nickname, int warn_if_unnamed))
{
const node_t *node;
if (!the_nodelist)
@@ -1258,20 +1273,28 @@ router_set_status(const char *digest, int up)
}
/** True iff, the last time we checked whether we had enough directory info
- * to build circuits, the answer was "yes". */
+ * to build circuits, the answer was "yes". If there are no exits in the
+ * consensus, we act as if we have 100% of the exit directory info. */
static int have_min_dir_info = 0;
+
+/** Does the consensus contain nodes that can exit? */
+static consensus_path_type_t have_consensus_path = CONSENSUS_PATH_UNKNOWN;
+
/** True iff enough has changed since the last time we checked whether we had
* enough directory info to build circuits that our old answer can no longer
* be trusted. */
static int need_to_update_have_min_dir_info = 1;
/** String describing what we're missing before we have enough directory
* info. */
-static char dir_info_status[256] = "";
-
-/** Return true iff we have enough networkstatus and router information to
- * start building circuits. Right now, this means "more than half the
- * networkstatus documents, and at least 1/4 of expected routers." */
-//XXX should consider whether we have enough exiting nodes here.
+static char dir_info_status[512] = "";
+
+/** Return true iff we have enough consensus information to
+ * start building circuits. Right now, this means "a consensus that's
+ * less than a day old, and at least 60% of router descriptors (configurable),
+ * weighted by bandwidth. Treat the exit fraction as 100% if there are
+ * no exits in the consensus."
+ * To obtain the final weighted bandwidth, we multiply the
+ * weighted bandwidth fraction for each position (guard, middle, exit). */
int
router_have_minimum_dir_info(void)
{
@@ -1293,6 +1316,24 @@ router_have_minimum_dir_info(void)
return have_min_dir_info;
}
+/** Set to CONSENSUS_PATH_EXIT if there is at least one exit node
+ * in the consensus. We update this flag in compute_frac_paths_available if
+ * there is at least one relay that has an Exit flag in the consensus.
+ * Used to avoid building exit circuits when they will almost certainly fail.
+ * Set to CONSENSUS_PATH_INTERNAL if there are no exits in the consensus.
+ * (This situation typically occurs during bootstrap of a test network.)
+ * Set to CONSENSUS_PATH_UNKNOWN if we have never checked, or have
+ * reason to believe our last known value was invalid or has expired.
+ * If we're in a network with TestingDirAuthVoteExit set,
+ * this can cause router_have_consensus_path() to be set to
+ * CONSENSUS_PATH_EXIT, even if there are no nodes with accept exit policies.
+ */
+consensus_path_type_t
+router_have_consensus_path(void)
+{
+ return have_consensus_path;
+}
+
/** Called when our internal view of the directory has changed. This can be
* when the authorities change, networkstatuses change, the list of routerdescs
* changes, or number of running routers changes.
@@ -1313,22 +1354,26 @@ get_dir_info_status_string(void)
}
/** Iterate over the servers listed in <b>consensus</b>, and count how many of
- * them seem like ones we'd use, and how many of <em>those</em> we have
- * descriptors for. Store the former in *<b>num_usable</b> and the latter in
- * *<b>num_present</b>. If <b>in_set</b> is non-NULL, only consider those
- * routers in <b>in_set</b>. If <b>exit_only</b> is true, only consider nodes
- * with the Exit flag. If *descs_out is present, add a node_t for each
- * usable descriptor to it.
+ * them seem like ones we'd use (store this in *<b>num_usable</b>), and how
+ * many of <em>those</em> we have descriptors for (store this in
+ * *<b>num_present</b>).
+ *
+ * If <b>in_set</b> is non-NULL, only consider those routers in <b>in_set</b>.
+ * If <b>exit_only</b> is USABLE_DESCRIPTOR_EXIT_ONLY, only consider nodes
+ * with the Exit flag.
+ * If *<b>descs_out</b> is present, add a node_t for each usable descriptor
+ * to it.
*/
static void
count_usable_descriptors(int *num_present, int *num_usable,
smartlist_t *descs_out,
const networkstatus_t *consensus,
const or_options_t *options, time_t now,
- routerset_t *in_set, int exit_only)
+ routerset_t *in_set,
+ usable_descriptor_t exit_only)
{
const int md = (consensus->flavor == FLAV_MICRODESC);
- *num_present = 0, *num_usable=0;
+ *num_present = 0, *num_usable = 0;
SMARTLIST_FOREACH_BEGIN(consensus->routerstatus_list, routerstatus_t *, rs)
{
@@ -1336,7 +1381,7 @@ count_usable_descriptors(int *num_present, int *num_usable,
if (!node)
continue; /* This would be a bug: every entry in the consensus is
* supposed to have a node. */
- if (exit_only && ! rs->is_exit)
+ if (exit_only == USABLE_DESCRIPTOR_EXIT_ONLY && ! rs->is_exit)
continue;
if (in_set && ! routerset_contains_routerstatus(in_set, rs, -1))
continue;
@@ -1360,11 +1405,22 @@ count_usable_descriptors(int *num_present, int *num_usable,
log_debug(LD_DIR, "%d usable, %d present (%s%s).",
*num_usable, *num_present,
- md ? "microdesc" : "desc", exit_only ? " exits" : "s");
+ md ? "microdesc" : "desc",
+ exit_only == USABLE_DESCRIPTOR_EXIT_ONLY ? " exits" : "s");
}
/** Return an estimate of which fraction of usable paths through the Tor
- * network we have available for use. */
+ * network we have available for use. Count how many routers seem like ones
+ * we'd use (store this in *<b>num_usable_out</b>), and how many of
+ * <em>those</em> we have descriptors for (store this in
+ * *<b>num_present_out</b>.)
+ *
+ * If **<b>status_out</b> is present, allocate a new string and print the
+ * available percentages of guard, middle, and exit nodes to it, noting
+ * whether there are exits in the consensus.
+ * If there are no guards in the consensus,
+ * we treat the exit fraction as 100%.
+ */
static double
compute_frac_paths_available(const networkstatus_t *consensus,
const or_options_t *options, time_t now,
@@ -1374,17 +1430,20 @@ compute_frac_paths_available(const networkstatus_t *consensus,
smartlist_t *guards = smartlist_new();
smartlist_t *mid = smartlist_new();
smartlist_t *exits = smartlist_new();
- smartlist_t *myexits= smartlist_new();
- smartlist_t *myexits_unflagged = smartlist_new();
- double f_guard, f_mid, f_exit, f_myexit, f_myexit_unflagged;
- int np, nu; /* Ignored */
+ double f_guard, f_mid, f_exit;
+ double f_path = 0.0;
+ /* Used to determine whether there are any exits in the consensus */
+ int np = 0;
+ /* Used to determine whether there are any exits with descriptors */
+ int nu = 0;
const int authdir = authdir_mode_v3(options);
count_usable_descriptors(num_present_out, num_usable_out,
- mid, consensus, options, now, NULL, 0);
+ mid, consensus, options, now, NULL,
+ USABLE_DESCRIPTOR_ALL);
if (options->EntryNodes) {
count_usable_descriptors(&np, &nu, guards, consensus, options, now,
- options->EntryNodes, 0);
+ options->EntryNodes, USABLE_DESCRIPTOR_ALL);
} else {
SMARTLIST_FOREACH(mid, const node_t *, node, {
if (authdir) {
@@ -1397,60 +1456,148 @@ compute_frac_paths_available(const networkstatus_t *consensus,
});
}
- /* All nodes with exit flag */
+ /* All nodes with exit flag
+ * If we're in a network with TestingDirAuthVoteExit set,
+ * this can cause false positives on have_consensus_path,
+ * incorrectly setting it to CONSENSUS_PATH_EXIT. This is
+ * an unavoidable feature of forcing authorities to declare
+ * certain nodes as exits.
+ */
count_usable_descriptors(&np, &nu, exits, consensus, options, now,
- NULL, 1);
- /* All nodes with exit flag in ExitNodes option */
- count_usable_descriptors(&np, &nu, myexits, consensus, options, now,
- options->ExitNodes, 1);
- /* Now compute the nodes in the ExitNodes option where which we don't know
- * what their exit policy is, or we know it permits something. */
- count_usable_descriptors(&np, &nu, myexits_unflagged,
- consensus, options, now,
- options->ExitNodes, 0);
- SMARTLIST_FOREACH_BEGIN(myexits_unflagged, const node_t *, node) {
- if (node_has_descriptor(node) && node_exit_policy_rejects_all(node))
- SMARTLIST_DEL_CURRENT(myexits_unflagged, node);
- } SMARTLIST_FOREACH_END(node);
+ NULL, USABLE_DESCRIPTOR_EXIT_ONLY);
+ log_debug(LD_NET,
+ "%s: %d present, %d usable",
+ "exits",
+ np,
+ nu);
+
+ /* We need at least 1 exit present in the consensus to consider
+ * building exit paths */
+ /* Update our understanding of whether the consensus has exits */
+ consensus_path_type_t old_have_consensus_path = have_consensus_path;
+ have_consensus_path = ((nu > 0) ?
+ CONSENSUS_PATH_EXIT :
+ CONSENSUS_PATH_INTERNAL);
+
+ if (have_consensus_path == CONSENSUS_PATH_INTERNAL
+ && old_have_consensus_path != have_consensus_path) {
+ log_notice(LD_NET,
+ "The current consensus has no exit nodes. "
+ "Tor can only build internal paths, "
+ "such as paths to hidden services.");
+
+ /* However, exit nodes can reachability self-test using this consensus,
+ * join the network, and appear in a later consensus. This will allow
+ * the network to build exit paths, such as paths for world wide web
+ * browsing (as distinct from hidden service web browsing). */
+ }
f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD);
f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID);
f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT);
- f_myexit= frac_nodes_with_descriptors(myexits,WEIGHT_FOR_EXIT);
- f_myexit_unflagged=
- frac_nodes_with_descriptors(myexits_unflagged,WEIGHT_FOR_EXIT);
-
- /* If our ExitNodes list has eliminated every possible Exit node, and there
- * were some possible Exit nodes, then instead consider nodes that permit
- * exiting to some ports. */
- if (smartlist_len(myexits) == 0 &&
- smartlist_len(myexits_unflagged)) {
- f_myexit = f_myexit_unflagged;
- }
+
+ log_debug(LD_NET,
+ "f_guard: %.2f, f_mid: %.2f, f_exit: %.2f",
+ f_guard,
+ f_mid,
+ f_exit);
smartlist_free(guards);
smartlist_free(mid);
smartlist_free(exits);
- smartlist_free(myexits);
- smartlist_free(myexits_unflagged);
- /* This is a tricky point here: we don't want to make it easy for a
- * directory to trickle exits to us until it learns which exits we have
- * configured, so require that we have a threshold both of total exits
- * and usable exits. */
- if (f_myexit < f_exit)
- f_exit = f_myexit;
+ if (options->ExitNodes) {
+ double f_myexit, f_myexit_unflagged;
+ smartlist_t *myexits= smartlist_new();
+ smartlist_t *myexits_unflagged = smartlist_new();
+
+ /* All nodes with exit flag in ExitNodes option */
+ count_usable_descriptors(&np, &nu, myexits, consensus, options, now,
+ options->ExitNodes, USABLE_DESCRIPTOR_EXIT_ONLY);
+ log_debug(LD_NET,
+ "%s: %d present, %d usable",
+ "myexits",
+ np,
+ nu);
+
+ /* Now compute the nodes in the ExitNodes option where which we don't know
+ * what their exit policy is, or we know it permits something. */
+ count_usable_descriptors(&np, &nu, myexits_unflagged,
+ consensus, options, now,
+ options->ExitNodes, USABLE_DESCRIPTOR_ALL);
+ log_debug(LD_NET,
+ "%s: %d present, %d usable",
+ "myexits_unflagged (initial)",
+ np,
+ nu);
+
+ SMARTLIST_FOREACH_BEGIN(myexits_unflagged, const node_t *, node) {
+ if (node_has_descriptor(node) && node_exit_policy_rejects_all(node)) {
+ SMARTLIST_DEL_CURRENT(myexits_unflagged, node);
+ /* this node is not actually an exit */
+ np--;
+ /* this node is unusable as an exit */
+ nu--;
+ }
+ } SMARTLIST_FOREACH_END(node);
+
+ log_debug(LD_NET,
+ "%s: %d present, %d usable",
+ "myexits_unflagged (final)",
+ np,
+ nu);
+
+ f_myexit= frac_nodes_with_descriptors(myexits,WEIGHT_FOR_EXIT);
+ f_myexit_unflagged=
+ frac_nodes_with_descriptors(myexits_unflagged,WEIGHT_FOR_EXIT);
+
+ log_debug(LD_NET,
+ "f_exit: %.2f, f_myexit: %.2f, f_myexit_unflagged: %.2f",
+ f_exit,
+ f_myexit,
+ f_myexit_unflagged);
+
+ /* If our ExitNodes list has eliminated every possible Exit node, and there
+ * were some possible Exit nodes, then instead consider nodes that permit
+ * exiting to some ports. */
+ if (smartlist_len(myexits) == 0 &&
+ smartlist_len(myexits_unflagged)) {
+ f_myexit = f_myexit_unflagged;
+ }
+
+ smartlist_free(myexits);
+ smartlist_free(myexits_unflagged);
+
+ /* This is a tricky point here: we don't want to make it easy for a
+ * directory to trickle exits to us until it learns which exits we have
+ * configured, so require that we have a threshold both of total exits
+ * and usable exits. */
+ if (f_myexit < f_exit)
+ f_exit = f_myexit;
+ }
+
+ /* if the consensus has no exits, treat the exit fraction as 100% */
+ if (router_have_consensus_path() != CONSENSUS_PATH_EXIT) {
+ f_exit = 1.0;
+ }
+
+ f_path = f_guard * f_mid * f_exit;
if (status_out)
tor_asprintf(status_out,
"%d%% of guards bw, "
"%d%% of midpoint bw, and "
- "%d%% of exit bw",
+ "%d%% of exit bw%s = "
+ "%d%% of path bw",
(int)(f_guard*100),
(int)(f_mid*100),
- (int)(f_exit*100));
+ (int)(f_exit*100),
+ (router_have_consensus_path() == CONSENSUS_PATH_EXIT ?
+ "" :
+ " (no exits in consensus)"),
+ (int)(f_path*100));
- return f_guard * f_mid * f_exit;
+ return f_path;
}
/** We just fetched a new set of descriptors. Compute how far through
@@ -1523,6 +1670,7 @@ update_router_have_minimum_dir_info(void)
using_md = consensus->flavor == FLAV_MICRODESC;
+ /* Check fraction of available paths */
{
char *status = NULL;
int num_present=0, num_usable=0;
@@ -1536,7 +1684,6 @@ update_router_have_minimum_dir_info(void)
"can only build %d%% of likely paths. (We have %s.)",
using_md?"micro":"", num_present, num_usable,
(int)(paths*100), status);
- /* log_notice(LD_NET, "%s", dir_info_status); */
tor_free(status);
res = 0;
control_event_bootstrap(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
@@ -1548,12 +1695,17 @@ update_router_have_minimum_dir_info(void)
}
done:
+
+ /* If paths have just become available in this update. */
if (res && !have_min_dir_info) {
- log_notice(LD_DIR,
- "We now have enough directory information to build circuits.");
control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
- control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0);
+ if (control_event_bootstrap(BOOTSTRAP_STATUS_CONN_OR, 0) == 0) {
+ log_notice(LD_DIR,
+ "We now have enough directory information to build circuits.");
+ }
}
+
+ /* If paths have just become unavailable in this update. */
if (!res && have_min_dir_info) {
int quiet = directory_too_idle_to_fetch_descriptors(options, now);
tor_log(quiet ? LOG_INFO : LOG_NOTICE, LD_DIR,
@@ -1564,8 +1716,8 @@ update_router_have_minimum_dir_info(void)
* is back up and usable, and b) disable some activities that Tor
* should only do while circuits are working, like reachability tests
* and fetching bridge descriptors only over circuits. */
- can_complete_circuit = 0;
-
+ note_that_we_maybe_cant_complete_circuits();
+ have_consensus_path = CONSENSUS_PATH_UNKNOWN;
control_event_client_status(LOG_NOTICE, "NOT_ENOUGH_DIR_INFO");
}
have_min_dir_info = res;
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 8e719e012d..a131e0dd4e 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -31,7 +31,8 @@ smartlist_t *nodelist_find_nodes_with_microdesc(const microdesc_t *md);
void nodelist_free_all(void);
void nodelist_assert_ok(void);
-const node_t *node_get_by_nickname(const char *nickname, int warn_if_unnamed);
+MOCK_DECL(const node_t *, node_get_by_nickname,
+ (const char *nickname, int warn_if_unnamed));
void node_get_verbose_nickname(const node_t *node,
char *verbose_name_out);
void node_get_verbose_nickname_by_id(const char *id_digest,
@@ -60,7 +61,7 @@ void node_get_pref_orport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out);
int node_has_curve25519_onion_key(const node_t *node);
-smartlist_t *nodelist_get_list(void);
+MOCK_DECL(smartlist_t *, nodelist_get_list, (void));
/* Temporary during transition to multiple addresses. */
void node_get_addr(const node_t *node, tor_addr_t *addr_out);
@@ -78,7 +79,37 @@ int node_is_unreliable(const node_t *router, int need_uptime,
int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
int need_uptime);
void router_set_status(const char *digest, int up);
+
+/** router_have_minimum_dir_info tests to see if we have enough
+ * descriptor information to create circuits.
+ * If there are exits in the consensus, we wait until we have enough
+ * info to create exit paths before creating any circuits. If there are
+ * no exits in the consensus, we wait for enough info to create internal
+ * paths, and should avoid creating exit paths, as they will simply fail.
+ * We make sure we create all available circuit types at the same time. */
int router_have_minimum_dir_info(void);
+
+/** Set to CONSENSUS_PATH_EXIT if there is at least one exit node
+ * in the consensus. We update this flag in compute_frac_paths_available if
+ * there is at least one relay that has an Exit flag in the consensus.
+ * Used to avoid building exit circuits when they will almost certainly fail.
+ * Set to CONSENSUS_PATH_INTERNAL if there are no exits in the consensus.
+ * (This situation typically occurs during bootstrap of a test network.)
+ * Set to CONSENSUS_PATH_UNKNOWN if we have never checked, or have
+ * reason to believe our last known value was invalid or has expired.
+ */
+typedef enum {
+ /* we haven't checked yet, or we have invalidated our previous check */
+ CONSENSUS_PATH_UNKNOWN = -1,
+ /* The consensus only has internal relays, and we should only
+ * create internal paths, circuits, streams, ... */
+ CONSENSUS_PATH_INTERNAL = 0,
+ /* The consensus has at least one exit, and can therefore (potentially)
+ * create exit and internal paths, circuits, streams, ... */
+ CONSENSUS_PATH_EXIT = 1
+} consensus_path_type_t;
+consensus_path_type_t router_have_consensus_path(void);
+
void router_dir_info_changed(void);
const char *get_dir_info_status_string(void);
int count_loading_descriptors_progress(void);
diff --git a/src/or/ntmain.c b/src/or/ntmain.c
index e848314043..833d870041 100644
--- a/src/or/ntmain.c
+++ b/src/or/ntmain.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
diff --git a/src/or/ntmain.h b/src/or/ntmain.h
index d3027936cd..eb55a296f6 100644
--- a/src/or/ntmain.h
+++ b/src/or/ntmain.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -13,10 +13,8 @@
#define TOR_NTMAIN_H
#ifdef _WIN32
-#if !defined (WINCE)
#define NT_SERVICE
#endif
-#endif
#ifdef NT_SERVICE
int nt_service_parse_options(int argc, char **argv, int *should_exit);
diff --git a/src/or/onion.c b/src/or/onion.c
index ae39f451f4..4864792511 100644
--- a/src/or/onion.c
+++ b/src/or/onion.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -111,15 +111,11 @@ have_room_for_onionskin(uint16_t type)
(uint64_t)options->MaxOnionQueueDelay)
return 0;
-#ifdef CURVE25519_ENABLED
/* If we support the ntor handshake, then don't let TAP handshakes use
* more than 2/3 of the space on the queue. */
if (type == ONION_HANDSHAKE_TYPE_TAP &&
tap_usec / 1000 > (uint64_t)options->MaxOnionQueueDelay * 2 / 3)
return 0;
-#else
- (void) type;
-#endif
return 1;
}
@@ -299,6 +295,8 @@ onion_pending_remove(or_circuit_t *circ)
victim = circ->onionqueue_entry;
if (victim)
onion_queue_entry_remove(victim);
+
+ cpuworker_cancel_circ_handshake(circ);
}
/** Remove a queue entry <b>victim</b> from the queue, unlinking it from
@@ -343,38 +341,35 @@ clear_pending_onions(void)
/* ============================================================ */
-/** Fill in a server_onion_keys_t object at <b>keys</b> with all of the keys
+/** Return a new server_onion_keys_t object with all of the keys
* and other info we might need to do onion handshakes. (We make a copy of
* our keys for each cpuworker to avoid race conditions with the main thread,
* and to avoid locking) */
-void
-setup_server_onion_keys(server_onion_keys_t *keys)
+server_onion_keys_t *
+server_onion_keys_new(void)
{
- memset(keys, 0, sizeof(server_onion_keys_t));
+ server_onion_keys_t *keys = tor_malloc_zero(sizeof(server_onion_keys_t));
memcpy(keys->my_identity, router_get_my_id_digest(), DIGEST_LEN);
dup_onion_keys(&keys->onion_key, &keys->last_onion_key);
-#ifdef CURVE25519_ENABLED
keys->curve25519_key_map = construct_ntor_key_map();
keys->junk_keypair = tor_malloc_zero(sizeof(curve25519_keypair_t));
curve25519_keypair_generate(keys->junk_keypair, 0);
-#endif
+ return keys;
}
-/** Release all storage held in <b>keys</b>, but do not free <b>keys</b>
- * itself (as it's likely to be stack-allocated.) */
+/** Release all storage held in <b>keys</b>. */
void
-release_server_onion_keys(server_onion_keys_t *keys)
+server_onion_keys_free(server_onion_keys_t *keys)
{
if (! keys)
return;
crypto_pk_free(keys->onion_key);
crypto_pk_free(keys->last_onion_key);
-#ifdef CURVE25519_ENABLED
ntor_key_map_free(keys->curve25519_key_map);
tor_free(keys->junk_keypair);
-#endif
- memset(keys, 0, sizeof(server_onion_keys_t));
+ memwipe(keys, 0, sizeof(server_onion_keys_t));
+ tor_free(keys);
}
/** Release whatever storage is held in <b>state</b>, depending on its
@@ -391,12 +386,10 @@ onion_handshake_state_release(onion_handshake_state_t *state)
fast_handshake_state_free(state->u.fast);
state->u.fast = NULL;
break;
-#ifdef CURVE25519_ENABLED
case ONION_HANDSHAKE_TYPE_NTOR:
ntor_handshake_state_free(state->u.ntor);
state->u.ntor = NULL;
break;
-#endif
default:
log_warn(LD_BUG, "called with unknown handshake state type %d",
(int)state->tag);
@@ -436,7 +429,6 @@ onion_skin_create(int type,
r = CREATE_FAST_LEN;
break;
case ONION_HANDSHAKE_TYPE_NTOR:
-#ifdef CURVE25519_ENABLED
if (tor_mem_is_zero((const char*)node->curve25519_onion_key.public_key,
CURVE25519_PUBKEY_LEN))
return -1;
@@ -447,9 +439,6 @@ onion_skin_create(int type,
return -1;
r = NTOR_ONIONSKIN_LEN;
-#else
- return -1;
-#endif
break;
default:
log_warn(LD_BUG, "called with unknown handshake state type %d", type);
@@ -501,7 +490,6 @@ onion_skin_server_handshake(int type,
memcpy(rend_nonce_out, reply_out+DIGEST_LEN, DIGEST_LEN);
break;
case ONION_HANDSHAKE_TYPE_NTOR:
-#ifdef CURVE25519_ENABLED
if (onionskin_len < NTOR_ONIONSKIN_LEN)
return -1;
{
@@ -522,9 +510,6 @@ onion_skin_server_handshake(int type,
tor_free(keys_tmp);
r = NTOR_REPLY_LEN;
}
-#else
- return -1;
-#endif
break;
default:
log_warn(LD_BUG, "called with unknown handshake state type %d", type);
@@ -541,13 +526,15 @@ onion_skin_server_handshake(int type,
* bytes worth of key material in <b>keys_out_len</b>, set
* <b>rend_authenticator_out</b> to the "KH" field that can be used to
* establish introduction points at this hop, and return 0. On failure,
- * return -1. */
+ * return -1, and set *msg_out to an error message if this is worth
+ * complaining to the usre about. */
int
onion_skin_client_handshake(int type,
const onion_handshake_state_t *handshake_state,
const uint8_t *reply, size_t reply_len,
uint8_t *keys_out, size_t keys_out_len,
- uint8_t *rend_authenticator_out)
+ uint8_t *rend_authenticator_out,
+ const char **msg_out)
{
if (handshake_state->tag != type)
return -1;
@@ -555,12 +542,14 @@ onion_skin_client_handshake(int type,
switch (type) {
case ONION_HANDSHAKE_TYPE_TAP:
if (reply_len != TAP_ONIONSKIN_REPLY_LEN) {
- log_warn(LD_CIRC, "TAP reply was not of the correct length.");
+ if (msg_out)
+ *msg_out = "TAP reply was not of the correct length.";
return -1;
}
if (onion_skin_TAP_client_handshake(handshake_state->u.tap,
(const char*)reply,
- (char *)keys_out, keys_out_len) < 0)
+ (char *)keys_out, keys_out_len,
+ msg_out) < 0)
return -1;
memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN);
@@ -568,27 +557,28 @@ onion_skin_client_handshake(int type,
return 0;
case ONION_HANDSHAKE_TYPE_FAST:
if (reply_len != CREATED_FAST_LEN) {
- log_warn(LD_CIRC, "CREATED_FAST reply was not of the correct length.");
+ if (msg_out)
+ *msg_out = "TAP reply was not of the correct length.";
return -1;
}
if (fast_client_handshake(handshake_state->u.fast, reply,
- keys_out, keys_out_len) < 0)
+ keys_out, keys_out_len, msg_out) < 0)
return -1;
memcpy(rend_authenticator_out, reply+DIGEST_LEN, DIGEST_LEN);
return 0;
-#ifdef CURVE25519_ENABLED
case ONION_HANDSHAKE_TYPE_NTOR:
if (reply_len < NTOR_REPLY_LEN) {
- log_warn(LD_CIRC, "ntor reply was not of the correct length.");
+ if (msg_out)
+ *msg_out = "ntor reply was not of the correct length.";
return -1;
}
{
size_t keys_tmp_len = keys_out_len + DIGEST_LEN;
uint8_t *keys_tmp = tor_malloc(keys_tmp_len);
if (onion_skin_ntor_client_handshake(handshake_state->u.ntor,
- reply,
- keys_tmp, keys_tmp_len) < 0) {
+ reply,
+ keys_tmp, keys_tmp_len, msg_out) < 0) {
tor_free(keys_tmp);
return -1;
}
@@ -598,7 +588,6 @@ onion_skin_client_handshake(int type,
tor_free(keys_tmp);
}
return 0;
-#endif
default:
log_warn(LD_BUG, "called with unknown handshake state type %d", type);
tor_fragile_assert();
@@ -637,12 +626,10 @@ check_create_cell(const create_cell_t *cell, int unknown_ok)
if (cell->handshake_len != CREATE_FAST_LEN)
return -1;
break;
-#ifdef CURVE25519_ENABLED
case ONION_HANDSHAKE_TYPE_NTOR:
if (cell->handshake_len != NTOR_ONIONSKIN_LEN)
return -1;
break;
-#endif
default:
if (! unknown_ok)
return -1;
diff --git a/src/or/onion.h b/src/or/onion.h
index d62f032b87..45454f480d 100644
--- a/src/or/onion.h
+++ b/src/or/onion.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,17 +23,15 @@ typedef struct server_onion_keys_t {
uint8_t my_identity[DIGEST_LEN];
crypto_pk_t *onion_key;
crypto_pk_t *last_onion_key;
-#ifdef CURVE25519_ENABLED
di_digest256_map_t *curve25519_key_map;
curve25519_keypair_t *junk_keypair;
-#endif
} server_onion_keys_t;
#define MAX_ONIONSKIN_CHALLENGE_LEN 255
#define MAX_ONIONSKIN_REPLY_LEN 255
-void setup_server_onion_keys(server_onion_keys_t *keys);
-void release_server_onion_keys(server_onion_keys_t *keys);
+server_onion_keys_t *server_onion_keys_new(void);
+void server_onion_keys_free(server_onion_keys_t *keys);
void onion_handshake_state_release(onion_handshake_state_t *state);
@@ -51,7 +49,8 @@ int onion_skin_client_handshake(int type,
const onion_handshake_state_t *handshake_state,
const uint8_t *reply, size_t reply_len,
uint8_t *keys_out, size_t key_out_len,
- uint8_t *rend_authenticator_out);
+ uint8_t *rend_authenticator_out,
+ const char **msg_out);
/** A parsed CREATE, CREATE_FAST, or CREATE2 cell. */
typedef struct create_cell_t {
diff --git a/src/or/onion_fast.c b/src/or/onion_fast.c
index 38b62decc3..7584112570 100644
--- a/src/or/onion_fast.c
+++ b/src/or/onion_fast.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -92,7 +92,8 @@ int
fast_client_handshake(const fast_handshake_state_t *handshake_state,
const uint8_t *handshake_reply_out,/*DIGEST_LEN*2 bytes*/
uint8_t *key_out,
- size_t key_out_len)
+ size_t key_out_len,
+ const char **msg_out)
{
uint8_t tmp[DIGEST_LEN+DIGEST_LEN];
uint8_t *out;
@@ -104,13 +105,14 @@ fast_client_handshake(const fast_handshake_state_t *handshake_state,
out_len = key_out_len+DIGEST_LEN;
out = tor_malloc(out_len);
if (crypto_expand_key_material_TAP(tmp, sizeof(tmp), out, out_len)) {
- log_warn(LD_CIRC, "Failed to expand key material");
+ if (msg_out)
+ *msg_out = "Failed to expand key material";
goto done;
}
if (tor_memneq(out, handshake_reply_out+DIGEST_LEN, DIGEST_LEN)) {
/* H(K) does *not* match. Something fishy. */
- log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on fast handshake. "
- "Bug or attack.");
+ if (msg_out)
+ *msg_out = "Digest DOES NOT MATCH on fast handshake. Bug or attack.";
goto done;
}
memcpy(key_out, out+DIGEST_LEN, key_out_len);
diff --git a/src/or/onion_fast.h b/src/or/onion_fast.h
index 8c078378d2..d50d503a73 100644
--- a/src/or/onion_fast.h
+++ b/src/or/onion_fast.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -32,7 +32,8 @@ int fast_server_handshake(const uint8_t *message_in,
int fast_client_handshake(const fast_handshake_state_t *handshake_state,
const uint8_t *handshake_reply_out,
uint8_t *key_out,
- size_t key_out_len);
+ size_t key_out_len,
+ const char **msg_out);
#endif
diff --git a/src/or/onion_ntor.c b/src/or/onion_ntor.c
index ef501f69da..539f06f61f 100644
--- a/src/or/onion_ntor.c
+++ b/src/or/onion_ntor.c
@@ -1,10 +1,10 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
-#include "crypto.h"
#define ONION_NTOR_PRIVATE
+#include "crypto.h"
#include "onion_ntor.h"
#include "torlog.h"
#include "util.h"
@@ -226,7 +226,8 @@ onion_skin_ntor_client_handshake(
const ntor_handshake_state_t *handshake_state,
const uint8_t *handshake_reply,
uint8_t *key_out,
- size_t key_out_len)
+ size_t key_out_len,
+ const char **msg_out)
{
const tweakset_t *T = &proto1_tweaks;
/* Sensitive stack-allocated material. Kept in an anonymous struct to make
@@ -292,7 +293,19 @@ onion_skin_ntor_client_handshake(
memwipe(&s, 0, sizeof(s));
if (bad) {
- log_warn(LD_PROTOCOL, "Invalid result from curve25519 handshake: %d", bad);
+ if (bad & 4) {
+ if (msg_out)
+ *msg_out = NULL; /* Don't report this one; we probably just had the
+ * wrong onion key.*/
+ log_fn(LOG_INFO, LD_PROTOCOL,
+ "Invalid result from curve25519 handshake: %d", bad);
+ }
+ if (bad & 3) {
+ if (msg_out)
+ *msg_out = "Zero output from curve25519 handshake";
+ log_fn(LOG_WARN, LD_PROTOCOL,
+ "Invalid result from curve25519 handshake: %d", bad);
+ }
}
return bad ? -1 : 0;
diff --git a/src/or/onion_ntor.h b/src/or/onion_ntor.h
index c942e6e0f0..0a39c1de16 100644
--- a/src/or/onion_ntor.h
+++ b/src/or/onion_ntor.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_ONION_NTOR_H
@@ -17,7 +17,6 @@ typedef struct ntor_handshake_state_t ntor_handshake_state_t;
/** Length of an ntor reply, as sent from server to client. */
#define NTOR_REPLY_LEN 64
-#ifdef CURVE25519_ENABLED
void ntor_handshake_state_free(ntor_handshake_state_t *state);
int onion_skin_ntor_create(const uint8_t *router_id,
@@ -37,7 +36,8 @@ int onion_skin_ntor_client_handshake(
const ntor_handshake_state_t *handshake_state,
const uint8_t *handshake_reply,
uint8_t *key_out,
- size_t key_out_len);
+ size_t key_out_len,
+ const char **msg_out);
#ifdef ONION_NTOR_PRIVATE
@@ -59,5 +59,3 @@ struct ntor_handshake_state_t {
#endif
-#endif
-
diff --git a/src/or/onion_tap.c b/src/or/onion_tap.c
index 65f8275f75..487cbeec04 100644
--- a/src/or/onion_tap.c
+++ b/src/or/onion_tap.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -183,7 +183,8 @@ int
onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
const char *handshake_reply, /* TAP_ONIONSKIN_REPLY_LEN bytes */
char *key_out,
- size_t key_out_len)
+ size_t key_out_len,
+ const char **msg_out)
{
ssize_t len;
char *key_material=NULL;
@@ -196,14 +197,15 @@ onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
handshake_reply, DH_KEY_LEN, key_material,
key_material_len);
if (len < 0) {
- log_warn(LD_PROTOCOL,"DH computation failed.");
+ if (msg_out)
+ *msg_out = "DH computation failed.";
goto err;
}
if (tor_memneq(key_material, handshake_reply+DH_KEY_LEN, DIGEST_LEN)) {
/* H(K) does *not* match. Something fishy. */
- log_warn(LD_PROTOCOL,"Digest DOES NOT MATCH on onion handshake. "
- "Bug or attack.");
+ if (msg_out)
+ *msg_out = "Digest DOES NOT MATCH on onion handshake. Bug or attack.";
goto err;
}
diff --git a/src/or/onion_tap.h b/src/or/onion_tap.h
index b978b66737..c548b3d99f 100644
--- a/src/or/onion_tap.h
+++ b/src/or/onion_tap.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -31,7 +31,8 @@ int onion_skin_TAP_server_handshake(const char *onion_skin,
int onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state,
const char *handshake_reply,
char *key_out,
- size_t key_out_len);
+ size_t key_out_len,
+ const char **msg_out);
#endif
diff --git a/src/or/or.h b/src/or/or.h
index adf3cfa866..0d81b54d94 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -14,7 +14,7 @@
#include "orconfig.h"
-#ifdef __COVERITY__
+#if defined(__clang_analyzer__) || defined(__COVERITY__)
/* If we're building for a static analysis, turn on all the off-by-default
* features. */
#ifndef INSTRUMENT_DOWNLOADS
@@ -119,6 +119,7 @@
* conflict with system-defined signals. */
#define SIGNEWNYM 129
#define SIGCLEARDNSCACHE 130
+#define SIGHEARTBEAT 131
#if (SIZEOF_CELL_T != 0)
/* On Irix, stdlib.h defines a cell_t type, so we need to make sure
@@ -212,8 +213,7 @@ typedef enum {
#define CONN_TYPE_DIR_LISTENER 8
/** Type for HTTP connections to the directory server. */
#define CONN_TYPE_DIR 9
-/** Connection from the main process to a CPU worker process. */
-#define CONN_TYPE_CPUWORKER 10
+/* Type 10 is unused. */
/** Type for listening for connections from user interface process. */
#define CONN_TYPE_CONTROL_LISTENER 11
/** Type for connections from user interface process. */
@@ -241,7 +241,7 @@ typedef enum {
#define PROXY_CONNECT 1
#define PROXY_SOCKS4 2
#define PROXY_SOCKS5 3
-/* !!!! If there is ever a PROXY_* type over 2, we must grow the proxy_type
+/* !!!! If there is ever a PROXY_* type over 3, we must grow the proxy_type
* field in or_connection_t */
/* Pluggable transport proxy type. Don't use this in or_connection_t,
@@ -275,17 +275,6 @@ typedef enum {
/** State for any listener connection. */
#define LISTENER_STATE_READY 0
-#define CPUWORKER_STATE_MIN_ 1
-/** State for a connection to a cpuworker process that's idle. */
-#define CPUWORKER_STATE_IDLE 1
-/** State for a connection to a cpuworker process that's processing a
- * handshake. */
-#define CPUWORKER_STATE_BUSY_ONION 2
-#define CPUWORKER_STATE_MAX_ 2
-
-#define CPUWORKER_TASK_ONION CPUWORKER_STATE_BUSY_ONION
-#define CPUWORKER_TASK_SHUTDOWN 255
-
#define OR_CONN_STATE_MIN_ 1
/** State for a connection to an OR: waiting for connect() to finish. */
#define OR_CONN_STATE_CONNECTING 1
@@ -676,6 +665,10 @@ typedef enum {
/* Negative reasons are internal: we never send them in a DESTROY or TRUNCATE
* call; they only go to the controller for tracking */
+
+/* Closing introduction point that were opened in parallel. */
+#define END_CIRC_REASON_IP_NOW_REDUNDANT -4
+
/** Our post-timeout circuit time measurement period expired.
* We must give up now */
#define END_CIRC_REASON_MEASUREMENT_EXPIRED -3
@@ -1138,6 +1131,51 @@ typedef struct socks_request_t socks_request_t;
#define generic_buffer_t buf_t
#endif
+typedef struct entry_port_cfg_t {
+ /* Client port types (socks, dns, trans, natd) only: */
+ uint8_t isolation_flags; /**< Zero or more isolation flags */
+ int session_group; /**< A session group, or -1 if this port is not in a
+ * session group. */
+
+ /* Socks only: */
+ /** When both no-auth and user/pass are advertised by a SOCKS client, select
+ * no-auth. */
+ unsigned int socks_prefer_no_auth : 1;
+
+ /* Client port types only: */
+ unsigned int ipv4_traffic : 1;
+ unsigned int ipv6_traffic : 1;
+ unsigned int prefer_ipv6 : 1;
+
+ /** For a socks listener: should we cache IPv4/IPv6 DNS information that
+ * exit nodes tell us?
+ *
+ * @{ */
+ unsigned int cache_ipv4_answers : 1;
+ unsigned int cache_ipv6_answers : 1;
+ /** @} */
+ /** For a socks listeners: if we find an answer in our client-side DNS cache,
+ * should we use it?
+ *
+ * @{ */
+ unsigned int use_cached_ipv4_answers : 1;
+ unsigned int use_cached_ipv6_answers : 1;
+ /** @} */
+ /** For socks listeners: When we can automap an address to IPv4 or IPv6,
+ * do we prefer IPv6? */
+ unsigned int prefer_ipv6_virtaddr : 1;
+
+} entry_port_cfg_t;
+
+typedef struct server_port_cfg_t {
+ /* Server port types (or, dir) only: */
+ unsigned int no_advertise : 1;
+ unsigned int no_listen : 1;
+ unsigned int all_addrs : 1;
+ unsigned int bind_ipv4_only : 1;
+ unsigned int bind_ipv6_only : 1;
+} server_port_cfg_t;
+
/* Values for connection_t.magic: used to make sure that downcasts (casts from
* connection_t to foo_connection_t) are safe. */
#define BASE_CONNECTION_MAGIC 0x7C3C304Eu
@@ -1273,52 +1311,7 @@ typedef struct listener_connection_t {
* to the evdns_server_port it uses to listen to and answer connections. */
struct evdns_server_port *dns_server_port;
- /** @name Isolation parameters
- *
- * For an AP listener, these fields describe how to isolate streams that
- * arrive on the listener.
- *
- * @{
- */
- /** The session group for this listener. */
- int session_group;
- /** One or more ISO_ flags to describe how to isolate streams. */
- uint8_t isolation_flags;
- /**@}*/
- /** For SOCKS connections only: If this is set, we will choose "no
- * authentication" instead of "username/password" authentication if both
- * are offered. Used as input to parse_socks. */
- unsigned int socks_prefer_no_auth : 1;
-
- /** For a SOCKS listeners, these fields describe whether we should
- * allow IPv4 and IPv6 addresses from our exit nodes, respectively.
- *
- * @{
- */
- unsigned int socks_ipv4_traffic : 1;
- unsigned int socks_ipv6_traffic : 1;
- /** @} */
- /** For a socks listener: should we tell the exit that we prefer IPv6
- * addresses? */
- unsigned int socks_prefer_ipv6 : 1;
-
- /** For a socks listener: should we cache IPv4/IPv6 DNS information that
- * exit nodes tell us?
- *
- * @{ */
- unsigned int cache_ipv4_answers : 1;
- unsigned int cache_ipv6_answers : 1;
- /** @} */
- /** For a socks listeners: if we find an answer in our client-side DNS cache,
- * should we use it?
- *
- * @{ */
- unsigned int use_cached_ipv4_answers : 1;
- unsigned int use_cached_ipv6_answers : 1;
- /** @} */
- /** For socks listeners: When we can automap an address to IPv4 or IPv6,
- * do we prefer IPv6? */
- unsigned int prefer_ipv6_virtaddr : 1;
+ entry_port_cfg_t entry_cfg;
} listener_connection_t;
@@ -1426,6 +1419,18 @@ typedef struct or_handshake_state_t {
/** Length of Extended ORPort connection identifier. */
#define EXT_OR_CONN_ID_LEN DIGEST_LEN /* 20 */
+/*
+ * OR_CONN_HIGHWATER and OR_CONN_LOWWATER moved from connection_or.c so
+ * channeltls.c can see them too.
+ */
+
+/** When adding cells to an OR connection's outbuf, keep adding until the
+ * outbuf is at least this long, or we run out of cells. */
+#define OR_CONN_HIGHWATER (32*1024)
+
+/** Add cells to an OR connection's outbuf whenever the outbuf's data length
+ * drops below this size. */
+#define OR_CONN_LOWWATER (16*1024)
/** Subtype of connection_t for an "OR connection" -- that is, one that speaks
* cells over TLS. */
@@ -1517,6 +1522,12 @@ typedef struct or_connection_t {
/** Last emptied write token bucket in msec since midnight; only used if
* TB_EMPTY events are enabled. */
uint32_t write_emptied_time;
+
+ /*
+ * Count the number of bytes flushed out on this orconn, and the number of
+ * bytes TLS actually sent - used for overhead estimation for scheduling.
+ */
+ uint64_t bytes_xmitted, bytes_xmitted_by_tls;
} or_connection_t;
/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap)
@@ -1588,12 +1599,10 @@ typedef struct entry_connection_t {
* only.) */
/* === Isolation related, AP only. === */
- /** AP only: based on which factors do we isolate this stream? */
- uint8_t isolation_flags;
- /** AP only: what session group is this stream in? */
- int session_group;
+ entry_port_cfg_t entry_cfg;
/** AP only: The newnym epoch in which we created this connection. */
unsigned nym_epoch;
+
/** AP only: The original requested address before we rewrote it. */
char *original_dest_address;
/* Other fields to isolate on already exist. The ClientAddr is addr. The
@@ -1652,33 +1661,8 @@ typedef struct entry_connection_t {
*/
unsigned int may_use_optimistic_data : 1;
- /** Should we permit IPv4 and IPv6 traffic to use this connection?
- *
- * @{ */
- unsigned int ipv4_traffic_ok : 1;
- unsigned int ipv6_traffic_ok : 1;
- /** @} */
- /** Should we say we prefer IPv6 traffic? */
- unsigned int prefer_ipv6_traffic : 1;
-
- /** For a socks listener: should we cache IPv4/IPv6 DNS information that
- * exit nodes tell us?
- *
- * @{ */
- unsigned int cache_ipv4_answers : 1;
- unsigned int cache_ipv6_answers : 1;
- /** @} */
- /** For a socks listeners: if we find an answer in our client-side DNS cache,
- * should we use it?
- *
- * @{ */
- unsigned int use_cached_ipv4_answers : 1;
- unsigned int use_cached_ipv6_answers : 1;
- /** @} */
- /** For socks listeners: When we can automap an address to IPv4 or IPv6,
- * do we prefer IPv6? */
- unsigned int prefer_ipv6_virtaddr : 1;
-
+ /** Are we a socks SocksSocket listener? */
+ unsigned int is_socks_socket:1;
} entry_connection_t;
typedef enum {
@@ -1958,6 +1942,7 @@ typedef struct download_status_t {
uint8_t n_download_failures; /**< Number of failures trying to download the
* most recent descriptor. */
download_schedule_bitfield_t schedule : 8;
+
} download_status_t;
/** If n_download_failures is this high, the download can never happen. */
@@ -2139,8 +2124,6 @@ typedef struct routerstatus_t {
* choice as an entry guard. */
unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for
* an exit node. */
- unsigned int is_bad_directory:1; /**< Do we think this directory is junky,
- * underpowered, or otherwise useless? */
unsigned int is_hs_dir:1; /**< True iff this router is a v2-or-later hidden
* service directory. */
/** True iff we know version info for this router. (i.e., a "v" entry was
@@ -2151,9 +2134,6 @@ typedef struct routerstatus_t {
/** True iff this router is a version that, if it caches directory info,
* we can get microdescriptors from. */
unsigned int version_supports_microdesc_cache:1;
- /** True iff this router is a version that allows DATA cells to arrive on
- * a stream before it has sent a CONNECTED cell. */
- unsigned int version_supports_optimistic_data:1;
/** True iff this router has a version that allows it to accept EXTEND2
* cells */
unsigned int version_supports_extend2_cells:1;
@@ -2165,6 +2145,12 @@ typedef struct routerstatus_t {
uint32_t bandwidth_kb; /**< Bandwidth (capacity) of the router as reported in
* the vote/consensus, in kilobytes/sec. */
+
+ /** The consensus has guardfraction information for this router. */
+ unsigned int has_guardfraction:1;
+ /** The guardfraction value of this router. */
+ uint32_t guardfraction_percentage;
+
char *exitsummary; /**< exit policy summary -
* XXX weasel: this probably should not stay a string. */
@@ -2300,8 +2286,6 @@ typedef struct node_t {
unsigned int is_exit:1; /**< Do we think this is an OK exit? */
unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked,
* or otherwise nasty? */
- unsigned int is_bad_directory:1; /**< Do we think this directory is junky,
- * underpowered, or otherwise useless? */
unsigned int is_hs_dir:1; /**< True iff this router is a hidden service
* directory according to the authorities. */
@@ -2439,6 +2423,9 @@ typedef struct networkstatus_t {
/** Vote only: what methods is this voter willing to use? */
smartlist_t *supported_methods;
+ /** List of 'package' lines describing hashes of downloadable packages */
+ smartlist_t *package_lines;
+
/** How long does this vote/consensus claim that authorities take to
* distribute their votes to one another? */
int vote_seconds;
@@ -2560,9 +2547,7 @@ typedef struct extend_info_t {
uint16_t port; /**< OR port. */
tor_addr_t addr; /**< IP address. */
crypto_pk_t *onion_key; /**< Current onionskin key. */
-#ifdef CURVE25519_ENABLED
curve25519_public_key_t curve25519_onion_key;
-#endif
} extend_info_t;
/** Certificate for v3 directory protocol: binds long-term authority identity
@@ -2719,8 +2704,14 @@ typedef struct {
time_t expiry_time;
} cpath_build_state_t;
+/** "magic" value for an origin_circuit_t */
#define ORIGIN_CIRCUIT_MAGIC 0x35315243u
+/** "magic" value for an or_circuit_t */
#define OR_CIRCUIT_MAGIC 0x98ABC04Fu
+/** "magic" value for a circuit that would have been freed by circuit_free,
+ * but which we're keeping around until a cpuworker reply arrives. See
+ * circuit_free() for more documentation. */
+#define DEAD_CIRCUIT_MAGIC 0xdeadc14c
struct create_cell_t;
@@ -2865,8 +2856,8 @@ typedef struct circuit_t {
/** Unique ID for measuring tunneled network status requests. */
uint64_t dirreq_id;
- /** Next circuit in linked list of all circuits (global_circuitlist). */
- TOR_LIST_ENTRY(circuit_t) head;
+ /** Index in smartlist of all circuits (global_circuitlist). */
+ int global_circuitlist_idx;
/** Next circuit in the doubly-linked ring of circuits waiting to add
* cells to n_conn. NULL if we have no cells pending, or if we're not
@@ -3140,6 +3131,10 @@ typedef struct or_circuit_t {
/** Pointer to an entry on the onion queue, if this circuit is waiting for a
* chance to give an onionskin to a cpuworker. Used only in onion.c */
struct onion_queue_t *onionqueue_entry;
+ /** Pointer to a workqueue entry, if this circuit has given an onionskin to
+ * a cpuworker and is waiting for a response. Used to decide whether it is
+ * safe to free a circuit or if it is still in use by a cpuworker. */
+ struct workqueue_entry_s *workqueue_entry;
/** The circuit_id used in the previous (backward) hop of this circuit. */
circid_t p_circ_id;
@@ -3192,6 +3187,10 @@ typedef struct or_circuit_t {
/** True iff this circuit was made with a CREATE_FAST cell. */
unsigned int is_first_hop : 1;
+ /** If set, this circuit carries HS traffic. Consider it in any HS
+ * statistics. */
+ unsigned int circuit_carries_hs_traffic_stats : 1;
+
/** Number of cells that were removed from circuit queue; reset every
* time when writing buffer stats to disk. */
uint32_t processed_cells;
@@ -3239,6 +3238,14 @@ static const or_circuit_t *CONST_TO_OR_CIRCUIT(const circuit_t *);
static origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *);
static const origin_circuit_t *CONST_TO_ORIGIN_CIRCUIT(const circuit_t *);
+/** Return 1 iff <b>node</b> has Exit flag and no BadExit flag.
+ * Otherwise, return 0.
+ */
+static INLINE int node_is_good_exit(const node_t *node)
+{
+ return node->is_exit && ! node->is_bad_exit;
+}
+
static INLINE or_circuit_t *TO_OR_CIRCUIT(circuit_t *x)
{
tor_assert(x->magic == OR_CIRCUIT_MAGIC);
@@ -3318,44 +3325,9 @@ typedef struct port_cfg_t {
uint8_t type; /**< One of CONN_TYPE_*_LISTENER */
unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */
- /* Client port types (socks, dns, trans, natd) only: */
- uint8_t isolation_flags; /**< Zero or more isolation flags */
- int session_group; /**< A session group, or -1 if this port is not in a
- * session group. */
- /* Socks only: */
- /** When both no-auth and user/pass are advertised by a SOCKS client, select
- * no-auth. */
- unsigned int socks_prefer_no_auth : 1;
-
- /* Server port types (or, dir) only: */
- unsigned int no_advertise : 1;
- unsigned int no_listen : 1;
- unsigned int all_addrs : 1;
- unsigned int bind_ipv4_only : 1;
- unsigned int bind_ipv6_only : 1;
-
- /* Client port types only: */
- unsigned int ipv4_traffic : 1;
- unsigned int ipv6_traffic : 1;
- unsigned int prefer_ipv6 : 1;
+ entry_port_cfg_t entry_cfg;
- /** For a socks listener: should we cache IPv4/IPv6 DNS information that
- * exit nodes tell us?
- *
- * @{ */
- unsigned int cache_ipv4_answers : 1;
- unsigned int cache_ipv6_answers : 1;
- /** @} */
- /** For a socks listeners: if we find an answer in our client-side DNS cache,
- * should we use it?
- *
- * @{ */
- unsigned int use_cached_ipv4_answers : 1;
- unsigned int use_cached_ipv6_answers : 1;
- /** @} */
- /** For socks listeners: When we can automap an address to IPv4 or IPv6,
- * do we prefer IPv6? */
- unsigned int prefer_ipv6_virtaddr : 1;
+ server_port_cfg_t server_cfg;
/* Unix sockets only: */
/** Path for an AF_UNIX address */
@@ -3406,6 +3378,8 @@ typedef struct {
int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which
* each log message occurs? */
+ int TruncateLogFile; /**< Boolean: Should we truncate the log file
+ before we start writing? */
char *DebugLogFile; /**< Where to send verbose log messages. */
char *DataDirectory; /**< OR only: where to store long-term data. */
@@ -3472,6 +3446,7 @@ typedef struct {
config_line_t *RecommendedVersions;
config_line_t *RecommendedClientVersions;
config_line_t *RecommendedServerVersions;
+ config_line_t *RecommendedPackages;
/** Whether dirservers allow router descriptors with private IPs. */
int DirAllowPrivateAddresses;
/** Whether routers accept EXTEND cells to routers with private IPs. */
@@ -3502,6 +3477,7 @@ typedef struct {
* for control connections. */
int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */
+ int SocksSocketsGroupWritable; /**< Boolean: Are SOCKS sockets g+rw? */
/** Ports to listen on for directory connections. */
config_line_t *DirPort_lines;
config_line_t *DNSPort_lines; /**< Ports to listen on for DNS requests. */
@@ -3511,6 +3487,8 @@ typedef struct {
uint64_t MaxMemInQueues_raw;
uint64_t MaxMemInQueues;/**< If we have more memory than this allocated
* for queues and buffers, run the OOM handler */
+ /** Above this value, consider ourselves low on RAM. */
+ uint64_t MaxMemInQueues_low_threshold;
/** @name port booleans
*
@@ -3534,8 +3512,6 @@ typedef struct {
int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
int V3AuthoritativeDir; /**< Boolean: is this an authoritative directory
* for version 3 directories? */
- int NamingAuthoritativeDir; /**< Boolean: is this an authoritative directory
- * that's willing to bind names? */
int VersioningAuthoritativeDir; /**< Boolean: is this an authoritative
* directory that's willing to recommend
* versions? */
@@ -3600,6 +3576,9 @@ typedef struct {
* circuits.) */
int Tor2webMode;
+ /** A routerset that should be used when picking RPs for HS circuits. */
+ routerset_t *Tor2webRendezvousPoints;
+
/** Close hidden service client circuits immediately when they reach
* the normal circuit-build timeout, even if they have already sent
* an INTRODUCE1 cell on its way to the service. */
@@ -3649,8 +3628,9 @@ typedef struct {
* hostname ending with one of the suffixes in
* <b>AutomapHostsSuffixes</b>, map it to a
* virtual address. */
- smartlist_t *AutomapHostsSuffixes; /**< List of suffixes for
- * <b>AutomapHostsOnResolve</b>. */
+ /** List of suffixes for <b>AutomapHostsOnResolve</b>. The special value
+ * "." means "match everything." */
+ smartlist_t *AutomapHostsSuffixes;
int RendPostPeriod; /**< How often do we post each rendezvous service
* descriptor? Remember to publish them independently. */
int KeepalivePeriod; /**< How often do we send padding cells to keep
@@ -3745,8 +3725,6 @@ typedef struct {
config_line_t *NodeFamilies; /**< List of config lines for
* node families */
smartlist_t *NodeFamilySets; /**< List of parsed NodeFamilies values. */
- config_line_t *AuthDirBadDir; /**< Address policy for descriptors to
- * mark as bad dir mirrors. */
config_line_t *AuthDirBadExit; /**< Address policy for descriptors to
* mark as bad exits. */
config_line_t *AuthDirReject; /**< Address policy for descriptors to
@@ -3755,23 +3733,18 @@ typedef struct {
* never mark as valid. */
/** @name AuthDir...CC
*
- * Lists of country codes to mark as BadDir, BadExit, or Invalid, or to
+ * Lists of country codes to mark as BadExit, or Invalid, or to
* reject entirely.
*
* @{
*/
- smartlist_t *AuthDirBadDirCCs;
smartlist_t *AuthDirBadExitCCs;
smartlist_t *AuthDirInvalidCCs;
smartlist_t *AuthDirRejectCCs;
/**@}*/
- int AuthDirListBadDirs; /**< True iff we should list bad dirs,
- * and vote for all other dir mirrors as good. */
int AuthDirListBadExits; /**< True iff we should list bad exits,
* and vote for all other exits as good. */
- int AuthDirRejectUnlisted; /**< Boolean: do we reject all routers that
- * aren't named in our fingerprint file? */
int AuthDirMaxServersPerAddr; /**< Do not permit more than this
* number of servers per IP address. */
int AuthDirMaxServersPerAuthAddr; /**< Do not permit more than this
@@ -3792,6 +3765,11 @@ typedef struct {
uint64_t AccountingMax; /**< How many bytes do we allow per accounting
* interval before hibernation? 0 for "never
* hibernate." */
+ /** How do we determine when our AccountingMax has been reached?
+ * "max" for when in or out reaches AccountingMax
+ * "sum for when in plus out reaches AccountingMax */
+ char *AccountingRule_option;
+ enum { ACCT_MAX, ACCT_SUM } AccountingRule;
/** Base64-encoded hash of accepted passwords for the control system. */
config_line_t *HashedControlPassword;
@@ -3847,6 +3825,12 @@ typedef struct {
int NumEntryGuards; /**< How many entry guards do we try to establish? */
int UseEntryGuardsAsDirGuards; /** Boolean: Do we try to get directory info
* from a smallish number of fixed nodes? */
+
+ /** If 1, we use any guardfraction information we see in the
+ * consensus. If 0, we don't. If -1, let the consensus parameter
+ * decide. */
+ int UseGuardFraction;
+
int NumDirectoryGuards; /**< How many dir guards do we try to establish?
* If 0, use value from NumEntryGuards. */
int RephistTrackTime; /**< How many seconds do we keep rephist info? */
@@ -3924,8 +3908,11 @@ typedef struct {
* instead of a hostname. */
int WarnUnsafeSocks;
- /** If true, the user wants us to collect statistics on clients
+ /** If true, we're configured to collect statistics on clients
* requesting network statuses from us as directory. */
+ int DirReqStatistics_option;
+ /** Internal variable to remember whether we're actually acting on
+ * DirReqStatistics_option -- yes if it's set and we're a server, else no. */
int DirReqStatistics;
/** If true, the user wants us to collect statistics on port usage. */
@@ -3940,6 +3927,10 @@ typedef struct {
/** If true, the user wants us to collect statistics as entry node. */
int EntryStatistics;
+ /** If true, the user wants us to collect statistics as hidden service
+ * directory, introduction point, or rendezvous point. */
+ int HiddenServiceStatistics;
+
/** If true, include statistics file contents in extra-info documents. */
int ExtraInfoStatistics;
@@ -3975,6 +3966,9 @@ typedef struct {
/** Location of bandwidth measurement file */
char *V3BandwidthsFile;
+ /** Location of guardfraction file */
+ char *GuardfractionFile;
+
/** Authority only: key=value pairs that we add to our networkstatus
* consensus vote on the 'params' line. */
char *ConsensusParams;
@@ -4065,10 +4059,19 @@ typedef struct {
/** Minimum value for the Fast flag threshold on testing networks. */
uint64_t TestingMinFastFlagThreshold;
+ /** Relays in a testing network which should be voted Exit
+ * regardless of exit policy. */
+ routerset_t *TestingDirAuthVoteExit;
+
/** Relays in a testing network which should be voted Guard
* regardless of uptime and bandwidth. */
routerset_t *TestingDirAuthVoteGuard;
+ /** Relays in a testing network which should be voted HSDir
+ * regardless of uptime and ORPort connectivity.
+ * Respects VoteOnHidServDirectoriesV2. */
+ routerset_t *TestingDirAuthVoteHSDir;
+
/** Enable CONN_BW events. Only altered on testing networks. */
int TestingEnableConnBwEvent;
@@ -4223,8 +4226,26 @@ typedef struct {
/** How long (seconds) do we keep a guard before picking a new one? */
int GuardLifetime;
- /** Should we send the timestamps that pre-023 hidden services want? */
- int Support022HiddenServices;
+ /** Low-water mark for global scheduler - start sending when estimated
+ * queued size falls below this threshold.
+ */
+ uint64_t SchedulerLowWaterMark__;
+ /** High-water mark for global scheduler - stop sending when estimated
+ * queued size exceeds this threshold.
+ */
+ uint64_t SchedulerHighWaterMark__;
+ /** Flush size for global scheduler - flush this many cells at a time
+ * when sending.
+ */
+ int SchedulerMaxFlushCells__;
+
+ /** Is this an exit node? This is a tristate, where "1" means "yes, and use
+ * the default exit policy if none is given" and "0" means "no; exit policy
+ * is 'reject *'" and "auto" (-1) means "same as 1, but warn the user."
+ *
+ * XXXX Eventually, the default will be 0. */
+ int ExitRelay;
+
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */
@@ -4315,7 +4336,8 @@ static INLINE void or_state_mark_dirty(or_state_t *state, time_t when)
/** Please turn this IP address into an FQDN, privately. */
#define SOCKS_COMMAND_RESOLVE_PTR 0xF1
-#define SOCKS_COMMAND_IS_CONNECT(c) ((c)==SOCKS_COMMAND_CONNECT)
+/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */
+#define SOCKS_COMMAND_IS_CONNECT(c) (((c)==SOCKS_COMMAND_CONNECT) || 0)
#define SOCKS_COMMAND_IS_RESOLVE(c) ((c)==SOCKS_COMMAND_RESOLVE || \
(c)==SOCKS_COMMAND_RESOLVE_PTR)
@@ -4894,7 +4916,8 @@ typedef struct rend_service_descriptor_t {
/** A cached rendezvous descriptor. */
typedef struct rend_cache_entry_t {
size_t len; /**< Length of <b>desc</b> */
- time_t received; /**< When was the descriptor received? */
+ time_t last_served; /**< When did we last write this one to somebody?
+ * (HSDir only) */
char *desc; /**< Service descriptor */
rend_service_descriptor_t *parsed; /**< Parsed value of 'desc' */
} rend_cache_entry_t;
@@ -4936,7 +4959,8 @@ typedef struct dir_server_t {
**/
} dir_server_t;
-#define ROUTER_REQUIRED_MIN_BANDWIDTH (20*1024)
+#define RELAY_REQUIRED_MIN_BANDWIDTH (75*1024)
+#define BRIDGE_REQUIRED_MIN_BANDWIDTH (50*1024)
#define ROUTER_MAX_DECLARED_BANDWIDTH INT32_MAX
@@ -4960,14 +4984,13 @@ typedef struct dir_server_t {
* or extrainfo documents.
*
* Passed to router_pick_directory_server (et al)
- *
- * [XXXX NOTE: This option is only implemented for pick_trusteddirserver,
- * not pick_directory_server. If we make it work on pick_directory_server
- * too, we could conservatively make it only prevent multiple fetches to
- * the same authority, or we could aggressively make it prevent multiple
- * fetches to _any_ single directory server.]
*/
#define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3)
+/** Flag to indicate that we should not use any directory authority to which
+ * we have an existing directory connection for downloading microdescs.
+ *
+ * Passed to router_pick_directory_server (et al)
+ */
#define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4)
/** This node is to be chosen as a directory guard, so don't choose any
@@ -4995,14 +5018,31 @@ typedef enum {
/** Return value for router_add_to_routerlist() and dirserv_add_descriptor() */
typedef enum was_router_added_t {
+ /* Router was added successfully. */
ROUTER_ADDED_SUCCESSFULLY = 1,
+ /* Router descriptor was added with warnings to submitter. */
ROUTER_ADDED_NOTIFY_GENERATOR = 0,
+ /* Extrainfo document was rejected because no corresponding router
+ * descriptor was found OR router descriptor was rejected because
+ * it was incompatible with its extrainfo document. */
ROUTER_BAD_EI = -1,
- ROUTER_WAS_NOT_NEW = -2,
+ /* Router descriptor was rejected because it is already known. */
+ ROUTER_IS_ALREADY_KNOWN = -2,
+ /* General purpose router was rejected, because it was not listed
+ * in consensus. */
ROUTER_NOT_IN_CONSENSUS = -3,
+ /* Router was neither in directory consensus nor in any of
+ * networkstatus documents. Caching it to access later.
+ * (Applies to fetched descriptors only.) */
ROUTER_NOT_IN_CONSENSUS_OR_NETWORKSTATUS = -4,
+ /* Router was rejected by directory authority. */
ROUTER_AUTHDIR_REJECTS = -5,
- ROUTER_WAS_NOT_WANTED = -6
+ /* Bridge descriptor was rejected because such bridge was not one
+ * of the bridges we have listed in our configuration. */
+ ROUTER_WAS_NOT_WANTED = -6,
+ /* Router descriptor was rejected because it was older than
+ * OLD_ROUTER_DESC_MAX_AGE. */
+ ROUTER_WAS_TOO_OLD = -7, /* note contrast with 'NOT_NEW' */
} was_router_added_t;
/********************************* routerparse.c ************************/
diff --git a/src/or/policies.c b/src/or/policies.c
index 8a91509a77..560b8cb4c3 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,9 +29,6 @@ static smartlist_t *authdir_reject_policy = NULL;
* to be marked as valid in our networkstatus. */
static smartlist_t *authdir_invalid_policy = NULL;
/** Policy that addresses for incoming router descriptors must <b>not</b>
- * match in order to not be marked as BadDirectory. */
-static smartlist_t *authdir_baddir_policy = NULL;
-/** Policy that addresses for incoming router descriptors must <b>not</b>
* match in order to not be marked as BadExit. */
static smartlist_t *authdir_badexit_policy = NULL;
@@ -65,6 +62,13 @@ static const char *private_nets[] = {
NULL
};
+static int policies_parse_exit_policy_internal(config_line_t *cfg,
+ smartlist_t **dest,
+ int ipv6_exit,
+ int rejectprivate,
+ uint32_t local_address,
+ int add_default_policy);
+
/** Replace all "private" entries in *<b>policy</b> with their expanded
* equivalents. */
void
@@ -400,17 +404,6 @@ authdir_policy_valid_address(uint32_t addr, uint16_t port)
return !addr_is_in_cc_list(addr, get_options()->AuthDirInvalidCCs);
}
-/** Return 1 if <b>addr</b>:<b>port</b> should be marked as a bad dir,
- * based on <b>authdir_baddir_policy</b>. Else return 0.
- */
-int
-authdir_policy_baddir_address(uint32_t addr, uint16_t port)
-{
- if (! addr_policy_permits_address(addr, port, authdir_baddir_policy))
- return 1;
- return addr_is_in_cc_list(addr, get_options()->AuthDirBadDirCCs);
-}
-
/** Return 1 if <b>addr</b>:<b>port</b> should be marked as a bad exit,
* based on <b>authdir_badexit_policy</b>. Else return 0.
*/
@@ -437,11 +430,36 @@ validate_addr_policies(const or_options_t *options, char **msg)
smartlist_t *addr_policy=NULL;
*msg = NULL;
- if (policies_parse_exit_policy(options->ExitPolicy, &addr_policy,
- options->IPv6Exit,
- options->ExitPolicyRejectPrivate, 0,
- !options->BridgeRelay))
+ if (policies_parse_exit_policy_from_options(options,0,&addr_policy)) {
REJECT("Error in ExitPolicy entry.");
+ }
+
+ static int warned_about_exitrelay = 0;
+
+ const int exitrelay_setting_is_auto = options->ExitRelay == -1;
+ const int policy_accepts_something =
+ ! (policy_is_reject_star(addr_policy, AF_INET) &&
+ policy_is_reject_star(addr_policy, AF_INET6));
+
+ if (server_mode(options) &&
+ ! warned_about_exitrelay &&
+ exitrelay_setting_is_auto &&
+ policy_accepts_something) {
+ /* Policy accepts something */
+ warned_about_exitrelay = 1;
+ log_warn(LD_CONFIG,
+ "Tor is running as an exit relay%s. If you did not want this "
+ "behavior, please set the ExitRelay option to 0. If you do "
+ "want to run an exit Relay, please set the ExitRelay option "
+ "to 1 to disable this warning, and for forward compatibility.",
+ options->ExitPolicy == NULL ?
+ " with the default exit policy" : "");
+ if (options->ExitPolicy == NULL) {
+ log_warn(LD_CONFIG,
+ "In a future version of Tor, ExitRelay 0 may become the "
+ "default when no ExitPolicy is given.");
+ }
+ }
/* The rest of these calls *append* to addr_policy. So don't actually
* use the results for anything other than checking if they parse! */
@@ -455,9 +473,6 @@ validate_addr_policies(const or_options_t *options, char **msg)
if (parse_addr_policy(options->AuthDirInvalid, &addr_policy,
ADDR_POLICY_REJECT))
REJECT("Error in AuthDirInvalid entry.");
- if (parse_addr_policy(options->AuthDirBadDir, &addr_policy,
- ADDR_POLICY_REJECT))
- REJECT("Error in AuthDirBadDir entry.");
if (parse_addr_policy(options->AuthDirBadExit, &addr_policy,
ADDR_POLICY_REJECT))
REJECT("Error in AuthDirBadExit entry.");
@@ -535,9 +550,6 @@ policies_parse_from_options(const or_options_t *options)
if (load_policy_from_option(options->AuthDirInvalid, "AuthDirInvalid",
&authdir_invalid_policy, ADDR_POLICY_REJECT) < 0)
ret = -1;
- if (load_policy_from_option(options->AuthDirBadDir, "AuthDirBadDir",
- &authdir_baddir_policy, ADDR_POLICY_REJECT) < 0)
- ret = -1;
if (load_policy_from_option(options->AuthDirBadExit, "AuthDirBadExit",
&authdir_badexit_policy, ADDR_POLICY_REJECT) < 0)
ret = -1;
@@ -629,8 +641,8 @@ policy_hash(const policy_map_ent_t *ent)
HT_PROTOTYPE(policy_map, policy_map_ent_t, node, policy_hash,
policy_eq)
-HT_GENERATE(policy_map, policy_map_ent_t, node, policy_hash,
- policy_eq, 0.6, malloc, realloc, free)
+HT_GENERATE2(policy_map, policy_map_ent_t, node, policy_hash,
+ policy_eq, 0.6, tor_reallocarray_, tor_free_)
/** Given a pointer to an addr_policy_t, return a copy of the pointer to the
* "canonical" copy of that addr_policy_t; the canonical copy is a single
@@ -769,9 +781,9 @@ compare_unknown_tor_addr_to_addr_policy(uint16_t port,
* We could do better by assuming that some ranges never match typical
* addresses (127.0.0.1, and so on). But we'll try this for now.
*/
-addr_policy_result_t
-compare_tor_addr_to_addr_policy(const tor_addr_t *addr, uint16_t port,
- const smartlist_t *policy)
+MOCK_IMPL(addr_policy_result_t,
+compare_tor_addr_to_addr_policy,(const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy))
{
if (!policy) {
/* no policy? accept all. */
@@ -968,11 +980,12 @@ exit_policy_remove_redundancies(smartlist_t *dest)
* the functions used to parse the exit policy from a router descriptor,
* see router_add_exit_policy.
*/
-int
-policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
- int ipv6_exit,
- int rejectprivate, uint32_t local_address,
- int add_default_policy)
+static int
+policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest,
+ int ipv6_exit,
+ int rejectprivate,
+ uint32_t local_address,
+ int add_default_policy)
{
if (!ipv6_exit) {
append_exit_policy_string(dest, "reject *6:*");
@@ -998,6 +1011,77 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
return 0;
}
+/** Parse exit policy in <b>cfg</b> into <b>dest</b> smartlist.
+ *
+ * Add entry that rejects all IPv6 destinations unless
+ * <b>EXIT_POLICY_IPV6_ENABLED</b> bit is set in <b>options</b> bitmask.
+ *
+ * If <b>EXIT_POLICY_REJECT_PRIVATE</b> bit is set in <b>options</b>,
+ * do add entry that rejects all destinations in private subnetwork
+ * Tor is running in.
+ *
+ * Respectively, if <b>EXIT_POLICY_ADD_DEFAULT</b> bit is set, add
+ * default exit policy entries to <b>result</b> smartlist.
+ */
+int
+policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
+ exit_policy_parser_cfg_t options,
+ uint32_t local_address)
+{
+ int ipv6_enabled = (options & EXIT_POLICY_IPV6_ENABLED) ? 1 : 0;
+ int reject_private = (options & EXIT_POLICY_REJECT_PRIVATE) ? 1 : 0;
+ int add_default = (options & EXIT_POLICY_ADD_DEFAULT) ? 1 : 0;
+
+ return policies_parse_exit_policy_internal(cfg,dest,ipv6_enabled,
+ reject_private,
+ local_address,
+ add_default);
+}
+
+/** Parse <b>ExitPolicy</b> member of <b>or_options</b> into <b>result</b>
+ * smartlist.
+ * If <b>or_options->IPv6Exit</b> is false, add an entry that
+ * rejects all IPv6 destinations.
+ *
+ * If <b>or_options->ExitPolicyRejectPrivate</b> is true, add entry that
+ * rejects all destinations in the private subnetwork of machine Tor
+ * instance is running in.
+ *
+ * If <b>or_options->BridgeRelay</b> is false, add entries of default
+ * Tor exit policy into <b>result</b> smartlist.
+ *
+ * If or_options->ExitRelay is false, then make our exit policy into
+ * "reject *:*" regardless.
+ */
+int
+policies_parse_exit_policy_from_options(const or_options_t *or_options,
+ uint32_t local_address,
+ smartlist_t **result)
+{
+ exit_policy_parser_cfg_t parser_cfg = 0;
+
+ if (or_options->ExitRelay == 0) {
+ append_exit_policy_string(result, "reject *4:*");
+ append_exit_policy_string(result, "reject *6:*");
+ return 0;
+ }
+
+ if (or_options->IPv6Exit) {
+ parser_cfg |= EXIT_POLICY_IPV6_ENABLED;
+ }
+
+ if (or_options->ExitPolicyRejectPrivate) {
+ parser_cfg |= EXIT_POLICY_REJECT_PRIVATE;
+ }
+
+ if (!or_options->BridgeRelay) {
+ parser_cfg |= EXIT_POLICY_ADD_DEFAULT;
+ }
+
+ return policies_parse_exit_policy(or_options->ExitPolicy,result,
+ parser_cfg,local_address);
+}
+
/** Add "reject *:*" to the end of the policy in *<b>dest</b>, allocating
* *<b>dest</b> as needed. */
void
@@ -1334,9 +1418,9 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p)
* The summary will either be an "accept" plus a comma-separated list of port
* ranges or a "reject" plus port-ranges, depending on which is shorter.
*
- * If no exits are allowed at all then NULL is returned, if no ports
- * are blocked instead of "reject " we return "accept 1-65535" (this
- * is an exception to the shorter-representation-wins rule).
+ * If no exits are allowed at all then "reject 1-65535" is returned. If no
+ * ports are blocked instead of "reject " we return "accept 1-65535". (These
+ * are an exception to the shorter-representation-wins rule).
*/
char *
policy_summarize(smartlist_t *policy, sa_family_t family)
@@ -1766,8 +1850,6 @@ policies_free_all(void)
authdir_reject_policy = NULL;
addr_policy_list_free(authdir_invalid_policy);
authdir_invalid_policy = NULL;
- addr_policy_list_free(authdir_baddir_policy);
- authdir_baddir_policy = NULL;
addr_policy_list_free(authdir_badexit_policy);
authdir_badexit_policy = NULL;
diff --git a/src/or/policies.h b/src/or/policies.h
index 91ac427492..0225b57a2c 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -18,6 +18,12 @@
*/
#define POLICY_BUF_LEN 72
+#define EXIT_POLICY_IPV6_ENABLED (1 << 0)
+#define EXIT_POLICY_REJECT_PRIVATE (1 << 1)
+#define EXIT_POLICY_ADD_DEFAULT (1 << 2)
+
+typedef int exit_policy_parser_cfg_t;
+
int firewall_is_fascist_or(void);
int fascist_firewall_allows_address_or(const tor_addr_t *addr, uint16_t port);
int fascist_firewall_allows_or(const routerinfo_t *ri);
@@ -27,7 +33,6 @@ int dir_policy_permits_address(const tor_addr_t *addr);
int socks_policy_permits_address(const tor_addr_t *addr);
int authdir_policy_permits_address(uint32_t addr, uint16_t port);
int authdir_policy_valid_address(uint32_t addr, uint16_t port);
-int authdir_policy_baddir_address(uint32_t addr, uint16_t port);
int authdir_policy_badexit_address(uint32_t addr, uint16_t port);
int validate_addr_policies(const or_options_t *options, char **msg);
@@ -37,16 +42,24 @@ int policies_parse_from_options(const or_options_t *options);
addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent);
int cmp_addr_policies(smartlist_t *a, smartlist_t *b);
-addr_policy_result_t compare_tor_addr_to_addr_policy(const tor_addr_t *addr,
- uint16_t port, const smartlist_t *policy);
+MOCK_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+ (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr,
uint16_t port, const node_t *node);
+/*
int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
int ipv6exit,
int rejectprivate, uint32_t local_address,
int add_default_policy);
+*/
+int policies_parse_exit_policy_from_options(const or_options_t *or_options,
+ uint32_t local_address,
+ smartlist_t **result);
+int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
+ exit_policy_parser_cfg_t options,
+ uint32_t local_address);
void policies_exit_policy_append_reject_star(smartlist_t **dest);
void addr_policy_append_reject_addr(smartlist_t **dest,
const tor_addr_t *addr);
diff --git a/src/or/reasons.c b/src/or/reasons.c
index 750e89bbe7..23ab6041a6 100644
--- a/src/or/reasons.c
+++ b/src/or/reasons.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -350,6 +350,8 @@ circuit_end_reason_to_control_string(int reason)
return "NOSUCHSERVICE";
case END_CIRC_REASON_MEASUREMENT_EXPIRED:
return "MEASUREMENT_EXPIRED";
+ case END_CIRC_REASON_IP_NOW_REDUNDANT:
+ return "IP_NOW_REDUNDANT";
default:
if (is_remote) {
/*
@@ -367,7 +369,7 @@ circuit_end_reason_to_control_string(int reason)
}
}
-/** Return a string corresponding to a SOCKS4 reponse code. */
+/** Return a string corresponding to a SOCKS4 response code. */
const char *
socks4_response_code_to_string(uint8_t code)
{
@@ -385,7 +387,7 @@ socks4_response_code_to_string(uint8_t code)
}
}
-/** Return a string corresponding to a SOCKS5 reponse code. */
+/** Return a string corresponding to a SOCKS5 response code. */
const char *
socks5_response_code_to_string(uint8_t code)
{
diff --git a/src/or/reasons.h b/src/or/reasons.h
index fe7e67722a..00a099061b 100644
--- a/src/or/reasons.h
+++ b/src/or/reasons.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/relay.c b/src/or/relay.c
index daf354c34c..bbb5f27c93 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -26,9 +26,6 @@
#include "control.h"
#include "geoip.h"
#include "main.h"
-#ifdef ENABLE_MEMPOOLS
-#include "mempool.h"
-#endif
#include "networkstatus.h"
#include "nodelist.h"
#include "onion.h"
@@ -39,6 +36,7 @@
#include "router.h"
#include "routerlist.h"
#include "routerparse.h"
+#include "scheduler.h"
static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell,
cell_direction_t cell_direction,
@@ -803,8 +801,10 @@ connection_ap_process_end_not_open(
return 0;
}
- if ((tor_addr_family(&addr) == AF_INET && !conn->ipv4_traffic_ok) ||
- (tor_addr_family(&addr) == AF_INET6 && !conn->ipv6_traffic_ok)) {
+ if ((tor_addr_family(&addr) == AF_INET &&
+ !conn->entry_cfg.ipv4_traffic) ||
+ (tor_addr_family(&addr) == AF_INET6 &&
+ !conn->entry_cfg.ipv6_traffic)) {
log_fn(LOG_PROTOCOL_WARN, LD_APP,
"Got an EXITPOLICY failure on a connection with a "
"mismatched family. Closing.");
@@ -1155,11 +1155,11 @@ connection_ap_handshake_socks_got_resolved_cell(entry_connection_t *conn,
addr_hostname = addr;
}
} else if (tor_addr_family(&addr->addr) == AF_INET) {
- if (!addr_ipv4 && conn->ipv4_traffic_ok) {
+ if (!addr_ipv4 && conn->entry_cfg.ipv4_traffic) {
addr_ipv4 = addr;
}
} else if (tor_addr_family(&addr->addr) == AF_INET6) {
- if (!addr_ipv6 && conn->ipv6_traffic_ok) {
+ if (!addr_ipv6 && conn->entry_cfg.ipv6_traffic) {
addr_ipv6 = addr;
}
}
@@ -1180,7 +1180,7 @@ connection_ap_handshake_socks_got_resolved_cell(entry_connection_t *conn,
return;
}
- if (conn->prefer_ipv6_traffic) {
+ if (conn->entry_cfg.prefer_ipv6) {
addr_best = addr_ipv6 ? addr_ipv6 : addr_ipv4;
} else {
addr_best = addr_ipv4 ? addr_ipv4 : addr_ipv6;
@@ -1326,8 +1326,8 @@ connection_edge_process_relay_cell_not_open(
return 0;
}
- if ((family == AF_INET && ! entry_conn->ipv4_traffic_ok) ||
- (family == AF_INET6 && ! entry_conn->ipv6_traffic_ok)) {
+ if ((family == AF_INET && ! entry_conn->entry_cfg.ipv4_traffic) ||
+ (family == AF_INET6 && ! entry_conn->entry_cfg.ipv6_traffic)) {
log_fn(LOG_PROTOCOL_WARN, LD_APP,
"Got a connected cell to %s with unsupported address family."
" Closing.", fmt_addr(&addr));
@@ -1644,8 +1644,9 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ,
}
if ((reason = circuit_finish_handshake(TO_ORIGIN_CIRCUIT(circ),
&extended_cell.created_cell)) < 0) {
- log_warn(domain,"circuit_finish_handshake failed.");
- return reason;
+ circuit_mark_for_close(circ, -reason);
+ return 0; /* We don't want to cause a warning, so we mark the circuit
+ * here. */
}
}
if ((reason=circuit_send_next_onion_skin(TO_ORIGIN_CIRCUIT(circ)))<0) {
@@ -2249,62 +2250,12 @@ circuit_consider_sending_sendme(circuit_t *circ, crypt_path_t *layer_hint)
/** The total number of cells we have allocated. */
static size_t total_cells_allocated = 0;
-#ifdef ENABLE_MEMPOOLS
-/** A memory pool to allocate packed_cell_t objects. */
-static mp_pool_t *cell_pool = NULL;
-
-/** Allocate structures to hold cells. */
-void
-init_cell_pool(void)
-{
- tor_assert(!cell_pool);
- cell_pool = mp_pool_new(sizeof(packed_cell_t), 128*1024);
-}
-
-/** Free all storage used to hold cells (and insertion times/commands if we
- * measure cell statistics and/or if CELL_STATS events are enabled). */
-void
-free_cell_pool(void)
-{
- /* Maybe we haven't called init_cell_pool yet; need to check for it. */
- if (cell_pool) {
- mp_pool_destroy(cell_pool);
- cell_pool = NULL;
- }
-}
-
-/** Free excess storage in cell pool. */
-void
-clean_cell_pool(void)
-{
- tor_assert(cell_pool);
- mp_pool_clean(cell_pool, 0, 1);
-}
-
-#define relay_alloc_cell() \
- mp_pool_get(cell_pool)
-#define relay_free_cell(cell) \
- mp_pool_release(cell)
-
-#define RELAY_CELL_MEM_COST (sizeof(packed_cell_t) + MP_POOL_ITEM_OVERHEAD)
-
-#else /* !ENABLE_MEMPOOLS case */
-
-#define relay_alloc_cell() \
- tor_malloc_zero(sizeof(packed_cell_t))
-#define relay_free_cell(cell) \
- tor_free(cell)
-
-#define RELAY_CELL_MEM_COST (sizeof(packed_cell_t))
-
-#endif /* ENABLE_MEMPOOLS */
-
/** Release storage held by <b>cell</b>. */
static INLINE void
packed_cell_free_unchecked(packed_cell_t *cell)
{
--total_cells_allocated;
- relay_free_cell(cell);
+ tor_free(cell);
}
/** Allocate and return a new packed_cell_t. */
@@ -2312,7 +2263,7 @@ STATIC packed_cell_t *
packed_cell_new(void)
{
++total_cells_allocated;
- return relay_alloc_cell();
+ return tor_malloc_zero(sizeof(packed_cell_t));
}
/** Return a packed cell used outside by channel_t lower layer */
@@ -2329,21 +2280,18 @@ packed_cell_free(packed_cell_t *cell)
void
dump_cell_pool_usage(int severity)
{
- circuit_t *c;
int n_circs = 0;
int n_cells = 0;
- TOR_LIST_FOREACH(c, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) {
n_cells += c->n_chan_cells.n;
if (!CIRCUIT_IS_ORIGIN(c))
n_cells += TO_OR_CIRCUIT(c)->p_chan_cells.n;
++n_circs;
}
+ SMARTLIST_FOREACH_END(c);
tor_log(severity, LD_MM,
"%d cells allocated on %d circuits. %d cells leaked.",
n_cells, n_circs, (int)total_cells_allocated - n_cells);
-#ifdef ENABLE_MEMPOOLS
- mp_pool_log_status(cell_pool, severity);
-#endif
}
/** Allocate a new copy of packed <b>cell</b>. */
@@ -2423,7 +2371,7 @@ cell_queue_pop(cell_queue_t *queue)
size_t
packed_cell_mem_cost(void)
{
- return RELAY_CELL_MEM_COST;
+ return sizeof(packed_cell_t);
}
/** DOCDOC */
@@ -2433,6 +2381,12 @@ cell_queues_get_total_allocation(void)
return total_cells_allocated * packed_cell_mem_cost();
}
+/** How long after we've been low on memory should we try to conserve it? */
+#define MEMORY_PRESSURE_INTERVAL (30*60)
+
+/** The time at which we were last low on memory. */
+static time_t last_time_under_memory_pressure = 0;
+
/** Check whether we've got too much space used for cells. If so,
* call the OOM handler and return 1. Otherwise, return 0. */
STATIC int
@@ -2440,13 +2394,38 @@ cell_queues_check_size(void)
{
size_t alloc = cell_queues_get_total_allocation();
alloc += buf_get_total_allocation();
- if (alloc >= get_options()->MaxMemInQueues) {
- circuits_handle_oom(alloc);
- return 1;
+ alloc += tor_zlib_get_total_allocation();
+ const size_t rend_cache_total = rend_cache_get_total_allocation();
+ alloc += rend_cache_total;
+ if (alloc >= get_options()->MaxMemInQueues_low_threshold) {
+ last_time_under_memory_pressure = approx_time();
+ if (alloc >= get_options()->MaxMemInQueues) {
+ /* If we're spending over 20% of the memory limit on hidden service
+ * descriptors, free them until we're down to 10%.
+ */
+ if (rend_cache_total > get_options()->MaxMemInQueues / 5) {
+ const size_t bytes_to_remove =
+ rend_cache_total - (size_t)(get_options()->MaxMemInQueues / 10);
+ rend_cache_clean_v2_descs_as_dir(time(NULL), bytes_to_remove);
+ alloc -= rend_cache_total;
+ alloc += rend_cache_get_total_allocation();
+ }
+ circuits_handle_oom(alloc);
+ return 1;
+ }
}
return 0;
}
+/** Return true if we've been under memory pressure in the last
+ * MEMORY_PRESSURE_INTERVAL seconds. */
+int
+have_been_under_memory_pressure(void)
+{
+ return last_time_under_memory_pressure + MEMORY_PRESSURE_INTERVAL
+ < approx_time();
+}
+
/**
* Update the number of cells available on the circuit's n_chan or p_chan's
* circuit mux.
@@ -2591,8 +2570,8 @@ packed_cell_get_circid(const packed_cell_t *cell, int wide_circ_ids)
* queue of the first active circuit on <b>chan</b>, and write them to
* <b>chan</b>-&gt;outbuf. Return the number of cells written. Advance
* the active circuit pointer to the next active circuit in the ring. */
-int
-channel_flush_from_first_active_circuit(channel_t *chan, int max)
+MOCK_IMPL(int,
+channel_flush_from_first_active_circuit, (channel_t *chan, int max))
{
circuitmux_t *cmux = NULL;
int n_flushed = 0;
@@ -2868,14 +2847,8 @@ append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
log_debug(LD_GENERAL, "Made a circuit active.");
}
- if (!channel_has_queued_writes(chan)) {
- /* There is no data at all waiting to be sent on the outbuf. Add a
- * cell, so that we can notice when it gets flushed, flushed_some can
- * get called, and we can start putting more data onto the buffer then.
- */
- log_debug(LD_GENERAL, "Primed a buffer.");
- channel_flush_from_first_active_circuit(chan, 1);
- }
+ /* New way: mark this as having waiting cells for the scheduler */
+ scheduler_channel_has_waiting_cells(chan);
}
/** Append an encoded value of <b>addr</b> to <b>payload_out</b>, which must
diff --git a/src/or/relay.h b/src/or/relay.h
index 969c6fb61d..a4f583d11e 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -42,14 +42,11 @@ extern uint64_t stats_n_data_bytes_packaged;
extern uint64_t stats_n_data_cells_received;
extern uint64_t stats_n_data_bytes_received;
-#ifdef ENABLE_MEMPOOLS
-void init_cell_pool(void);
-void free_cell_pool(void);
-void clean_cell_pool(void);
-#endif /* ENABLE_MEMPOOLS */
void dump_cell_pool_usage(int severity);
size_t packed_cell_mem_cost(void);
+int have_been_under_memory_pressure(void);
+
/* For channeltls.c */
void packed_cell_free(packed_cell_t *cell);
@@ -64,7 +61,8 @@ void append_cell_to_circuit_queue(circuit_t *circ, channel_t *chan,
cell_t *cell, cell_direction_t direction,
streamid_t fromstream);
void channel_unlink_all_circuits(channel_t *chan, smartlist_t *detached_out);
-int channel_flush_from_first_active_circuit(channel_t *chan, int max);
+MOCK_DECL(int, channel_flush_from_first_active_circuit,
+ (channel_t *chan, int max));
void assert_circuit_mux_okay(channel_t *chan);
void update_circuit_on_cmux_(circuit_t *circ, cell_direction_t direction,
const char *file, int lineno);
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 19a8cef1bf..162e0ac53e 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -130,16 +130,6 @@ rend_client_reextend_intro_circuit(origin_circuit_t *circ)
return result;
}
-/** Return true iff we should send timestamps in our INTRODUCE1 cells */
-static int
-rend_client_should_send_timestamp(void)
-{
- if (get_options()->Support022HiddenServices >= 0)
- return get_options()->Support022HiddenServices;
-
- return networkstatus_get_param(NULL, "Support022HiddenServices", 1, 0, 1);
-}
-
/** Called when we're trying to connect an ap conn; sends an INTRODUCE1 cell
* down introcirc if possible.
*/
@@ -251,14 +241,8 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
REND_DESC_COOKIE_LEN);
v3_shift += 2+REND_DESC_COOKIE_LEN;
}
- if (rend_client_should_send_timestamp()) {
- uint32_t now = (uint32_t)time(NULL);
- now += 300;
- now -= now % 600;
- set_uint32(tmp+v3_shift+1, htonl(now));
- } else {
- set_uint32(tmp+v3_shift+1, 0);
- }
+ /* Once this held a timestamp. */
+ set_uint32(tmp+v3_shift+1, 0);
v3_shift += 4;
} /* if version 2 only write version number */
else if (entry->parsed->protocols & (1<<2)) {
@@ -370,15 +354,13 @@ rend_client_rendcirc_has_opened(origin_circuit_t *circ)
}
/**
- * Called to close other intro circuits we launched in parallel
- * due to timeout.
+ * Called to close other intro circuits we launched in parallel.
*/
static void
rend_client_close_other_intros(const char *onion_address)
{
- circuit_t *c;
/* abort parallel intro circs, if any */
- TOR_LIST_FOREACH(c, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) {
if ((c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
c->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) &&
!c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) {
@@ -389,10 +371,11 @@ rend_client_close_other_intros(const char *onion_address)
log_info(LD_REND|LD_CIRC, "Closing introduction circuit %d that we "
"built in parallel (Purpose %d).", oc->global_identifier,
c->purpose);
- circuit_mark_for_close(c, END_CIRC_REASON_TIMEOUT);
+ circuit_mark_for_close(c, END_CIRC_REASON_IP_NOW_REDUNDANT);
}
}
}
+ SMARTLIST_FOREACH_END(c);
}
/** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.
@@ -468,6 +451,13 @@ rend_client_introduction_acked(origin_circuit_t *circ,
/* XXXX If that call failed, should we close the rend circuit,
* too? */
return result;
+ } else {
+ /* Close circuit because no more intro points are usable thus not
+ * useful anymore. Change it's purpose before so we don't report an
+ * intro point failure again triggering an extra descriptor fetch. */
+ circuit_change_purpose(TO_CIRCUIT(circ),
+ CIRCUIT_PURPOSE_C_INTRODUCE_ACKED);
+ circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_FINISHED);
}
}
return 0;
@@ -564,7 +554,12 @@ directory_clean_last_hid_serv_requests(time_t now)
/** Remove all requests related to the hidden service named
* <b>onion_address</b> from the history of times of requests to
- * hidden service directories. */
+ * hidden service directories.
+ *
+ * This is called from rend_client_note_connection_attempt_ended(), which
+ * must be idempotent, so any future changes to this function must leave
+ * it idempotent too.
+ */
static void
purge_hid_serv_from_last_hid_serv_requests(const char *onion_address)
{
@@ -625,7 +620,12 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query)
char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
time_t now = time(NULL);
char descriptor_cookie_base64[3*REND_DESC_COOKIE_LEN_BASE64];
+#ifdef ENABLE_TOR2WEB_MODE
const int tor2web_mode = options->Tor2webMode;
+ const int how_to_fetch = tor2web_mode ? DIRIND_ONEHOP : DIRIND_ANONYMOUS;
+#else
+ const int how_to_fetch = DIRIND_ANONYMOUS;
+#endif
int excluded_some;
tor_assert(desc_id);
tor_assert(rend_query);
@@ -702,7 +702,7 @@ directory_get_from_hs_dir(const char *desc_id, const rend_data_t *rend_query)
directory_initiate_command_routerstatus_rend(hs_dir,
DIR_PURPOSE_FETCH_RENDDESC_V2,
ROUTER_PURPOSE_GENERAL,
- tor2web_mode?DIRIND_ONEHOP:DIRIND_ANONYMOUS,
+ how_to_fetch,
desc_id_base32,
NULL, 0, 0,
rend_query);
@@ -1093,8 +1093,11 @@ rend_client_desc_trynow(const char *query)
/** Clear temporary state used only during an attempt to connect to
* the hidden service named <b>onion_address</b>. Called when a
- * connection attempt has ended; may be called occasionally at other
- * times, and should be reasonably harmless. */
+ * connection attempt has ended; it is possible for this to be called
+ * multiple times while handling an ended connection attempt, and
+ * any future changes to this function must ensure it remains
+ * idempotent.
+ */
void
rend_client_note_connection_attempt_ended(const char *onion_address)
{
diff --git a/src/or/rendclient.h b/src/or/rendclient.h
index 1f731d0ae5..098c61d0a1 100644
--- a/src/or/rendclient.h
+++ b/src/or/rendclient.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/rendcommon.c b/src/or/rendcommon.c
index 9637d4d838..0451ae62ee 100644
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -155,7 +155,7 @@ rend_compute_v2_desc_id(char *desc_id_out, const char *service_id,
}
/* Calculate current time-period. */
time_period = get_time_period(now, 0, service_id_binary);
- /* Calculate secret-id-part = h(time-period + replica). */
+ /* Calculate secret-id-part = h(time-period | replica). */
get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie,
replica);
/* Calculate descriptor ID. */
@@ -411,7 +411,7 @@ rend_desc_v2_is_parsable(rend_encoded_v2_service_descriptor_t *desc)
&test_intro_content,
&test_intro_size,
&test_encoded_size,
- &test_next, desc->desc_str);
+ &test_next, desc->desc_str, 1);
rend_service_descriptor_free(test_parsed);
tor_free(test_intro_content);
return (res >= 0);
@@ -528,7 +528,7 @@ rend_encode_v2_descriptors(smartlist_t *descs_out,
return -1;
}
/* Base64-encode introduction points. */
- ipos_base64 = tor_malloc_zero(ipos_len * 2);
+ ipos_base64 = tor_calloc(ipos_len, 2);
if (base64_encode(ipos_base64, ipos_len * 2, ipos, ipos_len)<0) {
log_warn(LD_REND, "Could not encode introduction point string to "
"base64. length=%d", (int)ipos_len);
@@ -556,7 +556,7 @@ rend_encode_v2_descriptors(smartlist_t *descs_out,
char desc_digest[DIGEST_LEN];
rend_encoded_v2_service_descriptor_t *enc =
tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
- /* Calculate secret-id-part = h(time-period + cookie + replica). */
+ /* Calculate secret-id-part = h(time-period | cookie | replica). */
get_secret_id_part_bytes(secret_id_part, time_period, descriptor_cookie,
k);
base32_encode(secret_id_part_base32, sizeof(secret_id_part_base32),
@@ -704,6 +704,9 @@ static strmap_t *rend_cache = NULL;
* directories. */
static digestmap_t *rend_cache_v2_dir = NULL;
+/** DOCDOC */
+static size_t rend_cache_total_allocation = 0;
+
/** Initializes the service descriptor cache.
*/
void
@@ -713,12 +716,64 @@ rend_cache_init(void)
rend_cache_v2_dir = digestmap_new();
}
+/** Return the approximate number of bytes needed to hold <b>e</b>. */
+static size_t
+rend_cache_entry_allocation(const rend_cache_entry_t *e)
+{
+ if (!e)
+ return 0;
+
+ /* This doesn't count intro_nodes or key size */
+ return sizeof(*e) + e->len + sizeof(*e->parsed);
+}
+
+/** DOCDOC */
+size_t
+rend_cache_get_total_allocation(void)
+{
+ return rend_cache_total_allocation;
+}
+
+/** Decrement the total bytes attributed to the rendezvous cache by n. */
+static void
+rend_cache_decrement_allocation(size_t n)
+{
+ static int have_underflowed = 0;
+
+ if (rend_cache_total_allocation >= n) {
+ rend_cache_total_allocation -= n;
+ } else {
+ rend_cache_total_allocation = 0;
+ if (! have_underflowed) {
+ have_underflowed = 1;
+ log_warn(LD_BUG, "Underflow in rend_cache_decrement_allocation");
+ }
+ }
+}
+
+/** Increase the total bytes attributed to the rendezvous cache by n. */
+static void
+rend_cache_increment_allocation(size_t n)
+{
+ static int have_overflowed = 0;
+ if (rend_cache_total_allocation <= SIZE_MAX - n) {
+ rend_cache_total_allocation += n;
+ } else {
+ rend_cache_total_allocation = SIZE_MAX;
+ if (! have_overflowed) {
+ have_overflowed = 1;
+ log_warn(LD_BUG, "Overflow in rend_cache_increment_allocation");
+ }
+ }
+}
+
/** Helper: free storage held by a single service descriptor cache entry. */
static void
rend_cache_entry_free(rend_cache_entry_t *e)
{
if (!e)
return;
+ rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
rend_service_descriptor_free(e->parsed);
tor_free(e->desc);
tor_free(e);
@@ -740,6 +795,7 @@ rend_cache_free_all(void)
digestmap_free(rend_cache_v2_dir, rend_cache_entry_free_);
rend_cache = NULL;
rend_cache_v2_dir = NULL;
+ rend_cache_total_allocation = 0;
}
/** Removes all old entries from the service descriptor cache.
@@ -777,31 +833,46 @@ rend_cache_purge(void)
}
/** Remove all old v2 descriptors and those for which this hidden service
- * directory is not responsible for any more. */
+ * directory is not responsible for any more.
+ *
+ * If at all possible, remove at least <b>force_remove</b> bytes of data.
+ */
void
-rend_cache_clean_v2_descs_as_dir(time_t now)
+rend_cache_clean_v2_descs_as_dir(time_t now, size_t force_remove)
{
digestmap_iter_t *iter;
time_t cutoff = now - REND_CACHE_MAX_AGE - REND_CACHE_MAX_SKEW;
- for (iter = digestmap_iter_init(rend_cache_v2_dir);
- !digestmap_iter_done(iter); ) {
- const char *key;
- void *val;
- rend_cache_entry_t *ent;
- digestmap_iter_get(iter, &key, &val);
- ent = val;
- if (ent->parsed->timestamp < cutoff ||
- !hid_serv_responsible_for_desc_id(key)) {
- char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN);
- log_info(LD_REND, "Removing descriptor with ID '%s' from cache",
- safe_str_client(key_base32));
- iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
- rend_cache_entry_free(ent);
- } else {
- iter = digestmap_iter_next(rend_cache_v2_dir, iter);
+ const int LAST_SERVED_CUTOFF_STEP = 1800;
+ time_t last_served_cutoff = cutoff;
+ size_t bytes_removed = 0;
+ do {
+ for (iter = digestmap_iter_init(rend_cache_v2_dir);
+ !digestmap_iter_done(iter); ) {
+ const char *key;
+ void *val;
+ rend_cache_entry_t *ent;
+ digestmap_iter_get(iter, &key, &val);
+ ent = val;
+ if (ent->parsed->timestamp < cutoff ||
+ ent->last_served < last_served_cutoff ||
+ !hid_serv_responsible_for_desc_id(key)) {
+ char key_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+ base32_encode(key_base32, sizeof(key_base32), key, DIGEST_LEN);
+ log_info(LD_REND, "Removing descriptor with ID '%s' from cache",
+ safe_str_client(key_base32));
+ bytes_removed += rend_cache_entry_allocation(ent);
+ iter = digestmap_iter_next_rmv(rend_cache_v2_dir, iter);
+ rend_cache_entry_free(ent);
+ } else {
+ iter = digestmap_iter_next(rend_cache_v2_dir, iter);
+ }
}
- }
+
+ /* In case we didn't remove enough bytes, advance the cutoff a little. */
+ last_served_cutoff += LAST_SERVED_CUTOFF_STEP;
+ if (last_served_cutoff > now)
+ break;
+ } while (bytes_removed < force_remove);
}
/** Determines whether <b>a</b> is in the interval of <b>b</b> (excluded) and
@@ -903,6 +974,7 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc)
e = digestmap_get(rend_cache_v2_dir, desc_id_digest);
if (e) {
*desc = e->desc;
+ e->last_served = approx_time();
return 1;
}
return 0;
@@ -924,6 +996,7 @@ rend_cache_lookup_v2_desc_as_dir(const char *desc_id, const char **desc)
rend_cache_store_status_t
rend_cache_store_v2_desc_as_dir(const char *desc)
{
+ const or_options_t *options = get_options();
rend_service_descriptor_t *parsed;
char desc_id[DIGEST_LEN];
char *intro_content;
@@ -945,7 +1018,7 @@ rend_cache_store_v2_desc_as_dir(const char *desc)
}
while (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
&intro_size, &encoded_size,
- &next_desc, current_desc) >= 0) {
+ &next_desc, current_desc, 1) >= 0) {
number_parsed++;
/* We don't care about the introduction points. */
tor_free(intro_content);
@@ -985,24 +1058,35 @@ rend_cache_store_v2_desc_as_dir(const char *desc)
if (e && !strcmp(desc, e->desc)) {
log_info(LD_REND, "We already have this service descriptor with desc "
"ID %s.", safe_str(desc_id_base32));
- e->received = time(NULL);
goto skip;
}
/* Store received descriptor. */
if (!e) {
e = tor_malloc_zero(sizeof(rend_cache_entry_t));
digestmap_set(rend_cache_v2_dir, desc_id, e);
+ /* Treat something just uploaded as having been served a little
+ * while ago, so that flooding with new descriptors doesn't help
+ * too much.
+ */
+ e->last_served = approx_time() - 3600;
} else {
+ rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
rend_service_descriptor_free(e->parsed);
tor_free(e->desc);
}
- e->received = time(NULL);
e->parsed = parsed;
e->desc = tor_strndup(current_desc, encoded_size);
e->len = encoded_size;
+ rend_cache_increment_allocation(rend_cache_entry_allocation(e));
log_info(LD_REND, "Successfully stored service descriptor with desc ID "
"'%s' and len %d.",
safe_str(desc_id_base32), (int)encoded_size);
+
+ /* Statistics: Note down this potentially new HS. */
+ if (options->HiddenServiceStatistics) {
+ rep_hist_stored_maybe_new_hs(e->parsed->pk);
+ }
+
number_stored++;
goto advance;
skip:
@@ -1034,10 +1118,14 @@ rend_cache_store_v2_desc_as_dir(const char *desc)
* If the descriptor's service ID does not match
* <b>rend_query</b>-\>onion_address, reject it.
*
+ * If the descriptor's descriptor ID doesn't match <b>desc_id_base32</b>,
+ * reject it.
+ *
* Return an appropriate rend_cache_store_status_t.
*/
rend_cache_store_status_t
rend_cache_store_v2_desc_as_client(const char *desc,
+ const char *desc_id_base32,
const rend_data_t *rend_query)
{
/*XXXX this seems to have a bit of duplicate code with
@@ -1064,14 +1152,23 @@ rend_cache_store_v2_desc_as_client(const char *desc,
time_t now = time(NULL);
char key[REND_SERVICE_ID_LEN_BASE32+2];
char service_id[REND_SERVICE_ID_LEN_BASE32+1];
+ char want_desc_id[DIGEST_LEN];
rend_cache_entry_t *e;
rend_cache_store_status_t retval = RCS_BADDESC;
tor_assert(rend_cache);
tor_assert(desc);
+ tor_assert(desc_id_base32);
+ memset(want_desc_id, 0, sizeof(want_desc_id));
+ if (base32_decode(want_desc_id, sizeof(want_desc_id),
+ desc_id_base32, strlen(desc_id_base32)) != 0) {
+ log_warn(LD_BUG, "Couldn't decode base32 %s for descriptor id.",
+ escaped_safe_str_client(desc_id_base32));
+ goto err;
+ }
/* Parse the descriptor. */
if (rend_parse_v2_service_descriptor(&parsed, desc_id, &intro_content,
&intro_size, &encoded_size,
- &next_desc, desc) < 0) {
+ &next_desc, desc, 0) < 0) {
log_warn(LD_REND, "Could not parse descriptor.");
goto err;
}
@@ -1086,6 +1183,12 @@ rend_cache_store_v2_desc_as_client(const char *desc,
service_id, safe_str(rend_query->onion_address));
goto err;
}
+ if (tor_memneq(desc_id, want_desc_id, DIGEST_LEN)) {
+ log_warn(LD_REND, "Received service descriptor for %s with incorrect "
+ "descriptor ID.", service_id);
+ goto err;
+ }
+
/* Decode/decrypt introduction points. */
if (intro_content && intro_size > 0) {
int n_intro_points;
@@ -1158,21 +1261,21 @@ rend_cache_store_v2_desc_as_client(const char *desc,
if (e && !strcmp(desc, e->desc)) {
log_info(LD_REND,"We already have this service descriptor %s.",
safe_str_client(service_id));
- e->received = time(NULL);
goto okay;
}
if (!e) {
e = tor_malloc_zero(sizeof(rend_cache_entry_t));
strmap_set_lc(rend_cache, key, e);
} else {
+ rend_cache_decrement_allocation(rend_cache_entry_allocation(e));
rend_service_descriptor_free(e->parsed);
tor_free(e->desc);
}
- e->received = time(NULL);
e->parsed = parsed;
e->desc = tor_malloc_zero(encoded_size + 1);
strlcpy(e->desc, desc, encoded_size + 1);
e->len = encoded_size;
+ rend_cache_increment_allocation(rend_cache_entry_allocation(e));
log_debug(LD_REND,"Successfully stored rend desc '%s', len %d.",
safe_str_client(service_id), (int)encoded_size);
return RCS_OKAY;
diff --git a/src/or/rendcommon.h b/src/or/rendcommon.h
index 07a47accfe..8396cc3551 100644
--- a/src/or/rendcommon.h
+++ b/src/or/rendcommon.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -33,7 +33,7 @@ void rend_intro_point_free(rend_intro_point_t *intro);
void rend_cache_init(void);
void rend_cache_clean(time_t now);
-void rend_cache_clean_v2_descs_as_dir(time_t now);
+void rend_cache_clean_v2_descs_as_dir(time_t now, size_t min_to_remove);
void rend_cache_purge(void);
void rend_cache_free_all(void);
int rend_valid_service_id(const char *query);
@@ -49,8 +49,8 @@ typedef enum {
rend_cache_store_status_t rend_cache_store_v2_desc_as_dir(const char *desc);
rend_cache_store_status_t rend_cache_store_v2_desc_as_client(const char *desc,
+ const char *desc_id_base32,
const rend_data_t *rend_query);
-
int rend_encode_v2_descriptors(smartlist_t *descs_out,
rend_service_descriptor_t *desc, time_t now,
uint8_t period, rend_auth_type_t auth_type,
@@ -63,6 +63,7 @@ int rend_id_is_in_interval(const char *a, const char *b, const char *c);
void rend_get_descriptor_id_bytes(char *descriptor_id_out,
const char *service_id,
const char *secret_id_part);
+size_t rend_cache_get_total_allocation(void);
#endif
diff --git a/src/or/rendmid.c b/src/or/rendmid.c
index 0e1f91c302..2451acb514 100644
--- a/src/or/rendmid.c
+++ b/src/or/rendmid.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -202,7 +202,7 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request,
"Unable to send INTRODUCE2 cell to Tor client.");
goto err;
}
- /* And sent an ack down Alice's circuit. Empty body means succeeded. */
+ /* And send an ack down Alice's circuit. Empty body means succeeded. */
if (relay_send_command_from_edge(0,TO_CIRCUIT(circ),
RELAY_COMMAND_INTRODUCE_ACK,
NULL,0,NULL)) {
@@ -213,7 +213,7 @@ rend_mid_introduce(or_circuit_t *circ, const uint8_t *request,
return 0;
err:
- /* Send the client an NACK */
+ /* Send the client a NACK */
nak_body[0] = 1;
if (relay_send_command_from_edge(0,TO_CIRCUIT(circ),
RELAY_COMMAND_INTRODUCE_ACK,
@@ -295,6 +295,7 @@ int
rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
size_t request_len)
{
+ const or_options_t *options = get_options();
or_circuit_t *rend_circ;
char hexid[9];
int reason = END_CIRC_REASON_INTERNAL;
@@ -330,6 +331,12 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request,
goto err;
}
+ /* Statistics: Mark this circuit as an RP circuit so that we collect
+ stats from it. */
+ if (options->HiddenServiceStatistics) {
+ circ->circuit_carries_hs_traffic_stats = 1;
+ }
+
/* Send the RENDEZVOUS2 cell to Alice. */
if (relay_send_command_from_edge(0, TO_CIRCUIT(rend_circ),
RELAY_COMMAND_RENDEZVOUS2,
diff --git a/src/or/rendmid.h b/src/or/rendmid.h
index 310276ac96..6bd691a740 100644
--- a/src/or/rendmid.h
+++ b/src/or/rendmid.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index d958de9df9..111b369b1c 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -16,6 +16,7 @@
#include "circuituse.h"
#include "config.h"
#include "directory.h"
+#include "main.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "rendclient.h"
@@ -65,9 +66,16 @@ static ssize_t rend_service_parse_intro_for_v3(
* a real port on some IP.
*/
typedef struct rend_service_port_config_t {
+ /* The incoming HS virtual port we're mapping */
uint16_t virtual_port;
+ /* Is this an AF_UNIX port? */
+ unsigned int is_unix_addr:1;
+ /* The outgoing TCP port to use, if !is_unix_addr */
uint16_t real_port;
+ /* The outgoing IPv4 or IPv6 address to use, if !is_unix_addr */
tor_addr_t real_addr;
+ /* The socket path to connect to, if is_unix_addr */
+ char unix_addr[FLEXIBLE_ARRAY_MEMBER];
} rend_service_port_config_t;
/** Try to maintain this many intro points per service by default. */
@@ -82,7 +90,7 @@ typedef struct rend_service_port_config_t {
#define MAX_INTRO_CIRCS_PER_PERIOD 10
/** How many times will a hidden service operator attempt to connect to
* a requested rendezvous point before giving up? */
-#define MAX_REND_FAILURES 8
+#define MAX_REND_FAILURES 1
/** How many seconds should we spend trying to connect to a requested
* rendezvous point before giving up? */
#define MAX_REND_TIMEOUT 30
@@ -95,6 +103,8 @@ typedef struct rend_service_port_config_t {
typedef struct rend_service_t {
/* Fields specified in config file */
char *directory; /**< where in the filesystem it stores it */
+ int dir_group_readable; /**< if 1, allow group read
+ permissions on directory */
smartlist_t *ports; /**< List of rend_service_port_config_t */
rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client
* authorization is performed. */
@@ -126,6 +136,9 @@ typedef struct rend_service_t {
* when they do, this keeps us from launching multiple simultaneous attempts
* to connect to the same rend point. */
replaycache_t *accepted_intro_dh_parts;
+ /** If true, we don't close circuits for making requests to unsupported
+ * ports. */
+ int allow_unknown_ports;
} rend_service_t;
/** A list of rend_service_t's for services run on this OP.
@@ -273,16 +286,48 @@ rend_add_service(rend_service_t *service)
service->directory);
for (i = 0; i < smartlist_len(service->ports); ++i) {
p = smartlist_get(service->ports, i);
- log_debug(LD_REND,"Service maps port %d to %s",
- p->virtual_port, fmt_addrport(&p->real_addr, p->real_port));
+ if (!(p->is_unix_addr)) {
+ log_debug(LD_REND,
+ "Service maps port %d to %s",
+ p->virtual_port,
+ fmt_addrport(&p->real_addr, p->real_port));
+ } else {
+#ifdef HAVE_SYS_UN_H
+ log_debug(LD_REND,
+ "Service maps port %d to socket at \"%s\"",
+ p->virtual_port, p->unix_addr);
+#else
+ log_debug(LD_REND,
+ "Service maps port %d to an AF_UNIX socket, but we "
+ "have no AF_UNIX support on this platform. This is "
+ "probably a bug.",
+ p->virtual_port);
+#endif /* defined(HAVE_SYS_UN_H) */
+ }
}
}
}
+/** Return a new rend_service_port_config_t with its path set to
+ * <b>socket_path</b> or empty if <b>socket_path</b> is NULL */
+static rend_service_port_config_t *
+rend_service_port_config_new(const char *socket_path)
+{
+ if (!socket_path)
+ return tor_malloc_zero(sizeof(rend_service_port_config_t) + 1);
+
+ const size_t pathlen = strlen(socket_path) + 1;
+ rend_service_port_config_t *conf =
+ tor_malloc_zero(sizeof(rend_service_port_config_t) + pathlen);
+ memcpy(conf->unix_addr, socket_path, pathlen);
+ conf->is_unix_addr = 1;
+ return conf;
+}
+
/** Parses a real-port to virtual-port mapping and returns a new
* rend_service_port_config_t.
*
- * The format is: VirtualPort (IP|RealPort|IP:RealPort)?
+ * The format is: VirtualPort (IP|RealPort|IP:RealPort|'socket':path)?
*
* IP defaults to 127.0.0.1; RealPort defaults to VirtualPort.
*/
@@ -291,11 +336,13 @@ parse_port_config(const char *string)
{
smartlist_t *sl;
int virtport;
- int realport;
+ int realport = 0;
uint16_t p;
tor_addr_t addr;
const char *addrport;
rend_service_port_config_t *result = NULL;
+ unsigned int is_unix_addr = 0;
+ char *socket_path = NULL;
sl = smartlist_new();
smartlist_split_string(sl, string, " ",
@@ -317,8 +364,21 @@ parse_port_config(const char *string)
realport = virtport;
tor_addr_from_ipv4h(&addr, 0x7F000001u); /* 127.0.0.1 */
} else {
+ int ret;
+
addrport = smartlist_get(sl,1);
- if (strchr(addrport, ':') || strchr(addrport, '.')) {
+ ret = config_parse_unix_port(addrport, &socket_path);
+ if (ret < 0 && ret != -ENOENT) {
+ if (ret == -EINVAL) {
+ log_warn(LD_CONFIG,
+ "Empty socket path in hidden service port configuration.");
+ }
+ goto err;
+ }
+ if (socket_path) {
+ is_unix_addr = 1;
+ } else if (strchr(addrport, ':') || strchr(addrport, '.')) {
+ /* else try it as an IP:port pair if it has a : or . in it */
if (tor_addr_port_lookup(addrport, &addr, &p)<0) {
log_warn(LD_CONFIG,"Unparseable address in hidden service port "
"configuration.");
@@ -337,13 +397,21 @@ parse_port_config(const char *string)
}
}
- result = tor_malloc(sizeof(rend_service_port_config_t));
+ /* Allow room for unix_addr */
+ result = rend_service_port_config_new(socket_path);
result->virtual_port = virtport;
- result->real_port = realport;
- tor_addr_copy(&result->real_addr, &addr);
+ result->is_unix_addr = is_unix_addr;
+ if (!is_unix_addr) {
+ result->real_port = realport;
+ tor_addr_copy(&result->real_addr, &addr);
+ result->unix_addr[0] = '\0';
+ }
+
err:
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
+ if (socket_path) tor_free(socket_path);
+
return result;
}
@@ -359,6 +427,7 @@ rend_config_services(const or_options_t *options, int validate_only)
rend_service_t *service = NULL;
rend_service_port_config_t *portcfg;
smartlist_t *old_service_list = NULL;
+ int ok = 0;
if (!validate_only) {
old_service_list = rend_service_list;
@@ -369,87 +438,114 @@ rend_config_services(const or_options_t *options, int validate_only)
if (!strcasecmp(line->key, "HiddenServiceDir")) {
if (service) { /* register the one we just finished parsing */
if (validate_only)
- rend_service_free(service);
- else
- rend_add_service(service);
- }
- service = tor_malloc_zero(sizeof(rend_service_t));
- service->directory = tor_strdup(line->value);
- service->ports = smartlist_new();
- service->intro_period_started = time(NULL);
- service->n_intro_points_wanted = NUM_INTRO_POINTS_DEFAULT;
- continue;
- }
- if (!service) {
- log_warn(LD_CONFIG, "%s with no preceding HiddenServiceDir directive",
- line->key);
- rend_service_free(service);
- return -1;
- }
- if (!strcasecmp(line->key, "HiddenServicePort")) {
- portcfg = parse_port_config(line->value);
- if (!portcfg) {
- rend_service_free(service);
- return -1;
- }
- smartlist_add(service->ports, portcfg);
- } else if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
- /* Parse auth type and comma-separated list of client names and add a
- * rend_authorized_client_t for each client to the service's list
- * of authorized clients. */
- smartlist_t *type_names_split, *clients;
- const char *authname;
- int num_clients;
- if (service->auth_type != REND_NO_AUTH) {
- log_warn(LD_CONFIG, "Got multiple HiddenServiceAuthorizeClient "
- "lines for a single service.");
- rend_service_free(service);
- return -1;
- }
- type_names_split = smartlist_new();
- smartlist_split_string(type_names_split, line->value, " ", 0, 2);
- if (smartlist_len(type_names_split) < 1) {
- log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This "
- "should have been prevented when parsing the "
- "configuration.");
- smartlist_free(type_names_split);
- rend_service_free(service);
- return -1;
- }
- authname = smartlist_get(type_names_split, 0);
- if (!strcasecmp(authname, "basic")) {
- service->auth_type = REND_BASIC_AUTH;
- } else if (!strcasecmp(authname, "stealth")) {
- service->auth_type = REND_STEALTH_AUTH;
- } else {
- log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
- "unrecognized auth-type '%s'. Only 'basic' or 'stealth' "
- "are recognized.",
- (char *) smartlist_get(type_names_split, 0));
- SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
- smartlist_free(type_names_split);
- rend_service_free(service);
- return -1;
- }
- service->clients = smartlist_new();
- if (smartlist_len(type_names_split) < 2) {
- log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
- "auth-type '%s', but no client names.",
- service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
- SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
- smartlist_free(type_names_split);
- continue;
- }
- clients = smartlist_new();
- smartlist_split_string(clients, smartlist_get(type_names_split, 1),
- ",", SPLIT_SKIP_SPACE, 0);
- SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
- smartlist_free(type_names_split);
- /* Remove duplicate client names. */
- num_clients = smartlist_len(clients);
- smartlist_sort_strings(clients);
- smartlist_uniq_strings(clients);
- if (smartlist_len(clients) < num_clients) {
+ rend_service_free(service);
+ else
+ rend_add_service(service);
+ }
+ service = tor_malloc_zero(sizeof(rend_service_t));
+ service->directory = tor_strdup(line->value);
+ service->ports = smartlist_new();
+ service->intro_period_started = time(NULL);
+ service->n_intro_points_wanted = NUM_INTRO_POINTS_DEFAULT;
+ continue;
+ }
+ if (!service) {
+ log_warn(LD_CONFIG, "%s with no preceding HiddenServiceDir directive",
+ line->key);
+ rend_service_free(service);
+ return -1;
+ }
+ if (!strcasecmp(line->key, "HiddenServicePort")) {
+ portcfg = parse_port_config(line->value);
+ if (!portcfg) {
+ rend_service_free(service);
+ return -1;
+ }
+ smartlist_add(service->ports, portcfg);
+ } else if (!strcasecmp(line->key, "HiddenServiceAllowUnknownPorts")) {
+ service->allow_unknown_ports = (int)tor_parse_long(line->value,
+ 10, 0, 1, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_CONFIG,
+ "HiddenServiceAllowUnknownPorts should be 0 or 1, not %s",
+ line->value);
+ rend_service_free(service);
+ return -1;
+ }
+ log_info(LD_CONFIG,
+ "HiddenServiceAllowUnknownPorts=%d for %s",
+ (int)service->allow_unknown_ports, service->directory);
+ } else if (!strcasecmp(line->key,
+ "HiddenServiceDirGroupReadable")) {
+ service->dir_group_readable = (int)tor_parse_long(line->value,
+ 10, 0, 1, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_CONFIG,
+ "HiddenServiceDirGroupReadable should be 0 or 1, not %s",
+ line->value);
+ rend_service_free(service);
+ return -1;
+ }
+ log_info(LD_CONFIG,
+ "HiddenServiceDirGroupReadable=%d for %s",
+ service->dir_group_readable, service->directory);
+ } else if (!strcasecmp(line->key, "HiddenServiceAuthorizeClient")) {
+ /* Parse auth type and comma-separated list of client names and add a
+ * rend_authorized_client_t for each client to the service's list
+ * of authorized clients. */
+ smartlist_t *type_names_split, *clients;
+ const char *authname;
+ int num_clients;
+ if (service->auth_type != REND_NO_AUTH) {
+ log_warn(LD_CONFIG, "Got multiple HiddenServiceAuthorizeClient "
+ "lines for a single service.");
+ rend_service_free(service);
+ return -1;
+ }
+ type_names_split = smartlist_new();
+ smartlist_split_string(type_names_split, line->value, " ", 0, 2);
+ if (smartlist_len(type_names_split) < 1) {
+ log_warn(LD_BUG, "HiddenServiceAuthorizeClient has no value. This "
+ "should have been prevented when parsing the "
+ "configuration.");
+ smartlist_free(type_names_split);
+ rend_service_free(service);
+ return -1;
+ }
+ authname = smartlist_get(type_names_split, 0);
+ if (!strcasecmp(authname, "basic")) {
+ service->auth_type = REND_BASIC_AUTH;
+ } else if (!strcasecmp(authname, "stealth")) {
+ service->auth_type = REND_STEALTH_AUTH;
+ } else {
+ log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
+ "unrecognized auth-type '%s'. Only 'basic' or 'stealth' "
+ "are recognized.",
+ (char *) smartlist_get(type_names_split, 0));
+ SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
+ smartlist_free(type_names_split);
+ rend_service_free(service);
+ return -1;
+ }
+ service->clients = smartlist_new();
+ if (smartlist_len(type_names_split) < 2) {
+ log_warn(LD_CONFIG, "HiddenServiceAuthorizeClient contains "
+ "auth-type '%s', but no client names.",
+ service->auth_type == REND_BASIC_AUTH ? "basic" : "stealth");
+ SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
+ smartlist_free(type_names_split);
+ continue;
+ }
+ clients = smartlist_new();
+ smartlist_split_string(clients, smartlist_get(type_names_split, 1),
+ ",", SPLIT_SKIP_SPACE, 0);
+ SMARTLIST_FOREACH(type_names_split, char *, cp, tor_free(cp));
+ smartlist_free(type_names_split);
+ /* Remove duplicate client names. */
+ num_clients = smartlist_len(clients);
+ smartlist_sort_strings(clients);
+ smartlist_uniq_strings(clients);
+ if (smartlist_len(clients) < num_clients) {
log_info(LD_CONFIG, "HiddenServiceAuthorizeClient contains %d "
"duplicate client name(s); removing.",
num_clients - smartlist_len(clients));
@@ -513,10 +609,21 @@ rend_config_services(const or_options_t *options, int validate_only)
}
}
if (service) {
- if (validate_only)
+ cpd_check_t check_opts = CPD_CHECK_MODE_ONLY|CPD_CHECK;
+ if (service->dir_group_readable) {
+ check_opts |= CPD_GROUP_READ;
+ }
+
+ if (check_private_dir(service->directory, check_opts, options->User) < 0) {
+ rend_service_free(service);
+ return -1;
+ }
+
+ if (validate_only) {
rend_service_free(service);
- else
+ } else {
rend_add_service(service);
+ }
}
/* If this is a reload and there were hidden services configured before,
@@ -524,7 +631,6 @@ rend_config_services(const or_options_t *options, int validate_only)
* other ones. */
if (old_service_list && !validate_only) {
smartlist_t *surviving_services = smartlist_new();
- circuit_t *circ;
/* Copy introduction points to new services. */
/* XXXX This is O(n^2), but it's only called on reconfigure, so it's
@@ -544,7 +650,7 @@ rend_config_services(const or_options_t *options, int validate_only)
/* XXXX it would be nicer if we had a nicer abstraction to use here,
* so we could just iterate over the list of services to close, but
* once again, this isn't critical-path code. */
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (!circ->marked_for_close &&
circ->state == CIRCUIT_STATE_OPEN &&
(circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -569,6 +675,7 @@ rend_config_services(const or_options_t *options, int validate_only)
/* XXXX Is there another reason we should use here? */
}
}
+ SMARTLIST_FOREACH_END(circ);
smartlist_free(surviving_services);
SMARTLIST_FOREACH(old_service_list, rend_service_t *, ptr,
rend_service_free(ptr));
@@ -693,10 +800,23 @@ rend_service_load_keys(rend_service_t *s)
{
char fname[512];
char buf[128];
+ cpd_check_t check_opts = CPD_CREATE;
+ if (s->dir_group_readable) {
+ check_opts |= CPD_GROUP_READ;
+ }
/* Check/create directory */
- if (check_private_dir(s->directory, CPD_CREATE, get_options()->User) < 0)
+ if (check_private_dir(s->directory, check_opts, get_options()->User) < 0) {
return -1;
+ }
+#ifndef _WIN32
+ if (s->dir_group_readable) {
+ /* Only new dirs created get new opts, also enforce group read. */
+ if (chmod(s->directory, 0750)) {
+ log_warn(LD_FS,"Unable to make %s group-readable.", s->directory);
+ }
+ }
+#endif
/* Load key */
if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) ||
@@ -706,7 +826,7 @@ rend_service_load_keys(rend_service_t *s)
s->directory);
return -1;
}
- s->private_key = init_key_from_file(fname, 1, LOG_ERR);
+ s->private_key = init_key_from_file(fname, 1, LOG_ERR, 0);
if (!s->private_key)
return -1;
@@ -733,6 +853,15 @@ rend_service_load_keys(rend_service_t *s)
memwipe(buf, 0, sizeof(buf));
return -1;
}
+#ifndef _WIN32
+ if (s->dir_group_readable) {
+ /* Also verify hostname file created with group read. */
+ if (chmod(fname, 0640))
+ log_warn(LD_FS,"Unable to make hidden hostname file %s group-readable.",
+ fname);
+ }
+#endif
+
memwipe(buf, 0, sizeof(buf));
/* If client authorization is configured, load or generate keys. */
@@ -1012,8 +1141,8 @@ rend_check_authorization(rend_service_t *service,
}
/* Allow the request. */
- log_debug(LD_REND, "Client %s authorized for service %s.",
- auth_client->client_name, service->service_id);
+ log_info(LD_REND, "Client %s authorized for service %s.",
+ auth_client->client_name, service->service_id);
return 1;
}
@@ -1456,10 +1585,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
memwipe(hexcookie, 0, sizeof(hexcookie));
/* Free the parsed cell */
- if (parsed_req) {
- rend_service_free_intro(parsed_req);
- parsed_req = NULL;
- }
+ rend_service_free_intro(parsed_req);
/* Free rp if we must */
if (need_rp_free) extend_info_free(rp);
@@ -1489,8 +1615,7 @@ find_rp_for_intro(const rend_intro_cell_t *intro,
}
if (intro->version == 0 || intro->version == 1) {
- if (intro->version == 1) rp_nickname = (const char *)(intro->u.v1.rp);
- else rp_nickname = (const char *)(intro->u.v0.rp);
+ rp_nickname = (const char *)(intro->u.v0_v1.rp);
node = node_get_by_nickname(rp_nickname, 0);
if (!node) {
@@ -1549,7 +1674,6 @@ void
rend_service_free_intro(rend_intro_cell_t *request)
{
if (!request) {
- log_info(LD_BUG, "rend_service_free_intro() called with NULL request!");
return;
}
@@ -1658,8 +1782,9 @@ rend_service_begin_parse_intro(const uint8_t *request,
goto done;
err:
- if (rv) rend_service_free_intro(rv);
+ rend_service_free_intro(rv);
rv = NULL;
+
if (err_msg_out && !err_msg) {
tor_asprintf(&err_msg,
"unknown INTRODUCE%d error",
@@ -1739,11 +1864,7 @@ rend_service_parse_intro_for_v0_or_v1(
goto err;
}
- if (intro->version == 1) {
- memcpy(intro->u.v1.rp, rp_nickname, endptr - rp_nickname + 1);
- } else {
- memcpy(intro->u.v0.rp, rp_nickname, endptr - rp_nickname + 1);
- }
+ memcpy(intro->u.v0_v1.rp, rp_nickname, endptr - rp_nickname + 1);
return ver_specific_len;
@@ -1767,7 +1888,7 @@ rend_service_parse_intro_for_v2(
/*
* We accept version 3 too so that the v3 parser can call this with
- * and adjusted buffer for the latter part of a v3 cell, which is
+ * an adjusted buffer for the latter part of a v3 cell, which is
* identical to a v2 cell.
*/
if (!(intro->version == 2 ||
@@ -2005,7 +2126,7 @@ rend_service_decrypt_intro(
char service_id[REND_SERVICE_ID_LEN_BASE32+1];
ssize_t key_len;
uint8_t buf[RELAY_PAYLOAD_SIZE];
- int result, status = 0;
+ int result, status = -1;
if (!intro || !key) {
if (err_msg_out) {
@@ -2084,6 +2205,8 @@ rend_service_decrypt_intro(
intro->plaintext = tor_malloc(intro->plaintext_len);
memcpy(intro->plaintext, buf, intro->plaintext_len);
+ status = 0;
+
goto done;
err:
@@ -2092,7 +2215,6 @@ rend_service_decrypt_intro(
"unknown INTRODUCE%d error decrypting encrypted part",
intro ? (int)(intro->type) : -1);
}
- if (status >= 0) status = -1;
done:
if (err_msg_out) *err_msg_out = err_msg;
@@ -2119,7 +2241,7 @@ rend_service_parse_intro_plaintext(
char *err_msg = NULL;
ssize_t ver_specific_len, ver_invariant_len;
uint8_t version;
- int status = 0;
+ int status = -1;
if (!intro) {
if (err_msg_out) {
@@ -2178,6 +2300,7 @@ rend_service_parse_intro_plaintext(
(int)(intro->type),
(long)(intro->plaintext_len));
status = -6;
+ goto err;
} else {
memcpy(intro->rc,
intro->plaintext + ver_specific_len,
@@ -2190,6 +2313,7 @@ rend_service_parse_intro_plaintext(
/* Flag it as being fully parsed */
intro->parsed = 1;
+ status = 0;
goto done;
err:
@@ -2198,7 +2322,6 @@ rend_service_parse_intro_plaintext(
"unknown INTRODUCE%d error parsing encrypted part",
intro ? (int)(intro->type) : -1);
}
- if (status >= 0) status = -1;
done:
if (err_msg_out) *err_msg_out = err_msg;
@@ -2404,8 +2527,7 @@ static int
count_established_intro_points(const char *query)
{
int num_ipos = 0;
- circuit_t *circ;
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
if (!circ->marked_for_close &&
circ->state == CIRCUIT_STATE_OPEN &&
(circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -2416,6 +2538,7 @@ count_established_intro_points(const char *query)
num_ipos++;
}
}
+ SMARTLIST_FOREACH_END(circ);
return num_ipos;
}
@@ -3049,15 +3172,20 @@ rend_services_introduce(void)
int intro_point_set_changed, prev_intro_nodes;
unsigned int n_intro_points_unexpired;
unsigned int n_intro_points_to_open;
- smartlist_t *intro_nodes;
time_t now;
const or_options_t *options = get_options();
+ /* List of nodes we need to _exclude_ when choosing a new node to establish
+ * an intro point to. */
+ smartlist_t *exclude_nodes;
+
+ if (!have_completed_a_circuit())
+ return;
- intro_nodes = smartlist_new();
+ exclude_nodes = smartlist_new();
now = time(NULL);
for (i=0; i < smartlist_len(rend_service_list); ++i) {
- smartlist_clear(intro_nodes);
+ smartlist_clear(exclude_nodes);
service = smartlist_get(rend_service_list, i);
tor_assert(service);
@@ -3156,8 +3284,10 @@ rend_services_introduce(void)
if (intro != NULL && intro->time_expiring == -1)
++n_intro_points_unexpired;
+ /* Add the valid node to the exclusion list so we don't try to establish
+ * an introduction point to it again. */
if (node)
- smartlist_add(intro_nodes, (void*)node);
+ smartlist_add(exclude_nodes, (void*)node);
} SMARTLIST_FOREACH_END(intro);
if (!intro_point_set_changed &&
@@ -3193,7 +3323,7 @@ rend_services_introduce(void)
router_crn_flags_t flags = CRN_NEED_UPTIME|CRN_NEED_DESC;
if (get_options()->AllowInvalid_ & ALLOW_INVALID_INTRODUCTION)
flags |= CRN_ALLOW_INVALID;
- node = router_choose_random_node(intro_nodes,
+ node = router_choose_random_node(exclude_nodes,
options->ExcludeNodes, flags);
if (!node) {
log_warn(LD_REND,
@@ -3204,7 +3334,9 @@ rend_services_introduce(void)
break;
}
intro_point_set_changed = 1;
- smartlist_add(intro_nodes, (void*)node);
+ /* Add the choosen node to the exclusion list in order to avoid to pick
+ * it again in the next iteration. */
+ smartlist_add(exclude_nodes, (void*)node);
intro = tor_malloc_zero(sizeof(rend_intro_point_t));
intro->extend_info = extend_info_from_node(node, 0);
intro->intro_key = crypto_pk_new();
@@ -3233,9 +3365,12 @@ rend_services_introduce(void)
}
}
}
- smartlist_free(intro_nodes);
+ smartlist_free(exclude_nodes);
}
+#define MIN_REND_INITIAL_POST_DELAY (30)
+#define MIN_REND_INITIAL_POST_DELAY_TESTING (5)
+
/** Regenerate and upload rendezvous service descriptors for all
* services, if necessary. If the descriptor has been dirty enough
* for long enough, definitely upload; else only upload when the
@@ -3250,6 +3385,9 @@ rend_consider_services_upload(time_t now)
int i;
rend_service_t *service;
int rendpostperiod = get_options()->RendPostPeriod;
+ int rendinitialpostdelay = (get_options()->TestingTorNetwork ?
+ MIN_REND_INITIAL_POST_DELAY_TESTING :
+ MIN_REND_INITIAL_POST_DELAY);
if (!get_options()->PublishHidServDescriptors)
return;
@@ -3257,17 +3395,17 @@ rend_consider_services_upload(time_t now)
for (i=0; i < smartlist_len(rend_service_list); ++i) {
service = smartlist_get(rend_service_list, i);
if (!service->next_upload_time) { /* never been uploaded yet */
- /* The fixed lower bound of 30 seconds ensures that the descriptor
- * is stable before being published. See comment below. */
+ /* The fixed lower bound of rendinitialpostdelay seconds ensures that
+ * the descriptor is stable before being published. See comment below. */
service->next_upload_time =
- now + 30 + crypto_rand_int(2*rendpostperiod);
+ now + rendinitialpostdelay + crypto_rand_int(2*rendpostperiod);
}
if (service->next_upload_time < now ||
(service->desc_is_dirty &&
- service->desc_is_dirty < now-30)) {
+ service->desc_is_dirty < now-rendinitialpostdelay)) {
/* if it's time, or if the directory servers have a wrong service
- * descriptor and ours has been stable for 30 seconds, upload a
- * new one of each format. */
+ * descriptor and ours has been stable for rendinitialpostdelay seconds,
+ * upload a new one of each format. */
rend_service_update_descriptor(service);
upload_service_descriptor(service);
}
@@ -3346,9 +3484,64 @@ rend_service_dump_stats(int severity)
}
}
+#ifdef HAVE_SYS_UN_H
+
+/** Given <b>ports</b>, a smarlist containing rend_service_port_config_t,
+ * add the given <b>p</b>, a AF_UNIX port to the list. Return 0 on success
+ * else return -ENOSYS if AF_UNIX is not supported (see function in the
+ * #else statement below). */
+static int
+add_unix_port(smartlist_t *ports, rend_service_port_config_t *p)
+{
+ tor_assert(ports);
+ tor_assert(p);
+ tor_assert(p->is_unix_addr);
+
+ smartlist_add(ports, p);
+ return 0;
+}
+
+/** Given <b>conn</b> set it to use the given port <b>p</b> values. Return 0
+ * on success else return -ENOSYS if AF_UNIX is not supported (see function
+ * in the #else statement below). */
+static int
+set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p)
+{
+ tor_assert(conn);
+ tor_assert(p);
+ tor_assert(p->is_unix_addr);
+
+ conn->base_.socket_family = AF_UNIX;
+ tor_addr_make_unspec(&conn->base_.addr);
+ conn->base_.port = 1;
+ conn->base_.address = tor_strdup(p->unix_addr);
+ return 0;
+}
+
+#else /* defined(HAVE_SYS_UN_H) */
+
+static int
+set_unix_port(edge_connection_t *conn, rend_service_port_config_t *p)
+{
+ (void) conn;
+ (void) p;
+ return -ENOSYS;
+}
+
+static int
+add_unix_port(smartlist_t *ports, rend_service_port_config_t *p)
+{
+ (void) ports;
+ (void) p;
+ return -ENOSYS;
+}
+
+#endif /* HAVE_SYS_UN_H */
+
/** Given <b>conn</b>, a rendezvous exit stream, look up the hidden service for
* 'circ', and look up the port and address based on conn-\>port.
- * Assign the actual conn-\>addr and conn-\>port. Return -1 if failure,
+ * Assign the actual conn-\>addr and conn-\>port. Return -2 on failure
+ * for which the circuit should be closed, -1 on other failure,
* or 0 for success.
*/
int
@@ -3359,6 +3552,7 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
smartlist_t *matching_ports;
rend_service_port_config_t *chosen_port;
+ unsigned int warn_once = 0;
tor_assert(circ->base_.purpose == CIRCUIT_PURPOSE_S_REND_JOINED);
tor_assert(circ->rend_data);
@@ -3371,24 +3565,53 @@ rend_service_set_connection_addr_port(edge_connection_t *conn,
log_warn(LD_REND, "Couldn't find any service associated with pk %s on "
"rendezvous circuit %u; closing.",
serviceid, (unsigned)circ->base_.n_circ_id);
- return -1;
+ return -2;
}
matching_ports = smartlist_new();
SMARTLIST_FOREACH(service->ports, rend_service_port_config_t *, p,
{
- if (conn->base_.port == p->virtual_port) {
+ if (conn->base_.port != p->virtual_port) {
+ continue;
+ }
+ if (!(p->is_unix_addr)) {
smartlist_add(matching_ports, p);
+ } else {
+ if (add_unix_port(matching_ports, p)) {
+ if (!warn_once) {
+ /* Unix port not supported so warn only once. */
+ log_warn(LD_REND,
+ "Saw AF_UNIX virtual port mapping for port %d on service "
+ "%s, which is unsupported on this platform. Ignoring it.",
+ conn->base_.port, serviceid);
+ }
+ warn_once++;
+ }
}
});
chosen_port = smartlist_choose(matching_ports);
smartlist_free(matching_ports);
if (chosen_port) {
- tor_addr_copy(&conn->base_.addr, &chosen_port->real_addr);
- conn->base_.port = chosen_port->real_port;
+ if (!(chosen_port->is_unix_addr)) {
+ /* Get a non-AF_UNIX connection ready for connection_exit_connect() */
+ tor_addr_copy(&conn->base_.addr, &chosen_port->real_addr);
+ conn->base_.port = chosen_port->real_port;
+ } else {
+ if (set_unix_port(conn, chosen_port)) {
+ /* Simply impossible to end up here else we were able to add a Unix
+ * port without AF_UNIX support... ? */
+ tor_assert(0);
+ }
+ }
return 0;
}
- log_info(LD_REND, "No virtual port mapping exists for port %d on service %s",
- conn->base_.port,serviceid);
- return -1;
+
+ log_info(LD_REND,
+ "No virtual port mapping exists for port %d on service %s",
+ conn->base_.port, serviceid);
+
+ if (service->allow_unknown_ports)
+ return -1;
+ else
+ return -2;
}
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index 40198b07ec..754f7c358c 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -38,13 +38,9 @@ struct rend_intro_cell_s {
/* Version-specific parts */
union {
struct {
- /* Rendezvous point nickname */
- uint8_t rp[20];
- } v0;
- struct {
/* Rendezvous point nickname or hex-encoded key digest */
uint8_t rp[42];
- } v1;
+ } v0_v1;
struct {
/* The extend_info_t struct has everything v2 uses */
extend_info_t *extend_info;
diff --git a/src/or/rephist.c b/src/or/rephist.c
index cedc56af07..fe0997c891 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -1996,12 +1996,9 @@ void
rep_hist_exit_stats_init(time_t now)
{
start_of_exit_stats_interval = now;
- exit_bytes_read = tor_malloc_zero(EXIT_STATS_NUM_PORTS *
- sizeof(uint64_t));
- exit_bytes_written = tor_malloc_zero(EXIT_STATS_NUM_PORTS *
- sizeof(uint64_t));
- exit_streams = tor_malloc_zero(EXIT_STATS_NUM_PORTS *
- sizeof(uint32_t));
+ exit_bytes_read = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint64_t));
+ exit_bytes_written = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint64_t));
+ exit_streams = tor_calloc(EXIT_STATS_NUM_PORTS, sizeof(uint32_t));
}
/** Reset counters for exit port statistics. */
@@ -2472,7 +2469,6 @@ rep_hist_format_buffer_stats(time_t now)
time_t
rep_hist_buffer_stats_write(time_t now)
{
- circuit_t *circ;
char *str = NULL;
if (!start_of_buffer_stats_interval)
@@ -2481,9 +2477,10 @@ rep_hist_buffer_stats_write(time_t now)
goto done; /* Not ready to write */
/* Add open circuits to the history. */
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+ SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
rep_hist_buffer_stats_add_circ(circ, now);
}
+ SMARTLIST_FOREACH_END(circ);
/* Generate history string. */
str = rep_hist_format_buffer_stats(now);
@@ -2570,7 +2567,7 @@ rep_hist_format_desc_stats(time_t now)
size = digestmap_size(served_descs);
if (size > 0) {
- vals = tor_malloc(size * sizeof(int));
+ vals = tor_calloc(size, sizeof(int));
for (iter = digestmap_iter_init(served_descs);
!digestmap_iter_done(iter);
iter = digestmap_iter_next(served_descs, iter)) {
@@ -2725,8 +2722,8 @@ bidi_map_ent_hash(const bidi_map_entry_t *entry)
HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
bidi_map_ent_eq);
-HT_GENERATE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
- bidi_map_ent_eq, 0.6, malloc, realloc, free);
+HT_GENERATE2(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
+ bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_)
/* DOCDOC bidi_map_free */
static void
@@ -2909,11 +2906,271 @@ rep_hist_log_circuit_handshake_stats(time_t now)
memset(onion_handshakes_requested, 0, sizeof(onion_handshakes_requested));
}
+/* Hidden service statistics section */
+
+/** Start of the current hidden service stats interval or 0 if we're
+ * not collecting hidden service statistics. */
+static time_t start_of_hs_stats_interval;
+
+/** Carries the various hidden service statistics, and any other
+ * information needed. */
+typedef struct hs_stats_t {
+ /** How many relay cells have we seen as rendezvous points? */
+ int64_t rp_relay_cells_seen;
+
+ /** Set of unique public key digests we've seen this stat period
+ * (could also be implemented as sorted smartlist). */
+ digestmap_t *onions_seen_this_period;
+} hs_stats_t;
+
+/** Our statistics structure singleton. */
+static hs_stats_t *hs_stats = NULL;
+
+/** Allocate, initialize and return an hs_stats_t structure. */
+static hs_stats_t *
+hs_stats_new(void)
+{
+ hs_stats_t * hs_stats = tor_malloc_zero(sizeof(hs_stats_t));
+ hs_stats->onions_seen_this_period = digestmap_new();
+
+ return hs_stats;
+}
+
+/** Free an hs_stats_t structure. */
+static void
+hs_stats_free(hs_stats_t *hs_stats)
+{
+ if (!hs_stats) {
+ return;
+ }
+
+ digestmap_free(hs_stats->onions_seen_this_period, NULL);
+ tor_free(hs_stats);
+}
+
+/** Initialize hidden service statistics. */
+void
+rep_hist_hs_stats_init(time_t now)
+{
+ if (!hs_stats) {
+ hs_stats = hs_stats_new();
+ }
+
+ start_of_hs_stats_interval = now;
+}
+
+/** Clear history of hidden service statistics and set the measurement
+ * interval start to <b>now</b>. */
+static void
+rep_hist_reset_hs_stats(time_t now)
+{
+ if (!hs_stats) {
+ hs_stats = hs_stats_new();
+ }
+
+ hs_stats->rp_relay_cells_seen = 0;
+
+ digestmap_free(hs_stats->onions_seen_this_period, NULL);
+ hs_stats->onions_seen_this_period = digestmap_new();
+
+ start_of_hs_stats_interval = now;
+}
+
+/** Stop collecting hidden service stats in a way that we can re-start
+ * doing so in rep_hist_buffer_stats_init(). */
+void
+rep_hist_hs_stats_term(void)
+{
+ rep_hist_reset_hs_stats(0);
+}
+
+/** We saw a new HS relay cell, Count it! */
+void
+rep_hist_seen_new_rp_cell(void)
+{
+ if (!hs_stats) {
+ return; // We're not collecting stats
+ }
+
+ hs_stats->rp_relay_cells_seen++;
+}
+
+/** As HSDirs, we saw another hidden service with public key
+ * <b>pubkey</b>. Check whether we have counted it before, if not
+ * count it now! */
+void
+rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey)
+{
+ char pubkey_hash[DIGEST_LEN];
+
+ if (!hs_stats) {
+ return; // We're not collecting stats
+ }
+
+ /* Get the digest of the pubkey which will be used to detect whether
+ we've seen this hidden service before or not. */
+ if (crypto_pk_get_digest(pubkey, pubkey_hash) < 0) {
+ /* This fail should not happen; key has been validated by
+ descriptor parsing code first. */
+ return;
+ }
+
+ /* Check if this is the first time we've seen this hidden
+ service. If it is, count it as new. */
+ if (!digestmap_get(hs_stats->onions_seen_this_period,
+ pubkey_hash)) {
+ digestmap_set(hs_stats->onions_seen_this_period,
+ pubkey_hash, (void*)(uintptr_t)1);
+ }
+}
+
+/* The number of cells that are supposed to be hidden from the adversary
+ * by adding noise from the Laplace distribution. This value, divided by
+ * EPSILON, is Laplace parameter b. */
+#define REND_CELLS_DELTA_F 2048
+/* Security parameter for obfuscating number of cells with a value between
+ * 0 and 1. Smaller values obfuscate observations more, but at the same
+ * time make statistics less usable. */
+#define REND_CELLS_EPSILON 0.3
+/* The number of cells that are supposed to be hidden from the adversary
+ * by rounding up to the next multiple of this number. */
+#define REND_CELLS_BIN_SIZE 1024
+/* The number of service identities that are supposed to be hidden from
+ * the adversary by adding noise from the Laplace distribution. This
+ * value, divided by EPSILON, is Laplace parameter b. */
+#define ONIONS_SEEN_DELTA_F 8
+/* Security parameter for obfuscating number of service identities with a
+ * value between 0 and 1. Smaller values obfuscate observations more, but
+ * at the same time make statistics less usable. */
+#define ONIONS_SEEN_EPSILON 0.3
+/* The number of service identities that are supposed to be hidden from
+ * the adversary by rounding up to the next multiple of this number. */
+#define ONIONS_SEEN_BIN_SIZE 8
+
+/** Allocate and return a string containing hidden service stats that
+ * are meant to be placed in the extra-info descriptor. */
+static char *
+rep_hist_format_hs_stats(time_t now)
+{
+ char t[ISO_TIME_LEN+1];
+ char *hs_stats_string;
+ int64_t obfuscated_cells_seen;
+ int64_t obfuscated_onions_seen;
+
+ obfuscated_cells_seen = round_int64_to_next_multiple_of(
+ hs_stats->rp_relay_cells_seen,
+ REND_CELLS_BIN_SIZE);
+ obfuscated_cells_seen = add_laplace_noise(obfuscated_cells_seen,
+ crypto_rand_double(),
+ REND_CELLS_DELTA_F, REND_CELLS_EPSILON);
+ obfuscated_onions_seen = round_int64_to_next_multiple_of(digestmap_size(
+ hs_stats->onions_seen_this_period),
+ ONIONS_SEEN_BIN_SIZE);
+ obfuscated_onions_seen = add_laplace_noise(obfuscated_onions_seen,
+ crypto_rand_double(), ONIONS_SEEN_DELTA_F,
+ ONIONS_SEEN_EPSILON);
+
+ format_iso_time(t, now);
+ tor_asprintf(&hs_stats_string, "hidserv-stats-end %s (%d s)\n"
+ "hidserv-rend-relayed-cells "I64_FORMAT" delta_f=%d "
+ "epsilon=%.2f bin_size=%d\n"
+ "hidserv-dir-onions-seen "I64_FORMAT" delta_f=%d "
+ "epsilon=%.2f bin_size=%d\n",
+ t, (unsigned) (now - start_of_hs_stats_interval),
+ I64_PRINTF_ARG(obfuscated_cells_seen), REND_CELLS_DELTA_F,
+ REND_CELLS_EPSILON, REND_CELLS_BIN_SIZE,
+ I64_PRINTF_ARG(obfuscated_onions_seen),
+ ONIONS_SEEN_DELTA_F,
+ ONIONS_SEEN_EPSILON, ONIONS_SEEN_BIN_SIZE);
+
+ return hs_stats_string;
+}
+
+/** If 24 hours have passed since the beginning of the current HS
+ * stats period, write buffer stats to $DATADIR/stats/hidserv-stats
+ * (possibly overwriting an existing file) and reset counters. Return
+ * when we would next want to write buffer stats or 0 if we never want to
+ * write. */
+time_t
+rep_hist_hs_stats_write(time_t now)
+{
+ char *str = NULL;
+
+ if (!start_of_hs_stats_interval) {
+ return 0; /* Not initialized. */
+ }
+
+ if (start_of_hs_stats_interval + WRITE_STATS_INTERVAL > now) {
+ goto done; /* Not ready to write */
+ }
+
+ /* Generate history string. */
+ str = rep_hist_format_hs_stats(now);
+
+ /* Reset HS history. */
+ rep_hist_reset_hs_stats(now);
+
+ /* Try to write to disk. */
+ if (!check_or_create_data_subdir("stats")) {
+ write_to_data_subdir("stats", "hidserv-stats", str,
+ "hidden service stats");
+ }
+
+ done:
+ tor_free(str);
+ return start_of_hs_stats_interval + WRITE_STATS_INTERVAL;
+}
+
+#define MAX_LINK_PROTO_TO_LOG 4
+static uint64_t link_proto_count[MAX_LINK_PROTO_TO_LOG+1][2];
+
+/** Note that we negotiated link protocol version <b>link_proto</b>, on
+ * a connection that started here iff <b>started_here</b> is true.
+ */
+void
+rep_hist_note_negotiated_link_proto(unsigned link_proto, int started_here)
+{
+ started_here = !!started_here; /* force to 0 or 1 */
+ if (link_proto > MAX_LINK_PROTO_TO_LOG) {
+ log_warn(LD_BUG, "Can't log link protocol %u", link_proto);
+ return;
+ }
+
+ link_proto_count[link_proto][started_here]++;
+}
+
+/** Log a heartbeat message explaining how many connections of each link
+ * protocol version we have used.
+ */
+void
+rep_hist_log_link_protocol_counts(void)
+{
+ log_notice(LD_HEARTBEAT,
+ "Since startup, we have initiated "
+ U64_FORMAT" v1 connections, "
+ U64_FORMAT" v2 connections, "
+ U64_FORMAT" v3 connections, and "
+ U64_FORMAT" v4 connections; and received "
+ U64_FORMAT" v1 connections, "
+ U64_FORMAT" v2 connections, "
+ U64_FORMAT" v3 connections, and "
+ U64_FORMAT" v4 connections.",
+ U64_PRINTF_ARG(link_proto_count[1][1]),
+ U64_PRINTF_ARG(link_proto_count[2][1]),
+ U64_PRINTF_ARG(link_proto_count[3][1]),
+ U64_PRINTF_ARG(link_proto_count[4][1]),
+ U64_PRINTF_ARG(link_proto_count[1][0]),
+ U64_PRINTF_ARG(link_proto_count[2][0]),
+ U64_PRINTF_ARG(link_proto_count[3][0]),
+ U64_PRINTF_ARG(link_proto_count[4][0]));
+}
+
/** Free all storage held by the OR/link history caches, by the
* bandwidth history arrays, by the port history, or by statistics . */
void
rep_hist_free_all(void)
{
+ hs_stats_free(hs_stats);
digestmap_free(history_map, free_or_history);
tor_free(read_array);
tor_free(write_array);
diff --git a/src/or/rephist.h b/src/or/rephist.h
index cd6231e6e4..f94b4e8ff1 100644
--- a/src/or/rephist.h
+++ b/src/or/rephist.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -99,7 +99,18 @@ void rep_hist_note_circuit_handshake_requested(uint16_t type);
void rep_hist_note_circuit_handshake_assigned(uint16_t type);
void rep_hist_log_circuit_handshake_stats(time_t now);
+void rep_hist_hs_stats_init(time_t now);
+void rep_hist_hs_stats_term(void);
+time_t rep_hist_hs_stats_write(time_t now);
+char *rep_hist_get_hs_stats_string(void);
+void rep_hist_seen_new_rp_cell(void);
+void rep_hist_stored_maybe_new_hs(const crypto_pk_t *pubkey);
+
void rep_hist_free_all(void);
+void rep_hist_note_negotiated_link_proto(unsigned link_proto,
+ int started_here);
+void rep_hist_log_link_protocol_counts(void);
+
#endif
diff --git a/src/or/replaycache.c b/src/or/replaycache.c
index 90f87c12d5..569e0736cb 100644
--- a/src/or/replaycache.c
+++ b/src/or/replaycache.c
@@ -1,4 +1,4 @@
- /* Copyright (c) 2012-2013, The Tor Project, Inc. */
+ /* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/*
diff --git a/src/or/replaycache.h b/src/or/replaycache.h
index cd713fe891..9b9daf3831 100644
--- a/src/or/replaycache.h
+++ b/src/or/replaycache.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/or/router.c b/src/or/router.c
index 2cdbb0c8bb..2ddaa895fc 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ROUTER_PRIVATE
@@ -55,13 +55,11 @@ static crypto_pk_t *onionkey=NULL;
/** Previous private onionskin decryption key: used to decode CREATE cells
* generated by clients that have an older version of our descriptor. */
static crypto_pk_t *lastonionkey=NULL;
-#ifdef CURVE25519_ENABLED
/** Current private ntor secret key: used to perform the ntor handshake. */
static curve25519_keypair_t curve25519_onion_key;
/** Previous private ntor secret key: used to perform the ntor handshake
* with clients that have an older version of our descriptor. */
static curve25519_keypair_t last_curve25519_onion_key;
-#endif
/** Private server "identity key": used to sign directory info and TLS
* certificates. Never changes. */
static crypto_pk_t *server_identitykey=NULL;
@@ -134,7 +132,6 @@ dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last)
tor_mutex_release(key_lock);
}
-#ifdef CURVE25519_ENABLED
/** Return the current secret onion key for the ntor handshake. Must only
* be called from the main thread. */
static const curve25519_keypair_t *
@@ -181,7 +178,6 @@ ntor_key_map_free(di_digest256_map_t *map)
return;
dimap_free(map, ntor_key_map_free_helper);
}
-#endif
/** Return the time when the onion key was last set. This is either the time
* when the process launched, or the time of the most recent key rotation since
@@ -313,12 +309,11 @@ rotate_onion_key(void)
char *fname, *fname_prev;
crypto_pk_t *prkey = NULL;
or_state_t *state = get_or_state();
-#ifdef CURVE25519_ENABLED
curve25519_keypair_t new_curve25519_keypair;
-#endif
time_t now;
fname = get_datadir_fname2("keys", "secret_onion_key");
fname_prev = get_datadir_fname2("keys", "secret_onion_key.old");
+ /* There isn't much point replacing an old key with an empty file */
if (file_status(fname) == FN_FILE) {
if (replace_file(fname, fname_prev))
goto error;
@@ -335,13 +330,13 @@ rotate_onion_key(void)
log_err(LD_FS,"Couldn't write generated onion key to \"%s\".", fname);
goto error;
}
-#ifdef CURVE25519_ENABLED
tor_free(fname);
tor_free(fname_prev);
fname = get_datadir_fname2("keys", "secret_onion_key_ntor");
fname_prev = get_datadir_fname2("keys", "secret_onion_key_ntor.old");
if (curve25519_keypair_generate(&new_curve25519_keypair, 1) < 0)
goto error;
+ /* There isn't much point replacing an old key with an empty file */
if (file_status(fname) == FN_FILE) {
if (replace_file(fname, fname_prev))
goto error;
@@ -351,18 +346,15 @@ rotate_onion_key(void)
log_err(LD_FS,"Couldn't write curve25519 onion key to \"%s\".",fname);
goto error;
}
-#endif
log_info(LD_GENERAL, "Rotating onion key");
tor_mutex_acquire(key_lock);
crypto_pk_free(lastonionkey);
lastonionkey = onionkey;
onionkey = prkey;
-#ifdef CURVE25519_ENABLED
memcpy(&last_curve25519_onion_key, &curve25519_onion_key,
sizeof(curve25519_keypair_t));
memcpy(&curve25519_onion_key, &new_curve25519_keypair,
sizeof(curve25519_keypair_t));
-#endif
now = time(NULL);
state->LastRotatedOnionKey = onionkey_set_at = now;
tor_mutex_release(key_lock);
@@ -374,20 +366,40 @@ rotate_onion_key(void)
if (prkey)
crypto_pk_free(prkey);
done:
-#ifdef CURVE25519_ENABLED
memwipe(&new_curve25519_keypair, 0, sizeof(new_curve25519_keypair));
-#endif
tor_free(fname);
tor_free(fname_prev);
}
+/** Log greeting message that points to new relay lifecycle document the
+ * first time this function has been called.
+ */
+static void
+log_new_relay_greeting(void)
+{
+ static int already_logged = 0;
+
+ if (already_logged)
+ return;
+
+ tor_log(LOG_NOTICE, LD_GENERAL, "You are running a new relay. "
+ "Thanks for helping the Tor network! If you wish to know "
+ "what will happen in the upcoming weeks regarding its usage, "
+ "have a look at https://blog.torproject.org/blog/lifecycle-of"
+ "-a-new-relay");
+
+ already_logged = 1;
+}
+
/** Try to read an RSA key from <b>fname</b>. If <b>fname</b> doesn't exist
* and <b>generate</b> is true, create a new RSA key and save it in
* <b>fname</b>. Return the read/created key, or NULL on error. Log all
- * errors at level <b>severity</b>.
+ * errors at level <b>severity</b>. If <b>log_greeting</b> is non-zero and a
+ * new key was created, log_new_relay_greeting() is called.
*/
crypto_pk_t *
-init_key_from_file(const char *fname, int generate, int severity)
+init_key_from_file(const char *fname, int generate, int severity,
+ int log_greeting)
{
crypto_pk_t *prkey = NULL;
@@ -401,7 +413,11 @@ init_key_from_file(const char *fname, int generate, int severity)
case FN_ERROR:
tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname);
goto error;
+ /* treat empty key files as if the file doesn't exist, and,
+ * if generate is set, replace the empty file in
+ * crypto_pk_write_private_key_to_filename() */
case FN_NOENT:
+ case FN_EMPTY:
if (generate) {
if (!have_lockfile()) {
if (try_locking(get_options(), 0)<0) {
@@ -425,6 +441,9 @@ init_key_from_file(const char *fname, int generate, int severity)
goto error;
}
log_info(LD_GENERAL, "Generated key seems valid");
+ if (log_greeting) {
+ log_new_relay_greeting();
+ }
if (crypto_pk_write_private_key_to_filename(prkey, fname)) {
tor_log(severity, LD_FS,
"Couldn't write generated key to \"%s\".", fname);
@@ -450,12 +469,11 @@ init_key_from_file(const char *fname, int generate, int severity)
return NULL;
}
-#ifdef CURVE25519_ENABLED
/** Load a curve25519 keypair from the file <b>fname</b>, writing it into
- * <b>keys_out</b>. If the file isn't found and <b>generate</b> is true,
- * create a new keypair and write it into the file. If there are errors, log
- * them at level <b>severity</b>. Generate files using <b>tag</b> in their
- * ASCII wrapper. */
+ * <b>keys_out</b>. If the file isn't found, or is empty, and <b>generate</b>
+ * is true, create a new keypair and write it into the file. If there are
+ * errors, log them at level <b>severity</b>. Generate files using <b>tag</b>
+ * in their ASCII wrapper. */
static int
init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out,
const char *fname,
@@ -468,7 +486,10 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out,
case FN_ERROR:
tor_log(severity, LD_FS,"Can't read key from \"%s\"", fname);
goto error;
+ /* treat empty key files as if the file doesn't exist, and, if generate
+ * is set, replace the empty file in curve25519_keypair_write_to_file() */
case FN_NOENT:
+ case FN_EMPTY:
if (generate) {
if (!have_lockfile()) {
if (try_locking(get_options(), 0)<0) {
@@ -488,7 +509,7 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out,
if (curve25519_keypair_write_to_file(keys_out, fname, tag)<0) {
tor_log(severity, LD_FS,
"Couldn't write generated key to \"%s\".", fname);
- memset(keys_out, 0, sizeof(*keys_out));
+ memwipe(keys_out, 0, sizeof(*keys_out));
goto error;
}
} else {
@@ -519,7 +540,6 @@ init_curve25519_keypair_from_file(curve25519_keypair_t *keys_out,
error:
return -1;
}
-#endif
/** Try to load the vote-signing private key and certificate for being a v3
* directory authority, and make sure they match. If <b>legacy</b>, load a
@@ -538,7 +558,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out,
fname = get_datadir_fname2("keys",
legacy ? "legacy_signing_key" : "authority_signing_key");
- signing_key = init_key_from_file(fname, 0, LOG_INFO);
+ signing_key = init_key_from_file(fname, 0, LOG_INFO, 0);
if (!signing_key) {
log_warn(LD_DIR, "No version 3 directory key found in %s", fname);
goto done;
@@ -821,7 +841,7 @@ init_keys(void)
/* 1b. Read identity key. Make it if none is found. */
keydir = get_datadir_fname2("keys", "secret_id_key");
log_info(LD_GENERAL,"Reading/making identity key \"%s\"...",keydir);
- prkey = init_key_from_file(keydir, 1, LOG_ERR);
+ prkey = init_key_from_file(keydir, 1, LOG_ERR, 1);
tor_free(keydir);
if (!prkey) return -1;
set_server_identity_key(prkey);
@@ -844,7 +864,7 @@ init_keys(void)
/* 2. Read onion key. Make it if none is found. */
keydir = get_datadir_fname2("keys", "secret_onion_key");
log_info(LD_GENERAL,"Reading/making onion key \"%s\"...",keydir);
- prkey = init_key_from_file(keydir, 1, LOG_ERR);
+ prkey = init_key_from_file(keydir, 1, LOG_ERR, 1);
tor_free(keydir);
if (!prkey) return -1;
set_onion_key(prkey);
@@ -869,13 +889,14 @@ init_keys(void)
keydir = get_datadir_fname2("keys", "secret_onion_key.old");
if (!lastonionkey && file_status(keydir) == FN_FILE) {
- prkey = init_key_from_file(keydir, 1, LOG_ERR); /* XXXX Why 1? */
+ /* Load keys from non-empty files only.
+ * Missing old keys won't be replaced with freshly generated keys. */
+ prkey = init_key_from_file(keydir, 0, LOG_ERR, 0);
if (prkey)
lastonionkey = prkey;
}
tor_free(keydir);
-#ifdef CURVE25519_ENABLED
{
/* 2b. Load curve25519 onion keys. */
int r;
@@ -891,12 +912,13 @@ init_keys(void)
last_curve25519_onion_key.pubkey.public_key,
CURVE25519_PUBKEY_LEN) &&
file_status(keydir) == FN_FILE) {
+ /* Load keys from non-empty files only.
+ * Missing old keys won't be replaced with freshly generated keys. */
init_curve25519_keypair_from_file(&last_curve25519_onion_key,
keydir, 0, LOG_ERR, "onion");
}
tor_free(keydir);
}
-#endif
/* 3. Initialize link key and TLS context. */
if (router_initialize_tls_context() < 0) {
@@ -911,14 +933,13 @@ init_keys(void)
const char *m = NULL;
routerinfo_t *ri;
/* We need to add our own fingerprint so it gets recognized. */
- if (dirserv_add_own_fingerprint(options->Nickname,
- get_server_identity_key())) {
- log_err(LD_GENERAL,"Error adding own fingerprint to approved set");
+ if (dirserv_add_own_fingerprint(get_server_identity_key())) {
+ log_err(LD_GENERAL,"Error adding own fingerprint to set of relays");
return -1;
}
if (mydesc) {
was_router_added_t added;
- ri = router_parse_entry_from_string(mydesc, NULL, 1, 0, NULL);
+ ri = router_parse_entry_from_string(mydesc, NULL, 1, 0, NULL, NULL);
if (!ri) {
log_err(LD_GENERAL,"Generated a routerinfo we couldn't parse.");
return -1;
@@ -1081,6 +1102,7 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port)
* they're confused or to get statistics. */
int interval_length = accounting_get_interval_length();
uint32_t effective_bw = get_effective_bwrate(options);
+ uint64_t acc_bytes;
if (!interval_length) {
log_warn(LD_BUG, "An accounting interval is not allowed to be zero "
"seconds long. Raising to 1.");
@@ -1091,8 +1113,12 @@ decide_to_advertise_dirport(const or_options_t *options, uint16_t dir_port)
"accounting interval length %d", effective_bw,
U64_PRINTF_ARG(options->AccountingMax),
interval_length);
+
+ acc_bytes = options->AccountingMax;
+ if (get_options()->AccountingRule == ACCT_SUM)
+ acc_bytes /= 2;
if (effective_bw >=
- options->AccountingMax / interval_length) {
+ acc_bytes / interval_length) {
new_choice = 0;
reason = "AccountingMax enabled";
}
@@ -1210,6 +1236,11 @@ router_orport_found_reachable(void)
" Publishing server descriptor." : "");
can_reach_or_port = 1;
mark_my_descriptor_dirty("ORPort found reachable");
+ /* This is a significant enough change to upload immediately,
+ * at least in a test network */
+ if (get_options()->TestingTorNetwork == 1) {
+ reschedule_descriptor_update_check();
+ }
control_event_server_status(LOG_NOTICE,
"REACHABILITY_SUCCEEDED ORADDRESS=%s:%d",
address, me->or_port);
@@ -1227,8 +1258,14 @@ router_dirport_found_reachable(void)
log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
"from the outside. Excellent.");
can_reach_dir_port = 1;
- if (decide_to_advertise_dirport(get_options(), me->dir_port))
+ if (decide_to_advertise_dirport(get_options(), me->dir_port)) {
mark_my_descriptor_dirty("DirPort found reachable");
+ /* This is a significant enough change to upload immediately,
+ * at least in a test network */
+ if (get_options()->TestingTorNetwork == 1) {
+ reschedule_descriptor_update_check();
+ }
+ }
control_event_server_status(LOG_NOTICE,
"REACHABILITY_SUCCEEDED DIRADDRESS=%s:%d",
address, me->dir_port);
@@ -1802,19 +1839,17 @@ router_rebuild_descriptor(int force)
ri->cache_info.published_on = time(NULL);
ri->onion_pkey = crypto_pk_dup_key(get_onion_key()); /* must invoke from
* main thread */
-#ifdef CURVE25519_ENABLED
ri->onion_curve25519_pkey =
tor_memdup(&get_current_curve25519_keypair()->pubkey,
sizeof(curve25519_public_key_t));
-#endif
/* For now, at most one IPv6 or-address is being advertised. */
{
const port_cfg_t *ipv6_orport = NULL;
SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) {
if (p->type == CONN_TYPE_OR_LISTENER &&
- ! p->no_advertise &&
- ! p->bind_ipv4_only &&
+ ! p->server_cfg.no_advertise &&
+ ! p->server_cfg.bind_ipv4_only &&
tor_addr_family(&p->addr) == AF_INET6) {
if (! tor_addr_is_internal(&p->addr, 0)) {
ipv6_orport = p;
@@ -1856,10 +1891,8 @@ router_rebuild_descriptor(int force)
/* DNS is screwed up; don't claim to be an exit. */
policies_exit_policy_append_reject_star(&ri->exit_policy);
} else {
- policies_parse_exit_policy(options->ExitPolicy, &ri->exit_policy,
- options->IPv6Exit,
- options->ExitPolicyRejectPrivate,
- ri->addr, !options->BridgeRelay);
+ policies_parse_exit_policy_from_options(options,ri->addr,
+ &ri->exit_policy);
}
ri->policy_is_reject_star =
policy_is_reject_star(ri->exit_policy, AF_INET) &&
@@ -1879,7 +1912,7 @@ router_rebuild_descriptor(int force)
family = smartlist_new();
ri->declared_family = smartlist_new();
smartlist_split_string(family, options->MyFamily, ",",
- SPLIT_SKIP_SPACE|SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK|SPLIT_STRIP_SPACE, 0);
SMARTLIST_FOREACH_BEGIN(family, char *, name) {
const node_t *member;
if (!strcasecmp(name, options->Nickname))
@@ -2063,7 +2096,8 @@ mark_my_descriptor_dirty(const char *reason)
}
/** How frequently will we republish our descriptor because of large (factor
- * of 2) shifts in estimated bandwidth? */
+ * of 2) shifts in estimated bandwidth? Note: We don't use this constant
+ * if our previous bandwidth estimate was exactly 0. */
#define MAX_BANDWIDTH_CHANGE_FREQ (20*60)
/** Check whether bandwidth has changed a lot since the last time we announced
@@ -2081,7 +2115,7 @@ check_descriptor_bandwidth_changed(time_t now)
if ((prev != cur && (!prev || !cur)) ||
cur > prev*2 ||
cur < prev/2) {
- if (last_changed+MAX_BANDWIDTH_CHANGE_FREQ < now) {
+ if (last_changed+MAX_BANDWIDTH_CHANGE_FREQ < now || !prev) {
log_info(LD_GENERAL,
"Measured bandwidth has changed; rebuilding descriptor.");
mark_my_descriptor_dirty("bandwidth has changed");
@@ -2371,7 +2405,8 @@ router_dump_router_to_string(routerinfo_t *router,
has_extra_info_digest ? "extra-info-digest " : "",
has_extra_info_digest ? extra_info_digest : "",
has_extra_info_digest ? "\n" : "",
- options->DownloadExtraInfo ? "caches-extra-info\n" : "",
+ (options->DownloadExtraInfo || options->V3AuthoritativeDir) ?
+ "caches-extra-info\n" : "",
onion_pkey, identity_pkey,
family_line,
we_are_hibernating() ? "hibernating 1\n" : "",
@@ -2385,7 +2420,6 @@ router_dump_router_to_string(routerinfo_t *router,
smartlist_add_asprintf(chunks, "contact %s\n", ci);
}
-#ifdef CURVE25519_ENABLED
if (router->onion_curve25519_pkey) {
char kbuf[128];
base64_encode(kbuf, sizeof(kbuf),
@@ -2393,7 +2427,6 @@ router_dump_router_to_string(routerinfo_t *router,
CURVE25519_PUBKEY_LEN);
smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
}
-#endif
/* Write the exit policy to the end of 's'. */
if (!router->exit_policy || !smartlist_len(router->exit_policy)) {
@@ -2443,7 +2476,7 @@ router_dump_router_to_string(routerinfo_t *router,
const char *cp;
routerinfo_t *ri_tmp;
cp = s_dup = tor_strdup(output);
- ri_tmp = router_parse_entry_from_string(cp, NULL, 1, 0, NULL);
+ ri_tmp = router_parse_entry_from_string(cp, NULL, 1, 0, NULL, NULL);
if (!ri_tmp) {
log_err(LD_BUG,
"We just generated a router descriptor we can't parse.");
@@ -2557,8 +2590,9 @@ router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport)
* <b>end_line</b>, ensure that its timestamp is not more than 25 hours in
* the past or more than 1 hour in the future with respect to <b>now</b>,
* and write the file contents starting with that line to *<b>out</b>.
- * Return 1 for success, 0 if the file does not exist, or -1 if the file
- * does not contain a line matching these criteria or other failure. */
+ * Return 1 for success, 0 if the file does not exist or is empty, or -1
+ * if the file does not contain a line matching these criteria or other
+ * failure. */
static int
load_stats_file(const char *filename, const char *end_line, time_t now,
char **out)
@@ -2592,7 +2626,9 @@ load_stats_file(const char *filename, const char *end_line, time_t now,
notfound:
tor_free(contents);
break;
+ /* treat empty stats files as if the file doesn't exist */
case FN_NOENT:
+ case FN_EMPTY:
r = 0;
break;
case FN_ERROR:
@@ -2649,6 +2685,11 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
"dirreq-stats-end", now, &contents) > 0) {
smartlist_add(chunks, contents);
}
+ if (options->HiddenServiceStatistics &&
+ load_stats_file("stats"PATH_SEPARATOR"hidserv-stats",
+ "hidserv-stats-end", now, &contents) > 0) {
+ smartlist_add(chunks, contents);
+ }
if (options->EntryStatistics &&
load_stats_file("stats"PATH_SEPARATOR"entry-stats",
"entry-stats-end", now, &contents) > 0) {
@@ -2725,7 +2766,7 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
s = smartlist_join_strings(chunks, "", 0, NULL);
cp = s_dup = tor_strdup(s);
- ei_tmp = extrainfo_parse_entry_from_string(cp, NULL, 1, NULL);
+ ei_tmp = extrainfo_parse_entry_from_string(cp, NULL, 1, NULL, NULL);
if (!ei_tmp) {
if (write_stats_to_extrainfo) {
log_warn(LD_GENERAL, "We just generated an extra-info descriptor "
@@ -3069,10 +3110,8 @@ router_free_all(void)
crypto_pk_free(legacy_signing_key);
authority_cert_free(legacy_key_certificate);
-#ifdef CURVE25519_ENABLED
memwipe(&curve25519_onion_key, 0, sizeof(curve25519_onion_key));
memwipe(&last_curve25519_onion_key, 0, sizeof(last_curve25519_onion_key));
-#endif
if (warned_nonexistent_family) {
SMARTLIST_FOREACH(warned_nonexistent_family, char *, cp, tor_free(cp));
diff --git a/src/or/router.h b/src/or/router.h
index d18ff065ea..8108ffb22f 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,13 +29,11 @@ crypto_pk_t *get_my_v3_legacy_signing_key(void);
void dup_onion_keys(crypto_pk_t **key, crypto_pk_t **last);
void rotate_onion_key(void);
crypto_pk_t *init_key_from_file(const char *fname, int generate,
- int severity);
+ int severity, int log_greeting);
void v3_authority_check_key_expiry(void);
-#ifdef CURVE25519_ENABLED
di_digest256_map_t *construct_ntor_key_map(void);
void ntor_key_map_free(di_digest256_map_t *map);
-#endif
int router_initialize_tls_context(void);
int init_keys(void);
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 07e87724ba..af8e68e880 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -65,7 +65,7 @@ static int compute_weighted_bandwidths(const smartlist_t *sl,
bandwidth_weight_rule_t rule,
u64_dbl_t **bandwidths_out);
static const routerstatus_t *router_pick_directory_server_impl(
- dirinfo_type_t auth, int flags);
+ dirinfo_type_t auth, int flags, int *n_busy_out);
static const routerstatus_t *router_pick_trusteddirserver_impl(
const smartlist_t *sourcelist, dirinfo_type_t auth,
int flags, int *n_busy_out);
@@ -79,6 +79,7 @@ static const char *signed_descriptor_get_body_impl(
const signed_descriptor_t *desc,
int with_annotations);
static void list_pending_downloads(digestmap_t *result,
+ digest256map_t *result256,
int purpose, const char *prefix);
static void list_pending_fpsk_downloads(fp_pair_map_t *result);
static void launch_dummy_descriptor_download_as_needed(time_t now,
@@ -448,46 +449,69 @@ trusted_dirs_flush_certs_to_disk(void)
trusted_dir_servers_certs_changed = 0;
}
-/** Remove all v3 authority certificates that have been superseded for more
- * than 48 hours. (If the most recent cert was published more than 48 hours
- * ago, then we aren't going to get any consensuses signed with older
+static int
+compare_certs_by_pubdates(const void **_a, const void **_b)
+{
+ const authority_cert_t *cert1 = *_a, *cert2=*_b;
+
+ if (cert1->cache_info.published_on < cert2->cache_info.published_on)
+ return -1;
+ else if (cert1->cache_info.published_on > cert2->cache_info.published_on)
+ return 1;
+ else
+ return 0;
+}
+
+/** Remove all expired v3 authority certificates that have been superseded for
+ * more than 48 hours or, if not expired, that were published more than 7 days
+ * before being superseded. (If the most recent cert was published more than 48
+ * hours ago, then we aren't going to get any consensuses signed with older
* keys.) */
static void
trusted_dirs_remove_old_certs(void)
{
time_t now = time(NULL);
#define DEAD_CERT_LIFETIME (2*24*60*60)
-#define OLD_CERT_LIFETIME (7*24*60*60)
+#define SUPERSEDED_CERT_LIFETIME (2*24*60*60)
if (!trusted_dir_certs)
return;
DIGESTMAP_FOREACH(trusted_dir_certs, key, cert_list_t *, cl) {
- authority_cert_t *newest = NULL;
- SMARTLIST_FOREACH(cl->certs, authority_cert_t *, cert,
- if (!newest || (cert->cache_info.published_on >
- newest->cache_info.published_on))
- newest = cert);
- if (newest) {
- const time_t newest_published = newest->cache_info.published_on;
- SMARTLIST_FOREACH_BEGIN(cl->certs, authority_cert_t *, cert) {
- int expired;
- time_t cert_published;
- if (newest == cert)
- continue;
- expired = now > cert->expires;
- cert_published = cert->cache_info.published_on;
- /* Store expired certs for 48 hours after a newer arrives;
+ /* Sort the list from first-published to last-published */
+ smartlist_sort(cl->certs, compare_certs_by_pubdates);
+
+ SMARTLIST_FOREACH_BEGIN(cl->certs, authority_cert_t *, cert) {
+ if (cert_sl_idx == smartlist_len(cl->certs) - 1) {
+ /* This is the most recently published cert. Keep it. */
+ continue;
+ }
+ authority_cert_t *next_cert = smartlist_get(cl->certs, cert_sl_idx+1);
+ const time_t next_cert_published = next_cert->cache_info.published_on;
+ if (next_cert_published > now) {
+ /* All later certs are published in the future. Keep everything
+ * we didn't discard. */
+ break;
+ }
+ int should_remove = 0;
+ if (cert->expires + DEAD_CERT_LIFETIME < now) {
+ /* Certificate has been expired for at least DEAD_CERT_LIFETIME.
+ * Remove it. */
+ should_remove = 1;
+ } else if (next_cert_published + SUPERSEDED_CERT_LIFETIME < now) {
+ /* Certificate has been superseded for OLD_CERT_LIFETIME.
+ * Remove it.
*/
- if (expired ?
- (newest_published + DEAD_CERT_LIFETIME < now) :
- (cert_published + OLD_CERT_LIFETIME < newest_published)) {
- SMARTLIST_DEL_CURRENT(cl->certs, cert);
- authority_cert_free(cert);
- trusted_dir_servers_certs_changed = 1;
- }
- } SMARTLIST_FOREACH_END(cert);
- }
+ should_remove = 1;
+ }
+ if (should_remove) {
+ SMARTLIST_DEL_CURRENT_KEEPORDER(cl->certs, cert);
+ authority_cert_free(cert);
+ trusted_dir_servers_certs_changed = 1;
+ }
+ } SMARTLIST_FOREACH_END(cert);
+
} DIGESTMAP_FOREACH_END;
+#undef DEAD_CERT_LIFETIME
#undef OLD_CERT_LIFETIME
trusted_dirs_flush_certs_to_disk();
@@ -713,7 +737,8 @@ authority_certs_fetch_missing(networkstatus_t *status, time_t now)
* First, we get the lists of already pending downloads so we don't
* duplicate effort.
*/
- list_pending_downloads(pending_id, DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
+ list_pending_downloads(pending_id, NULL,
+ DIR_PURPOSE_FETCH_CERTIFICATE, "fp/");
list_pending_fpsk_downloads(pending_cert);
/*
@@ -1200,6 +1225,7 @@ router_reload_router_list_impl(desc_store_t *store)
tor_free(fname);
fname = get_datadir_fname_suffix(store->fname_base, ".new");
+ /* don't load empty files - we wouldn't get any data, even if we tried */
if (file_status(fname) == FN_FILE)
contents = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
if (contents) {
@@ -1281,22 +1307,32 @@ router_get_fallback_dir_servers(void)
const routerstatus_t *
router_pick_directory_server(dirinfo_type_t type, int flags)
{
+ int busy = 0;
const routerstatus_t *choice;
if (!routerlist)
return NULL;
- choice = router_pick_directory_server_impl(type, flags);
+ choice = router_pick_directory_server_impl(type, flags, &busy);
if (choice || !(flags & PDS_RETRY_IF_NO_SERVERS))
return choice;
+ if (busy) {
+ /* If the reason that we got no server is that servers are "busy",
+ * we must be excluding good servers because we already have serverdesc
+ * fetches with them. Do not mark down servers up because of this. */
+ tor_assert((flags & (PDS_NO_EXISTING_SERVERDESC_FETCH|
+ PDS_NO_EXISTING_MICRODESC_FETCH)));
+ return NULL;
+ }
+
log_info(LD_DIR,
"No reachable router entries for dirservers. "
"Trying them all again.");
/* mark all authdirservers as up again */
mark_all_dirservers_up(fallback_dir_servers);
/* try again */
- choice = router_pick_directory_server_impl(type, flags);
+ choice = router_pick_directory_server_impl(type, flags, NULL);
return choice;
}
@@ -1406,11 +1442,15 @@ router_pick_dirserver_generic(smartlist_t *sourcelist,
#define DIR_503_TIMEOUT (60*60)
/** Pick a random running valid directory server/mirror from our
- * routerlist. Arguments are as for router_pick_directory_server(), except
- * that RETRY_IF_NO_SERVERS is ignored.
+ * routerlist. Arguments are as for router_pick_directory_server(), except:
+ *
+ * If <b>n_busy_out</b> is provided, set *<b>n_busy_out</b> to the number of
+ * directories that we excluded for no other reason than
+ * PDS_NO_EXISTING_SERVERDESC_FETCH or PDS_NO_EXISTING_MICRODESC_FETCH.
*/
static const routerstatus_t *
-router_pick_directory_server_impl(dirinfo_type_t type, int flags)
+router_pick_directory_server_impl(dirinfo_type_t type, int flags,
+ int *n_busy_out)
{
const or_options_t *options = get_options();
const node_t *result;
@@ -1419,10 +1459,12 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
smartlist_t *overloaded_direct, *overloaded_tunnel;
time_t now = time(NULL);
const networkstatus_t *consensus = networkstatus_get_latest_consensus();
- int requireother = ! (flags & PDS_ALLOW_SELF);
- int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
- int for_guard = (flags & PDS_FOR_GUARD);
- int try_excluding = 1, n_excluded = 0;
+ const int requireother = ! (flags & PDS_ALLOW_SELF);
+ const int fascistfirewall = ! (flags & PDS_IGNORE_FASCISTFIREWALL);
+ const int no_serverdesc_fetching =(flags & PDS_NO_EXISTING_SERVERDESC_FETCH);
+ const int no_microdesc_fetching = (flags & PDS_NO_EXISTING_MICRODESC_FETCH);
+ const int for_guard = (flags & PDS_FOR_GUARD);
+ int try_excluding = 1, n_excluded = 0, n_busy = 0;
if (!consensus)
return NULL;
@@ -1438,7 +1480,7 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
/* Find all the running dirservers we know about. */
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
- int is_trusted;
+ int is_trusted, is_trusted_extrainfo;
int is_overloaded;
tor_addr_t addr;
const routerstatus_t *status = node->rs;
@@ -1448,13 +1490,13 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
if (!node->is_running || !status->dir_port || !node->is_valid)
continue;
- if (node->is_bad_directory)
- continue;
if (requireother && router_digest_is_me(node->identity))
continue;
is_trusted = router_digest_is_trusted_dir(node->identity);
+ is_trusted_extrainfo = router_digest_is_trusted_dir_type(
+ node->identity, EXTRAINFO_DIRINFO);
if ((type & EXTRAINFO_DIRINFO) &&
- !router_supports_extrainfo(node->identity, 0))
+ !router_supports_extrainfo(node->identity, is_trusted_extrainfo))
continue;
if ((type & MICRODESC_DIRINFO) && !is_trusted &&
!node->rs->version_supports_microdesc_cache)
@@ -1475,7 +1517,24 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
}
/* XXXX IP6 proposal 118 */
- tor_addr_from_ipv4h(&addr, node->rs->addr);
+ tor_addr_from_ipv4h(&addr, status->addr);
+
+ if (no_serverdesc_fetching && (
+ connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR, &addr, status->dir_port, DIR_PURPOSE_FETCH_SERVERDESC)
+ || connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR, &addr, status->dir_port, DIR_PURPOSE_FETCH_EXTRAINFO)
+ )) {
+ ++n_busy;
+ continue;
+ }
+
+ if (no_microdesc_fetching && connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR, &addr, status->dir_port, DIR_PURPOSE_FETCH_MICRODESC)
+ ) {
+ ++n_busy;
+ continue;
+ }
is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now;
@@ -1515,14 +1574,19 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags)
smartlist_free(overloaded_direct);
smartlist_free(overloaded_tunnel);
- if (result == NULL && try_excluding && !options->StrictNodes && n_excluded) {
+ if (result == NULL && try_excluding && !options->StrictNodes && n_excluded
+ && !n_busy) {
/* If we got no result, and we are excluding nodes, and StrictNodes is
* not set, try again without excluding nodes. */
try_excluding = 0;
n_excluded = 0;
+ n_busy = 0;
goto retry_without_exclude;
}
+ if (n_busy_out)
+ *n_busy_out = n_busy;
+
return result ? result->rs : NULL;
}
@@ -1536,7 +1600,7 @@ dirserver_choose_by_weight(const smartlist_t *servers, double authority_weight)
u64_dbl_t *weights;
const dir_server_t *ds;
- weights = tor_malloc(sizeof(u64_dbl_t) * n);
+ weights = tor_calloc(n, sizeof(u64_dbl_t));
for (i = 0; i < n; ++i) {
ds = smartlist_get(servers, i);
weights[i].dbl = ds->weight;
@@ -1736,7 +1800,7 @@ routerlist_add_node_and_family(smartlist_t *sl, const routerinfo_t *router)
/** Add every suitable node from our nodelist to <b>sl</b>, so that
* we can pick a node for a circuit.
*/
-static void
+void
router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid,
int need_uptime, int need_capacity,
int need_guard, int need_desc)
@@ -1808,15 +1872,16 @@ scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
uint64_t *total_out)
{
double total = 0.0;
- double scale_factor;
+ double scale_factor = 0.0;
int i;
/* big, but far away from overflowing an int64_t */
-#define SCALE_TO_U64_MAX (INT64_MAX / 4)
+#define SCALE_TO_U64_MAX ((int64_t) (INT64_MAX / 4))
for (i = 0; i < n_entries; ++i)
total += entries[i].dbl;
- scale_factor = SCALE_TO_U64_MAX / total;
+ if (total > 0.0)
+ scale_factor = SCALE_TO_U64_MAX / total;
for (i = 0; i < n_entries; ++i)
entries[i].u64 = tor_llround(entries[i].dbl * scale_factor);
@@ -1963,6 +2028,7 @@ compute_weighted_bandwidths(const smartlist_t *sl,
double Wg = -1, Wm = -1, We = -1, Wd = -1;
double Wgb = -1, Wmb = -1, Web = -1, Wdb = -1;
uint64_t weighted_bw = 0;
+ guardfraction_bandwidth_t guardfraction_bw;
u64_dbl_t *bandwidths;
/* Can't choose exit and guard at same time */
@@ -2029,9 +2095,10 @@ compute_weighted_bandwidths(const smartlist_t *sl,
if (Wg < 0 || Wm < 0 || We < 0 || Wd < 0 || Wgb < 0 || Wmb < 0 || Wdb < 0
|| Web < 0) {
log_debug(LD_CIRC,
- "Got negative bandwidth weights. Defaulting to old selection"
+ "Got negative bandwidth weights. Defaulting to naive selection"
" algorithm.");
- return -1; // Use old algorithm.
+ Wg = Wm = We = Wd = weight_scale;
+ Wgb = Wmb = Web = Wdb = weight_scale;
}
Wg /= weight_scale;
@@ -2044,26 +2111,32 @@ compute_weighted_bandwidths(const smartlist_t *sl,
Web /= weight_scale;
Wdb /= weight_scale;
- bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl));
+ bandwidths = tor_calloc(smartlist_len(sl), sizeof(u64_dbl_t));
// Cycle through smartlist and total the bandwidth.
+ static int warned_missing_bw = 0;
SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
int is_exit = 0, is_guard = 0, is_dir = 0, this_bw = 0;
double weight = 1;
+ double weight_without_guard_flag = 0; /* Used for guardfraction */
+ double final_weight = 0;
is_exit = node->is_exit && ! node->is_bad_exit;
is_guard = node->is_possible_guard;
is_dir = node_is_dir(node);
if (node->rs) {
if (!node->rs->has_bandwidth) {
- tor_free(bandwidths);
/* This should never happen, unless all the authorites downgrade
* to 0.2.0 or rogue routerstatuses get inserted into our consensus. */
- log_warn(LD_BUG,
- "Consensus is not listing bandwidths. Defaulting back to "
- "old router selection algorithm.");
- return -1;
+ if (! warned_missing_bw) {
+ log_warn(LD_BUG,
+ "Consensus is missing some bandwidths. Using a naive "
+ "router selection algorithm");
+ warned_missing_bw = 1;
+ }
+ this_bw = 30000; /* Chosen arbitrarily */
+ } else {
+ this_bw = kb_to_bytes(node->rs->bandwidth_kb);
}
- this_bw = kb_to_bytes(node->rs->bandwidth_kb);
} else if (node->ri) {
/* bridge or other descriptor not in our consensus */
this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
@@ -2074,8 +2147,10 @@ compute_weighted_bandwidths(const smartlist_t *sl,
if (is_guard && is_exit) {
weight = (is_dir ? Wdb*Wd : Wd);
+ weight_without_guard_flag = (is_dir ? Web*We : We);
} else if (is_guard) {
weight = (is_dir ? Wgb*Wg : Wg);
+ weight_without_guard_flag = (is_dir ? Wmb*Wm : Wm);
} else if (is_exit) {
weight = (is_dir ? Web*We : We);
} else { // middle
@@ -2087,8 +2162,43 @@ compute_weighted_bandwidths(const smartlist_t *sl,
this_bw = 0;
if (weight < 0.0)
weight = 0.0;
+ if (weight_without_guard_flag < 0.0)
+ weight_without_guard_flag = 0.0;
+
+ /* If guardfraction information is available in the consensus, we
+ * want to calculate this router's bandwidth according to its
+ * guardfraction. Quoting from proposal236:
+ *
+ * Let Wpf denote the weight from the 'bandwidth-weights' line a
+ * client would apply to N for position p if it had the guard
+ * flag, Wpn the weight if it did not have the guard flag, and B the
+ * measured bandwidth of N in the consensus. Then instead of choosing
+ * N for position p proportionally to Wpf*B or Wpn*B, clients should
+ * choose N proportionally to F*Wpf*B + (1-F)*Wpn*B.
+ */
+ if (node->rs && node->rs->has_guardfraction && rule != WEIGHT_FOR_GUARD) {
+ /* XXX The assert should actually check for is_guard. However,
+ * that crashes dirauths because of #13297. This should be
+ * equivalent: */
+ tor_assert(node->rs->is_possible_guard);
+
+ guard_get_guardfraction_bandwidth(&guardfraction_bw,
+ this_bw,
+ node->rs->guardfraction_percentage);
+
+ /* Calculate final_weight = F*Wpf*B + (1-F)*Wpn*B */
+ final_weight =
+ guardfraction_bw.guard_bw * weight +
+ guardfraction_bw.non_guard_bw * weight_without_guard_flag;
+
+ log_debug(LD_GENERAL, "%s: Guardfraction weight %f instead of %f (%s)",
+ node->rs->nickname, final_weight, weight*this_bw,
+ bandwidth_weight_rule_to_string(rule));
+ } else { /* no guardfraction information. calculate the weight normally. */
+ final_weight = weight*this_bw;
+ }
- bandwidths[node_sl_idx].dbl = weight*this_bw + 0.5;
+ bandwidths[node_sl_idx].dbl = final_weight + 0.5;
} SMARTLIST_FOREACH_END(node);
log_debug(LD_CIRC, "Generated weighted bandwidths for rule %s based "
@@ -2140,226 +2250,13 @@ frac_nodes_with_descriptors(const smartlist_t *sl,
return present / total;
}
-/** Helper function:
- * choose a random node_t element of smartlist <b>sl</b>, weighted by
- * the advertised bandwidth of each element.
- *
- * If <b>rule</b>==WEIGHT_FOR_EXIT. we're picking an exit node: consider all
- * nodes' bandwidth equally regardless of their Exit status, since there may
- * be some in the list because they exit to obscure ports. If
- * <b>rule</b>==NO_WEIGHTING, we're picking a non-exit node: weight
- * exit-node's bandwidth less depending on the smallness of the fraction of
- * Exit-to-total bandwidth. If <b>rule</b>==WEIGHT_FOR_GUARD, we're picking a
- * guard node: consider all guard's bandwidth equally. Otherwise, weight
- * guards proportionally less.
- */
-static const node_t *
-smartlist_choose_node_by_bandwidth(const smartlist_t *sl,
- bandwidth_weight_rule_t rule)
-{
- unsigned int i;
- u64_dbl_t *bandwidths;
- int is_exit;
- int is_guard;
- int is_fast;
- double total_nonexit_bw = 0, total_exit_bw = 0;
- double total_nonguard_bw = 0, total_guard_bw = 0;
- double exit_weight;
- double guard_weight;
- int n_unknown = 0;
- bitarray_t *fast_bits;
- bitarray_t *exit_bits;
- bitarray_t *guard_bits;
-
- // This function does not support WEIGHT_FOR_DIR
- // or WEIGHT_FOR_MID
- if (rule == WEIGHT_FOR_DIR || rule == WEIGHT_FOR_MID) {
- rule = NO_WEIGHTING;
- }
-
- /* Can't choose exit and guard at same time */
- tor_assert(rule == NO_WEIGHTING ||
- rule == WEIGHT_FOR_EXIT ||
- rule == WEIGHT_FOR_GUARD);
-
- if (smartlist_len(sl) == 0) {
- log_info(LD_CIRC,
- "Empty routerlist passed in to old node selection for rule %s",
- bandwidth_weight_rule_to_string(rule));
- return NULL;
- }
-
- /* First count the total bandwidth weight, and make a list
- * of each value. We use UINT64_MAX to indicate "unknown". */
- bandwidths = tor_malloc_zero(sizeof(u64_dbl_t)*smartlist_len(sl));
- fast_bits = bitarray_init_zero(smartlist_len(sl));
- exit_bits = bitarray_init_zero(smartlist_len(sl));
- guard_bits = bitarray_init_zero(smartlist_len(sl));
-
- /* Iterate over all the routerinfo_t or routerstatus_t, and */
- SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) {
- /* first, learn what bandwidth we think i has */
- int is_known = 1;
- uint32_t this_bw = 0;
- i = node_sl_idx;
-
- is_exit = node->is_exit;
- is_guard = node->is_possible_guard;
- if (node->rs) {
- if (node->rs->has_bandwidth) {
- this_bw = kb_to_bytes(node->rs->bandwidth_kb);
- } else { /* guess */
- is_known = 0;
- }
- } else if (node->ri) {
- /* Must be a bridge if we're willing to use it */
- this_bw = bridge_get_advertised_bandwidth_bounded(node->ri);
- }
-
- if (is_exit)
- bitarray_set(exit_bits, i);
- if (is_guard)
- bitarray_set(guard_bits, i);
- if (node->is_fast)
- bitarray_set(fast_bits, i);
-
- if (is_known) {
- bandwidths[i].dbl = this_bw;
- if (is_guard)
- total_guard_bw += this_bw;
- else
- total_nonguard_bw += this_bw;
- if (is_exit)
- total_exit_bw += this_bw;
- else
- total_nonexit_bw += this_bw;
- } else {
- ++n_unknown;
- bandwidths[i].dbl = -1.0;
- }
- } SMARTLIST_FOREACH_END(node);
-
-#define EPSILON .1
-
- /* Now, fill in the unknown values. */
- if (n_unknown) {
- int32_t avg_fast, avg_slow;
- if (total_exit_bw+total_nonexit_bw < EPSILON) {
- /* if there's some bandwidth, there's at least one known router,
- * so no worries about div by 0 here */
- int n_known = smartlist_len(sl)-n_unknown;
- avg_fast = avg_slow = (int32_t)
- ((total_exit_bw+total_nonexit_bw)/((uint64_t) n_known));
- } else {
- avg_fast = 40000;
- avg_slow = 20000;
- }
- for (i=0; i<(unsigned)smartlist_len(sl); ++i) {
- if (bandwidths[i].dbl >= 0.0)
- continue;
- is_fast = bitarray_is_set(fast_bits, i);
- is_exit = bitarray_is_set(exit_bits, i);
- is_guard = bitarray_is_set(guard_bits, i);
- bandwidths[i].dbl = is_fast ? avg_fast : avg_slow;
- if (is_exit)
- total_exit_bw += bandwidths[i].dbl;
- else
- total_nonexit_bw += bandwidths[i].dbl;
- if (is_guard)
- total_guard_bw += bandwidths[i].dbl;
- else
- total_nonguard_bw += bandwidths[i].dbl;
- }
- }
-
- /* If there's no bandwidth at all, pick at random. */
- if (total_exit_bw+total_nonexit_bw < EPSILON) {
- tor_free(bandwidths);
- tor_free(fast_bits);
- tor_free(exit_bits);
- tor_free(guard_bits);
- return smartlist_choose(sl);
- }
-
- /* Figure out how to weight exits and guards */
- {
- double all_bw = U64_TO_DBL(total_exit_bw+total_nonexit_bw);
- double exit_bw = U64_TO_DBL(total_exit_bw);
- double guard_bw = U64_TO_DBL(total_guard_bw);
- /*
- * For detailed derivation of this formula, see
- * http://archives.seul.org/or/dev/Jul-2007/msg00056.html
- */
- if (rule == WEIGHT_FOR_EXIT || total_exit_bw<EPSILON)
- exit_weight = 1.0;
- else
- exit_weight = 1.0 - all_bw/(3.0*exit_bw);
-
- if (rule == WEIGHT_FOR_GUARD || total_guard_bw<EPSILON)
- guard_weight = 1.0;
- else
- guard_weight = 1.0 - all_bw/(3.0*guard_bw);
-
- if (exit_weight <= 0.0)
- exit_weight = 0.0;
-
- if (guard_weight <= 0.0)
- guard_weight = 0.0;
-
- for (i=0; i < (unsigned)smartlist_len(sl); i++) {
- tor_assert(bandwidths[i].dbl >= 0.0);
-
- is_exit = bitarray_is_set(exit_bits, i);
- is_guard = bitarray_is_set(guard_bits, i);
- if (is_exit && is_guard)
- bandwidths[i].dbl *= exit_weight * guard_weight;
- else if (is_guard)
- bandwidths[i].dbl *= guard_weight;
- else if (is_exit)
- bandwidths[i].dbl *= exit_weight;
- }
- }
-
-#if 0
- log_debug(LD_CIRC, "Total weighted bw = "U64_FORMAT
- ", exit bw = "U64_FORMAT
- ", nonexit bw = "U64_FORMAT", exit weight = %f "
- "(for exit == %d)"
- ", guard bw = "U64_FORMAT
- ", nonguard bw = "U64_FORMAT", guard weight = %f "
- "(for guard == %d)",
- U64_PRINTF_ARG(total_bw),
- U64_PRINTF_ARG(total_exit_bw), U64_PRINTF_ARG(total_nonexit_bw),
- exit_weight, (int)(rule == WEIGHT_FOR_EXIT),
- U64_PRINTF_ARG(total_guard_bw), U64_PRINTF_ARG(total_nonguard_bw),
- guard_weight, (int)(rule == WEIGHT_FOR_GUARD));
-#endif
-
- scale_array_elements_to_u64(bandwidths, smartlist_len(sl), NULL);
-
- {
- int idx = choose_array_element_by_weight(bandwidths,
- smartlist_len(sl));
- tor_free(bandwidths);
- tor_free(fast_bits);
- tor_free(exit_bits);
- tor_free(guard_bits);
- return idx < 0 ? NULL : smartlist_get(sl, idx);
- }
-}
-
/** Choose a random element of status list <b>sl</b>, weighted by
* the advertised bandwidth of each node */
const node_t *
node_sl_choose_by_bandwidth(const smartlist_t *sl,
bandwidth_weight_rule_t rule)
{ /*XXXX MOVE */
- const node_t *ret;
- if ((ret = smartlist_choose_node_by_bandwidth_weights(sl, rule))) {
- return ret;
- } else {
- return smartlist_choose_node_by_bandwidth(sl, rule);
- }
+ return smartlist_choose_node_by_bandwidth_weights(sl, rule);
}
/** Return a random running node from the nodelist. Never
@@ -2417,11 +2314,29 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
router_add_running_nodes_to_smartlist(sl, allow_invalid,
need_uptime, need_capacity,
need_guard, need_desc);
+ log_debug(LD_CIRC,
+ "We found %d running nodes.",
+ smartlist_len(sl));
+
smartlist_subtract(sl,excludednodes);
- if (excludedsmartlist)
+ log_debug(LD_CIRC,
+ "We removed %d excludednodes, leaving %d nodes.",
+ smartlist_len(excludednodes),
+ smartlist_len(sl));
+
+ if (excludedsmartlist) {
smartlist_subtract(sl,excludedsmartlist);
- if (excludedset)
+ log_debug(LD_CIRC,
+ "We removed %d excludedsmartlist, leaving %d nodes.",
+ smartlist_len(excludedsmartlist),
+ smartlist_len(sl));
+ }
+ if (excludedset) {
routerset_subtract_nodes(sl,excludedset);
+ log_debug(LD_CIRC,
+ "We removed excludedset, leaving %d nodes.",
+ smartlist_len(sl));
+ }
// Always weight by bandwidth
choice = node_sl_choose_by_bandwidth(sl, rule);
@@ -2535,7 +2450,7 @@ router_is_named(const routerinfo_t *router)
/** Return true iff <b>digest</b> is the digest of the identity key of a
* trusted directory matching at least one bit of <b>type</b>. If <b>type</b>
- * is zero, any authority is okay. */
+ * is zero (NO_DIRINFO), or ALL_DIRINFO, any authority is okay. */
int
router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
{
@@ -2616,8 +2531,8 @@ router_get_by_descriptor_digest(const char *digest)
/** Return the signed descriptor for the router in our routerlist whose
* 20-byte extra-info digest is <b>digest</b>. Return NULL if no such router
* is known. */
-signed_descriptor_t *
-router_get_by_extrainfo_digest(const char *digest)
+MOCK_IMPL(signed_descriptor_t *,
+router_get_by_extrainfo_digest,(const char *digest))
{
tor_assert(digest);
@@ -2938,17 +2853,19 @@ routerlist_insert(routerlist_t *rl, routerinfo_t *ri)
}
/** Adds the extrainfo_t <b>ei</b> to the routerlist <b>rl</b>, if there is a
- * corresponding router in rl-\>routers or rl-\>old_routers. Return true iff
- * we actually inserted <b>ei</b>. Free <b>ei</b> if it isn't inserted. */
-static int
-extrainfo_insert(routerlist_t *rl, extrainfo_t *ei)
+ * corresponding router in rl-\>routers or rl-\>old_routers. Return the status
+ * of inserting <b>ei</b>. Free <b>ei</b> if it isn't inserted. */
+MOCK_IMPL(STATIC was_router_added_t,
+extrainfo_insert,(routerlist_t *rl, extrainfo_t *ei, int warn_if_incompatible))
{
- int r = 0;
+ was_router_added_t r;
+ const char *compatibility_error_msg;
routerinfo_t *ri = rimap_get(rl->identity_map,
ei->cache_info.identity_digest);
signed_descriptor_t *sd =
sdmap_get(rl->desc_by_eid_map, ei->cache_info.signed_descriptor_digest);
extrainfo_t *ei_tmp;
+ const int severity = warn_if_incompatible ? LOG_WARN : LOG_INFO;
{
extrainfo_t *ei_generated = router_get_my_extrainfo();
@@ -2957,9 +2874,41 @@ extrainfo_insert(routerlist_t *rl, extrainfo_t *ei)
if (!ri) {
/* This router is unknown; we can't even verify the signature. Give up.*/
+ r = ROUTER_NOT_IN_CONSENSUS;
+ goto done;
+ }
+ if (! sd) {
+ /* The extrainfo router doesn't have a known routerdesc to attach it to.
+ * This just won't work. */;
+ static ratelim_t no_sd_ratelim = RATELIM_INIT(1800);
+ r = ROUTER_BAD_EI;
+ log_fn_ratelim(&no_sd_ratelim, severity, LD_BUG,
+ "No entry found in extrainfo map.");
goto done;
}
- if (routerinfo_incompatible_with_extrainfo(ri, ei, sd, NULL)) {
+ if (tor_memneq(ei->cache_info.signed_descriptor_digest,
+ sd->extra_info_digest, DIGEST_LEN)) {
+ static ratelim_t digest_mismatch_ratelim = RATELIM_INIT(1800);
+ /* The sd we got from the map doesn't match the digest we used to look
+ * it up. This makes no sense. */
+ r = ROUTER_BAD_EI;
+ log_fn_ratelim(&digest_mismatch_ratelim, severity, LD_BUG,
+ "Mismatch in digest in extrainfo map.");
+ goto done;
+ }
+ if (routerinfo_incompatible_with_extrainfo(ri, ei, sd,
+ &compatibility_error_msg)) {
+ char d1[HEX_DIGEST_LEN+1], d2[HEX_DIGEST_LEN+1];
+ r = (ri->cache_info.extrainfo_is_bogus) ?
+ ROUTER_BAD_EI : ROUTER_NOT_IN_CONSENSUS;
+
+ base16_encode(d1, sizeof(d1), ri->cache_info.identity_digest, DIGEST_LEN);
+ base16_encode(d2, sizeof(d2), ei->cache_info.identity_digest, DIGEST_LEN);
+
+ log_fn(severity,LD_DIR,
+ "router info incompatible with extra info (ri id: %s, ei id %s, "
+ "reason: %s)", d1, d2, compatibility_error_msg);
+
goto done;
}
@@ -2969,7 +2918,7 @@ extrainfo_insert(routerlist_t *rl, extrainfo_t *ei)
ei_tmp = eimap_set(rl->extra_info_map,
ei->cache_info.signed_descriptor_digest,
ei);
- r = 1;
+ r = ROUTER_ADDED_SUCCESSFULLY;
if (ei_tmp) {
rl->extrainfo_store.bytes_dropped +=
ei_tmp->cache_info.signed_descriptor_len;
@@ -2977,7 +2926,7 @@ extrainfo_insert(routerlist_t *rl, extrainfo_t *ei)
}
done:
- if (r == 0)
+ if (r != ROUTER_ADDED_SUCCESSFULLY)
extrainfo_free(ei);
#ifdef DEBUG_ROUTERLIST
@@ -3252,7 +3201,7 @@ routerlist_reparse_old(routerlist_t *rl, signed_descriptor_t *sd)
ri = router_parse_entry_from_string(body,
body+sd->signed_descriptor_len+sd->annotations_len,
- 0, 1, NULL);
+ 0, 1, NULL, NULL);
if (!ri)
return NULL;
memcpy(&ri->cache_info, sd, sizeof(signed_descriptor_t));
@@ -3298,6 +3247,14 @@ routerlist_reset_warnings(void)
networkstatus_reset_warnings();
}
+/** Return 1 if the signed descriptor of this router is older than
+ * <b>seconds</b> seconds. Otherwise return 0. */
+MOCK_IMPL(int,
+router_descriptor_is_older_than,(const routerinfo_t *router, int seconds))
+{
+ return router->cache_info.published_on < approx_time() - seconds;
+}
+
/** Add <b>router</b> to the routerlist, if we don't already have it. Replace
* older entries (if any) with the same key. Note: Callers should not hold
* their pointers to <b>router</b> if this function fails; <b>router</b>
@@ -3364,7 +3321,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
router_describe(router));
*msg = "Router descriptor was not new.";
routerinfo_free(router);
- return ROUTER_WAS_NOT_NEW;
+ return ROUTER_IS_ALREADY_KNOWN;
}
}
@@ -3449,7 +3406,7 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
&routerlist->desc_store);
routerlist_insert_old(routerlist, router);
*msg = "Router descriptor was not new.";
- return ROUTER_WAS_NOT_NEW;
+ return ROUTER_IS_ALREADY_KNOWN;
} else {
/* Same key, and either new, or listed in the consensus. */
log_debug(LD_DIR, "Replacing entry for router %s",
@@ -3467,10 +3424,10 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
}
if (!in_consensus && from_cache &&
- router->cache_info.published_on < time(NULL) - OLD_ROUTER_DESC_MAX_AGE) {
+ router_descriptor_is_older_than(router, OLD_ROUTER_DESC_MAX_AGE)) {
*msg = "Router descriptor was really old.";
routerinfo_free(router);
- return ROUTER_WAS_NOT_NEW;
+ return ROUTER_WAS_TOO_OLD;
}
/* We haven't seen a router with this identity before. Add it to the end of
@@ -3491,21 +3448,18 @@ was_router_added_t
router_add_extrainfo_to_routerlist(extrainfo_t *ei, const char **msg,
int from_cache, int from_fetch)
{
- int inserted;
+ was_router_added_t inserted;
(void)from_fetch;
if (msg) *msg = NULL;
/*XXXX023 Do something with msg */
- inserted = extrainfo_insert(router_get_routerlist(), ei);
+ inserted = extrainfo_insert(router_get_routerlist(), ei, !from_cache);
- if (inserted && !from_cache)
+ if (WRA_WAS_ADDED(inserted) && !from_cache)
signed_desc_append_to_journal(&ei->cache_info,
&routerlist->extrainfo_store);
- if (inserted)
- return ROUTER_ADDED_SUCCESSFULLY;
- else
- return ROUTER_BAD_EI;
+ return inserted;
}
/** Sorting helper: return &lt;0, 0, or &gt;0 depending on whether the
@@ -3575,9 +3529,9 @@ routerlist_remove_old_cached_routers_with_id(time_t now,
n_extra = n - mdpr;
}
- lifespans = tor_malloc_zero(sizeof(struct duration_idx_t)*n);
- rmv = tor_malloc_zero(sizeof(uint8_t)*n);
- must_keep = tor_malloc_zero(sizeof(uint8_t)*n);
+ lifespans = tor_calloc(n, sizeof(struct duration_idx_t));
+ rmv = tor_calloc(n, sizeof(uint8_t));
+ must_keep = tor_calloc(n, sizeof(uint8_t));
/* Set lifespans to contain the lifespan and index of each server. */
/* Set rmv[i-lo]=1 if we're going to remove a server for being too old. */
for (i = lo; i <= hi; ++i) {
@@ -3800,7 +3754,8 @@ router_load_single_router(const char *s, uint8_t purpose, int cache,
"@source controller\n"
"@purpose %s\n", router_purpose_to_string(purpose));
- if (!(ri = router_parse_entry_from_string(s, NULL, 1, 0, annotation_buf))) {
+ if (!(ri = router_parse_entry_from_string(s, NULL, 1, 0,
+ annotation_buf, NULL))) {
log_warn(LD_DIR, "Error parsing router descriptor; dropping.");
*msg = "Couldn't parse router descriptor.";
return -1;
@@ -3864,9 +3819,11 @@ router_load_routers_from_string(const char *s, const char *eos,
int from_cache = (saved_location != SAVED_NOWHERE);
int allow_annotations = (saved_location != SAVED_NOWHERE);
int any_changed = 0;
+ smartlist_t *invalid_digests = smartlist_new();
router_parse_list_from_string(&s, eos, routers, saved_location, 0,
- allow_annotations, prepend_annotations);
+ allow_annotations, prepend_annotations,
+ invalid_digests);
routers_update_status_from_consensus_networkstatus(routers, !from_cache);
@@ -3902,7 +3859,7 @@ router_load_routers_from_string(const char *s, const char *eos,
smartlist_add(changed, ri);
routerlist_descriptors_added(changed, from_cache);
smartlist_clear(changed);
- } else if (WRA_WAS_REJECTED(r)) {
+ } else if (WRA_NEVER_DOWNLOADABLE(r)) {
download_status_t *dl_status;
dl_status = router_get_dl_status_by_descriptor_digest(d);
if (dl_status) {
@@ -3913,6 +3870,27 @@ router_load_routers_from_string(const char *s, const char *eos,
}
} SMARTLIST_FOREACH_END(ri);
+ SMARTLIST_FOREACH_BEGIN(invalid_digests, const uint8_t *, bad_digest) {
+ /* This digest is never going to be parseable. */
+ base16_encode(fp, sizeof(fp), (char*)bad_digest, DIGEST_LEN);
+ if (requested_fingerprints && descriptor_digests) {
+ if (! smartlist_contains_string(requested_fingerprints, fp)) {
+ /* But we didn't ask for it, so we should assume shennanegans. */
+ continue;
+ }
+ smartlist_string_remove(requested_fingerprints, fp);
+ }
+ download_status_t *dls;
+ dls = router_get_dl_status_by_descriptor_digest((char*)bad_digest);
+ if (dls) {
+ log_info(LD_GENERAL, "Marking router with descriptor %s as unparseable, "
+ "and therefore undownloadable", fp);
+ download_status_mark_impossible(dls);
+ }
+ } SMARTLIST_FOREACH_END(bad_digest);
+ SMARTLIST_FOREACH(invalid_digests, uint8_t *, d, tor_free(d));
+ smartlist_free(invalid_digests);
+
routerlist_assert_ok(routerlist);
if (any_changed)
@@ -3936,13 +3914,16 @@ router_load_extrainfo_from_string(const char *s, const char *eos,
smartlist_t *extrainfo_list = smartlist_new();
const char *msg;
int from_cache = (saved_location != SAVED_NOWHERE);
+ smartlist_t *invalid_digests = smartlist_new();
router_parse_list_from_string(&s, eos, extrainfo_list, saved_location, 1, 0,
- NULL);
+ NULL, invalid_digests);
log_info(LD_DIR, "%d elements to add", smartlist_len(extrainfo_list));
SMARTLIST_FOREACH_BEGIN(extrainfo_list, extrainfo_t *, ei) {
+ uint8_t d[DIGEST_LEN];
+ memcpy(d, ei->cache_info.signed_descriptor_digest, DIGEST_LEN);
was_router_added_t added =
router_add_extrainfo_to_routerlist(ei, &msg, from_cache, !from_cache);
if (WRA_WAS_ADDED(added) && requested_fingerprints) {
@@ -3956,9 +3937,39 @@ router_load_extrainfo_from_string(const char *s, const char *eos,
* so long as we would have wanted them anyway. Since we always fetch
* all the extrainfos we want, and we never actually act on them
* inside Tor, this should be harmless. */
+ } else if (WRA_NEVER_DOWNLOADABLE(added)) {
+ signed_descriptor_t *sd = router_get_by_extrainfo_digest((char*)d);
+ if (sd) {
+ log_info(LD_GENERAL, "Marking extrainfo with descriptor %s as "
+ "unparseable, and therefore undownloadable",
+ hex_str((char*)d,DIGEST_LEN));
+ download_status_mark_impossible(&sd->ei_dl_status);
+ }
}
} SMARTLIST_FOREACH_END(ei);
+ SMARTLIST_FOREACH_BEGIN(invalid_digests, const uint8_t *, bad_digest) {
+ /* This digest is never going to be parseable. */
+ char fp[HEX_DIGEST_LEN+1];
+ base16_encode(fp, sizeof(fp), (char*)bad_digest, DIGEST_LEN);
+ if (requested_fingerprints) {
+ if (! smartlist_contains_string(requested_fingerprints, fp)) {
+ /* But we didn't ask for it, so we should assume shennanegans. */
+ continue;
+ }
+ smartlist_string_remove(requested_fingerprints, fp);
+ }
+ signed_descriptor_t *sd =
+ router_get_by_extrainfo_digest((char*)bad_digest);
+ if (sd) {
+ log_info(LD_GENERAL, "Marking extrainfo with descriptor %s as "
+ "unparseable, and therefore undownloadable", fp);
+ download_status_mark_impossible(&sd->ei_dl_status);
+ }
+ } SMARTLIST_FOREACH_END(bad_digest);
+ SMARTLIST_FOREACH(invalid_digests, uint8_t *, d, tor_free(d));
+ smartlist_free(invalid_digests);
+
routerlist_assert_ok(routerlist);
router_rebuild_store(0, &router_get_routerlist()->extrainfo_store);
@@ -4204,7 +4215,7 @@ clear_dir_servers(void)
* corresponding elements of <b>result</b> to a nonzero value.
*/
static void
-list_pending_downloads(digestmap_t *result,
+list_pending_downloads(digestmap_t *result, digest256map_t *result256,
int purpose, const char *prefix)
{
const size_t p_len = strlen(prefix);
@@ -4214,7 +4225,7 @@ list_pending_downloads(digestmap_t *result,
if (purpose == DIR_PURPOSE_FETCH_MICRODESC)
flags = DSR_DIGEST256|DSR_BASE64;
- tor_assert(result);
+ tor_assert(result || result256);
SMARTLIST_FOREACH_BEGIN(conns, connection_t *, conn) {
if (conn->type == CONN_TYPE_DIR &&
@@ -4227,11 +4238,19 @@ list_pending_downloads(digestmap_t *result,
}
} SMARTLIST_FOREACH_END(conn);
- SMARTLIST_FOREACH(tmp, char *, d,
+ if (result) {
+ SMARTLIST_FOREACH(tmp, char *, d,
{
digestmap_set(result, d, (void*)1);
tor_free(d);
});
+ } else if (result256) {
+ SMARTLIST_FOREACH(tmp, uint8_t *, d,
+ {
+ digest256map_set(result256, d, (void*)1);
+ tor_free(d);
+ });
+ }
smartlist_free(tmp);
}
@@ -4243,20 +4262,16 @@ list_pending_descriptor_downloads(digestmap_t *result, int extrainfo)
{
int purpose =
extrainfo ? DIR_PURPOSE_FETCH_EXTRAINFO : DIR_PURPOSE_FETCH_SERVERDESC;
- list_pending_downloads(result, purpose, "d/");
+ list_pending_downloads(result, NULL, purpose, "d/");
}
/** For every microdescriptor we are currently downloading by descriptor
- * digest, set result[d] to (void*)1. (Note that microdescriptor digests
- * are 256-bit, and digestmap_t only holds 160-bit digests, so we're only
- * getting the first 20 bytes of each digest here.)
- *
- * XXXX Let there be a digestmap256_t, and use that instead.
+ * digest, set result[d] to (void*)1.
*/
void
-list_pending_microdesc_downloads(digestmap_t *result)
+list_pending_microdesc_downloads(digest256map_t *result)
{
- list_pending_downloads(result, DIR_PURPOSE_FETCH_MICRODESC, "d/");
+ list_pending_downloads(NULL, result, DIR_PURPOSE_FETCH_MICRODESC, "d/");
}
/** For every certificate we are currently downloading by (identity digest,
@@ -4299,51 +4314,57 @@ list_pending_fpsk_downloads(fp_pair_map_t *result)
* range.) If <b>source</b> is given, download from <b>source</b>;
* otherwise, download from an appropriate random directory server.
*/
-static void
-initiate_descriptor_downloads(const routerstatus_t *source,
- int purpose,
- smartlist_t *digests,
- int lo, int hi, int pds_flags)
+MOCK_IMPL(STATIC void, initiate_descriptor_downloads,
+ (const routerstatus_t *source, int purpose, smartlist_t *digests,
+ int lo, int hi, int pds_flags))
{
- int i, n = hi-lo;
char *resource, *cp;
- size_t r_len;
-
- int digest_len = DIGEST_LEN, enc_digest_len = HEX_DIGEST_LEN;
- char sep = '+';
- int b64_256 = 0;
+ int digest_len, enc_digest_len;
+ const char *sep;
+ int b64_256;
+ smartlist_t *tmp;
if (purpose == DIR_PURPOSE_FETCH_MICRODESC) {
/* Microdescriptors are downloaded by "-"-separated base64-encoded
* 256-bit digests. */
digest_len = DIGEST256_LEN;
- enc_digest_len = BASE64_DIGEST256_LEN;
- sep = '-';
+ enc_digest_len = BASE64_DIGEST256_LEN + 1;
+ sep = "-";
b64_256 = 1;
+ } else {
+ digest_len = DIGEST_LEN;
+ enc_digest_len = HEX_DIGEST_LEN + 1;
+ sep = "+";
+ b64_256 = 0;
}
- if (n <= 0)
- return;
if (lo < 0)
lo = 0;
if (hi > smartlist_len(digests))
hi = smartlist_len(digests);
- r_len = 8 + (enc_digest_len+1)*n;
- cp = resource = tor_malloc(r_len);
- memcpy(cp, "d/", 2);
- cp += 2;
- for (i = lo; i < hi; ++i) {
+ if (hi-lo <= 0)
+ return;
+
+ tmp = smartlist_new();
+
+ for (; lo < hi; ++lo) {
+ cp = tor_malloc(enc_digest_len);
if (b64_256) {
- digest256_to_base64(cp, smartlist_get(digests, i));
+ digest256_to_base64(cp, smartlist_get(digests, lo));
} else {
- base16_encode(cp, r_len-(cp-resource),
- smartlist_get(digests,i), digest_len);
+ base16_encode(cp, enc_digest_len, smartlist_get(digests, lo),
+ digest_len);
}
- cp += enc_digest_len;
- *cp++ = sep;
+ smartlist_add(tmp, cp);
}
- memcpy(cp-1, ".z", 3);
+
+ cp = smartlist_join_strings(tmp, sep, 0, NULL);
+ tor_asprintf(&resource, "d/%s.z", cp);
+
+ SMARTLIST_FOREACH(tmp, char *, cp1, tor_free(cp1));
+ smartlist_free(tmp);
+ tor_free(cp);
if (source) {
/* We know which authority we want. */
@@ -4358,14 +4379,28 @@ initiate_descriptor_downloads(const routerstatus_t *source,
tor_free(resource);
}
-/** Max amount of hashes to download per request.
- * Since squid does not like URLs >= 4096 bytes we limit it to 96.
- * 4096 - strlen(http://255.255.255.255/tor/server/d/.z) == 4058
- * 4058/41 (40 for the hash and 1 for the + that separates them) => 98
- * So use 96 because it's a nice number.
+/** Return the max number of hashes to put in a URL for a given request.
*/
-#define MAX_DL_PER_REQUEST 96
-#define MAX_MICRODESC_DL_PER_REQUEST 92
+static int
+max_dl_per_request(const or_options_t *options, int purpose)
+{
+ /* Since squid does not like URLs >= 4096 bytes we limit it to 96.
+ * 4096 - strlen(http://255.255.255.255/tor/server/d/.z) == 4058
+ * 4058/41 (40 for the hash and 1 for the + that separates them) => 98
+ * So use 96 because it's a nice number.
+ */
+ int max = 96;
+ if (purpose == DIR_PURPOSE_FETCH_MICRODESC) {
+ max = 92;
+ }
+ /* If we're going to tunnel our connections, we can ask for a lot more
+ * in a request. */
+ if (!directory_fetches_from_authorities(options)) {
+ max = 500;
+ }
+ return max;
+}
+
/** Don't split our requests so finely that we are requesting fewer than
* this number per server. */
#define MIN_DL_PER_REQUEST 4
@@ -4387,92 +4422,89 @@ launch_descriptor_downloads(int purpose,
smartlist_t *downloadable,
const routerstatus_t *source, time_t now)
{
- int should_delay = 0, n_downloadable;
const or_options_t *options = get_options();
const char *descname;
+ const int fetch_microdesc = (purpose == DIR_PURPOSE_FETCH_MICRODESC);
+ int n_downloadable = smartlist_len(downloadable);
+
+ int i, n_per_request, max_dl_per_req;
+ const char *req_plural = "", *rtr_plural = "";
+ int pds_flags = PDS_RETRY_IF_NO_SERVERS;
- tor_assert(purpose == DIR_PURPOSE_FETCH_SERVERDESC ||
- purpose == DIR_PURPOSE_FETCH_MICRODESC);
+ tor_assert(fetch_microdesc || purpose == DIR_PURPOSE_FETCH_SERVERDESC);
+ descname = fetch_microdesc ? "microdesc" : "routerdesc";
- descname = (purpose == DIR_PURPOSE_FETCH_SERVERDESC) ?
- "routerdesc" : "microdesc";
+ if (!n_downloadable)
+ return;
- n_downloadable = smartlist_len(downloadable);
if (!directory_fetches_dir_info_early(options)) {
if (n_downloadable >= MAX_DL_TO_DELAY) {
log_debug(LD_DIR,
"There are enough downloadable %ss to launch requests.",
descname);
- should_delay = 0;
} else {
- should_delay = (last_descriptor_download_attempted +
- options->TestingClientMaxIntervalWithoutRequest) > now;
- if (!should_delay && n_downloadable) {
- if (last_descriptor_download_attempted) {
- log_info(LD_DIR,
- "There are not many downloadable %ss, but we've "
- "been waiting long enough (%d seconds). Downloading.",
- descname,
- (int)(now-last_descriptor_download_attempted));
- } else {
- log_info(LD_DIR,
- "There are not many downloadable %ss, but we haven't "
- "tried downloading descriptors recently. Downloading.",
- descname);
- }
+
+ /* should delay */
+ if ((last_descriptor_download_attempted +
+ options->TestingClientMaxIntervalWithoutRequest) > now)
+ return;
+
+ if (last_descriptor_download_attempted) {
+ log_info(LD_DIR,
+ "There are not many downloadable %ss, but we've "
+ "been waiting long enough (%d seconds). Downloading.",
+ descname,
+ (int)(now-last_descriptor_download_attempted));
+ } else {
+ log_info(LD_DIR,
+ "There are not many downloadable %ss, but we haven't "
+ "tried downloading descriptors recently. Downloading.",
+ descname);
}
}
}
- if (! should_delay && n_downloadable) {
- int i, n_per_request;
- const char *req_plural = "", *rtr_plural = "";
- int pds_flags = PDS_RETRY_IF_NO_SERVERS;
- if (! authdir_mode_any_nonhidserv(options)) {
- /* If we wind up going to the authorities, we want to only open one
- * connection to each authority at a time, so that we don't overload
- * them. We do this by setting PDS_NO_EXISTING_SERVERDESC_FETCH
- * regardless of whether we're a cache or not; it gets ignored if we're
- * not calling router_pick_trusteddirserver.
- *
- * Setting this flag can make initiate_descriptor_downloads() ignore
- * requests. We need to make sure that we do in fact call
- * update_router_descriptor_downloads() later on, once the connections
- * have succeeded or failed.
- */
- pds_flags |= (purpose == DIR_PURPOSE_FETCH_MICRODESC) ?
- PDS_NO_EXISTING_MICRODESC_FETCH :
- PDS_NO_EXISTING_SERVERDESC_FETCH;
- }
+ if (!authdir_mode_any_nonhidserv(options)) {
+ /* If we wind up going to the authorities, we want to only open one
+ * connection to each authority at a time, so that we don't overload
+ * them. We do this by setting PDS_NO_EXISTING_SERVERDESC_FETCH
+ * regardless of whether we're a cache or not.
+ *
+ * Setting this flag can make initiate_descriptor_downloads() ignore
+ * requests. We need to make sure that we do in fact call
+ * update_router_descriptor_downloads() later on, once the connections
+ * have succeeded or failed.
+ */
+ pds_flags |= fetch_microdesc ?
+ PDS_NO_EXISTING_MICRODESC_FETCH :
+ PDS_NO_EXISTING_SERVERDESC_FETCH;
+ }
- n_per_request = CEIL_DIV(n_downloadable, MIN_REQUESTS);
- if (purpose == DIR_PURPOSE_FETCH_MICRODESC) {
- if (n_per_request > MAX_MICRODESC_DL_PER_REQUEST)
- n_per_request = MAX_MICRODESC_DL_PER_REQUEST;
- } else {
- if (n_per_request > MAX_DL_PER_REQUEST)
- n_per_request = MAX_DL_PER_REQUEST;
- }
- if (n_per_request < MIN_DL_PER_REQUEST)
- n_per_request = MIN_DL_PER_REQUEST;
-
- if (n_downloadable > n_per_request)
- req_plural = rtr_plural = "s";
- else if (n_downloadable > 1)
- rtr_plural = "s";
-
- log_info(LD_DIR,
- "Launching %d request%s for %d %s%s, %d at a time",
- CEIL_DIV(n_downloadable, n_per_request), req_plural,
- n_downloadable, descname, rtr_plural, n_per_request);
- smartlist_sort_digests(downloadable);
- for (i=0; i < n_downloadable; i += n_per_request) {
- initiate_descriptor_downloads(source, purpose,
- downloadable, i, i+n_per_request,
- pds_flags);
- }
- last_descriptor_download_attempted = now;
+ n_per_request = CEIL_DIV(n_downloadable, MIN_REQUESTS);
+ max_dl_per_req = max_dl_per_request(options, purpose);
+
+ if (n_per_request > max_dl_per_req)
+ n_per_request = max_dl_per_req;
+
+ if (n_per_request < MIN_DL_PER_REQUEST)
+ n_per_request = MIN_DL_PER_REQUEST;
+
+ if (n_downloadable > n_per_request)
+ req_plural = rtr_plural = "s";
+ else if (n_downloadable > 1)
+ rtr_plural = "s";
+
+ log_info(LD_DIR,
+ "Launching %d request%s for %d %s%s, %d at a time",
+ CEIL_DIV(n_downloadable, n_per_request), req_plural,
+ n_downloadable, descname, rtr_plural, n_per_request);
+ smartlist_sort_digests(downloadable);
+ for (i=0; i < n_downloadable; i += n_per_request) {
+ initiate_descriptor_downloads(source, purpose,
+ downloadable, i, i+n_per_request,
+ pds_flags);
}
+ last_descriptor_download_attempted = now;
}
/** For any descriptor that we want that's currently listed in
@@ -4652,8 +4684,8 @@ update_extrainfo_downloads(time_t now)
routerlist_t *rl;
smartlist_t *wanted;
digestmap_t *pending;
- int old_routers, i;
- int n_no_ei = 0, n_pending = 0, n_have = 0, n_delay = 0;
+ int old_routers, i, max_dl_per_req;
+ int n_no_ei = 0, n_pending = 0, n_have = 0, n_delay = 0, n_bogus[2] = {0,0};
if (! options->DownloadExtraInfo)
return;
if (should_delay_dir_fetches(options, NULL))
@@ -4698,19 +4730,54 @@ update_extrainfo_downloads(time_t now)
++n_pending;
continue;
}
+
+ const signed_descriptor_t *sd2 = router_get_by_extrainfo_digest(d);
+ if (sd2 != sd) {
+ if (sd2 != NULL) {
+ char d1[HEX_DIGEST_LEN+1], d2[HEX_DIGEST_LEN+1];
+ char d3[HEX_DIGEST_LEN+1], d4[HEX_DIGEST_LEN+1];
+ base16_encode(d1, sizeof(d1), sd->identity_digest, DIGEST_LEN);
+ base16_encode(d2, sizeof(d2), sd2->identity_digest, DIGEST_LEN);
+ base16_encode(d3, sizeof(d3), d, DIGEST_LEN);
+ base16_encode(d4, sizeof(d3), sd2->extra_info_digest, DIGEST_LEN);
+
+ log_info(LD_DIR, "Found an entry in %s with mismatched "
+ "router_get_by_extrainfo_digest() value. This has ID %s "
+ "but the entry in the map has ID %s. This has EI digest "
+ "%s and the entry in the map has EI digest %s.",
+ old_routers?"old_routers":"routers",
+ d1, d2, d3, d4);
+ } else {
+ char d1[HEX_DIGEST_LEN+1], d2[HEX_DIGEST_LEN+1];
+ base16_encode(d1, sizeof(d1), sd->identity_digest, DIGEST_LEN);
+ base16_encode(d2, sizeof(d2), d, DIGEST_LEN);
+
+ log_info(LD_DIR, "Found an entry in %s with NULL "
+ "router_get_by_extrainfo_digest() value. This has ID %s "
+ "and EI digest %s.",
+ old_routers?"old_routers":"routers",
+ d1, d2);
+ }
+ ++n_bogus[old_routers];
+ continue;
+ }
smartlist_add(wanted, d);
}
}
digestmap_free(pending, NULL);
log_info(LD_DIR, "Extrainfo download status: %d router with no ei, %d "
- "with present ei, %d delaying, %d pending, %d downloadable.",
- n_no_ei, n_have, n_delay, n_pending, smartlist_len(wanted));
+ "with present ei, %d delaying, %d pending, %d downloadable, %d "
+ "bogus in routers, %d bogus in old_routers",
+ n_no_ei, n_have, n_delay, n_pending, smartlist_len(wanted),
+ n_bogus[0], n_bogus[1]);
smartlist_shuffle(wanted);
- for (i = 0; i < smartlist_len(wanted); i += MAX_DL_PER_REQUEST) {
+
+ max_dl_per_req = max_dl_per_request(options, DIR_PURPOSE_FETCH_EXTRAINFO);
+ for (i = 0; i < smartlist_len(wanted); i += max_dl_per_req) {
initiate_descriptor_downloads(NULL, DIR_PURPOSE_FETCH_EXTRAINFO,
- wanted, i, i + MAX_DL_PER_REQUEST,
+ wanted, i, i+max_dl_per_req,
PDS_RETRY_IF_NO_SERVERS|PDS_NO_EXISTING_SERVERDESC_FETCH);
}
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index 6e2f2eaea0..78c3fbb880 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -58,6 +58,10 @@ const routerstatus_t *router_pick_fallback_dirserver(dirinfo_type_t type,
int router_get_my_share_of_directory_requests(double *v3_share_out);
void router_reset_status_download_failures(void);
int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
+void router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid,
+ int need_uptime, int need_capacity,
+ int need_guard, int need_desc);
+
const routerinfo_t *routerlist_find_my_routerinfo(void);
uint32_t router_get_advertised_bandwidth(const routerinfo_t *router);
uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router);
@@ -82,7 +86,8 @@ int hexdigest_to_digest(const char *hexdigest, char *digest);
const routerinfo_t *router_get_by_id_digest(const char *digest);
routerinfo_t *router_get_mutable_by_digest(const char *digest);
signed_descriptor_t *router_get_by_descriptor_digest(const char *digest);
-signed_descriptor_t *router_get_by_extrainfo_digest(const char *digest);
+MOCK_DECL(signed_descriptor_t *,router_get_by_extrainfo_digest,
+ (const char *digest));
signed_descriptor_t *extrainfo_get_by_descriptor_digest(const char *digest);
const char *signed_descriptor_get_body(const signed_descriptor_t *desc);
const char *signed_descriptor_get_annotations(const signed_descriptor_t *desc);
@@ -99,6 +104,7 @@ void routerlist_reset_warnings(void);
static int WRA_WAS_ADDED(was_router_added_t s);
static int WRA_WAS_OUTDATED(was_router_added_t s);
static int WRA_WAS_REJECTED(was_router_added_t s);
+static int WRA_NEVER_DOWNLOADABLE(was_router_added_t s);
/** Return true iff the outcome code in <b>s</b> indicates that the descriptor
* was added. It might still be necessary to check whether the descriptor
* generator should be notified.
@@ -115,7 +121,8 @@ WRA_WAS_ADDED(was_router_added_t s) {
*/
static INLINE int WRA_WAS_OUTDATED(was_router_added_t s)
{
- return (s == ROUTER_WAS_NOT_NEW ||
+ return (s == ROUTER_WAS_TOO_OLD ||
+ s == ROUTER_IS_ALREADY_KNOWN ||
s == ROUTER_NOT_IN_CONSENSUS ||
s == ROUTER_NOT_IN_CONSENSUS_OR_NETWORKSTATUS);
}
@@ -125,6 +132,14 @@ static INLINE int WRA_WAS_REJECTED(was_router_added_t s)
{
return (s == ROUTER_AUTHDIR_REJECTS);
}
+/** Return true iff the outcome code in <b>s</b> indicates that the descriptor
+ * was flat-out rejected. */
+static INLINE int WRA_NEVER_DOWNLOADABLE(was_router_added_t s)
+{
+ return (s == ROUTER_AUTHDIR_REJECTS ||
+ s == ROUTER_BAD_EI ||
+ s == ROUTER_WAS_TOO_OLD);
+}
was_router_added_t router_add_to_routerlist(routerinfo_t *router,
const char **msg,
int from_cache,
@@ -185,7 +200,7 @@ int hid_serv_get_responsible_directories(smartlist_t *responsible_dirs,
int hid_serv_acting_as_directory(void);
int hid_serv_responsible_for_desc_id(const char *id);
-void list_pending_microdesc_downloads(digestmap_t *result);
+void list_pending_microdesc_downloads(digest256map_t *result);
void launch_descriptor_downloads(int purpose,
smartlist_t *downloadable,
const routerstatus_t *source,
@@ -212,6 +227,16 @@ STATIC int choose_array_element_by_weight(const u64_dbl_t *entries,
int n_entries);
STATIC void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
uint64_t *total_out);
+
+MOCK_DECL(int, router_descriptor_is_older_than, (const routerinfo_t *router,
+ int seconds));
+MOCK_DECL(STATIC was_router_added_t, extrainfo_insert,
+ (routerlist_t *rl, extrainfo_t *ei, int warn_if_incompatible));
+
+MOCK_DECL(STATIC void, initiate_descriptor_downloads,
+ (const routerstatus_t *source, int purpose, smartlist_t *digests,
+ int lo, int hi, int pds_flags));
+
#endif
#endif
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 524a575480..2d181e123f 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -1,7 +1,7 @@
-/* Copyright (c) 2001 Matej Pfajfar.
+ /* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -9,6 +9,8 @@
* \brief Code to parse and validate router descriptors and directories.
**/
+#define ROUTERPARSE_PRIVATE
+
#include "or.h"
#include "config.h"
#include "circuitstats.h"
@@ -23,6 +25,7 @@
#include "networkstatus.h"
#include "rephist.h"
#include "routerparse.h"
+#include "entrynodes.h"
#undef log
#include <math.h>
@@ -131,6 +134,7 @@ typedef enum {
K_CONSENSUS_METHOD,
K_LEGACY_DIR_KEY,
K_DIRECTORY_FOOTER,
+ K_PACKAGE,
A_PURPOSE,
A_LAST_LISTED,
@@ -420,6 +424,7 @@ static token_rule_t networkstatus_token_table[] = {
T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ),
T01("params", K_PARAMS, ARGS, NO_OBJ ),
T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
+ T0N("package", K_PACKAGE, CONCAT_ARGS, NO_OBJ ),
CERTIFICATE_MEMBERS
@@ -911,7 +916,9 @@ find_start_of_next_router_or_extrainfo(const char **s_ptr,
* descriptor in the signed_descriptor_body field of each routerinfo_t. If it
* isn't SAVED_NOWHERE, remember the offset of each descriptor.
*
- * Returns 0 on success and -1 on failure.
+ * Returns 0 on success and -1 on failure. Adds a digest to
+ * <b>invalid_digests_out</b> for every entry that was unparseable or
+ * invalid. (This may cause duplicate entries.)
*/
int
router_parse_list_from_string(const char **s, const char *eos,
@@ -919,7 +926,8 @@ router_parse_list_from_string(const char **s, const char *eos,
saved_location_t saved_location,
int want_extrainfo,
int allow_annotations,
- const char *prepend_annotations)
+ const char *prepend_annotations,
+ smartlist_t *invalid_digests_out)
{
routerinfo_t *router;
extrainfo_t *extrainfo;
@@ -939,6 +947,9 @@ router_parse_list_from_string(const char **s, const char *eos,
tor_assert(eos >= *s);
while (1) {
+ char raw_digest[DIGEST_LEN];
+ int have_raw_digest = 0;
+ int dl_again = 0;
if (find_start_of_next_router_or_extrainfo(s, eos, &have_extrainfo) < 0)
break;
@@ -955,18 +966,20 @@ router_parse_list_from_string(const char **s, const char *eos,
if (have_extrainfo && want_extrainfo) {
routerlist_t *rl = router_get_routerlist();
+ have_raw_digest = router_get_extrainfo_hash(*s, end-*s, raw_digest) == 0;
extrainfo = extrainfo_parse_entry_from_string(*s, end,
saved_location != SAVED_IN_CACHE,
- rl->identity_map);
+ rl->identity_map, &dl_again);
if (extrainfo) {
signed_desc = &extrainfo->cache_info;
elt = extrainfo;
}
} else if (!have_extrainfo && !want_extrainfo) {
+ have_raw_digest = router_get_router_hash(*s, end-*s, raw_digest) == 0;
router = router_parse_entry_from_string(*s, end,
saved_location != SAVED_IN_CACHE,
allow_annotations,
- prepend_annotations);
+ prepend_annotations, &dl_again);
if (router) {
log_debug(LD_DIR, "Read router '%s', purpose '%s'",
router_describe(router),
@@ -975,6 +988,9 @@ router_parse_list_from_string(const char **s, const char *eos,
elt = router;
}
}
+ if (! elt && ! dl_again && have_raw_digest && invalid_digests_out) {
+ smartlist_add(invalid_digests_out, tor_memdup(raw_digest, DIGEST_LEN));
+ }
if (!elt) {
*s = end;
continue;
@@ -1068,11 +1084,17 @@ find_single_ipv6_orport(const smartlist_t *list,
* around when caching the router.
*
* Only one of allow_annotations and prepend_annotations may be set.
+ *
+ * If <b>can_dl_again_out</b> is provided, set *<b>can_dl_again_out</b> to 1
+ * if it's okay to try to download a descriptor with this same digest again,
+ * and 0 if it isn't. (It might not be okay to download it again if part of
+ * the part covered by the digest is invalid.)
*/
routerinfo_t *
router_parse_entry_from_string(const char *s, const char *end,
int cache_copy, int allow_annotations,
- const char *prepend_annotations)
+ const char *prepend_annotations,
+ int *can_dl_again_out)
{
routerinfo_t *router = NULL;
char digest[128];
@@ -1083,6 +1105,9 @@ router_parse_entry_from_string(const char *s, const char *end,
size_t prepend_len = prepend_annotations ? strlen(prepend_annotations) : 0;
int ok = 1;
memarea_t *area = NULL;
+ /* Do not set this to '1' until we have parsed everything that we intend to
+ * parse that's covered by the hash. */
+ int can_dl_again = 0;
tor_assert(!allow_annotations || !prepend_annotations);
@@ -1389,19 +1414,21 @@ router_parse_entry_from_string(const char *s, const char *end,
verified_digests = digestmap_new();
digestmap_set(verified_digests, signed_digest, (void*)(uintptr_t)1);
#endif
- if (check_signature_token(digest, DIGEST_LEN, tok, router->identity_pkey, 0,
- "router descriptor") < 0)
- goto err;
if (!router->or_port) {
log_warn(LD_DIR,"or_port unreadable or 0. Failing.");
goto err;
}
+ /* We've checked everything that's covered by the hash. */
+ can_dl_again = 1;
+ if (check_signature_token(digest, DIGEST_LEN, tok, router->identity_pkey, 0,
+ "router descriptor") < 0)
+ goto err;
+
if (!router->platform) {
router->platform = tor_strdup("<unknown>");
}
-
goto done;
err:
@@ -1418,6 +1445,8 @@ router_parse_entry_from_string(const char *s, const char *end,
DUMP_AREA(area, "routerinfo");
memarea_drop_all(area);
}
+ if (can_dl_again_out)
+ *can_dl_again_out = can_dl_again;
return router;
}
@@ -1426,10 +1455,16 @@ router_parse_entry_from_string(const char *s, const char *end,
* <b>cache_copy</b> is true, make a copy of the extra-info document in the
* cache_info fields of the result. If <b>routermap</b> is provided, use it
* as a map from router identity to routerinfo_t when looking up signing keys.
+ *
+ * If <b>can_dl_again_out</b> is provided, set *<b>can_dl_again_out</b> to 1
+ * if it's okay to try to download an extrainfo with this same digest again,
+ * and 0 if it isn't. (It might not be okay to download it again if part of
+ * the part covered by the digest is invalid.)
*/
extrainfo_t *
extrainfo_parse_entry_from_string(const char *s, const char *end,
- int cache_copy, struct digest_ri_map_t *routermap)
+ int cache_copy, struct digest_ri_map_t *routermap,
+ int *can_dl_again_out)
{
extrainfo_t *extrainfo = NULL;
char digest[128];
@@ -1439,6 +1474,9 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
routerinfo_t *router = NULL;
memarea_t *area = NULL;
const char *s_dup = s;
+ /* Do not set this to '1' until we have parsed everything that we intend to
+ * parse that's covered by the hash. */
+ int can_dl_again = 0;
if (!end) {
end = s + strlen(s);
@@ -1498,6 +1536,9 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
goto err;
}
+ /* We've checked everything that's covered by the hash. */
+ can_dl_again = 1;
+
if (routermap &&
(router = digestmap_get((digestmap_t*)routermap,
extrainfo->cache_info.identity_digest))) {
@@ -1540,6 +1581,8 @@ extrainfo_parse_entry_from_string(const char *s, const char *end,
DUMP_AREA(area, "extrainfo");
memarea_drop_all(area);
}
+ if (can_dl_again_out)
+ *can_dl_again_out = can_dl_again;
return extrainfo;
}
@@ -1754,6 +1797,63 @@ find_start_of_next_routerstatus(const char *s)
return eos;
}
+/** Parse the GuardFraction string from a consensus or vote.
+ *
+ * If <b>vote</b> or <b>vote_rs</b> are set the document getting
+ * parsed is a vote routerstatus. Otherwise it's a consensus. This is
+ * the same semantic as in routerstatus_parse_entry_from_string(). */
+STATIC int
+routerstatus_parse_guardfraction(const char *guardfraction_str,
+ networkstatus_t *vote,
+ vote_routerstatus_t *vote_rs,
+ routerstatus_t *rs)
+{
+ int ok;
+ const char *end_of_header = NULL;
+ int is_consensus = !vote_rs;
+ uint32_t guardfraction;
+
+ tor_assert(bool_eq(vote, vote_rs));
+
+ /* If this info comes from a consensus, but we should't apply
+ guardfraction, just exit. */
+ if (is_consensus && !should_apply_guardfraction(NULL)) {
+ return 0;
+ }
+
+ end_of_header = strchr(guardfraction_str, '=');
+ if (!end_of_header) {
+ return -1;
+ }
+
+ guardfraction = (uint32_t)tor_parse_ulong(end_of_header+1,
+ 10, 0, 100, &ok, NULL);
+ if (!ok) {
+ log_warn(LD_DIR, "Invalid GuardFraction %s", escaped(guardfraction_str));
+ return -1;
+ }
+
+ log_debug(LD_GENERAL, "[*] Parsed %s guardfraction '%s' for '%s'.",
+ is_consensus ? "consensus" : "vote",
+ guardfraction_str, rs->nickname);
+
+ if (!is_consensus) { /* We are parsing a vote */
+ vote_rs->status.guardfraction_percentage = guardfraction;
+ vote_rs->status.has_guardfraction = 1;
+ } else {
+ /* We are parsing a consensus. Only apply guardfraction to guards. */
+ if (rs->is_possible_guard) {
+ rs->guardfraction_percentage = guardfraction;
+ rs->has_guardfraction = 1;
+ } else {
+ log_warn(LD_BUG, "Got GuardFraction for non-guard %s. "
+ "This is not supposed to happen. Not applying. ", rs->nickname);
+ }
+ }
+
+ return 0;
+}
+
/** Given a string at *<b>s</b>, containing a routerstatus object, and an
* empty smartlist at <b>tokens</b>, parse and return the first router status
* object in the string, and advance *<b>s</b> to just after the end of the
@@ -1900,8 +2000,6 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->is_possible_guard = 1;
else if (!strcmp(tok->args[i], "BadExit"))
rs->is_bad_exit = 1;
- else if (!strcmp(tok->args[i], "BadDirectory"))
- rs->is_bad_directory = 1;
else if (!strcmp(tok->args[i], "Authority"))
rs->is_authority = 1;
else if (!strcmp(tok->args[i], "Unnamed") &&
@@ -1918,12 +2016,9 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->version_known = 1;
if (strcmpstart(tok->args[0], "Tor ")) {
rs->version_supports_microdesc_cache = 1;
- rs->version_supports_optimistic_data = 1;
} else {
rs->version_supports_microdesc_cache =
tor_version_supports_microdescriptors(tok->args[0]);
- rs->version_supports_optimistic_data =
- tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha");
rs->version_supports_extend2_cells =
tor_version_as_new_as(tok->args[0], "0.2.4.8-alpha");
}
@@ -1961,6 +2056,11 @@ routerstatus_parse_entry_from_string(memarea_t *area,
vote->has_measured_bws = 1;
} else if (!strcmpstart(tok->args[i], "Unmeasured=1")) {
rs->bw_is_unmeasured = 1;
+ } else if (!strcmpstart(tok->args[i], "GuardFraction=")) {
+ if (routerstatus_parse_guardfraction(tok->args[i],
+ vote, vote_rs, rs) < 0) {
+ goto err;
+ }
}
}
}
@@ -2048,6 +2148,7 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method)
double Gtotal=0, Mtotal=0, Etotal=0;
const char *casename = NULL;
int valid = 1;
+ (void) consensus_method;
weight_scale = networkstatus_get_weight_scale_param(ns);
Wgg = networkstatus_get_bw_weight(ns, "Wgg", -1);
@@ -2127,12 +2228,8 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method)
// Then, gather G, M, E, D, T to determine case
SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
int is_exit = 0;
- if (consensus_method >= MIN_METHOD_TO_CUT_BADEXIT_WEIGHT) {
- /* Bug #2203: Don't count bad exits as exits for balancing */
- is_exit = rs->is_exit && !rs->is_bad_exit;
- } else {
- is_exit = rs->is_exit;
- }
+ /* Bug #2203: Don't count bad exits as exits for balancing */
+ is_exit = rs->is_exit && !rs->is_bad_exit;
if (rs->has_bandwidth) {
T += rs->bandwidth_kb;
if (is_exit && rs->is_possible_guard) {
@@ -2568,11 +2665,15 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
(int) tor_parse_long(tok->args[1], 10, 0, INT_MAX, &ok, NULL);
if (!ok)
goto err;
- if (ns->valid_after + MIN_VOTE_INTERVAL > ns->fresh_until) {
+ if (ns->valid_after +
+ (get_options()->TestingTorNetwork ?
+ MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL) > ns->fresh_until) {
log_warn(LD_DIR, "Vote/consensus freshness interval is too short");
goto err;
}
- if (ns->valid_after + MIN_VOTE_INTERVAL*2 > ns->valid_until) {
+ if (ns->valid_after +
+ (get_options()->TestingTorNetwork ?
+ MIN_VOTE_INTERVAL_TESTING : MIN_VOTE_INTERVAL)*2 > ns->valid_until) {
log_warn(LD_DIR, "Vote/consensus liveness interval is too short");
goto err;
}
@@ -2592,6 +2693,16 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
ns->server_versions = tor_strdup(tok->args[0]);
}
+ {
+ smartlist_t *package_lst = find_all_by_keyword(tokens, K_PACKAGE);
+ ns->package_lines = smartlist_new();
+ if (package_lst) {
+ SMARTLIST_FOREACH(package_lst, directory_token_t *, t,
+ smartlist_add(ns->package_lines, tor_strdup(t->args[0])));
+ }
+ smartlist_free(package_lst);
+ }
+
tok = find_by_keyword(tokens, K_KNOWN_FLAGS);
ns->known_flags = smartlist_new();
inorder = 1;
@@ -3247,8 +3358,8 @@ networkstatus_parse_detached_signatures(const char *s, const char *eos)
* AF_UNSPEC for '*'. Use policy_expand_unspec() to turn this into a pair
* of AF_INET and AF_INET6 items.
*/
-addr_policy_t *
-router_parse_addr_policy_item_from_string(const char *s, int assume_action)
+MOCK_IMPL(addr_policy_t *,
+router_parse_addr_policy_item_from_string,(const char *s, int assume_action))
{
directory_token_t *tok = NULL;
const char *cp, *eos;
@@ -4014,12 +4125,15 @@ find_start_of_next_microdesc(const char *s, const char *eos)
* If <b>saved_location</b> isn't SAVED_IN_CACHE, make a local copy of each
* descriptor in the body field of each microdesc_t.
*
- * Return all newly
- * parsed microdescriptors in a newly allocated smartlist_t. */
+ * Return all newly parsed microdescriptors in a newly allocated
+ * smartlist_t. If <b>invalid_disgests_out</b> is provided, add a SHA256
+ * microdesc digest to it for every microdesc that we found to be badly
+ * formed. (This may cause duplicates) */
smartlist_t *
microdescs_parse_from_string(const char *s, const char *eos,
int allow_annotations,
- saved_location_t where)
+ saved_location_t where,
+ smartlist_t *invalid_digests_out)
{
smartlist_t *tokens;
smartlist_t *result;
@@ -4041,21 +4155,20 @@ microdescs_parse_from_string(const char *s, const char *eos,
tokens = smartlist_new();
while (s < eos) {
+ int okay = 0;
+
start_of_next_microdesc = find_start_of_next_microdesc(s, eos);
if (!start_of_next_microdesc)
start_of_next_microdesc = eos;
- if (tokenize_string(area, s, start_of_next_microdesc, tokens,
- microdesc_token_table, flags)) {
- log_warn(LD_DIR, "Unparseable microdescriptor");
- goto next;
- }
-
md = tor_malloc_zero(sizeof(microdesc_t));
{
const char *cp = tor_memstr(s, start_of_next_microdesc-s,
"onion-key");
- tor_assert(cp);
+ const int no_onion_key = (cp == NULL);
+ if (no_onion_key) {
+ cp = s; /* So that we have *some* junk to put in the body */
+ }
md->bodylen = start_of_next_microdesc - cp;
md->saved_location = where;
@@ -4064,6 +4177,18 @@ microdescs_parse_from_string(const char *s, const char *eos,
else
md->body = (char*)cp;
md->off = cp - start;
+ crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
+ if (no_onion_key) {
+ log_fn(LOG_PROTOCOL_WARN, LD_DIR, "Malformed or truncated descriptor");
+ goto next;
+ }
+ }
+
+
+ if (tokenize_string(area, s, start_of_next_microdesc, tokens,
+ microdesc_token_table, flags)) {
+ log_warn(LD_DIR, "Unparseable microdescriptor");
+ goto next;
}
if ((tok = find_opt_by_keyword(tokens, A_LAST_LISTED))) {
@@ -4121,12 +4246,15 @@ microdescs_parse_from_string(const char *s, const char *eos,
md->ipv6_exit_policy = parse_short_policy(tok->args[0]);
}
- crypto_digest256(md->digest, md->body, md->bodylen, DIGEST_SHA256);
-
smartlist_add(result, md);
+ okay = 1;
md = NULL;
next:
+ if (! okay && invalid_digests_out) {
+ smartlist_add(invalid_digests_out,
+ tor_memdup(md->digest, DIGEST256_LEN));
+ }
microdesc_free(md);
md = NULL;
@@ -4207,40 +4335,50 @@ tor_version_parse(const char *s, tor_version_t *out)
char *eos=NULL;
const char *cp=NULL;
/* Format is:
- * "Tor " ? NUM dot NUM dot NUM [ ( pre | rc | dot ) NUM [ - tag ] ]
+ * "Tor " ? NUM dot NUM [ dot NUM [ ( pre | rc | dot ) NUM ] ] [ - tag ]
*/
tor_assert(s);
tor_assert(out);
memset(out, 0, sizeof(tor_version_t));
-
+ out->status = VER_RELEASE;
if (!strcasecmpstart(s, "Tor "))
s += 4;
- /* Get major. */
- out->major = (int)strtol(s,&eos,10);
- if (!eos || eos==s || *eos != '.') return -1;
- cp = eos+1;
-
- /* Get minor */
- out->minor = (int) strtol(cp,&eos,10);
- if (!eos || eos==cp || *eos != '.') return -1;
- cp = eos+1;
-
- /* Get micro */
- out->micro = (int) strtol(cp,&eos,10);
- if (!eos || eos==cp) return -1;
- if (!*eos) {
- out->status = VER_RELEASE;
- out->patchlevel = 0;
+ cp = s;
+
+#define NUMBER(m) \
+ do { \
+ out->m = (int)strtol(cp, &eos, 10); \
+ if (!eos || eos == cp) \
+ return -1; \
+ cp = eos; \
+ } while (0)
+
+#define DOT() \
+ do { \
+ if (*cp != '.') \
+ return -1; \
+ ++cp; \
+ } while (0)
+
+ NUMBER(major);
+ DOT();
+ NUMBER(minor);
+ if (*cp == 0)
return 0;
- }
- cp = eos;
+ else if (*cp == '-')
+ goto status_tag;
+ DOT();
+ NUMBER(micro);
/* Get status */
- if (*cp == '.') {
- out->status = VER_RELEASE;
+ if (*cp == 0) {
+ return 0;
+ } else if (*cp == '.') {
++cp;
+ } else if (*cp == '-') {
+ goto status_tag;
} else if (0==strncmp(cp, "pre", 3)) {
out->status = VER_PRE;
cp += 3;
@@ -4251,11 +4389,9 @@ tor_version_parse(const char *s, tor_version_t *out)
return -1;
}
- /* Get patchlevel */
- out->patchlevel = (int) strtol(cp,&eos,10);
- if (!eos || eos==cp) return -1;
- cp = eos;
+ NUMBER(patchlevel);
+ status_tag:
/* Get status tag. */
if (*cp == '-' || *cp == '.')
++cp;
@@ -4291,6 +4427,8 @@ tor_version_parse(const char *s, tor_version_t *out)
}
return 0;
+#undef NUMBER
+#undef DOT
}
/** Compare two tor versions; Return <0 if a < b; 0 if a ==b, >0 if a >
@@ -4389,6 +4527,9 @@ sort_version_list(smartlist_t *versions, int remove_duplicates)
* to *<b>encoded_size_out</b>, and a pointer to the possibly next
* descriptor to *<b>next_out</b>; return 0 for success (including validation)
* and -1 for failure.
+ *
+ * If <b>as_hsdir</b> is 1, we're parsing this as an HSDir, and we should
+ * be strict about time formats.
*/
int
rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
@@ -4396,7 +4537,8 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
char **intro_points_encrypted_out,
size_t *intro_points_encrypted_size_out,
size_t *encoded_size_out,
- const char **next_out, const char *desc)
+ const char **next_out, const char *desc,
+ int as_hsdir)
{
rend_service_descriptor_t *result =
tor_malloc_zero(sizeof(rend_service_descriptor_t));
@@ -4410,6 +4552,8 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
char public_key_hash[DIGEST_LEN];
char test_desc_id[DIGEST_LEN];
memarea_t *area = NULL;
+ const int strict_time_fmt = as_hsdir;
+
tor_assert(desc);
/* Check if desc starts correctly. */
if (strncmp(desc, "rendezvous-service-descriptor ",
@@ -4504,7 +4648,7 @@ rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
* descriptor. */
tok = find_by_keyword(tokens, R_PUBLICATION_TIME);
tor_assert(tok->n_args == 1);
- if (parse_iso_time(tok->args[0], &result->timestamp) < 0) {
+ if (parse_iso_time_(tok->args[0], &result->timestamp, strict_time_fmt) < 0) {
log_warn(LD_REND, "Invalid publication time: '%s'", tok->args[0]);
goto err;
}
diff --git a/src/or/routerparse.h b/src/or/routerparse.h
index 5d5d9e59ef..fc21cb1041 100644
--- a/src/or/routerparse.h
+++ b/src/or/routerparse.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -29,16 +29,19 @@ int router_parse_list_from_string(const char **s, const char *eos,
saved_location_t saved_location,
int is_extrainfo,
int allow_annotations,
- const char *prepend_annotations);
+ const char *prepend_annotations,
+ smartlist_t *invalid_digests_out);
routerinfo_t *router_parse_entry_from_string(const char *s, const char *end,
int cache_copy,
int allow_annotations,
- const char *prepend_annotations);
+ const char *prepend_annotations,
+ int *can_dl_again_out);
extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end,
- int cache_copy, struct digest_ri_map_t *routermap);
-addr_policy_t *router_parse_addr_policy_item_from_string(const char *s,
- int assume_action);
+ int cache_copy, struct digest_ri_map_t *routermap,
+ int *can_dl_again_out);
+MOCK_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
+ (const char *s, int assume_action));
version_status_t tor_version_is_obsolete(const char *myversion,
const char *versionlist);
int tor_version_supports_microdescriptors(const char *platform);
@@ -60,7 +63,8 @@ ns_detached_signatures_t *networkstatus_parse_detached_signatures(
smartlist_t *microdescs_parse_from_string(const char *s, const char *eos,
int allow_annotations,
- saved_location_t where);
+ saved_location_t where,
+ smartlist_t *invalid_digests_out);
authority_cert_t *authority_cert_parse_from_string(const char *s,
const char **end_of_string);
@@ -69,7 +73,8 @@ int rend_parse_v2_service_descriptor(rend_service_descriptor_t **parsed_out,
char **intro_points_encrypted_out,
size_t *intro_points_encrypted_size_out,
size_t *encoded_size_out,
- const char **next_out, const char *desc);
+ const char **next_out, const char *desc,
+ int as_hsdir);
int rend_decrypt_introduction_points(char **ipos_decrypted,
size_t *ipos_decrypted_size,
const char *descriptor_cookie,
@@ -80,5 +85,12 @@ int rend_parse_introduction_points(rend_service_descriptor_t *parsed,
size_t intro_points_encoded_size);
int rend_parse_client_keys(strmap_t *parsed_clients, const char *str);
+#ifdef ROUTERPARSE_PRIVATE
+STATIC int routerstatus_parse_guardfraction(const char *guardfraction_str,
+ networkstatus_t *vote,
+ vote_routerstatus_t *vote_rs,
+ routerstatus_t *rs);
+#endif
+
#endif
diff --git a/src/or/routerset.c b/src/or/routerset.c
index 7aee90d6db..99de11ed5e 100644
--- a/src/or/routerset.c
+++ b/src/or/routerset.c
@@ -1,9 +1,11 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#define ROUTERSET_PRIVATE
+
#include "or.h"
#include "geoip.h"
#include "nodelist.h"
@@ -12,39 +14,6 @@
#include "routerparse.h"
#include "routerset.h"
-/** A routerset specifies constraints on a set of possible routerinfos, based
- * on their names, identities, or addresses. It is optimized for determining
- * whether a router is a member or not, in O(1+P) time, where P is the number
- * of address policy constraints. */
-struct routerset_t {
- /** A list of strings for the elements of the policy. Each string is either
- * a nickname, a hexadecimal identity fingerprint, or an address policy. A
- * router belongs to the set if its nickname OR its identity OR its address
- * matches an entry here. */
- smartlist_t *list;
- /** A map from lowercase nicknames of routers in the set to (void*)1 */
- strmap_t *names;
- /** A map from identity digests routers in the set to (void*)1 */
- digestmap_t *digests;
- /** An address policy for routers in the set. For implementation reasons,
- * a router belongs to the set if it is _rejected_ by this policy. */
- smartlist_t *policies;
-
- /** A human-readable description of what this routerset is for. Used in
- * log messages. */
- char *description;
-
- /** A list of the country codes in this set. */
- smartlist_t *country_names;
- /** Total number of countries we knew about when we built <b>countries</b>.*/
- int n_countries;
- /** Bit array mapping the return value of geoip_get_country() to 1 iff the
- * country is a member of this routerset. Note that we MUST call
- * routerset_refresh_countries() whenever the geoip country list is
- * reloaded. */
- bitarray_t *countries;
-};
-
/** Return a new empty routerset. */
routerset_t *
routerset_new(void)
@@ -60,7 +29,7 @@ routerset_new(void)
/** If <b>c</b> is a country code in the form {cc}, return a newly allocated
* string holding the "cc" part. Else, return NULL. */
-static char *
+STATIC char *
routerset_get_countryname(const char *c)
{
char *country;
@@ -200,7 +169,7 @@ routerset_is_empty(const routerset_t *set)
*
* (If country is -1, then we take the country
* from addr.) */
-static int
+STATIC int
routerset_contains(const routerset_t *set, const tor_addr_t *addr,
uint16_t orport,
const char *nickname, const char *id_digest,
diff --git a/src/or/routerset.h b/src/or/routerset.h
index 8261c7fb09..8d41de8b6b 100644
--- a/src/or/routerset.h
+++ b/src/or/routerset.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -39,5 +39,45 @@ char *routerset_to_string(const routerset_t *routerset);
int routerset_equal(const routerset_t *old, const routerset_t *new);
void routerset_free(routerset_t *routerset);
+#ifdef ROUTERSET_PRIVATE
+STATIC char * routerset_get_countryname(const char *c);
+STATIC int routerset_contains(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport,
+ const char *nickname, const char *id_digest,
+ country_t country);
+
+/** A routerset specifies constraints on a set of possible routerinfos, based
+ * on their names, identities, or addresses. It is optimized for determining
+ * whether a router is a member or not, in O(1+P) time, where P is the number
+ * of address policy constraints. */
+struct routerset_t {
+ /** A list of strings for the elements of the policy. Each string is either
+ * a nickname, a hexadecimal identity fingerprint, or an address policy. A
+ * router belongs to the set if its nickname OR its identity OR its address
+ * matches an entry here. */
+ smartlist_t *list;
+ /** A map from lowercase nicknames of routers in the set to (void*)1 */
+ strmap_t *names;
+ /** A map from identity digests routers in the set to (void*)1 */
+ digestmap_t *digests;
+ /** An address policy for routers in the set. For implementation reasons,
+ * a router belongs to the set if it is _rejected_ by this policy. */
+ smartlist_t *policies;
+
+ /** A human-readable description of what this routerset is for. Used in
+ * log messages. */
+ char *description;
+
+ /** A list of the country codes in this set. */
+ smartlist_t *country_names;
+ /** Total number of countries we knew about when we built <b>countries</b>.*/
+ int n_countries;
+ /** Bit array mapping the return value of geoip_get_country() to 1 iff the
+ * country is a member of this routerset. Note that we MUST call
+ * routerset_refresh_countries() whenever the geoip country list is
+ * reloaded. */
+ bitarray_t *countries;
+};
+#endif
#endif
diff --git a/src/or/scheduler.c b/src/or/scheduler.c
new file mode 100644
index 0000000000..931bb6b744
--- /dev/null
+++ b/src/or/scheduler.c
@@ -0,0 +1,711 @@
+/* * Copyright (c) 2013-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file scheduler.c
+ * \brief Relay scheduling system
+ **/
+
+#include "or.h"
+
+#define TOR_CHANNEL_INTERNAL_ /* For channel_flush_some_cells() */
+#include "channel.h"
+
+#include "compat_libevent.h"
+#define SCHEDULER_PRIVATE_
+#include "scheduler.h"
+
+#ifdef HAVE_EVENT2_EVENT_H
+#include <event2/event.h>
+#else
+#include <event.h>
+#endif
+
+/*
+ * Scheduler high/low watermarks
+ */
+
+static uint32_t sched_q_low_water = 16384;
+static uint32_t sched_q_high_water = 32768;
+
+/*
+ * Maximum cells to flush in a single call to channel_flush_some_cells();
+ * setting this low means more calls, but too high and we could overshoot
+ * sched_q_high_water.
+ */
+
+static uint32_t sched_max_flush_cells = 16;
+
+/*
+ * Write scheduling works by keeping track of which channels can
+ * accept cells, and have cells to write. From the scheduler's perspective,
+ * a channel can be in four possible states:
+ *
+ * 1.) Not open for writes, no cells to send
+ * - Not much to do here, and the channel will have scheduler_state ==
+ * SCHED_CHAN_IDLE
+ * - Transitions from:
+ * - Open for writes/has cells by simultaneously draining all circuit
+ * queues and filling the output buffer.
+ * - Transitions to:
+ * - Not open for writes/has cells by arrival of cells on an attached
+ * circuit (this would be driven from append_cell_to_circuit_queue())
+ * - Open for writes/no cells by a channel type specific path;
+ * driven from connection_or_flushed_some() for channel_tls_t.
+ *
+ * 2.) Open for writes, no cells to send
+ * - Not much here either; this will be the state an idle but open channel
+ * can be expected to settle in. It will have scheduler_state ==
+ * SCHED_CHAN_WAITING_FOR_CELLS
+ * - Transitions from:
+ * - Not open for writes/no cells by flushing some of the output
+ * buffer.
+ * - Open for writes/has cells by the scheduler moving cells from
+ * circuit queues to channel output queue, but not having enough
+ * to fill the output queue.
+ * - Transitions to:
+ * - Open for writes/has cells by arrival of new cells on an attached
+ * circuit, in append_cell_to_circuit_queue()
+ *
+ * 3.) Not open for writes, cells to send
+ * - This is the state of a busy circuit limited by output bandwidth;
+ * cells have piled up in the circuit queues waiting to be relayed.
+ * The channel will have scheduler_state == SCHED_CHAN_WAITING_TO_WRITE.
+ * - Transitions from:
+ * - Not open for writes/no cells by arrival of cells on an attached
+ * circuit
+ * - Open for writes/has cells by filling an output buffer without
+ * draining all cells from attached circuits
+ * - Transitions to:
+ * - Opens for writes/has cells by draining some of the output buffer
+ * via the connection_or_flushed_some() path (for channel_tls_t).
+ *
+ * 4.) Open for writes, cells to send
+ * - This connection is ready to relay some cells and waiting for
+ * the scheduler to choose it. The channel will have scheduler_state ==
+ * SCHED_CHAN_PENDING.
+ * - Transitions from:
+ * - Not open for writes/has cells by the connection_or_flushed_some()
+ * path
+ * - Open for writes/no cells by the append_cell_to_circuit_queue()
+ * path
+ * - Transitions to:
+ * - Not open for writes/no cells by draining all circuit queues and
+ * simultaneously filling the output buffer.
+ * - Not open for writes/has cells by writing enough cells to fill the
+ * output buffer
+ * - Open for writes/no cells by draining all attached circuit queues
+ * without also filling the output buffer
+ *
+ * Other event-driven parts of the code move channels between these scheduling
+ * states by calling scheduler functions; the scheduler only runs on open-for-
+ * writes/has-cells channels and is the only path for those to transition to
+ * other states. The scheduler_run() function gives us the opportunity to do
+ * scheduling work, and is called from other scheduler functions whenever a
+ * state transition occurs, and periodically from the main event loop.
+ */
+
+/* Scheduler global data structures */
+
+/*
+ * We keep a list of channels that are pending - i.e, have cells to write
+ * and can accept them to send. The enum scheduler_state in channel_t
+ * is reserved for our use.
+ */
+
+/* Pqueue of channels that can write and have cells (pending work) */
+STATIC smartlist_t *channels_pending = NULL;
+
+/*
+ * This event runs the scheduler from its callback, and is manually
+ * activated whenever a channel enters open for writes/cells to send.
+ */
+
+STATIC struct event *run_sched_ev = NULL;
+
+/*
+ * Queue heuristic; this is not the queue size, but an 'effective queuesize'
+ * that ages out contributions from stalled channels.
+ */
+
+STATIC uint64_t queue_heuristic = 0;
+
+/*
+ * Timestamp for last queue heuristic update
+ */
+
+STATIC time_t queue_heuristic_timestamp = 0;
+
+/* Scheduler static function declarations */
+
+static void scheduler_evt_callback(evutil_socket_t fd,
+ short events, void *arg);
+static int scheduler_more_work(void);
+static void scheduler_retrigger(void);
+#if 0
+static void scheduler_trigger(void);
+#endif
+
+/* Scheduler function implementations */
+
+/** Free everything and shut down the scheduling system */
+
+void
+scheduler_free_all(void)
+{
+ log_debug(LD_SCHED, "Shutting down scheduler");
+
+ if (run_sched_ev) {
+ if (event_del(run_sched_ev) < 0) {
+ log_warn(LD_BUG, "Problem deleting run_sched_ev");
+ }
+ tor_event_free(run_sched_ev);
+ run_sched_ev = NULL;
+ }
+
+ if (channels_pending) {
+ smartlist_free(channels_pending);
+ channels_pending = NULL;
+ }
+}
+
+/**
+ * Comparison function to use when sorting pending channels
+ */
+
+MOCK_IMPL(STATIC int,
+scheduler_compare_channels, (const void *c1_v, const void *c2_v))
+{
+ channel_t *c1 = NULL, *c2 = NULL;
+ /* These are a workaround for -Wbad-function-cast throwing a fit */
+ const circuitmux_policy_t *p1, *p2;
+ uintptr_t p1_i, p2_i;
+
+ tor_assert(c1_v);
+ tor_assert(c2_v);
+
+ c1 = (channel_t *)(c1_v);
+ c2 = (channel_t *)(c2_v);
+
+ tor_assert(c1);
+ tor_assert(c2);
+
+ if (c1 != c2) {
+ if (circuitmux_get_policy(c1->cmux) ==
+ circuitmux_get_policy(c2->cmux)) {
+ /* Same cmux policy, so use the mux comparison */
+ return circuitmux_compare_muxes(c1->cmux, c2->cmux);
+ } else {
+ /*
+ * Different policies; not important to get this edge case perfect
+ * because the current code never actually gives different channels
+ * different cmux policies anyway. Just use this arbitrary but
+ * definite choice.
+ */
+ p1 = circuitmux_get_policy(c1->cmux);
+ p2 = circuitmux_get_policy(c2->cmux);
+ p1_i = (uintptr_t)p1;
+ p2_i = (uintptr_t)p2;
+
+ return (p1_i < p2_i) ? -1 : 1;
+ }
+ } else {
+ /* c1 == c2, so always equal */
+ return 0;
+ }
+}
+
+/*
+ * Scheduler event callback; this should get triggered once per event loop
+ * if any scheduling work was created during the event loop.
+ */
+
+static void
+scheduler_evt_callback(evutil_socket_t fd, short events, void *arg)
+{
+ (void)fd;
+ (void)events;
+ (void)arg;
+ log_debug(LD_SCHED, "Scheduler event callback called");
+
+ tor_assert(run_sched_ev);
+
+ /* Run the scheduler */
+ scheduler_run();
+
+ /* Do we have more work to do? */
+ if (scheduler_more_work()) scheduler_retrigger();
+}
+
+/** Mark a channel as no longer ready to accept writes */
+
+MOCK_IMPL(void,
+scheduler_channel_doesnt_want_writes,(channel_t *chan))
+{
+ tor_assert(chan);
+
+ tor_assert(channels_pending);
+
+ /* If it's already in pending, we can put it in waiting_to_write */
+ if (chan->scheduler_state == SCHED_CHAN_PENDING) {
+ /*
+ * It's in channels_pending, so it shouldn't be in any of
+ * the other lists. It can't write any more, so it goes to
+ * channels_waiting_to_write.
+ */
+ smartlist_pqueue_remove(channels_pending,
+ scheduler_compare_channels,
+ STRUCT_OFFSET(channel_t, sched_heap_idx),
+ chan);
+ chan->scheduler_state = SCHED_CHAN_WAITING_TO_WRITE;
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p went from pending "
+ "to waiting_to_write",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+ } else {
+ /*
+ * It's not in pending, so it can't become waiting_to_write; it's
+ * either not in any of the lists (nothing to do) or it's already in
+ * waiting_for_cells (remove it, can't write any more).
+ */
+ if (chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS) {
+ chan->scheduler_state = SCHED_CHAN_IDLE;
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p left waiting_for_cells",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+ }
+ }
+}
+
+/** Mark a channel as having waiting cells */
+
+MOCK_IMPL(void,
+scheduler_channel_has_waiting_cells,(channel_t *chan))
+{
+ int became_pending = 0;
+
+ tor_assert(chan);
+ tor_assert(channels_pending);
+
+ /* First, check if this one also writeable */
+ if (chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS) {
+ /*
+ * It's in channels_waiting_for_cells, so it shouldn't be in any of
+ * the other lists. It has waiting cells now, so it goes to
+ * channels_pending.
+ */
+ chan->scheduler_state = SCHED_CHAN_PENDING;
+ smartlist_pqueue_add(channels_pending,
+ scheduler_compare_channels,
+ STRUCT_OFFSET(channel_t, sched_heap_idx),
+ chan);
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p went from waiting_for_cells "
+ "to pending",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+ became_pending = 1;
+ } else {
+ /*
+ * It's not in waiting_for_cells, so it can't become pending; it's
+ * either not in any of the lists (we add it to waiting_to_write)
+ * or it's already in waiting_to_write or pending (we do nothing)
+ */
+ if (!(chan->scheduler_state == SCHED_CHAN_WAITING_TO_WRITE ||
+ chan->scheduler_state == SCHED_CHAN_PENDING)) {
+ chan->scheduler_state = SCHED_CHAN_WAITING_TO_WRITE;
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p entered waiting_to_write",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+ }
+ }
+
+ /*
+ * If we made a channel pending, we potentially have scheduling work
+ * to do.
+ */
+ if (became_pending) scheduler_retrigger();
+}
+
+/** Set up the scheduling system */
+
+void
+scheduler_init(void)
+{
+ log_debug(LD_SCHED, "Initting scheduler");
+
+ tor_assert(!run_sched_ev);
+ run_sched_ev = tor_event_new(tor_libevent_get_base(), -1,
+ 0, scheduler_evt_callback, NULL);
+
+ channels_pending = smartlist_new();
+ queue_heuristic = 0;
+ queue_heuristic_timestamp = approx_time();
+}
+
+/** Check if there's more scheduling work */
+
+static int
+scheduler_more_work(void)
+{
+ tor_assert(channels_pending);
+
+ return ((scheduler_get_queue_heuristic() < sched_q_low_water) &&
+ ((smartlist_len(channels_pending) > 0))) ? 1 : 0;
+}
+
+/** Retrigger the scheduler in a way safe to use from the callback */
+
+static void
+scheduler_retrigger(void)
+{
+ tor_assert(run_sched_ev);
+ event_active(run_sched_ev, EV_TIMEOUT, 1);
+}
+
+/** Notify the scheduler of a channel being closed */
+
+MOCK_IMPL(void,
+scheduler_release_channel,(channel_t *chan))
+{
+ tor_assert(chan);
+ tor_assert(channels_pending);
+
+ if (chan->scheduler_state == SCHED_CHAN_PENDING) {
+ smartlist_pqueue_remove(channels_pending,
+ scheduler_compare_channels,
+ STRUCT_OFFSET(channel_t, sched_heap_idx),
+ chan);
+ }
+
+ chan->scheduler_state = SCHED_CHAN_IDLE;
+}
+
+/** Run the scheduling algorithm if necessary */
+
+MOCK_IMPL(void,
+scheduler_run, (void))
+{
+ int n_cells, n_chans_before, n_chans_after;
+ uint64_t q_len_before, q_heur_before, q_len_after, q_heur_after;
+ ssize_t flushed, flushed_this_time;
+ smartlist_t *to_readd = NULL;
+ channel_t *chan = NULL;
+
+ log_debug(LD_SCHED, "We have a chance to run the scheduler");
+
+ if (scheduler_get_queue_heuristic() < sched_q_low_water) {
+ n_chans_before = smartlist_len(channels_pending);
+ q_len_before = channel_get_global_queue_estimate();
+ q_heur_before = scheduler_get_queue_heuristic();
+
+ while (scheduler_get_queue_heuristic() <= sched_q_high_water &&
+ smartlist_len(channels_pending) > 0) {
+ /* Pop off a channel */
+ chan = smartlist_pqueue_pop(channels_pending,
+ scheduler_compare_channels,
+ STRUCT_OFFSET(channel_t, sched_heap_idx));
+ tor_assert(chan);
+
+ /* Figure out how many cells we can write */
+ n_cells = channel_num_cells_writeable(chan);
+ if (n_cells > 0) {
+ log_debug(LD_SCHED,
+ "Scheduler saw pending channel " U64_FORMAT " at %p with "
+ "%d cells writeable",
+ U64_PRINTF_ARG(chan->global_identifier), chan, n_cells);
+
+ flushed = 0;
+ while (flushed < n_cells &&
+ scheduler_get_queue_heuristic() <= sched_q_high_water) {
+ flushed_this_time =
+ channel_flush_some_cells(chan,
+ MIN(sched_max_flush_cells,
+ (size_t) n_cells - flushed));
+ if (flushed_this_time <= 0) break;
+ flushed += flushed_this_time;
+ }
+
+ if (flushed < n_cells) {
+ /* We ran out of cells to flush */
+ chan->scheduler_state = SCHED_CHAN_WAITING_FOR_CELLS;
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p "
+ "entered waiting_for_cells from pending",
+ U64_PRINTF_ARG(chan->global_identifier),
+ chan);
+ } else {
+ /* The channel may still have some cells */
+ if (channel_more_to_flush(chan)) {
+ /* The channel goes to either pending or waiting_to_write */
+ if (channel_num_cells_writeable(chan) > 0) {
+ /* Add it back to pending later */
+ if (!to_readd) to_readd = smartlist_new();
+ smartlist_add(to_readd, chan);
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p "
+ "is still pending",
+ U64_PRINTF_ARG(chan->global_identifier),
+ chan);
+ } else {
+ /* It's waiting to be able to write more */
+ chan->scheduler_state = SCHED_CHAN_WAITING_TO_WRITE;
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p "
+ "entered waiting_to_write from pending",
+ U64_PRINTF_ARG(chan->global_identifier),
+ chan);
+ }
+ } else {
+ /* No cells left; it can go to idle or waiting_for_cells */
+ if (channel_num_cells_writeable(chan) > 0) {
+ /*
+ * It can still accept writes, so it goes to
+ * waiting_for_cells
+ */
+ chan->scheduler_state = SCHED_CHAN_WAITING_FOR_CELLS;
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p "
+ "entered waiting_for_cells from pending",
+ U64_PRINTF_ARG(chan->global_identifier),
+ chan);
+ } else {
+ /*
+ * We exactly filled up the output queue with all available
+ * cells; go to idle.
+ */
+ chan->scheduler_state = SCHED_CHAN_IDLE;
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p "
+ "become idle from pending",
+ U64_PRINTF_ARG(chan->global_identifier),
+ chan);
+ }
+ }
+ }
+
+ log_debug(LD_SCHED,
+ "Scheduler flushed %d cells onto pending channel "
+ U64_FORMAT " at %p",
+ (int)flushed, U64_PRINTF_ARG(chan->global_identifier),
+ chan);
+ } else {
+ log_info(LD_SCHED,
+ "Scheduler saw pending channel " U64_FORMAT " at %p with "
+ "no cells writeable",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+ /* Put it back to WAITING_TO_WRITE */
+ chan->scheduler_state = SCHED_CHAN_WAITING_TO_WRITE;
+ }
+ }
+
+ /* Readd any channels we need to */
+ if (to_readd) {
+ SMARTLIST_FOREACH_BEGIN(to_readd, channel_t *, chan) {
+ chan->scheduler_state = SCHED_CHAN_PENDING;
+ smartlist_pqueue_add(channels_pending,
+ scheduler_compare_channels,
+ STRUCT_OFFSET(channel_t, sched_heap_idx),
+ chan);
+ } SMARTLIST_FOREACH_END(chan);
+ smartlist_free(to_readd);
+ }
+
+ n_chans_after = smartlist_len(channels_pending);
+ q_len_after = channel_get_global_queue_estimate();
+ q_heur_after = scheduler_get_queue_heuristic();
+ log_debug(LD_SCHED,
+ "Scheduler handled %d of %d pending channels, queue size from "
+ U64_FORMAT " to " U64_FORMAT ", queue heuristic from "
+ U64_FORMAT " to " U64_FORMAT,
+ n_chans_before - n_chans_after, n_chans_before,
+ U64_PRINTF_ARG(q_len_before), U64_PRINTF_ARG(q_len_after),
+ U64_PRINTF_ARG(q_heur_before), U64_PRINTF_ARG(q_heur_after));
+ }
+}
+
+/** Trigger the scheduling event so we run the scheduler later */
+
+#if 0
+static void
+scheduler_trigger(void)
+{
+ log_debug(LD_SCHED, "Triggering scheduler event");
+
+ tor_assert(run_sched_ev);
+
+ event_add(run_sched_ev, EV_TIMEOUT, 1);
+}
+#endif
+
+/** Mark a channel as ready to accept writes */
+
+void
+scheduler_channel_wants_writes(channel_t *chan)
+{
+ int became_pending = 0;
+
+ tor_assert(chan);
+ tor_assert(channels_pending);
+
+ /* If it's already in waiting_to_write, we can put it in pending */
+ if (chan->scheduler_state == SCHED_CHAN_WAITING_TO_WRITE) {
+ /*
+ * It can write now, so it goes to channels_pending.
+ */
+ smartlist_pqueue_add(channels_pending,
+ scheduler_compare_channels,
+ STRUCT_OFFSET(channel_t, sched_heap_idx),
+ chan);
+ chan->scheduler_state = SCHED_CHAN_PENDING;
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p went from waiting_to_write "
+ "to pending",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+ became_pending = 1;
+ } else {
+ /*
+ * It's not in SCHED_CHAN_WAITING_TO_WRITE, so it can't become pending;
+ * it's either idle and goes to WAITING_FOR_CELLS, or it's a no-op.
+ */
+ if (!(chan->scheduler_state == SCHED_CHAN_WAITING_FOR_CELLS ||
+ chan->scheduler_state == SCHED_CHAN_PENDING)) {
+ chan->scheduler_state = SCHED_CHAN_WAITING_FOR_CELLS;
+ log_debug(LD_SCHED,
+ "Channel " U64_FORMAT " at %p entered waiting_for_cells",
+ U64_PRINTF_ARG(chan->global_identifier), chan);
+ }
+ }
+
+ /*
+ * If we made a channel pending, we potentially have scheduling work
+ * to do.
+ */
+ if (became_pending) scheduler_retrigger();
+}
+
+/**
+ * Notify the scheduler that a channel's position in the pqueue may have
+ * changed
+ */
+
+void
+scheduler_touch_channel(channel_t *chan)
+{
+ tor_assert(chan);
+
+ if (chan->scheduler_state == SCHED_CHAN_PENDING) {
+ /* Remove and re-add it */
+ smartlist_pqueue_remove(channels_pending,
+ scheduler_compare_channels,
+ STRUCT_OFFSET(channel_t, sched_heap_idx),
+ chan);
+ smartlist_pqueue_add(channels_pending,
+ scheduler_compare_channels,
+ STRUCT_OFFSET(channel_t, sched_heap_idx),
+ chan);
+ }
+ /* else no-op, since it isn't in the queue */
+}
+
+/**
+ * Notify the scheduler of a queue size adjustment, to recalculate the
+ * queue heuristic.
+ */
+
+void
+scheduler_adjust_queue_size(channel_t *chan, int dir, uint64_t adj)
+{
+ time_t now = approx_time();
+
+ log_debug(LD_SCHED,
+ "Queue size adjustment by %s" U64_FORMAT " for channel "
+ U64_FORMAT,
+ (dir >= 0) ? "+" : "-",
+ U64_PRINTF_ARG(adj),
+ U64_PRINTF_ARG(chan->global_identifier));
+
+ /* Get the queue heuristic up to date */
+ scheduler_update_queue_heuristic(now);
+
+ /* Adjust as appropriate */
+ if (dir >= 0) {
+ /* Increasing it */
+ queue_heuristic += adj;
+ } else {
+ /* Decreasing it */
+ if (queue_heuristic > adj) queue_heuristic -= adj;
+ else queue_heuristic = 0;
+ }
+
+ log_debug(LD_SCHED,
+ "Queue heuristic is now " U64_FORMAT,
+ U64_PRINTF_ARG(queue_heuristic));
+}
+
+/**
+ * Query the current value of the queue heuristic
+ */
+
+STATIC uint64_t
+scheduler_get_queue_heuristic(void)
+{
+ time_t now = approx_time();
+
+ scheduler_update_queue_heuristic(now);
+
+ return queue_heuristic;
+}
+
+/**
+ * Adjust the queue heuristic value to the present time
+ */
+
+STATIC void
+scheduler_update_queue_heuristic(time_t now)
+{
+ time_t diff;
+
+ if (queue_heuristic_timestamp == 0) {
+ /*
+ * Nothing we can sensibly do; must not have been initted properly.
+ * Oh well.
+ */
+ queue_heuristic_timestamp = now;
+ } else if (queue_heuristic_timestamp < now) {
+ diff = now - queue_heuristic_timestamp;
+ /*
+ * This is a simple exponential age-out; the other proposed alternative
+ * was a linear age-out using the bandwidth history in rephist.c; I'm
+ * going with this out of concern that if an adversary can jam the
+ * scheduler long enough, it would cause the bandwidth to drop to
+ * zero and render the aging mechanism ineffective thereafter.
+ */
+ if (0 <= diff && diff < 64) queue_heuristic >>= diff;
+ else queue_heuristic = 0;
+
+ queue_heuristic_timestamp = now;
+
+ log_debug(LD_SCHED,
+ "Queue heuristic is now " U64_FORMAT,
+ U64_PRINTF_ARG(queue_heuristic));
+ }
+ /* else no update needed, or time went backward */
+}
+
+/**
+ * Set scheduler watermarks and flush size
+ */
+
+void
+scheduler_set_watermarks(uint32_t lo, uint32_t hi, uint32_t max_flush)
+{
+ /* Sanity assertions - caller should ensure these are true */
+ tor_assert(lo > 0);
+ tor_assert(hi > lo);
+ tor_assert(max_flush > 0);
+
+ sched_q_low_water = lo;
+ sched_q_high_water = hi;
+ sched_max_flush_cells = max_flush;
+}
+
diff --git a/src/or/scheduler.h b/src/or/scheduler.h
new file mode 100644
index 0000000000..27dd2d8388
--- /dev/null
+++ b/src/or/scheduler.h
@@ -0,0 +1,50 @@
+/* * Copyright (c) 2013-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file scheduler.h
+ * \brief Header file for scheduler.c
+ **/
+
+#ifndef TOR_SCHEDULER_H
+#define TOR_SCHEDULER_H
+
+#include "or.h"
+#include "channel.h"
+#include "testsupport.h"
+
+/* Global-visibility scheduler functions */
+
+/* Set up and shut down the scheduler from main.c */
+void scheduler_free_all(void);
+void scheduler_init(void);
+MOCK_DECL(void, scheduler_run, (void));
+
+/* Mark channels as having cells or wanting/not wanting writes */
+MOCK_DECL(void,scheduler_channel_doesnt_want_writes,(channel_t *chan));
+MOCK_DECL(void,scheduler_channel_has_waiting_cells,(channel_t *chan));
+void scheduler_channel_wants_writes(channel_t *chan);
+
+/* Notify the scheduler of a channel being closed */
+MOCK_DECL(void,scheduler_release_channel,(channel_t *chan));
+
+/* Notify scheduler of queue size adjustments */
+void scheduler_adjust_queue_size(channel_t *chan, int dir, uint64_t adj);
+
+/* Notify scheduler that a channel's queue position may have changed */
+void scheduler_touch_channel(channel_t *chan);
+
+/* Adjust the watermarks from config file*/
+void scheduler_set_watermarks(uint32_t lo, uint32_t hi, uint32_t max_flush);
+
+/* Things only scheduler.c and its test suite should see */
+
+#ifdef SCHEDULER_PRIVATE_
+MOCK_DECL(STATIC int, scheduler_compare_channels,
+ (const void *c1_v, const void *c2_v));
+STATIC uint64_t scheduler_get_queue_heuristic(void);
+STATIC void scheduler_update_queue_heuristic(time_t now);
+#endif
+
+#endif /* !defined(TOR_SCHEDULER_H) */
+
diff --git a/src/or/statefile.c b/src/or/statefile.c
index 7b9998fc1a..dd1894beb7 100644
--- a/src/or/statefile.c
+++ b/src/or/statefile.c
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define STATEFILE_PRIVATE
@@ -323,7 +323,10 @@ or_state_load(void)
goto done;
}
break;
+ /* treat empty state files as if the file doesn't exist, and generate
+ * a new state file, overwriting the empty file in or_state_save() */
case FN_NOENT:
+ case FN_EMPTY:
break;
case FN_ERROR:
case FN_DIR:
diff --git a/src/or/statefile.h b/src/or/statefile.h
index 15bb0b4aae..8c790ea206 100644
--- a/src/or/statefile.h
+++ b/src/or/statefile.h
@@ -1,7 +1,7 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_STATEFILE_H
diff --git a/src/or/status.c b/src/or/status.c
index afaa9de840..8f7be0aa3c 100644
--- a/src/or/status.c
+++ b/src/or/status.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Tor Project, Inc. */
+/* Copyright (c) 2010-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -23,18 +23,13 @@
#include "statefile.h"
static void log_accounting(const time_t now, const or_options_t *options);
+#include "geoip.h"
/** Return the total number of circuits. */
STATIC int
count_circuits(void)
{
- circuit_t *circ;
- int nr=0;
-
- TOR_LIST_FOREACH(circ, circuit_get_global_list(), head)
- nr++;
-
- return nr;
+ return smartlist_len(circuit_get_global_list());
}
/** Take seconds <b>secs</b> and return a newly allocated human-readable
@@ -98,7 +93,6 @@ log_heartbeat(time_t now)
const int hibernating = we_are_hibernating();
const or_options_t *options = get_options();
- (void)now;
if (public_server_mode(options) && !hibernating) {
/* Let's check if we are in the current cached consensus. */
@@ -116,28 +110,47 @@ log_heartbeat(time_t now)
log_fn(LOG_NOTICE, LD_HEARTBEAT, "Heartbeat: Tor's uptime is %s, with %d "
"circuits open. I've sent %s and received %s.%s",
- uptime, count_circuits(),bw_sent,bw_rcvd,
+ uptime, count_circuits(), bw_sent, bw_rcvd,
hibernating?" We are currently hibernating.":"");
if (server_mode(options) && accounting_is_enabled(options) && !hibernating) {
log_accounting(now, options);
}
- if (stats_n_data_cells_packaged && !hibernating)
- log_notice(LD_HEARTBEAT, "Average packaged cell fullness: %2.3f%%",
- 100*(U64_TO_DBL(stats_n_data_bytes_packaged) /
- U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) );
-
- if (r > 1.0) {
- double overhead = ( r - 1.0 ) * 100.0;
- log_notice(LD_HEARTBEAT, "TLS write overhead: %.f%%", overhead);
+ double fullness_pct = 100;
+ if (stats_n_data_cells_packaged && !hibernating) {
+ fullness_pct =
+ 100*(U64_TO_DBL(stats_n_data_bytes_packaged) /
+ U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE));
}
+ const double overhead_pct = ( r - 1.0 ) * 100.0;
+
+#define FULLNESS_PCT_THRESHOLD 80
+#define TLS_OVERHEAD_THRESHOLD 15
+
+ const int severity = (fullness_pct < FULLNESS_PCT_THRESHOLD ||
+ overhead_pct > TLS_OVERHEAD_THRESHOLD)
+ ? LOG_NOTICE : LOG_INFO;
- if (public_server_mode(options))
+ log_fn(severity, LD_HEARTBEAT,
+ "Average packaged cell fullness: %2.3f%%. "
+ "TLS write overhead: %.f%%", fullness_pct, overhead_pct);
+
+ if (public_server_mode(options)) {
rep_hist_log_circuit_handshake_stats(now);
+ rep_hist_log_link_protocol_counts();
+ }
circuit_log_ancient_one_hop_circuits(1800);
+ if (options->BridgeRelay) {
+ char *msg = NULL;
+ msg = format_client_stats_heartbeat(now);
+ if (msg)
+ log_notice(LD_HEARTBEAT, "%s", msg);
+ tor_free(msg);
+ }
+
tor_free(uptime);
tor_free(bw_sent);
tor_free(bw_rcvd);
@@ -151,10 +164,14 @@ log_accounting(const time_t now, const or_options_t *options)
or_state_t *state = get_or_state();
char *acc_rcvd = bytes_to_usage(state->AccountingBytesReadInInterval);
char *acc_sent = bytes_to_usage(state->AccountingBytesWrittenInInterval);
- char *acc_max = bytes_to_usage(options->AccountingMax);
+ uint64_t acc_bytes = options->AccountingMax;
+ char *acc_max;
time_t interval_end = accounting_get_end_time();
char end_buf[ISO_TIME_LEN + 1];
char *remaining = NULL;
+ if (options->AccountingRule == ACCT_SUM)
+ acc_bytes *= 2;
+ acc_max = bytes_to_usage(acc_bytes);
format_local_iso_time(end_buf, interval_end);
remaining = secs_to_uptime(interval_end - now);
diff --git a/src/or/status.h b/src/or/status.h
index 13458ea476..3dd8206e0f 100644
--- a/src/or/status.h
+++ b/src/or/status.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Tor Project, Inc. */
+/* Copyright (c) 2010-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_STATUS_H
diff --git a/src/or/tor_main.c b/src/or/tor_main.c
index 05dc0bf0bf..af03b8c06a 100644
--- a/src/or/tor_main.c
+++ b/src/or/tor_main.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/** String describing which Tor Git repository version the source was
diff --git a/src/or/transports.c b/src/or/transports.c
index dc30754162..6f07054ea8 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Tor Project, Inc. */
+/* Copyright (c) 2011-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -112,8 +112,6 @@ static void parse_method_error(const char *line, int is_server_method);
#define parse_server_method_error(l) parse_method_error(l, 1)
#define parse_client_method_error(l) parse_method_error(l, 0)
-static INLINE void free_execve_args(char **arg);
-
/** Managed proxy protocol strings */
#define PROTO_ENV_ERROR "ENV-ERROR"
#define PROTO_NEG_SUCCESS "VERSION"
@@ -124,6 +122,8 @@ static INLINE void free_execve_args(char **arg);
#define PROTO_SMETHOD_ERROR "SMETHOD-ERROR"
#define PROTO_CMETHODS_DONE "CMETHODS DONE"
#define PROTO_SMETHODS_DONE "SMETHODS DONE"
+#define PROTO_PROXY_DONE "PROXY DONE"
+#define PROTO_PROXY_ERROR "PROXY-ERROR"
/** The first and only supported - at the moment - configuration
protocol version. */
@@ -324,9 +324,9 @@ transport_add(transport_t *t)
/** Remember a new pluggable transport proxy at <b>addr</b>:<b>port</b>.
* <b>name</b> is set to the name of the protocol this proxy uses.
* <b>socks_ver</b> is set to the SOCKS version of the proxy. */
-int
-transport_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver)
+MOCK_IMPL(int,
+transport_add_from_config, (const tor_addr_t *addr, uint16_t port,
+ const char *name, int socks_ver))
{
transport_t *t = transport_new(addr, port, name, socks_ver, NULL);
@@ -439,6 +439,17 @@ add_transport_to_proxy(const char *transport, managed_proxy_t *mp)
static int
proxy_needs_restart(const managed_proxy_t *mp)
{
+ int ret = 1;
+ char* proxy_uri;
+
+ /* If the PT proxy config has changed, then all existing pluggable transports
+ * should be restarted.
+ */
+
+ proxy_uri = get_pt_proxy_uri();
+ if (strcmp_opt(proxy_uri, mp->proxy_uri) != 0)
+ goto needs_restart;
+
/* mp->transport_to_launch is populated with the names of the
transports that must be launched *after* the SIGHUP.
mp->transports is populated with the transports that were
@@ -459,10 +470,10 @@ proxy_needs_restart(const managed_proxy_t *mp)
} SMARTLIST_FOREACH_END(t);
- return 0;
-
+ ret = 0;
needs_restart:
- return 1;
+ tor_free(proxy_uri);
+ return ret;
}
/** Managed proxy <b>mp</b> must be restarted. Do all the necessary
@@ -493,6 +504,11 @@ proxy_prepare_for_restart(managed_proxy_t *mp)
SMARTLIST_FOREACH(mp->transports, transport_t *, t, transport_free(t));
smartlist_clear(mp->transports);
+ /* Reset the proxy's HTTPS/SOCKS proxy */
+ tor_free(mp->proxy_uri);
+ mp->proxy_uri = get_pt_proxy_uri();
+ mp->proxy_supported = 0;
+
/* flag it as an infant proxy so that it gets launched on next tick */
mp->conf_state = PT_PROTO_INFANT;
unconfigured_proxies_n++;
@@ -727,12 +743,54 @@ managed_proxy_destroy(managed_proxy_t *mp,
/* free the argv */
free_execve_args(mp->argv);
+ /* free the outgoing proxy URI */
+ tor_free(mp->proxy_uri);
+
tor_process_handle_destroy(mp->process_handle, also_terminate_process);
mp->process_handle = NULL;
tor_free(mp);
}
+/** Convert the tor proxy options to a URI suitable for TOR_PT_PROXY.
+ * Return a newly allocated string containing the URI, or NULL if no
+ * proxy is set. */
+STATIC char *
+get_pt_proxy_uri(void)
+{
+ const or_options_t *options = get_options();
+ char *uri = NULL;
+
+ if (options->Socks4Proxy || options->Socks5Proxy || options->HTTPSProxy) {
+ char addr[TOR_ADDR_BUF_LEN+1];
+
+ if (options->Socks4Proxy) {
+ tor_addr_to_str(addr, &options->Socks4ProxyAddr, sizeof(addr), 1);
+ tor_asprintf(&uri, "socks4a://%s:%d", addr, options->Socks4ProxyPort);
+ } else if (options->Socks5Proxy) {
+ tor_addr_to_str(addr, &options->Socks5ProxyAddr, sizeof(addr), 1);
+ if (!options->Socks5ProxyUsername && !options->Socks5ProxyPassword) {
+ tor_asprintf(&uri, "socks5://%s:%d", addr, options->Socks5ProxyPort);
+ } else {
+ tor_asprintf(&uri, "socks5://%s:%s@%s:%d",
+ options->Socks5ProxyUsername,
+ options->Socks5ProxyPassword,
+ addr, options->Socks5ProxyPort);
+ }
+ } else if (options->HTTPSProxy) {
+ tor_addr_to_str(addr, &options->HTTPSProxyAddr, sizeof(addr), 1);
+ if (!options->HTTPSProxyAuthenticator) {
+ tor_asprintf(&uri, "http://%s:%d", addr, options->HTTPSProxyPort);
+ } else {
+ tor_asprintf(&uri, "http://%s@%s:%d", options->HTTPSProxyAuthenticator,
+ addr, options->HTTPSProxyPort);
+ }
+ }
+ }
+
+ return uri;
+}
+
/** Handle a configured or broken managed proxy <b>mp</b>. */
static void
handle_finished_proxy(managed_proxy_t *mp)
@@ -745,6 +803,13 @@ handle_finished_proxy(managed_proxy_t *mp)
managed_proxy_destroy(mp, 0); /* destroy it but don't terminate */
break;
case PT_PROTO_CONFIGURED: /* if configured correctly: */
+ if (mp->proxy_uri && !mp->proxy_supported) {
+ log_warn(LD_CONFIG, "Managed proxy '%s' did not configure the "
+ "specified outgoing proxy and will be terminated.",
+ mp->argv[0]);
+ managed_proxy_destroy(mp, 1); /* annihilate it. */
+ break;
+ }
register_proxy(mp); /* register its transports */
mp->conf_state = PT_PROTO_COMPLETED; /* and mark it as completed. */
break;
@@ -862,6 +927,22 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
goto err;
return;
+ } else if (!strcmpstart(line, PROTO_PROXY_DONE)) {
+ if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
+ goto err;
+
+ if (mp->proxy_uri) {
+ mp->proxy_supported = 1;
+ return;
+ }
+
+ /* No proxy was configured, this should log */
+ } else if (!strcmpstart(line, PROTO_PROXY_ERROR)) {
+ if (mp->conf_state != PT_PROTO_ACCEPTING_METHODS)
+ goto err;
+
+ parse_proxy_error(line);
+ goto err;
} else if (!strcmpstart(line, SPAWN_ERROR_MESSAGE)) {
/* managed proxy launch failed: parse error message to learn why. */
int retval, child_state, saved_errno;
@@ -1128,6 +1209,21 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp)
return r;
}
+/** Parses an PROXY-ERROR <b>line</b> and warns the user accordingly. */
+STATIC void
+parse_proxy_error(const char *line)
+{
+ /* (Length of the protocol string) plus (a space) and (the first char of
+ the error message) */
+ if (strlen(line) < (strlen(PROTO_PROXY_ERROR) + 2))
+ log_notice(LD_CONFIG, "Managed proxy sent us an %s without an error "
+ "message.", PROTO_PROXY_ERROR);
+
+ log_warn(LD_CONFIG, "Managed proxy failed to configure the "
+ "pluggable transport's outgoing proxy. (%s)",
+ line+strlen(PROTO_PROXY_ERROR)+1);
+}
+
/** Return a newly allocated string that tor should place in
* TOR_PT_SERVER_TRANSPORT_OPTIONS while configuring the server
* manged proxy in <b>mp</b>. Return NULL if no such options are found. */
@@ -1292,6 +1388,14 @@ create_managed_proxy_environment(const managed_proxy_t *mp)
} else {
smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT=");
}
+ } else {
+ /* If ClientTransportPlugin has a HTTPS/SOCKS proxy configured, set the
+ * TOR_PT_PROXY line.
+ */
+
+ if (mp->proxy_uri) {
+ smartlist_add_asprintf(envs, "TOR_PT_PROXY=%s", mp->proxy_uri);
+ }
}
SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) {
@@ -1324,6 +1428,7 @@ managed_proxy_create(const smartlist_t *transport_list,
mp->is_server = is_server;
mp->argv = proxy_argv;
mp->transports = smartlist_new();
+ mp->proxy_uri = get_pt_proxy_uri();
mp->transports_to_launch = smartlist_new();
SMARTLIST_FOREACH(transport_list, const char *, transport,
@@ -1349,9 +1454,9 @@ managed_proxy_create(const smartlist_t *transport_list,
* Requires that proxy_argv be a NULL-terminated array of command-line
* elements, containing at least one element.
**/
-void
-pt_kickstart_proxy(const smartlist_t *transport_list,
- char **proxy_argv, int is_server)
+MOCK_IMPL(void,
+pt_kickstart_proxy, (const smartlist_t *transport_list,
+ char **proxy_argv, int is_server))
{
managed_proxy_t *mp=NULL;
transport_t *old_transport = NULL;
@@ -1395,7 +1500,7 @@ pt_kickstart_proxy(const smartlist_t *transport_list,
/** Frees the array of pointers in <b>arg</b> used as arguments to
execve(2). */
-static INLINE void
+STATIC void
free_execve_args(char **arg)
{
char **tmp = arg;
diff --git a/src/or/transports.h b/src/or/transports.h
index 1365ead006..7c69941496 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -32,14 +32,16 @@ typedef struct transport_t {
void mark_transport_list(void);
void sweep_transport_list(void);
-int transport_add_from_config(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver);
+MOCK_DECL(int, transport_add_from_config,
+ (const tor_addr_t *addr, uint16_t port,
+ const char *name, int socks_ver));
void transport_free(transport_t *transport);
transport_t *transport_get_by_name(const char *name);
-void pt_kickstart_proxy(const smartlist_t *transport_list, char **proxy_argv,
- int is_server);
+MOCK_DECL(void, pt_kickstart_proxy,
+ (const smartlist_t *transport_list, char **proxy_argv,
+ int is_server));
#define pt_kickstart_client_proxy(tl, pa) \
pt_kickstart_proxy(tl, pa, 0)
@@ -81,6 +83,9 @@ typedef struct {
char **argv; /* the cli arguments of this proxy */
int conf_protocol; /* the configuration protocol version used */
+ char *proxy_uri; /* the outgoing proxy in TOR_PT_PROXY URI format */
+ unsigned int proxy_supported : 1; /* the proxy honors TOR_PT_PROXY */
+
int is_server; /* is it a server proxy? */
/* A pointer to the process handle of this managed proxy. */
@@ -112,6 +117,7 @@ STATIC int parse_smethod_line(const char *line, managed_proxy_t *mp);
STATIC int parse_version(const char *line, managed_proxy_t *mp);
STATIC void parse_env_error(const char *line);
+STATIC void parse_proxy_error(const char *line);
STATIC void handle_proxy_line(const char *line, managed_proxy_t *mp);
STATIC char *get_transport_options_for_server_proxy(const managed_proxy_t *mp);
@@ -123,6 +129,10 @@ STATIC managed_proxy_t *managed_proxy_create(const smartlist_t *transport_list,
STATIC int configure_proxy(managed_proxy_t *mp);
+STATIC char* get_pt_proxy_uri(void);
+
+STATIC void free_execve_args(char **arg);
+
#endif
#endif
diff --git a/src/test/Makefile.nmake b/src/test/Makefile.nmake
index 822431f3b8..0435617683 100644
--- a/src/test/Makefile.nmake
+++ b/src/test/Makefile.nmake
@@ -11,11 +11,12 @@ LIBS = ..\..\..\build-alpha\lib\libevent.lib \
ws2_32.lib advapi32.lib shell32.lib \
crypt32.lib gdi32.lib user32.lib
-TEST_OBJECTS = test.obj test_addr.obj test_containers.obj \
- test_controller_events.ogj test_crypto.obj test_data.obj test_dir.obj \
- test_microdesc.obj test_pt.obj test_util.obj test_config.obj \
- test_cell_formats.obj test_replay.obj test_introduce.obj tinytest.obj \
- test_hs.obj
+TEST_OBJECTS = test.obj test_addr.obj test_channel.obj test_channeltls.obj \
+ test_containers.obj \
+ test_controller_events.obj test_crypto.obj test_data.obj test_dir.obj \
+ test_checkdir.obj test_microdesc.obj test_pt.obj test_util.obj test_config.obj \
+ test_cell_formats.obj test_relay.obj test_replay.obj \
+ test_scheduler.obj test_introduce.obj test_hs.obj tinytest.obj
tinytest.obj: ..\ext\tinytest.c
$(CC) $(CFLAGS) /D snprintf=_snprintf /c ..\ext\tinytest.c
diff --git a/src/test/bench.c b/src/test/bench.c
index f6c33626f2..5cbc072700 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Ordinarily defined in tor_main.c; this bit is just here to provide one
@@ -26,10 +26,9 @@ const char tor_git_revision[] = "";
#endif
#include "config.h"
-#ifdef CURVE25519_ENABLED
#include "crypto_curve25519.h"
#include "onion_ntor.h"
-#endif
+#include "crypto_ed25519.h"
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
static uint64_t nanostart;
@@ -79,6 +78,9 @@ perftime(void)
#define NANOCOUNT(start,end,iters) \
( ((double)((end)-(start))) / (iters) )
+#define MICROCOUNT(start,end,iters) \
+ ( NANOCOUNT((start), (end), (iters)) / 1000.0 )
+
/** Run AES performance benchmarks. */
static void
bench_aes(void)
@@ -162,7 +164,8 @@ bench_onion_TAP(void)
char key_out[CPATH_KEY_MATERIAL_LEN];
int s;
dh = crypto_dh_dup(dh_out);
- s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out));
+ s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out),
+ NULL);
crypto_dh_free(dh);
tor_assert(s == 0);
}
@@ -175,7 +178,6 @@ bench_onion_TAP(void)
crypto_pk_free(key2);
}
-#ifdef CURVE25519_ENABLED
static void
bench_onion_ntor(void)
{
@@ -222,7 +224,8 @@ bench_onion_ntor(void)
for (i = 0; i < iters; ++i) {
uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
int s;
- s = onion_skin_ntor_client_handshake(state, or, key_out, sizeof(key_out));
+ s = onion_skin_ntor_client_handshake(state, or, key_out, sizeof(key_out),
+ NULL);
tor_assert(s == 0);
}
end = perftime();
@@ -232,7 +235,63 @@ bench_onion_ntor(void)
ntor_handshake_state_free(state);
dimap_free(keymap, NULL);
}
-#endif
+
+static void
+bench_ed25519(void)
+{
+ uint64_t start, end;
+ const int iters = 1<<12;
+ int i;
+ const uint8_t msg[] = "but leaving, could not tell what they had heard";
+ ed25519_signature_t sig;
+ ed25519_keypair_t kp;
+ curve25519_keypair_t curve_kp;
+ ed25519_public_key_t pubkey_tmp;
+
+ ed25519_secret_key_generate(&kp.seckey, 0);
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ ed25519_public_key_generate(&kp.pubkey, &kp.seckey);
+ }
+ end = perftime();
+ printf("Generate public key: %.2f usec\n",
+ MICROCOUNT(start, end, iters));
+
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ ed25519_sign(&sig, msg, sizeof(msg), &kp);
+ }
+ end = perftime();
+ printf("Sign a short message: %.2f usec\n",
+ MICROCOUNT(start, end, iters));
+
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ ed25519_checksig(&sig, msg, sizeof(msg), &kp.pubkey);
+ }
+ end = perftime();
+ printf("Verify signature: %.2f usec\n",
+ MICROCOUNT(start, end, iters));
+
+ curve25519_keypair_generate(&curve_kp, 0);
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ ed25519_public_key_from_curve25519_public_key(&pubkey_tmp,
+ &curve_kp.pubkey, 1);
+ }
+ end = perftime();
+ printf("Convert public point from curve25519: %.2f usec\n",
+ MICROCOUNT(start, end, iters));
+
+ curve25519_keypair_generate(&curve_kp, 0);
+ start = perftime();
+ for (i = 0; i < iters; ++i) {
+ ed25519_public_blind(&pubkey_tmp, &kp.pubkey, msg);
+ }
+ end = perftime();
+ printf("Blind a public key: %.2f usec\n",
+ MICROCOUNT(start, end, iters));
+}
static void
bench_cell_aes(void)
@@ -512,9 +571,9 @@ static struct benchmark_t benchmarks[] = {
ENT(siphash),
ENT(aes),
ENT(onion_TAP),
-#ifdef CURVE25519_ENABLED
ENT(onion_ntor),
-#endif
+ ENT(ed25519),
+
ENT(cell_aes),
ENT(cell_ops),
ENT(dh),
@@ -569,7 +628,7 @@ main(int argc, const char **argv)
crypto_seed_rng(1);
crypto_init_siphash_key();
options = options_new();
- init_logging();
+ init_logging(1);
options->command = CMD_RUN_UNITTESTS;
options->DataDirectory = tor_strdup("");
options_init(options);
diff --git a/src/test/bt_test.py b/src/test/bt_test.py
index 8290509fa7..0afe797a6d 100755
--- a/src/test/bt_test.py
+++ b/src/test/bt_test.py
@@ -1,4 +1,4 @@
-# Copyright 2013, The Tor Project, Inc
+# Copyright 2013-2015, The Tor Project, Inc
# See LICENSE for licensing information
"""
diff --git a/src/test/ed25519_exts_ref.py b/src/test/ed25519_exts_ref.py
new file mode 100644
index 0000000000..d5a3a79910
--- /dev/null
+++ b/src/test/ed25519_exts_ref.py
@@ -0,0 +1,234 @@
+#!/usr/bin/python
+# Copyright 2014-2015, The Tor Project, Inc
+# See LICENSE for licensing information
+
+"""
+ Reference implementations for the ed25519 tweaks that Tor uses.
+
+ Includes self-tester and test vector generator.
+"""
+
+import slow_ed25519
+from slow_ed25519 import *
+
+import os
+import random
+import slownacl_curve25519
+import unittest
+import binascii
+import textwrap
+
+#define a synonym that doesn't look like 1
+ell = l
+
+# This replaces expmod above and makes it go a lot faster.
+slow_ed25519.expmod = pow
+
+def curve25519ToEd25519(c, sign):
+ u = decodeint(c)
+ y = ((u - 1) * inv(u + 1)) % q
+ x = xrecover(y)
+ if x & 1 != sign: x = q-x
+ return encodepoint([x,y])
+
+def blindESK(esk, param):
+ h = H("Derive temporary signing key" + param)
+ mult = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
+ s = decodeint(esk[:32])
+ s_prime = (s * mult) % ell
+ k = esk[32:]
+ assert(len(k) == 32)
+ k_prime = H("Derive temporary signing key hash input" + k)[:32]
+ return encodeint(s_prime) + k_prime
+
+def blindPK(pk, param):
+ h = H("Derive temporary signing key" + param)
+ mult = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
+ P = decodepoint(pk)
+ return encodepoint(scalarmult(P, mult))
+
+def expandSK(sk):
+ h = H(sk)
+ a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
+ k = ''.join([h[i] for i in range(b/8,b/4)])
+ assert len(k) == 32
+ return encodeint(a)+k
+
+def publickeyFromESK(h):
+ a = decodeint(h[:32])
+ A = scalarmult(B,a)
+ return encodepoint(A)
+
+def signatureWithESK(m,h,pk):
+ a = decodeint(h[:32])
+ r = Hint(''.join([h[i] for i in range(b/8,b/4)]) + m)
+ R = scalarmult(B,r)
+ S = (r + Hint(encodepoint(R) + pk + m) * a) % l
+ return encodepoint(R) + encodeint(S)
+
+def newSK():
+ return os.urandom(32)
+
+# ------------------------------------------------------------
+
+MSG = "This is extremely silly. But it is also incredibly serious business!"
+
+class SelfTest(unittest.TestCase):
+
+ def _testSignatures(self, esk, pk):
+ sig = signatureWithESK(MSG, esk, pk)
+ checkvalid(sig, MSG, pk)
+ bad = False
+ try:
+ checkvalid(sig, MSG*2, pk)
+ bad = True
+ except Exception:
+ pass
+
+ self.failIf(bad)
+
+ def testExpand(self):
+ sk = newSK()
+ pk = publickey(sk)
+ esk = expandSK(sk)
+ sig1 = signature(MSG, sk, pk)
+ sig2 = signatureWithESK(MSG, esk, pk)
+ self.assertEquals(sig1, sig2)
+
+ def testSignatures(self):
+ sk = newSK()
+ esk = expandSK(sk)
+ pk = publickeyFromESK(esk)
+ pk2 = publickey(sk)
+ self.assertEquals(pk, pk2)
+
+ self._testSignatures(esk, pk)
+
+ def testDerivation(self):
+ priv = slownacl_curve25519.Private()
+ pub = priv.get_public()
+
+ ed_pub0 = publickeyFromESK(priv.private)
+ sign = (ord(ed_pub0[31]) & 255) >> 7
+ ed_pub1 = curve25519ToEd25519(pub.public, sign)
+
+ self.assertEquals(ed_pub0, ed_pub1)
+
+ def testBlinding(self):
+ sk = newSK()
+ esk = expandSK(sk)
+ pk = publickeyFromESK(esk)
+ param = os.urandom(32)
+ besk = blindESK(esk, param)
+ bpk = blindPK(pk, param)
+ bpk2 = publickeyFromESK(besk)
+ self.assertEquals(bpk, bpk2)
+
+ self._testSignatures(besk, bpk)
+
+# ------------------------------------------------------------
+
+# From pprint.pprint([ binascii.b2a_hex(os.urandom(32)) for _ in xrange(8) ])
+RAND_INPUTS = [
+ '26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36',
+ 'fba7a5366b5cb98c2667a18783f5cf8f4f8d1a2ce939ad22a6e685edde85128d',
+ '67e3aa7a14fac8445d15e45e38a523481a69ae35513c9e4143eb1c2196729a0e',
+ 'd51385942033a76dc17f089a59e6a5a7fe80d9c526ae8ddd8c3a506b99d3d0a6',
+ '5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb433',
+ 'eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86',
+ '4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d',
+ 'c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b']
+
+# From pprint.pprint([ binascii.b2a_hex(os.urandom(32)) for _ in xrange(8) ])
+BLINDING_PARAMS = [
+ '54a513898b471d1d448a2f3c55c1de2c0ef718c447b04497eeb999ed32027823',
+ '831e9b5325b5d31b7ae6197e9c7a7baf2ec361e08248bce055908971047a2347',
+ 'ac78a1d46faf3bfbbdc5af5f053dc6dc9023ed78236bec1760dadfd0b2603760',
+ 'f9c84dc0ac31571507993df94da1b3d28684a12ad14e67d0a068aba5c53019fc',
+ 'b1fe79d1dec9bc108df69f6612c72812755751f21ecc5af99663b30be8b9081f',
+ '81f1512b63ab5fb5c1711a4ec83d379c420574aedffa8c3368e1c3989a3a0084',
+ '97f45142597c473a4b0e9a12d64561133ad9e1155fe5a9807fe6af8a93557818',
+ '3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0']
+
+PREFIX = "ED25519_"
+
+def writeArray(name, array):
+ print "static const char *{prefix}{name}[] = {{".format(
+ prefix=PREFIX,name=name)
+ for a in array:
+ h = binascii.b2a_hex(a)
+ if len(h) > 70:
+ h1 = h[:70]
+ h2 = h[70:]
+ print ' "{0}"\n "{1}",'.format(h1,h2)
+ else:
+ print ' "{0}",'.format(h)
+ print "};\n"
+
+def comment(text, initial="/**"):
+ print initial
+ print textwrap.fill(text,initial_indent=" * ",subsequent_indent=" * ")
+ print " */"
+
+def makeTestVectors():
+ comment("""Test vectors for our ed25519 implementation and related
+ functions. These were automatically generated by the
+ ed25519_exts_ref.py script.""", initial="/*")
+
+
+ comment("""Secret key seeds used as inputs for the ed25519 test vectors.
+ Randomly generated. """)
+ secretKeys = [ binascii.a2b_hex(r) for r in RAND_INPUTS ]
+ writeArray("SECRET_KEYS", secretKeys)
+
+ comment("""Secret ed25519 keys after expansion from seeds. This is how Tor
+ represents them internally.""")
+ expandedSecretKeys = [ expandSK(sk) for sk in secretKeys ]
+ writeArray("EXPANDED_SECRET_KEYS", expandedSecretKeys)
+
+ comment("""Public keys derived from the above secret keys""")
+ publicKeys = [ publickey(sk) for sk in secretKeys ]
+ writeArray("PUBLIC_KEYS", publicKeys)
+
+ comment("""The curve25519 public keys from which the ed25519 keys can be
+ derived. Used to test our 'derive ed25519 from curve25519'
+ code.""")
+ writeArray("CURVE25519_PUBLIC_KEYS",
+ (slownacl_curve25519.smult_curve25519_base(sk[:32])
+ for sk in expandedSecretKeys))
+
+ comment("""Parameters used for key blinding tests. Randomly generated.""")
+ blindingParams = [ binascii.a2b_hex(r) for r in BLINDING_PARAMS ]
+ writeArray("BLINDING_PARAMS", blindingParams)
+
+ comment("""Blinded secret keys for testing key blinding. The nth blinded
+ key corresponds to the nth secret key blidned with the nth
+ blinding parameter.""")
+ writeArray("BLINDED_SECRET_KEYS",
+ (blindESK(expandSK(sk), bp)
+ for sk,bp in zip(secretKeys,blindingParams)))
+
+ comment("""Blinded public keys for testing key blinding. The nth blinded
+ key corresponds to the nth public key blidned with the nth
+ blinding parameter.""")
+ writeArray("BLINDED_PUBLIC_KEYS",
+ (blindPK(pk, bp) for pk,bp in zip(publicKeys,blindingParams)))
+
+ comment("""Signatures of the public keys, made with their corresponding
+ secret keys.""")
+ writeArray("SELF_SIGNATURES",
+ (signature(pk, sk, pk) for pk,sk in zip(publicKeys,secretKeys)))
+
+
+
+if __name__ == '__main__':
+ import sys
+ if len(sys.argv) == 1 or sys.argv[1] not in ("SelfTest", "MakeVectors"):
+ print "You should specify one of 'SelfTest' or 'MakeVectors'"
+ sys.exit(1)
+ if sys.argv[1] == 'SelfTest':
+ unittest.main()
+ else:
+ makeTestVectors()
+
+
diff --git a/src/test/ed25519_vectors.inc b/src/test/ed25519_vectors.inc
new file mode 100644
index 0000000000..760bafb971
--- /dev/null
+++ b/src/test/ed25519_vectors.inc
@@ -0,0 +1,150 @@
+/*
+ * Test vectors for our ed25519 implementation and related
+ * functions. These were automatically generated by the
+ * ed25519_exts_ref.py script.
+ */
+/**
+ * Secret key seeds used as inputs for the ed25519 test vectors.
+ * Randomly generated.
+ */
+static const char *ED25519_SECRET_KEYS[] = {
+ "26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36",
+ "fba7a5366b5cb98c2667a18783f5cf8f4f8d1a2ce939ad22a6e685edde85128d",
+ "67e3aa7a14fac8445d15e45e38a523481a69ae35513c9e4143eb1c2196729a0e",
+ "d51385942033a76dc17f089a59e6a5a7fe80d9c526ae8ddd8c3a506b99d3d0a6",
+ "5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb433",
+ "eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86",
+ "4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d",
+ "c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b",
+};
+
+/**
+ * Secret ed25519 keys after expansion from seeds. This is how Tor
+ * represents them internally.
+ */
+static const char *ED25519_EXPANDED_SECRET_KEYS[] = {
+ "c0a4de23cc64392d85aa1da82b3defddbea946d13bb053bf8489fa9296281f495022f1"
+ "f7ec0dcf52f07d4c7965c4eaed121d5d88d0a8ff546b06116a20e97755",
+ "18a8a69a06790dac778e882f7e868baacfa12521a5c058f5194f3a729184514a2a656f"
+ "e7799c3e41f43d756da8d9cd47a061316cfe6147e23ea2f90d1ca45f30",
+ "58d84f8862d2ecfa30eb491a81c36d05b574310ea69dae18ecb57e992a896656b98218"
+ "7ee96c15bf4caeeab2d0b0ae4cd0b8d17470fc7efa98bb26428f4ef36d",
+ "50702d20b3550c6e16033db5ad4fba16436f1ecc7485be6af62b0732ceb5d173c47ccd"
+ "9d044b6ea99dd99256adcc9c62191be194e7cb1a5b58ddcec85d876a2b",
+ "7077464c864c2ed5ed21c9916dc3b3ba6256f8b742fec67658d8d233dadc8d5a7a82c3"
+ "71083cc86892c2c8782dda2a09b6baf016aec51b689183ae59ce932ff2",
+ "8883c1387a6c86fc0bd7b9f157b4e4cd83f6885bf55e2706d2235d4527a2f05311a359"
+ "5953282e436df0349e1bb313a19b3ddbf7a7b91ecce8a2c34abadb38b3",
+ "186791ac8d03a3ac8efed6ac360467edd5a3bed2d02b3be713ddd5be53b3287ee37436"
+ "e5fd7ac43794394507ad440ecfdf59c4c255f19b768a273109e06d7d8e",
+ "b003077c1e52a62308eef7950b2d532e1d4a7eea50ad22d8ac11b892851f1c40ffb9c9"
+ "ff8dcd0c6c233f665a2e176324d92416bfcfcd1f787424c0c667452d86",
+};
+
+/**
+ * Public keys derived from the above secret keys
+ */
+static const char *ED25519_PUBLIC_KEYS[] = {
+ "c2247870536a192d142d056abefca68d6193158e7c1a59c1654c954eccaff894",
+ "1519a3b15816a1aafab0b213892026ebf5c0dc232c58b21088d88cb90e9b940d",
+ "081faa81992e360ea22c06af1aba096e7a73f1c665bc8b3e4e531c46455fd1dd",
+ "73cfa1189a723aad7966137cbffa35140bb40d7e16eae4c40b79b5f0360dd65a",
+ "66c1a77104d86461b6f98f73acf3cd229c80624495d2d74d6fda1e940080a96b",
+ "d21c294db0e64cb2d8976625786ede1d9754186ae8197a64d72f68c792eecc19",
+ "c4d58b4cf85a348ff3d410dd936fa460c4f18da962c01b1963792b9dcc8a6ea6",
+ "95126f14d86494020665face03f2d42ee2b312a85bc729903eb17522954a1c4a",
+};
+
+/**
+ * The curve25519 public keys from which the ed25519 keys can be
+ * derived. Used to test our 'derive ed25519 from curve25519'
+ * code.
+ */
+static const char *ED25519_CURVE25519_PUBLIC_KEYS[] = {
+ "17ba77846e04c7ee5ca17cade774ac1884408f9701f439d4df32cbd8736c6a1f",
+ "022be2124bc1899a78ba2b4167d191af3b59cadf94f0382bc31ce183a117f161",
+ "bf4fd38ef22f718f03c0a12ba5127bd1e3afd494793753f519728b29cc577571",
+ "56c493e490261cef31633efd2461d2b896908e90459e4eecde950a895aef681d",
+ "089675a3e8ff2a7d8b2844a79269c95b7f97a4b8b5ea0cbeec669c6f2dea9b39",
+ "59e20dcb691c4a345fe86c8a79ac817e5b514d84bbf0512a842a08e43f7f087e",
+ "9e43b820b320eda35f66f122c155b2bf8e2192c468617b7115bf067d19e08369",
+ "861f33296cb57f8f01e4a5e8a7e5d5d7043a6247586ab36dea8a1a3c4403ee30",
+};
+
+/**
+ * Parameters used for key blinding tests. Randomly generated.
+ */
+static const char *ED25519_BLINDING_PARAMS[] = {
+ "54a513898b471d1d448a2f3c55c1de2c0ef718c447b04497eeb999ed32027823",
+ "831e9b5325b5d31b7ae6197e9c7a7baf2ec361e08248bce055908971047a2347",
+ "ac78a1d46faf3bfbbdc5af5f053dc6dc9023ed78236bec1760dadfd0b2603760",
+ "f9c84dc0ac31571507993df94da1b3d28684a12ad14e67d0a068aba5c53019fc",
+ "b1fe79d1dec9bc108df69f6612c72812755751f21ecc5af99663b30be8b9081f",
+ "81f1512b63ab5fb5c1711a4ec83d379c420574aedffa8c3368e1c3989a3a0084",
+ "97f45142597c473a4b0e9a12d64561133ad9e1155fe5a9807fe6af8a93557818",
+ "3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0",
+};
+
+/**
+ * Blinded secret keys for testing key blinding. The nth blinded
+ * key corresponds to the nth secret key blidned with the nth
+ * blinding parameter.
+ */
+static const char *ED25519_BLINDED_SECRET_KEYS[] = {
+ "014e83abadb2ca9a27e0ffe23920333d817729f48700e97656ec2823d694050e171d43"
+ "f24e3f53e70ec7ac280044ac77d4942dee5d6807118a59bdf3ee647e89",
+ "fad8cca0b4335847795288b1452508752b253e64e6c7c78d4a02dbbd7d46aa0eb8ceff"
+ "20dfcf53eb52b891fc078c934efbf0353af7242e7dc51bb32a093afa29",
+ "116eb0ae0a4a91763365bdf86db427b00862db448487808788cc339ac10e5e089217f5"
+ "2e92797462bd890fc274672e05c98f2c82970d640084781334aae0f940",
+ "bd1fbb0ee5acddc4adbcf5f33e95d9445f40326ce579fdd764a24483a9ccb20f509ece"
+ "e77082ce088f7c19d5a00e955eeef8df6fa41686abc1030c2d76807733",
+ "237f5345cefe8573ce9fa7e216381a1172796c9e3f70668ab503b1352952530fb57b95"
+ "a440570659a440a3e4771465022a8e67af86bdf2d0990c54e7bb87ff9a",
+ "ba8ff23bc4ad2b739e1ccffc9fbc7837053ea81cdfdb15073f56411cfbae1d0ec492fc"
+ "87d5ec2a1b185ca5a40541fdef0b1e128fd5c2380c888bfa924711bcab",
+ "0fa68f969de038c7a90a4a74ee6167c77582006f2dedecc1956501ba6b6fb10391b476"
+ "8f8e556d78f4bdcb9a13b6f6066fe81d3134ae965dc48cd0785b3af2b8",
+ "deaa3456d1c21944d5dcd361a646858c6cf9336b0a6851d925717eb1ae186902053d9c"
+ "00c81e1331c06ab50087be8cfc7dc11691b132614474f1aa9c2503cccd",
+};
+
+/**
+ * Blinded public keys for testing key blinding. The nth blinded
+ * key corresponds to the nth public key blidned with the nth
+ * blinding parameter.
+ */
+static const char *ED25519_BLINDED_PUBLIC_KEYS[] = {
+ "722d6da6348e618967ef782e71061e27163a8b35f21856475d9d2023f65b6495",
+ "1dffa0586da6cbfcff2024eedf4fc6c818242d9a82dbbe635d6da1b975a1160d",
+ "5ed81f98fed5a6acda4ea6da2c34fab0ab359d950c510c256473f1f33ff438b4",
+ "6e6f92a54fb282120c46d9603df41135f025bc1f58f283809d04be96aeb04040",
+ "cda236f28edc4c7e02d18007b8dab49d669265b0f7aefb1824d7cc8e73a2cd63",
+ "367b03b17b67ca7329b89a520bdab91782402a41cd67264e34b5541a4b3f875b",
+ "8d486b03ac4e3b486b7a1d563706c7fdac75aee789a7cf6f22789eedeff61a31",
+ "9f297ff0aa2ceda91c5ab1b6446f12533d145940de6d850dc323417afde0cb78",
+};
+
+/**
+ * Signatures of the public keys, made with their corresponding
+ * secret keys.
+ */
+static const char *ED25519_SELF_SIGNATURES[] = {
+ "d23188eac3773a316d46006fa59c095060be8b1a23582a0dd99002a82a0662bd246d84"
+ "49e172e04c5f46ac0d1404cebe4aabd8a75a1457aa06cae41f3334f104",
+ "3a785ac1201c97ee5f6f0d99323960d5f264c7825e61aa7cc81262f15bef75eb4fa572"
+ "3add9b9d45b12311b6d403eb3ac79ff8e4e631fc3cd51e4ad2185b200b",
+ "cf431fd0416bfbd20c9d95ef9b723e2acddffb33900edc72195dea95965d52d888d30b"
+ "7b8a677c0bd8ae1417b1e1a0ec6700deadd5d8b54b6689275e04a04509",
+ "2375380cd72d1a6c642aeddff862be8a5804b916acb72c02d9ed052c1561881aa658a5"
+ "af856fcd6d43113e42f698cd6687c99efeef7f2ce045824440d26c5d00",
+ "2385a472f599ca965bbe4d610e391cdeabeba9c336694b0d6249e551458280be122c24"
+ "41dd9746a81bbfb9cd619364bab0df37ff4ceb7aefd24469c39d3bc508",
+ "e500cd0b8cfff35442f88008d894f3a2fa26ef7d3a0ca5714ae0d3e2d40caae58ba7cd"
+ "f69dd126994dad6be536fcda846d89dd8138d1683cc144c8853dce7607",
+ "d187b9e334b0050154de10bf69b3e4208a584e1a65015ec28b14bcc252cf84b8baa9c9"
+ "4867daa60f2a82d09ba9652d41e8dde292b624afc8d2c26441b95e3c0e",
+ "815213640a643d198bd056e02bba74e1c8d2d931643e84497adf3347eb485079c9afe0"
+ "afce9284cdc084946b561abbb214f1304ca11228ff82702185cf28f60d",
+};
+
diff --git a/src/test/example_extrainfo.inc b/src/test/example_extrainfo.inc
new file mode 100644
index 0000000000..606279a765
--- /dev/null
+++ b/src/test/example_extrainfo.inc
@@ -0,0 +1,192 @@
+static const char EX_EI_MINIMAL[] =
+ "extra-info bob 3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "K5GAkVjpUlofL78NIOE1VDxFn8yYbHK50rVuZG2HxqG/727bon+uMprv4MHjfDcP\n"
+ "V3l9u1uUdGiUPOl8j+hRNw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi\n"
+ "zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2R3EA=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_EI_MINIMAL_FP[] = "3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B";
+static const char EX_EI_MINIMAL_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALSppIF3t3wOAm4fzxRvK+q/wh1gGAWwS0JEn8d+c/x+rt1oQabGkqsB\n"
+ "GU6rz1z1AN02W0P2+EcyJQVBjGR3gHQNoDGx0KIdnr3caGAw3XmQXrJLPaViEk28\n"
+ "RJMxx6umpP27YKSyEMHgVTDXblKImT0mE7fVOx8tD0EWRYazmp4NAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
+
+static const char EX_EI_MAXIMAL[] =
+ "extra-info bob FF8248FE780A7236D3FA5D62DEA642055135F942\n"
+ "published 2014-10-05 20:07:00\n"
+ "opt foobarbaz\n"
+ "read-history 900 1,2,3\n"
+ "write-history 900 1,2,3\n"
+ "dirreq-v2-ips 1\n"
+ "dirreq-v3-ips 100\n"
+ "dirreq-v3-reqs blahblah\n"
+ "dirreq-v2-share blahblah\n"
+ "dirreq-v3-share blahblah\n"
+ "dirreq-v2-resp djfkdj\n"
+ "dirreq-v3-resp djfkdj\n"
+ "dirreq-v2-direct-dl djfkdj\n"
+ "dirreq-v3-direct-dl djfkdj\n"
+ "dirreq-v2-tunneled-dl djfkdj\n"
+ "dirreq-v3-tunneled-dl djfkdj\n"
+ "dirreq-stats-end foobar\n"
+ "entry-ips jfsdfds\n"
+ "entry-stats-end ksdflkjfdkf\n"
+ "cell-stats-end FOO\n"
+ "cell-processed-cells FOO\n"
+ "cell-queued-cells FOO\n"
+ "cell-time-in-queue FOO\n"
+ "cell-circuits-per-decile FOO\n"
+ "exit-stats-end FOO\n"
+ "exit-kibibytes-written FOO\n"
+ "exit-kibibytes-read FOO\n"
+ "exit-streams-opened FOO\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "ZO79bLlWVNIruCnWW9duDcOKydPWbL5DfrpUv5IRLF4MMFoacMUdJPDUs9e+wY2C\n"
+ "zndHe6i2JK7yKJj+uCOSC8cx61OLG+kVxMLJ/qhA4H5thrYb+GpzMKwbHzQc3PTH\n"
+ "zHRzj041iWXTL7/DMaQlpJOBoac/wTSIKzoV2B00jBw=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_EI_MAXIMAL_FP[] = "FF8248FE780A7236D3FA5D62DEA642055135F942";
+static const char EX_EI_MAXIMAL_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANSpkYhHUW1EqodY4d3JRbvEM1vjjR/vEE8gjONiJ5t2Sten53jzt8bh\n"
+ "8/VJn7pQGs8zR5CIxCw4P68xMtZJJedS3hhjqubheOE/yW1DtpkiCf+zVEaLpeA8\n"
+ "fYQChkRICnR/BZd4W9bbohLVII5ym2PaJt2ihB3FeVZIsGXm4wxhAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
+
+static const char EX_EI_BAD_SIG1[] =
+ "extra-info bob 3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "K5GAkVjpUlofL78NIOE1VDxFn8yYbHK50rVuZG2HxqG/727bon+uMprv4MHjfDcP\n"
+ "V3l9u1uUdGiUPOl8j+hXXw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi\n"
+ "zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2R3EA=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_EI_BAD_SIG2[] =
+ "extra-info bob 3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B\n"
+ "published 2014-10-06 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "K5GAkVjpUlofL78NIOE1VDxFn8yYbHK50rVuZG2HxqG/727bon+uMprv4MHjfDcP\n"
+ "V3l9u1uUdGiUPOl8j+hRNw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi\n"
+ "zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2R3EA=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_EI_BAD_SIG3[] =
+ "extra-info bob 3E1B2DC141F2B7C6A0F3C4ED9A14A9C35762E24B\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "K5GAkVjpUlofL78NIOE1VDxFn8yYbHK50rVuZG2HxqG/727bon+uMprv4MHjfDcP\n"
+ "V3l9u1uUdGiUPOl8j+hRNw4z/ODeCj/24r2+L32MTjyfUhK49Ld2IlK9iZKlgKYi\n"
+ "zyoatxdAjU8Xc5WPX692HO4/R9CGLsUfYcEEFU2=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_EI_BAD_FP[] =
+ "extra-info bob C34293303F0F1E42CB14E593717B834E8E53797D8888\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "IDA8ryUYeMx7+Au/xQmX7Y8fXksoHUOXmePND2JYM4rPfishQJ1LpQ15KrolOZDH\n"
+ "FVIk3RmCefNlJeS1/UgWPcU8u2nGw1YQuRBHF4ViTmZ0OevI1pTsSApl4+oIx2dy\n"
+ "DGgCQmKfMbaOixIK8Ioh1Z2NUfMkjbUUE2WWgFTAsac=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_EI_BAD_FP_FP[] = "C34293303F0F1E42CB14E593717B834E8E53797D";
+static const char EX_EI_BAD_FP_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKXMSbif4fG+BW/5lIq5V1tMRondIUfKiNizp0E6EcBw5LvYfQV6zrj8\n"
+ "HmMFbB/WGf9XGVMxIBzxzeQBRvCQJh+0QH7+ju5/isIHJZsACMILepr6ywmCcjVU\n"
+ "iYRtC8zGQLqfkf2cNoo7AhcI5i/YzyW2u1zmbPX5J+8sUErfxydbAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
+
+static const char EX_EI_BAD_NICKNAME[] =
+ "extra-info bobhasaverylongnameandidontthinkweshouldlethim A4EA2389A52459B3F7C7121A46012F098BDFC2A4\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "e2wLJFThRMGawxKrQPuH2XCLek/LJsg4XOB8waAjE0xdHOrzjur9x1jIxy7DVU6t\n"
+ "z1edbIoL24qucMJvFy2xjSQhFRX4OsyNc0nWr3LfJnTW9aEmxuwXM+mltUD2uFN1\n"
+ "2vYOIQjUmJwS2yfeSKnhXEl2PWVUmgzYL3r4S5kHco4=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_EI_BAD_NICKNAME_FP[] = "A4EA2389A52459B3F7C7121A46012F098BDFC2A4";
+static const char EX_EI_BAD_NICKNAME_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKfq7oxD1kMu1+zeG2UVXN4vOu6FDp0V/olA3ttmXpUCgCiBxWTgtwNl\n"
+ "nPf0HcKMaCp/0D9XrbhvIoOsg0OTf1TcJfGsA/zPG7jrWYa4xhD50KYvty9EINK9\n"
+ "/UBWNSyXCFDMqnddb/LZ8+VgttmxfYkpeRzSSmDijN3RbOvYJhhBAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
+
+const char EX_EI_BAD_TOKENS[] =
+ "extra-info bob 6F314FB01A31162BD5E473D4977AC570DC5B86BB\n"
+ "published 2014-10-05 20:07:00\n"
+ "published 2014-10-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "lhRIafrkKoQmnUoBLiq4XC8XKXrleGJZ5vefkLcgjOJ5IffsvVdIA7Vqq/ISbPrG\n"
+ "b/Zs0sJNL6naHPxJBglgHJqksSyiYHaeOetXg2Rb+vZ1v2S5BrVgk1nPMDhyIzqc\n"
+ "zU7eCxFf/1sXKtWlEKxGdX4LmVfnIln5aI31Bc4xRrE=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+const char EX_EI_BAD_TOKENS_FP[] = "6F314FB01A31162BD5E473D4977AC570DC5B86BB";
+const char EX_EI_BAD_TOKENS_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL7Z8tz45Tb4tnEFS2sAyjubBV/giSfZdmXRkDV8Jo4xqWqhWFJn7+zN\n"
+ "AXBWBThGeVH2WXrpz5seNJXgZJPxMTMsrnSCGcRXZw0Npti2MkLuQ6+prZa+OPwE\n"
+ "OyC6jivtAaY/o9iYQjDC2avLXD3N4LvoygyF418KnNcjbzuFygffAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
+
+static const char EX_EI_BAD_START[] =
+ "published 2014-10-05 20:07:00\n"
+ "extra-info bob 5CCCACE71A9BDB5E8E0C942AB3407452350434C0\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "BOiWgexqCAMZ8uyJ7jwBwRkz7Ox8cT4BImkmkV3bQiZgcWvPiYA3EnCm2ye48Ldg\n"
+ "zBST2p6zJM5o4MEDYGMxfViS86Abj/z7DOY1gtLhjmAaVjIIpXc3koxEZtzCecqy\n"
+ "JQz6xEg9/KoEuoT0DRrfYQ+KtQfzBDWrotfOvEa1rvc=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_EI_BAD_START_FP[] = "5CCCACE71A9BDB5E8E0C942AB3407452350434C0";
+static const char EX_EI_BAD_START_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAK2OCIfM6Cin/lq99Z3w9tl6HeyGlkBZu9MQEPHxqGIHTq78lIC1UkrC\n"
+ "6NTqlrHBV9dmfzdwJn4GgMWsCZafL0FPIH3HNyNKUxLgyjixyKljHx2rfErSfOxI\n"
+ "bMoOGBKv7m1EZZ0O5uG9ly9MBiNGdJyLdlnVvH7wSCnYciizpO4lAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
+
+static const char EX_EI_BAD_PUBLISHED[] =
+ "extra-info bob E67C477E3536BDE348BD407426D9679E5AE0BC16\n"
+ "published 2014-99-05 20:07:00\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "l45IziBaXRKIjPAIUogMFNjQgH6k6Vm0+6r5+oByr4sP+B3ufNdUA6+WqBs43F0Z\n"
+ "IqcJiT9nFn0DuNd/liOyOCixppDLx5h5NrhoGqcT3ySADEEXhzjlmc35TI3YBNVO\n"
+ "v98fotmwIEg9YRWVGPg6XuIn2PRyiboFyjUpaYGCV0Q=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_EI_BAD_PUBLISHED_FP[] = "E67C477E3536BDE348BD407426D9679E5AE0BC16";
+static const char EX_EI_BAD_PUBLISHED_KEY[] =
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL7q8GEI18iv8Fo0QbNHmFatQ2FNacalPldpmKUdMJYEVZtdOR0nhcrY\n"
+ "BvG6303md3INygg+KP49RvWEJR/cU4RZ9QfHpORxH2OocMyRedw2rLex2E7jNNSi\n"
+ "52yd1sHFYI8ZQ4aff+ZHUjJUGKRyqpbc8okVbq/Rl7vug0dd12eHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n";
diff --git a/src/test/failing_routerdescs.inc b/src/test/failing_routerdescs.inc
new file mode 100644
index 0000000000..b49d59fd8a
--- /dev/null
+++ b/src/test/failing_routerdescs.inc
@@ -0,0 +1,668 @@
+/* This one actually succeeds */
+static const char EX_RI_MINIMAL[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAObzT4opT9uaThByupbb96tYxVpGxzL9CRPKUcU0beGpHyognD9USHWc\n"
+ "SpSpKfBL5P3xr2i/XTs34M4UTbT9PE7bVyxv7RD/BZmI4gc8R3PMU77xxbpEU5bK\n"
+ "LF3QUPpuB88m/2fXUGgMNVDc5MIq6pod2NRoDpeU7WA8T3ewXzK5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM1QKsQiup9DNMCgNeE2FkAhCWzpMZKCn1nNlZbDGfE3Z22ex6bdWWY6\n"
+ "ocEZ3JZDsZsnaZrdYxrL3Mquq7MbHdfx90EdlOvDRP1SAIbZ55mLR77fZTu4BKd/\n"
+ "h9BC6I26uZE0QavFq3+BhoVVhVn5Mqv05nR9CeUMSSZLxw/RJm4DAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Ft/y3JXowjItgfTHwYcZzuUgXrskluoINW5sr+GQoNYE2F4sT8o0tBBJwqJ6FwKd\n"
+ "fkIprv9UXqkv5iY+pXSYSI12mY1K5GMNkXiObk46NjuoNNP9l8oidhO6eNfcE+k3\n"
+ "CRIYS4FbBaD0fWUSwgMuo0Bp83/Wzp3B9ytEBh0/624=\n"
+ "-----END SIGNATURE-----\n";
+
+/* So does this, and it's bigger. */
+static const char EX_RI_MAXIMAL[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANNI56H+b7SW5LMzvXyY5NJzXszsHZZ4O1CPm4CePhBsAz1r0s1JYJ1F\n"
+ "Anrc0mEcLtmj0c5+HnhPBNrfpjO6G94Wp3NZMVykHDhfNVDBRyFZMroG8/GlysYB\n"
+ "MQPGQYR0xBgiuclNHoyk/vygQhZekumamu2O86EIPcfg9LhGIgEbAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALvuNVSmg6R9USFbQcNbRjMCJAV0Rwdv0DlS6Rl02ibJgb01G7v391xE\n"
+ "d9Njzgf93n8gOrE195bkUbvS6k/DM3HFGgArq6q9AZ2LTbu3KbAYy1YPsSIh07kB\n"
+ "/8kkvRRGx37X9WGZU3j5VUEuzqI//xDE9lbanlnnFXpnb6ymehDJAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject 127.0.0.1:*\n"
+ "accept *:80\n"
+ "reject *:*\n"
+ "ipv6-policy accept 80,100,101\n"
+ "ntor-onion-key s7rSohmz9SXn8WWh1EefTHIsWePthsEntQi0WL+ScVw\n"
+ "uptime 1000\n"
+ "hibernating 0\n"
+ "unrecognized-keywords are just dandy in this format\n"
+ "platform Tor 0.2.4.23 on a Banana PC Jr 6000 Series\n"
+ "contact O.W.Jones\n"
+ "fingerprint CC43 DC8E 8C9E 3E6D 59CD 0399 2491 0C8C E1E4 50D2\n"
+ "read-history 900 1,2,3,4\n"
+ "write-history 900 1,2,3,4\n"
+ "extra-info-digest AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
+ "hidden-service-dir\n"
+ "allow-single-hop-exits\n"
+ "family $AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n"
+ "caches-extra-info\n"
+ "or-address [::1:2:3:4]:9999\n"
+ "or-address 127.0.0.99:10000\n"
+ "opt fred is a fine router\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "x5cxL2h2UsEKk2OVnCTxOF8a89HAe/HwQnSlrBy8+l0YdVCcePDJhm1WyWU7ToHZ\n"
+ "K8auwreuw+u/n14sQHPYrM9NQE689hP4LC9AYOnrCnMHysfVqKuou+DSKYYRgs0D\n"
+ "ySCmJ9p+xekfmms+JBmS5o5DVo48VGlG0VksegoB264=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+/* I've messed with 12 bits of the signature on this one */
+static const char EX_RI_BAD_SIG1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAObzT4opT9uaThByupbb96tYxVpGxzL9CRPKUcU0beGpHyognD9USHWc\n"
+ "SpSpKfBL5P3xr2i/XTs34M4UTbT9PE7bVyxv7RD/BZmI4gc8R3PMU77xxbpEU5bK\n"
+ "LF3QUPpuB88m/2fXUGgMNVDc5MIq6pod2NRoDpeU7WA8T3ewXzK5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM1QKsQiup9DNMCgNeE2FkAhCWzpMZKCn1nNlZbDGfE3Z22ex6bdWWY6\n"
+ "ocEZ3JZDsZsnaZrdYxrL3Mquq7MbHdfx90EdlOvDRP1SAIbZ55mLR77fZTu4BKd/\n"
+ "h9BC6I26uZE0QavFq3+BhoVVhVn5Mqv05nR9CeUMSSZLxw/RJm4DAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Ft/y3JXowjItgfTHwYcZzuUgXrskluoINW5sr+GQoNYE2F4sT8o0tBBJwqJ6FwKd\n"
+ "fkIprv9UXqkv5iY+pXSYXX12mY1K5GMNkXiObk46NjuoNNP9l8oidhO6eNfcE+k3\n"
+ "CRIYS4FbBaD0fWUSwgMuo0Bp83/Wzp3B9ytEBh0/624=\n"
+ "-----END SIGNATURE-----\n";
+
+/* This is a good signature of the wrong data: I changed 'published' */
+static const char EX_RI_BAD_SIG2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAObzT4opT9uaThByupbb96tYxVpGxzL9CRPKUcU0beGpHyognD9USHWc\n"
+ "SpSpKfBL5P3xr2i/XTs34M4UTbT9PE7bVyxv7RD/BZmI4gc8R3PMU77xxbpEU5bK\n"
+ "LF3QUPpuB88m/2fXUGgMNVDc5MIq6pod2NRoDpeU7WA8T3ewXzK5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM1QKsQiup9DNMCgNeE2FkAhCWzpMZKCn1nNlZbDGfE3Z22ex6bdWWY6\n"
+ "ocEZ3JZDsZsnaZrdYxrL3Mquq7MbHdfx90EdlOvDRP1SAIbZ55mLR77fZTu4BKd/\n"
+ "h9BC6I26uZE0QavFq3+BhoVVhVn5Mqv05nR9CeUMSSZLxw/RJm4DAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:01\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Ft/y3JXowjItgfTHwYcZzuUgXrskluoINW5sr+GQoNYE2F4sT8o0tBBJwqJ6FwKd\n"
+ "fkIprv9UXqkv5iY+pXSYSI12mY1K5GMNkXiObk46NjuoNNP9l8oidhO6eNfcE+k3\n"
+ "CRIYS4FbBaD0fWUSwgMuo0Bp83/Wzp3B9ytEBh0/624=\n"
+ "-----END SIGNATURE-----\n";
+
+/* This one will fail while tokenizing the first line. */
+static const char EX_RI_BAD_TOKENS[] =
+ "router bob\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANGCgvZc+JRtAzuzk3gBD2rH9SHrXzjJ1wqdU3tLKr7FamKCMI2pLwSA\n"
+ "FZUpTuSqB9wJ/iVcYws+/kA3FjLqgPtzJFI0SVLvQcz5oIC1rEWpuP6t88duMlO9\n"
+ "flOUzmYu29sBffrXkQr8pesYvakyXArOJVeRR7fSvouneV5aDYWrAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAML+pYZoYc+whKLijupd63xn0gzlEQqe7k07x/lWMqWFT37FfG6YeNr5\n"
+ "fpFoo77FDfuFaL+VfPfI8i88g157hcPKBVX6OyRH54+l5By0tN91S0H+abXjXQpv\n"
+ "U/Bvmul+5QpUeVJa1nPg71HRIauoDnBNexUQ7Xf/Bwb2xCt+IJ6DAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "tbxtYYzyVqi6w6jz1k8NPjFvZaSNR0WzixVTTvKKGoMPx/6+Z8QAFK1ILzRUVucB\n"
+ "nRhmZMFaPr3vREMErLRE47ODAzwoBCE9C+vYFvROhgfzuQ3cYXla+4sMaRXYZzjH\n"
+ "PQ82bTwvSbHsR8fTTgePD/Ac082WxXTGpx6HOLBfNsQ=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_RI_BAD_PUBLISHED[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMoipSwZgTG6SpSOm6ENbyALS1Ljqqa1LSGmtHSRfGYgUQGWZXERXKQj\n"
+ "P5ql6o7EbGr1wnispGW/KB8Age09jGDvd/oGhQ9TDFluhLZon3obkZSFw7f9iA7Q\n"
+ "s29rNxoeXXLZVyS7+sux70b8x2Dt4CeG8GA8nQLljy1euwU+qYYJAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPzfzQ+2WFMUvnB3z0xD+zwczWcFyYYNW8Lj7/aRGSNN2DICp5uzSjKq\n"
+ "qkYQ+C8jG21+MR2PE+ZBmq6CL5mvlFKlWKouXUlN7BejwWf2gw0UYag0SYctae1b\n"
+ "bu8NuUEvdeGWg5Odgs+abH7U9S0hEtjKrmE5vvJS5L841IcaPLCFAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 99:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "G92pnwCIXGJ9Q0fI9y4m/fHpWCsD0Hnk81/6T4TmRH3jt77fc0uRdomUOC5id4kz\n"
+ "J2M4vqXwRs5OK+eaPbtxf8Yv6FPmB3OBNCIhwNHIIqzKQStHUhPxD3P6j8uJFwot\n"
+ "/CNGciDN+owZ2DzwrXpszDfzcyp/nmwhApbi3W601vY=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+/* Bandwidth field isn't an integer. */
+static const char EX_RI_BAD_BANDWIDTH[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAN32LAvXQaq0p554FcL4LVwnxyiZvscfuFnfpXwWTDRJJHd2+JCttWIx\n"
+ "v+eW7dNq+rq/tzSzaZwnp8b4V2skLRojSt6UUHD234eZcsPwUNhSr0y1eMuoZbnV\n"
+ "UBBPevpuXea85aSFEXXRlIpQfvFc43y3/UFoRzo5iMPqReo2uQ4BAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMBuF1GvOyVcRDNjzlEmGHJkTA7qkaWgTp33NSY/DPEJoahg0Qswuh2w\n"
+ "1YCBqem6Txp+/Vl9hoUoUGwb7Vwq0+YDMSyr0z3Ih2NcNjOMZPVtjJuv+3wXrQC8\n"
+ "LPpCpfU9m9QvhQ7f9zprEqUHOQTT0v5j2a5bpfd++6LFxrMUNwbfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth hello world today\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "svABTGDNJOgaiPLqDlkRU6ldYJcoEe2qHlr4O30lVM2hS3Gg6o4QARL7QRt7VepT\n"
+ "SruR6pE83xOr7/5Ijq5PlamS4WtODMJSH3DXT2hM5dYYrEX5jsJNZTQ+cYwPQI3y\n"
+ "ykuvQIutH6ipz5MYc9n0GWAzDjLq1G8wlcEfFXQLD10=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+/* Onion key is actually a signature. */
+static const char EX_RI_BAD_ONIONKEY1[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANByIdFOKA3r2nnWyLjdZE8oGHqJE62T1zjW/nsCzCJQ8/kBMRYeGDu4\n"
+ "SeUJJ2rsh2t3PNzkqJM14f4DKmc2q76STsOW0Zcj70Bjhxb9r/OfyELVsi+x3CsE\n"
+ "Zo/W4JtdlVFjqevhODJdyFNLKOvqwG7sZo/K++Hx01Iu0zXLeg8nAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "svABTGDNJOgaiPLqDlkRU6ldYJcoEe2qHlr4O30lVM2hS3Gg6o4QARL7QRt7VepT\n"
+ "SruR6pE83xOr7/5Ijq5PlamS4WtODMJSH3DXT2hM5dYYrEX5jsJNZTQ+cYwPQI3y\n"
+ "ykuvQIutH6ipz5MYc9n0GWAzDjLq1G8wlcEfFXQLD10=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Cc/Y22KFvxXPXZtjvGIyQdjm4EMhXVXJEBwt8PvK7qlO1AgiVjEBPkUrTQQ/paLQ\n"
+ "lmeCN6jEVcZ8lNiVZgzRQ/2mTO3xLBPj26UNSDuouUwZ01tZ4wPENylNYnLKv5hg\n"
+ "gYARg/nXEJiTVe9LHl99Hr9EWWruRG2wFQjjTILaWzI=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+/* Onion key has exponent 3 */
+static const char EX_RI_BAD_ONIONKEY2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKP1kWHsH/BZhNSZmn0FyzIrAHtMl1IVPzc7ABbx+kK+IIEMD9k1fy2h\n"
+ "AP2JTm2UmJDUwutVxPsxmndI+9QsRDpu33E5Ai4U1Rb6Qu+2BRj43YAyg414caIu\n"
+ "J5LLn6bOzt7gtz0+q69WHbnwgI4zUgUbwYpwoB7k0dRY97xip9fHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGHAoGBANBKlyoqApWzG7UzmXcxhXM4T370FbN1edPbw4WAczBDXJslXCU9Xk1r\n"
+ "fKfoi/+WiTGvH7RcZWPm7wnThq2u2EAO/IPPcLE9cshLBkK28EvDg5K/WsYedbY9\n"
+ "1Gou+7ZSwMEPv2b13c7eWnSW1YvFa64pVDKu2sKnIjX6Bm0HZGbXAgED\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "cYcBOlapA+R4xq3nn5CjpnzNXdDArMlHuXv4MairjleF1n755ecH8A/R8YIc2ioV\n"
+ "n/C1TACzFVQ12Q9P3iikVOjIXNxYzaz4Lm/L/Lq4sEOPRJC38QEXeIHEaeM51lE6\n"
+ "p6kCqXcGu/51p5vAFCSiXI1ciucmx93N+TH1yGKRLV0=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_RI_BAD_PORTS[] =
+ "router fred 127.0.0.1 900001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANVi/MVWhzT5uo3Jxw4ElS7UGmA24dnckdkCLetMhZOcE9e9mg4WcImL\n"
+ "NuBe2L/9YaL4PFVchCGlq73phKG6yFdqJdjDV8Qh9MJdAYWW2ORrjRvCrspPaYPN\n"
+ "BGJrkD2Gd4u3sq7f26TIkzmBx0Acd/FD4PQf8+XOt9YYd36ooS4vAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALtP4cIpAYp9nqo1ak4SxALcndFw4o51U36R4oa+uJS/lYQPHkMMOj6K\n"
+ "+AVnj9sxkDJ1POaU5lsCQ5JPG1t+Tkh7vDlJb6RCUy25vJOuaQCb9GVVY7KQTJqA\n"
+ "E0fU73JdKACNjMlbF36aliQhrG4Fq2Uv+y7yp8qsRxQ8jvzEMES/AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "xzu2T+pMZtdsS5q1cwXM2hMIH2c8mpAV31G2hKIuiQRwtPD1ne4iJsnoVCXhFakd\n"
+ "QTq7eTXM174fGWyIT93wvQx/Uqnp29dGZp/VaNOsxHFdYVB4VIVqkBh757h+PSJ+\n"
+ "VNV5JUm4XQ1QbmniJGdTQp4PLBM++fOXMR3ZNd6rt4o=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_NEG_BANDWIDTH[] =
+ "router fred 100.127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMCG/ZCXNCF02uXRSCP7qWBN75jDMQZ363ubnQWhF9KDDNWWiwj3UiZR\n"
+ "zqsM4zKRgjtarWZvp2qxKABFAODd+j9iq5DvUGRbbXv+aR8TT/ifMtwwxHZQBk1F\n"
+ "1hbsLdwWzGIiyz5k2MVhXnt6JTlklH2hgT++gt9YTHYKxkssaq5TAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM3vk/4kOTB1VXrve29JeHOzNUsPwKruBcjxJf+aatxjf6KO2/RW41bM\n"
+ "gRYq9V7VAYeZTsbS727fy03F5rk3QIBhMJxm9FHatQ6rT/iEDD4Q1UZQsNtm+OLf\n"
+ "/TkZZhgfB3MiDQ4ld/+GKd7qww8HXTE+m/g1rXNyZPKozn8K7YUHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 -1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "bUBBZYZWqCbsH4/7fNXtC/HgIZNGOfDF9v4d9YfKaDs5xDYf2o67hRcwx5imhrgC\n"
+ "IU7n9AI4AGxkFoN6g3Y/t4pqebxdkF678rRDCtrlwwreAiUktgrwnetp9Tpo16xj\n"
+ "V7Uf6LcqQdvu78lRh1dsrY78sf7sb90vusFMPLXGUKM=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_IP[] =
+ "router fred 100.127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMtMrM24AJpJCevxnseIpRlSuAIMksfkfky2+noe7Rok8xn6AMQzMrwx\n"
+ "AiCJ8Jy4DBzIKUiJK4/y1FimyM08qZGR0xeqblCxZ1lbSiXv6OYxoaD2xmWw8zEP\n"
+ "Zgu4jKReHh+gan1D+XpAbFNY0KrANhjRo96ZZ3AQsZQcWBiPKCynAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOPclmBO/amw1RWTSI1y80qY/EPjc0I+sk9HKr0BQOovxqJ0lmy9Gaue\n"
+ "y+MOejQ9H2hNev0nd7z1fPxEogt7SCe22qJHHX3xDf+D9RpKsvVzDYZsk7hVL7T1\n"
+ "mwHzuiV/dtRa7yAMp7+q0vTUGesU2PYFYMOyPvz5skNLSWrXOm05AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "g6besL/zxOp0N6Q5/7QZgai2kmCU5EAWJlvZrf5jyrjKhsv2a4LDkap07m9QRFqW\n"
+ "GGe7g5iiABIqnl0kzv7NLX7ah+d/xxv+IILXyZfVTxSw0e+zFb3uPlQ7f9JsGJ8i\n"
+ "a+w8wyyDBpOAmi8Ny866Cnp9ojVzCyIErUYHFaPvKao=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_RI_BAD_DIRPORT[] =
+ "router fred 127.0.0.1 9001 0 bob\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANKcD6DJ16X3yvdq05jatdwgjO+hyoIpckW9sV/OkdfIZwf+S6Q4pZGC\n"
+ "doMw5XeOM52gjpx42kUp6M2WlTGDFEpaNU0VyeZYG/M1CM1xvfj3+1PoebioAGdf\n"
+ "GuhNBCHZdaYNiOGnh9t2GgUomgpE6njdS/lovSrDeTL469hfcUghAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANWeGHig5wE9UijaNnEW5au3B3hZKSlzCi+T6MYDPbbYhm8qJaVoXUXF\n"
+ "EP1EUgzDcX3dPEo9upUA1+91GkjGQCo9eOYlqGib8kHIwKnHZK+hernBc/DnOeUp\n"
+ "Wyk9SW5s+fi12OQhr3NGjbSn76FMY9XU3Qt7m3EviTwWpI3Jr5eRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "t77wEoLjyfMf9LKgBfjveosgwvJ8Go0nb27Ae3Ng9tGtR4qaJQfmwZ5fOOuVU9QC\n"
+ "3s8ww3aY91KD3NTcN3v3FKngxWtRM8AIfwh4pqT3zW6OSP4+nO3xml7ql0Zf6wfj\n"
+ "TPFV2941O3yplAsmBJ41sRSWizF04wTtZAIgzY7dMLA=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_NAME2[] =
+ "router verylongnamethatnevereverendsandgoesontoolong 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL0mcUxg7GJ6oxgciLiBCbo+NuZ/OVKRrERCSM6j6iHERcB9+ciSRgQ5\n"
+ "H6o6FUX2LoRmHYzBk1x7kIjHa9kx9g6CAbBamdZrQbdVnc1y2NrdHB/jvwLj3C48\n"
+ "PgzFIrLg9OlkuoWck/E+YpPllONfF65e0+ualgVjPgpQpXwmz+ktAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOgHvvTAxyjJtHx9W2X7aOI05H9sYDDY+sxhovT/8EpAHrioex54tsMT\n"
+ "ifgtoXTjGIBEOTDi/1ry39nEW5WPbowqvyzRfR2M43pc96WV7e1nhmD/JrnTYgtR\n"
+ "5/15KxcMJxoDhod7WZ/wlXBnHc2VevX8JTaeOe9KYORCj5iNbtVZAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "j/nFT5gyj20cLHWv94O1jmnqy3n6qkO8Av0OdvvfNeXsMK2UHxk84vzFvEwpUF/Y\n"
+ "i+VR3LXY4CjTpuliMtjt7BQGtmJSvB8W0CeIUenIGzfwDxW9dG2o7spDldKDB/OU\n"
+ "C1wyHvKaA6Yss/02RIDa4AxyjsfbgdJ91qK+aAnYAtA=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_BANDWIDTH2[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALQDCm9VEopiYILmt4X9kP6DQazfgKnLXv+6rHbc4qtmvQQD3TVYbxMP\n"
+ "F4sEUaz+YHAPnomfDVW3a0YFRYXwDzUm1n47YYCyhUzEaD2f69Mcl/gLpKdg+QOy\n"
+ "boGB1oD4CStWL3y05KhxxTNiTrg+veMzXTqNwryCYm+GoihIAM9fAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALYHwdx6bmYy09AW5ElN/DWh0fHh3mBK97ryiIMi8FImYfzbw2BR6xuT\n"
+ "aQT5omqS3PNJJcNWZt5gOyDtA9kLh03cch7t1PenXSYJshbME2bDrZDJKVJMN6vV\n"
+ "B1v/9HjXsVF50jBzZsJo3j26XCPT5s6u9wqUFWW09QR3E/1HInHVAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 -1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "p09ijyuvcW+WKRj4mJA/nkLCvZkRcMzykAWheJi1IHCoqhXFdkFLiIRqjaeDVHRr\n"
+ "zBtD+YCQiGvFcaQJ9IUhh7IleHcyyljmDYlvuBAxWiKvVZstJac0kclCU4W+g8yK\n"
+ "0Qug3PmGKk115x2TllHaCZqMo5OkK4I/WAsKp+DnJ1A=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_UPTIME[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMM0Nubr1VXQ/FcgIQTFxZpZDlAEh2XN8FoJ8d+X5S46VDGijmMoYmyN\n"
+ "oLXqMTGmOaR0RGZOeGLgDzeY8tLrfF821IjfkXeAANZibUjdsHwqHO3wlWD2v+GN\n"
+ "0GBocWXEdAp/os229mQQKgYAATJ0Ib3jKhBdtgm5R444u8VX5XnbAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMpyOr4kEtSTZw4H9eSkH2+WmwIlO4VBpY2HkPS00l6L5fM2REjt50Xi\n"
+ "lsNOz8Q6mAn5cMYmsGlv61kg01mCvYc7Z715jGh+1hhVAxMaNS3ED/nSPnslyjhq\n"
+ "BUm51LhYNHD4ktISIqPMurx6aC8B68UYgKzLgCYNzkathFXSBpjRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "uptime forever-and-a-day\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "NHYeiQOu0nZdrhSy31Xz4F0T6OTU23hPQDzoLax1/zq6iTVrz9xi3HGm7HhOMW1j\n"
+ "YgFGK3+Xm4iJL+DwriunsAIuL5axr3z2hlmFDQHYItP//KyPpOqSrfEOhwcuj/PE\n"
+ "VbWsiVYwz9VJLO8SfHoBeHI6PsjQRQFt2REBKZhYdxA=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+
+static const char EX_RI_BAD_BANDWIDTH3[] =
+ "router lucy 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAO6HrITQTEjV/v/rInQ2REmCFZa4dZg8zIh6+B51U/I6hDiZaKGwpNey\n"
+ "9OfjoRqT2DwyLEe3ORm9A2RAz2twLBixrpt5IvC0sbGustmW964BHW7k9VvRupwl\n"
+ "ovujHpLIj5dkLxD15jGXHoTp1yHUVk9NkMGN+ahg6y+QhTbIrWbRAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOEpciJFXauEqs31GMTUTzu6edBj9WtV+sIflhGKvU1KKRfwCgOcuKMx\n"
+ "QiLHHD9AjhMAFGT/qtNbPFkzfYxHKLHw+NLJsxmNtdkYM26FX3ButPiX+69sq9fI\n"
+ "PCHqQy6z/A7hHwtEk6niWgK2PLhAZCg9duAv+mqFVXe2QEBjax/lAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 electric\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Jk0Xk1RMJSjEflNRcp4qznaHKcfe2r0kOc7TdLAnM8zyNDVj6+Bn8HWmyp/oFmf6\n"
+ "xtWKKgkKxriAVIJgqZMchPbr9RuZS+i+cad++FCwpTVkyBP920XWC47jA3ZXSBee\n"
+ "HK6FaoK5LfmUm8XEU9BVhiwISXaUfTdkR8HfzugFbWk=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_NTOR_KEY[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKYDCSr0Jh9d/mJKjnGYAHKNBcxR3EJk6GGLwKUrRpN8z/aHRxdWlZF2\n"
+ "lBml6yQNK/VPftcvOekxrKq3/dISrIFBzFYj6XHNtg31d09UgitVkk0VfRarZiGu\n"
+ "O6Yv55GSJ9a3AZDE4YmIp5eBjVuChyVkeDFYKVn0ed4sj9gg35rjAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALXdUQuq1pYHyYP0qU6Ik+oOmwl0eOsuwiLWf9Vd+dsgEszICX4DRWPx\n"
+ "syDxfxyA/g9FEPvlI7Nglx6cKe2MT0AutSRLbbML4smfuRZNIF35Cnfu5qTGVVzL\n"
+ "GWVSA2Ip7p+9S9xLhLBdc6qmrxEXCPL6anEhCR4f8AeybXAsz2JLAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "ntor-onion-key s7rSohmz9SXn8WWh1EefTHIsWePthsEntQi0WL+ScVfjdklsdfjkf\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Yf9axWyzPudnRvQstNdbtBYo7pGpUEIdECMGcJtFb6v/00pxk4Tt3RiOKa84cOBV\n"
+ "7V9NjOLdqlx88pGz0DNCJKqToIrwjZDeQ8Q1yi9XClLDkC32fQRX4y6vNBZ3LXLe\n"
+ "ayVrdRrb41/DP+E7FP4RNPA5czujTfs8xLBMbGew8AA=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_FINGERPRINT[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM0wDWF2dBLzsmoIDHRugzosCSR9TSvEE0TkvKu6+agfogGtkQJwQ5zO\n"
+ "sGzZbRR+okO7d+QCED2i3rUs1iikoMUT+pwgvOm8Bxg9R64GK7fl9K5WuAiG11Uj\n"
+ "DQAfSx5Fo30+rhOhe16c9CT7xJhj//ZKDbXUW7BrJI8zpuOnvgD5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKACg1nWM/WjpUiGwlLQsY3Tq1h0RTz/HmOMx/6rTRxS5HLz0KnLg5zV\n"
+ "dvmfhxqQVKBkt1N2+y+qO7x71oFzIsFMfHYWSxOCEo8Nkff1BqAPqxxUHvM0HwJo\n"
+ "d7lswJ/UT1j4+WZNZ4sFIujsIW2/zZqKlxG9xaw0GXJ082Cj9XkPAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "fingerprint 5555\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "mlqyJ/ZGBINKwSNEi7GpNBCMqIVbL0pGAOBYHJF1GbRlU28uRyNyeELIxIK5ZIet\n"
+ "ZzKr7KPvlBxlyolScPhTJfP98TFSubrwYz7NnQv0vLI0bD0OyoBf/9/1GYlzgTso\n"
+ "3mKfnV7THUalpxe9EjQ/x61Yqf26Co0+jYpt8/Ck6tg=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_MISMATCHED_FINGERPRINT[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANUAvwbpGbsAyA+mBwjFkvurtRzdw9btDqNKtPImufIE+q+AFTaCnwPr\n"
+ "kA7vm/O6h6OhgfdYEC2GfYJfwPGM7MDuz+NnuKxUb3qb2DQN2laqow6qWs9La/if\n"
+ "oHKUjC5mNeAgHcbWapx9CygwaFeVW6FBPl6Db6GIRAlywPSX+XMJAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANlSGd+Vm9nLiUk6zgu8dPnSFfw4F0R2GYfmzncIGJWtRFTF9ThW/0av\n"
+ "/9vZAWyVBjjtnpAP5R1BzdJYV2RwimC/6tqoHtkSbCBhdq5Cb/EHG7Xgb8KwNWVJ\n"
+ "NV1EESDwvWnRfSPGTreRw9+2LkdXri17FhDo2GjRxAq/N7YkLK5hAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "fingerprint CC43 DC8E 8C9E 3E6D 59CD 0399 2491 0C8C E1E4 50D2\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Y8MwYBeEfMhoAABK/FgpVRYolZ7jQ2BJL+8Lb6i4yAuk+HeVmPKTX7MqQoekUuin\n"
+ "/HdPKP+g/9HPMS5pCiW4FMwnXAF0ZocPXF0ndmsTuh0/7VWVOUGgvBpPbIW6guvt\n"
+ "sLLQ3Cq9a4Kwmd+koatfLB6xSZjhXmOn7nRy7gOdwJ8=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_HAS_ACCEPT6[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAJfPJNA3zZ77v2nlX2j5dXImcB/NhRtkG8XQgF7z+3H17sqoXgBgZ1dq\n"
+ "IbyJmAy2Lrvk/8VkXNFrT5/ErThn1B98V/PsJOOW1x7jGcix6X4zDYn/MvwC+AxA\n"
+ "zNP0ozNcVZ6BzVYq8w4I1V4O3Cd6VJesxRVX6mUeSeNawOb7fBY7AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKBzfB4mDEJjFTnmtqZxDG8G1yAiccVgAtq9ECEREL/BOQyukixUBeBe\n"
+ "j/FgXzbMJ7DZAuopuJZU2ma6h14G63fZs7eNFceDtmdLpuCOsFuvJ5Mlkf3hDZ1u\n"
+ "1KK5q+tiG7MKxgnGrqjPBUO2uubs2Cpx0HmsqBNUalXd/KAkFJbXAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "accept6 *:80\n"
+ "reject6 *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "Dp9dLgs9s5beMPxfD0m96as9gNBvlmKhH1RQ/kcOKscia4R8Q42CnUtIqLkCdjOu\n"
+ "zErc2Vj9QzjKOvlqUqHxP+J+l+ZJez6F+E1tcmK/Ydz3exL8cg9f4sAOCSXcpBey\n"
+ "llTFDibz6GkQ2j3/Uc4bN/uLzoyZKunpJbSKZP5nt8Q=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_NO_EXIT_POLICY[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAK4fbjTKYqv2fygfjzY53sVTdtbNMjq293/uffKKxFYnOVvPzrHlP6Go\n"
+ "2S19ZcyDxOuH1unbBChPnV0GpxXX6+bgfDkaFh7+jef0RQ3fpJl84hSvdM8J8SCt\n"
+ "Q/F4Oqk3NeKKs+zAHDjhAU1G4LkF9/SZ9WZVXlH4a4pf7xgQtaShAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKahvyDkmh33ob/bLVO1icgz2ntOZN6ZQUfgpMU4Cd6DQtOEwFUGhbVt\n"
+ "gvtMHv2+VbxM31ZfUsyBqJ1rJBLpOqlPvSoYwSac2+twa+w/qjfGqcJYhBjP9TV9\n"
+ "n9y8DzBX85p6vRcCzcuZ4qUJ2nRzdLHwjdgzeLmmCHuPO2dQxQhXAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "ntgCtMC0VrsY42dKts8igGQ2Nu1BpuzUltisIsJz75dDx2LCqTn7p4VpWbTrj1sH\n"
+ "MRNOvEPFxVMs0Lu50ZUGRzeV6GrHmzIRnOIWanb3I/jyrJLM0jTIjCOLwdMRA298\n"
+ "tw8Y9Hnwj4K7K6VvgU8LP4l7MAJNfR6UT46AJ6vkgL0=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_IPV6_EXIT_POLICY[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKHJKLHqjYoW9M+1q0CGHJRT5u2CnZWb8Qr1DpLkkusQ6ru+cDAG12so\n"
+ "IpDQh7IyB2JosVJi9ogekYxJ3O1p5WlFUi0X19DMoer9FJ9J7/3s4enGJ/yMBeuu\n"
+ "jLVRkjMJhsfhj3Cykon+8Rrf520wSmBg1dpJQCXTwtb7DARgYRpZAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPJH61Ir6XSu9/Q9tXGaINbXO1GWQQUXtwh6TX9lxnaCNDLGnxiY+ZZw\n"
+ "+Vqj3LAQoMrz1PpPsF5e0VIxok10Vc8y4cWC+kIitcecut4vWC5FYTtVVP9wtlyg\n"
+ "YCcVOVhtFQxtLiGqprl84+EVxrR7RQVCMLNDUXIgxAfdnS24eBPDAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "ipv6-policy kfdslfdfj sdjfk sdfjsdf\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "XWorzVT5Owg+QcsBtksiUNtpQQ5+IdvbsN+0O9FbFtGZeaeBAbPJ3Poz+KFCUjZY\n"
+ "DeDAiu1cVgODx2St+99LpwEuIBx78HaD8RYU8tHx8LoA+mGC43ogQQS9lmfxzvP5\n"
+ "eT5WXhkOS5AZ8LZOCOmT+tj/LkSXev2x/NC9+Vc1HPo=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_FAMILY[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM62QoRxSPnm+ZM4fv9p03Qqbz5SzhXYSNjKWqylBruaofTw6oIM8DtX\n"
+ "7QnrEe/ou/WtfB+swV/2rt/r0EzmeWBWuDmuSUrN5TC2AdOi9brSJMgXVW6VW77X\n"
+ "fuIlLd5DVSId2zs3cKLDqp36CUsooA9sS6I5HrvW9QDf3VS3pGBtAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANg1trpnRzkCi4t4Z4qnBKF612H5A3Zrjg7Jo2b3ajUnON/KEuLPTc3t\n"
+ "PPN0W4qqeCMmVQEuxf3DRbTPS20ycy4B/JDWYfxCNwuj5YAx04REf7T0Hlx7Aee/\n"
+ "sHEQBhIBfasA2idhTh3cAm4DMYn+00BqjxF6jmyRA0hyntEABabrAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "family aaaa,bbbb\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "xOgP3liKF/WEvwbbGzUUVRZ5WPrOI7jex8pZU/02UEnHjit7vCf9fsUcvkeo0xjz\n"
+ "n3FQHIO1iAJS7dEaEM4nz6wtPUb2iXSU9QajkGBkJ9/V7NHMFIU3FGfP47PIJJkd\n"
+ "nz5INoS+AsE7PmnDjUMm1H45TCCl8N8y4FO6TtN7p8I=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_BAD_EI_DIGEST[] =
+ "router fred 127.0.0.1 9001 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAJ8Sn8AxBRbeIAHUvaKjqmcYOvXz7YFlpYFiVHp/cn+l+KUkIYTOFQXf\n"
+ "K8AtwjmJ4R2qJIbNlY/6oZGFbizt/B+WPuWsTj+8ACEEDlxx0ibg3EJRB8AZYiWv\n"
+ "0zC/loiUvHm6fXF5ghvDr9BQzEUo9kBk5haoHwROtGawr1+vOEiNAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMzok3ZJtLjXOC8RKltXI8xulwn/ctCvQFHImR0+ccA1uBxaZNYgiIcc\n"
+ "q8XngROfV8xEgDbYPiWiLXJOMSwOd7hfs3YzRWF+LKftYs8PuRyMJcCoBjOPZ4QX\n"
+ "HRfTetEvu2SijZMby+lkqpZg2nuF/ipsXUjrabRZdNiIGhC451vdAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "extra-info-digest not-a-digest\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "c/6zAxO04izQvqdM4bZVGE+ak0nna5pz9XZizFkieZEDWGzWQuVMhXyL5sbsFbsx\n"
+ "6Hn7DvNRYR/2nA0teDeRyIHMoMHi76te5X9OFDgaeUVCbyJ8h/KZYfPnN86IDbsR\n"
+ "dCSmj9kX55keu64ccCAH1CqwcN/UsbplXiJJVG5pTfI=\n"
+ "-----END SIGNATURE-----\n"
+ ;
+static const char EX_RI_ZERO_ORPORT[] =
+ "router fred 127.0.0.1 0 0 9002\n"
+ "signing-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMc4MOhLG3PKPgc+xYVf4eScWzeOf8wq7Cb/JxZm50G0LuvVbhHtHEZX\n"
+ "VOSHI7mLE1ifakJvCFJRLobMU7lU0yhn18/nKl2Cu5NfFHHeF/NieUBSxBGb2wD6\n"
+ "aM1azheXrRqvDVVfbI0DLc/XfQC/YNiohOsQ/c9C6wuffA4+Sg85AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALBWdl9/Vft+NQKQlg5kgvZo+krnhNTRVQojWtUEzom4TFIT+NNKJyMG\n"
+ "reQXcNdzNptTB0aOBGGwqAesqzsZ2Hje699NsDe7hdl7Sb5yhKDqtdQY6yDXJUFt\n"
+ "zqpAUkmYMLe2p3kPiWefNso56KYXrZrlNAiIS/FhQ5cmuMC2jPydAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "published 2014-10-05 12:00:00\n"
+ "bandwidth 1000 1000 1000\n"
+ "reject *:*\n"
+ "router-signature\n"
+ "-----BEGIN SIGNATURE-----\n"
+ "gFg08P9A6QNQjURlebfdhU3DSV0BeM0j2SFza1jF9JcBOWDRmT8FvYFK1B3js6jK\n"
+ "8LNV8JOUssv14z5CnUY9CO1BD0xSl+vGlSS4VOXD7rxui8IoWgnqnZsitq+Qzs95\n"
+ "wgFKhHI/49NHyWHX5IMQpeicg0T7Qa6qwnUvspH62p8=\n"
+ "-----END SIGNATURE-----\n"
+ ;
diff --git a/src/test/fakechans.h b/src/test/fakechans.h
new file mode 100644
index 0000000000..8fb8f420a8
--- /dev/null
+++ b/src/test/fakechans.h
@@ -0,0 +1,26 @@
+ /* Copyright (c) 2014-2015, The Tor Project, Inc. */
+ /* See LICENSE for licensing information */
+
+#ifndef TOR_FAKECHANS_H
+#define TOR_FAKECHANS_H
+
+/**
+ * \file fakechans.h
+ * \brief Declarations for fake channels for test suite use
+ */
+
+void make_fake_cell(cell_t *c);
+void make_fake_var_cell(var_cell_t *c);
+channel_t * new_fake_channel(void);
+void free_fake_channel(channel_t *c);
+
+/* Also exposes some a mock used by both test_channel.c and test_relay.c */
+void scheduler_channel_has_waiting_cells_mock(channel_t *ch);
+void scheduler_release_channel_mock(channel_t *ch);
+
+/* Query some counters used by the exposed mocks */
+int get_mock_scheduler_has_waiting_cells_count(void);
+int get_mock_scheduler_release_channel_count(void);
+
+#endif /* !defined(TOR_FAKECHANS_H) */
+
diff --git a/src/test/include.am b/src/test/include.am
index fba439a616..d20d2f66b9 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -1,8 +1,12 @@
-TESTS += src/test/test
+TESTS += src/test/test src/test/test-slow
noinst_PROGRAMS+= src/test/bench
if UNITTESTS_ENABLED
-noinst_PROGRAMS+= src/test/test src/test/test-child
+noinst_PROGRAMS+= \
+ src/test/test \
+ src/test/test-slow \
+ src/test/test-child \
+ src/test/test_workqueue
endif
src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
@@ -17,36 +21,59 @@ src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \
src_test_test_SOURCES = \
src/test/test.c \
+ src/test/test_accounting.c \
src/test/test_addr.c \
+ src/test/test_address.c \
src/test/test_buffers.c \
src/test/test_cell_formats.c \
+ src/test/test_cell_queue.c \
+ src/test/test_channel.c \
+ src/test/test_channeltls.c \
+ src/test/test_checkdir.c \
src/test/test_circuitlist.c \
src/test/test_circuitmux.c \
+ src/test/test_config.c \
src/test/test_containers.c \
src/test/test_controller_events.c \
src/test/test_crypto.c \
- src/test/test_cell_queue.c \
src/test/test_data.c \
src/test/test_dir.c \
+ src/test/test_entryconn.c \
+ src/test/test_entrynodes.c \
+ src/test/test_guardfraction.c \
src/test/test_extorport.c \
+ src/test/test_hs.c \
src/test/test_introduce.c \
src/test/test_logging.c \
src/test/test_microdesc.c \
+ src/test/test_nodelist.c \
src/test/test_oom.c \
src/test/test_options.c \
+ src/test/test_policy.c \
src/test/test_pt.c \
+ src/test/test_relay.c \
src/test/test_relaycell.c \
src/test/test_replay.c \
src/test/test_routerkeys.c \
+ src/test/test_routerlist.c \
+ src/test/test_routerset.c \
+ src/test/test_scheduler.c \
src/test/test_socks.c \
- src/test/test_util.c \
- src/test/test_config.c \
- src/test/test_hs.c \
- src/test/test_nodelist.c \
- src/test/test_policy.c \
src/test/test_status.c \
+ src/test/test_threads.c \
+ src/test/test_util.c \
+ src/test/test_helpers.c \
+ src/test/testing_common.c \
+ src/ext/tinytest.c
+
+src_test_test_slow_SOURCES = \
+ src/test/test_slow.c \
+ src/test/test_crypto_slow.c \
+ src/test/test_util_slow.c \
+ src/test/testing_common.c \
src/ext/tinytest.c
+
src_test_test_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS)
@@ -54,13 +81,24 @@ src_test_test_CPPFLAGS= $(src_test_AM_CPPFLAGS)
src_test_bench_SOURCES = \
src/test/bench.c
+src_test_test_workqueue_SOURCES = \
+ src/test/test_workqueue.c
+src_test_test_workqueue_CPPFLAGS= $(src_test_AM_CPPFLAGS)
+src_test_test_workqueue_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
src_test_test_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
src/common/libor-crypto-testing.a $(LIBDONNA) \
- src/common/libor-event-testing.a \
+ src/common/libor-event-testing.a src/trunnel/libor-trunnel-testing.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
- @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
+ @TOR_SYSTEMD_LIBS@
+
+src_test_test_slow_CPPFLAGS = $(src_test_test_CPPFLAGS)
+src_test_test_slow_CFLAGS = $(src_test_test_CFLAGS)
+src_test_test_slow_LDADD = $(src_test_test_LDADD)
+src_test_test_slow_LDFLAGS = $(src_test_test_LDFLAGS)
src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
@TOR_LDFLAGS_libevent@
@@ -68,12 +106,28 @@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
src/common/libor-crypto.a $(LIBDONNA) \
src/common/libor-event.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
+ @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
+ @TOR_SYSTEMD_LIBS@
+
+src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
+ @TOR_LDFLAGS_libevent@
+src_test_test_workqueue_LDADD = src/or/libtor-testing.a \
+ src/common/libor-testing.a \
+ src/common/libor-crypto-testing.a $(LIBDONNA) \
+ src/common/libor-event-testing.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
noinst_HEADERS+= \
- src/test/test.h
+ src/test/fakechans.h \
+ src/test/test.h \
+ src/test/test_helpers.h \
+ src/test/test_descriptors.inc \
+ src/test/example_extrainfo.inc \
+ src/test/failing_routerdescs.inc \
+ src/test/ed25519_vectors.inc \
+ src/test/test_descriptors.inc
-if CURVE25519_ENABLED
noinst_PROGRAMS+= src/test/test-ntor-cl
src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c
src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
@@ -84,9 +138,6 @@ src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \
src_test_test_ntor_cl_AM_CPPFLAGS = \
-I"$(top_srcdir)/src/or"
NTOR_TEST_DEPS=src/test/test-ntor-cl
-else
-NTOR_TEST_DEPS=
-endif
if COVERAGE_ENABLED
CMDLINE_TEST_TOR = ./src/or/tor-cov
@@ -106,16 +157,16 @@ src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS)
check-local: $(NTOR_TEST_DEPS) $(CMDLINE_TEST_TOR)
if USEPYTHON
$(PYTHON) $(top_srcdir)/src/test/test_cmdline_args.py $(CMDLINE_TEST_TOR) "${top_srcdir}"
-if CURVE25519_ENABLED
$(PYTHON) $(top_srcdir)/src/test/ntor_ref.py test-tor
$(PYTHON) $(top_srcdir)/src/test/ntor_ref.py self-test
-endif
./src/test/test-bt-cl assert | $(PYTHON) $(top_srcdir)/src/test/bt_test.py
./src/test/test-bt-cl crash | $(PYTHON) $(top_srcdir)/src/test/bt_test.py
endif
+ $(top_srcdir)/src/test/zero_length_keys.sh
EXTRA_DIST += \
src/test/bt_test.py \
src/test/ntor_ref.py \
src/test/slownacl_curve25519.py \
- src/test/test_cmdline_args.py
+ src/test/test_cmdline_args.py \
+ src/test/zero_length_keys.sh
diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py
index 7d6e43e716..e37637d92a 100755
--- a/src/test/ntor_ref.py
+++ b/src/test/ntor_ref.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-# Copyright 2012-2013, The Tor Project, Inc
+# Copyright 2012-2015, The Tor Project, Inc
# See LICENSE for licensing information
"""
diff --git a/src/test/slow_ed25519.py b/src/test/slow_ed25519.py
new file mode 100644
index 0000000000..f44708b200
--- /dev/null
+++ b/src/test/slow_ed25519.py
@@ -0,0 +1,115 @@
+# This is the ed25519 implementation from
+# http://ed25519.cr.yp.to/python/ed25519.py .
+# It is in the public domain.
+#
+# It isn't constant-time. Don't use it except for testing. Also, see
+# warnings about how very slow it is. Only use this for generating
+# test vectors, I'd suggest.
+#
+# Don't edit this file. Mess with ed25519_ref.py
+
+import hashlib
+
+b = 256
+q = 2**255 - 19
+l = 2**252 + 27742317777372353535851937790883648493
+
+def H(m):
+ return hashlib.sha512(m).digest()
+
+def expmod(b,e,m):
+ if e == 0: return 1
+ t = expmod(b,e/2,m)**2 % m
+ if e & 1: t = (t*b) % m
+ return t
+
+def inv(x):
+ return expmod(x,q-2,q)
+
+d = -121665 * inv(121666)
+I = expmod(2,(q-1)/4,q)
+
+def xrecover(y):
+ xx = (y*y-1) * inv(d*y*y+1)
+ x = expmod(xx,(q+3)/8,q)
+ if (x*x - xx) % q != 0: x = (x*I) % q
+ if x % 2 != 0: x = q-x
+ return x
+
+By = 4 * inv(5)
+Bx = xrecover(By)
+B = [Bx % q,By % q]
+
+def edwards(P,Q):
+ x1 = P[0]
+ y1 = P[1]
+ x2 = Q[0]
+ y2 = Q[1]
+ x3 = (x1*y2+x2*y1) * inv(1+d*x1*x2*y1*y2)
+ y3 = (y1*y2+x1*x2) * inv(1-d*x1*x2*y1*y2)
+ return [x3 % q,y3 % q]
+
+def scalarmult(P,e):
+ if e == 0: return [0,1]
+ Q = scalarmult(P,e/2)
+ Q = edwards(Q,Q)
+ if e & 1: Q = edwards(Q,P)
+ return Q
+
+def encodeint(y):
+ bits = [(y >> i) & 1 for i in range(b)]
+ return ''.join([chr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b/8)])
+
+def encodepoint(P):
+ x = P[0]
+ y = P[1]
+ bits = [(y >> i) & 1 for i in range(b - 1)] + [x & 1]
+ return ''.join([chr(sum([bits[i * 8 + j] << j for j in range(8)])) for i in range(b/8)])
+
+def bit(h,i):
+ return (ord(h[i/8]) >> (i%8)) & 1
+
+def publickey(sk):
+ h = H(sk)
+ a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
+ A = scalarmult(B,a)
+ return encodepoint(A)
+
+def Hint(m):
+ h = H(m)
+ return sum(2**i * bit(h,i) for i in range(2*b))
+
+def signature(m,sk,pk):
+ h = H(sk)
+ a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
+ r = Hint(''.join([h[i] for i in range(b/8,b/4)]) + m)
+ R = scalarmult(B,r)
+ S = (r + Hint(encodepoint(R) + pk + m) * a) % l
+ return encodepoint(R) + encodeint(S)
+
+def isoncurve(P):
+ x = P[0]
+ y = P[1]
+ return (-x*x + y*y - 1 - d*x*x*y*y) % q == 0
+
+def decodeint(s):
+ return sum(2**i * bit(s,i) for i in range(0,b))
+
+def decodepoint(s):
+ y = sum(2**i * bit(s,i) for i in range(0,b-1))
+ x = xrecover(y)
+ if x & 1 != bit(s,b-1): x = q-x
+ P = [x,y]
+ if not isoncurve(P): raise Exception("decoding point that is not on curve")
+ return P
+
+def checkvalid(s,m,pk):
+ if len(s) != b/4: raise Exception("signature length is wrong")
+ if len(pk) != b/8: raise Exception("public-key length is wrong")
+ R = decodepoint(s[0:b/8])
+ A = decodepoint(pk)
+ S = decodeint(s[b/8:b/4])
+ h = Hint(encodepoint(R) + pk + m)
+ if scalarmult(B,S) != edwards(R,scalarmult(A,h)):
+ raise Exception("signature does not pass verification")
+
diff --git a/src/test/test-child.c b/src/test/test-child.c
index 756782e70b..2ce01ea9bb 100644
--- a/src/test/test-child.c
+++ b/src/test/test-child.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2013, The Tor Project, Inc. */
+/* Copyright (c) 2011-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include <stdio.h>
diff --git a/src/test/test-network.sh b/src/test/test-network.sh
index 7b59864166..be57cafb7f 100755
--- a/src/test/test-network.sh
+++ b/src/test/test-network.sh
@@ -1,5 +1,7 @@
#! /bin/sh
+ECHO_N="/bin/echo -n"
+
until [ -z $1 ]
do
case $1 in
@@ -15,6 +17,10 @@ do
export NETWORK_FLAVOUR="$2"
shift
;;
+ --delay|--sleep|--bootstrap-time|--time)
+ export BOOTSTRAP_TIME="$2"
+ shift
+ ;;
*)
echo "Sorry, I don't know what to do with '$1'."
exit 2
@@ -39,9 +45,14 @@ PATH="$TOR_DIR/src/or:$TOR_DIR/src/tools:$PATH"
# Sleep some, waiting for the network to bootstrap.
# TODO: Add chutney command 'bootstrap-status' and use that instead.
-BOOTSTRAP_TIME=18
-echo -n "$myname: sleeping for $BOOTSTRAP_TIME seconds"
+BOOTSTRAP_TIME=${BOOTSTRAP_TIME:-25}
+$ECHO_N "$myname: sleeping for $BOOTSTRAP_TIME seconds"
n=$BOOTSTRAP_TIME; while [ $n -gt 0 ]; do
- sleep 1; n=$(expr $n - 1); echo -n .
+ sleep 1; n=$(expr $n - 1); $ECHO_N .
done; echo ""
./chutney verify $CHUTNEY_NETWORK
+VERIFY_EXIT_STATUS=$?
+# work around a bug/feature in make -j2 (or more)
+# where make hangs if any child processes are still alive
+./chutney stop $CHUTNEY_NETWORK
+exit $VERIFY_EXIT_STATUS
diff --git a/src/test/test.c b/src/test/test.c
index 8bce9c91f4..0524a6978f 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,12 +1,8 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-/* Ordinarily defined in tor_main.c; this bit is just here to provide one
- * since we're not linking to tor_main.c */
-const char tor_git_revision[] = "";
-
/**
* \file test.c
* \brief Unit tests for many pieces of the lower level Tor modules.
@@ -43,6 +39,7 @@ long int lround(double x);
double fabs(double x);
#include "or.h"
+#include "backtrace.h"
#include "buffers.h"
#include "circuitlist.h"
#include "circuitstats.h"
@@ -52,9 +49,6 @@ double fabs(double x);
#include "rendcommon.h"
#include "test.h"
#include "torgzip.h"
-#ifdef ENABLE_MEMPOOLS
-#include "mempool.h"
-#endif
#include "memarea.h"
#include "onion.h"
#include "onion_ntor.h"
@@ -63,168 +57,12 @@ double fabs(double x);
#include "rephist.h"
#include "routerparse.h"
#include "statefile.h"
-#ifdef CURVE25519_ENABLED
#include "crypto_curve25519.h"
#include "onion_ntor.h"
-#endif
-
-#ifdef USE_DMALLOC
-#include <dmalloc.h>
-#include <openssl/crypto.h>
-#include "main.h"
-#endif
-
-/** Set to true if any unit test has failed. Mostly, this is set by the macros
- * in test.h */
-int have_failed = 0;
-
-/** Temporary directory (set up by setup_directory) under which we store all
- * our files during testing. */
-static char temp_dir[256];
-#ifdef _WIN32
-#define pid_t int
-#endif
-static pid_t temp_dir_setup_in_pid = 0;
-
-/** Select and create the temporary directory we'll use to run our unit tests.
- * Store it in <b>temp_dir</b>. Exit immediately if we can't create it.
- * idempotent. */
-static void
-setup_directory(void)
-{
- static int is_setup = 0;
- int r;
- char rnd[256], rnd32[256];
- if (is_setup) return;
-
-/* Due to base32 limitation needs to be a multiple of 5. */
-#define RAND_PATH_BYTES 5
- crypto_rand(rnd, RAND_PATH_BYTES);
- base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
-
-#ifdef _WIN32
- {
- char buf[MAX_PATH];
- const char *tmp = buf;
- /* If this fails, we're probably screwed anyway */
- if (!GetTempPathA(sizeof(buf),buf))
- tmp = "c:\\windows\\temp";
- tor_snprintf(temp_dir, sizeof(temp_dir),
- "%s\\tor_test_%d_%s", tmp, (int)getpid(), rnd32);
- r = mkdir(temp_dir);
- }
-#else
- tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
- (int) getpid(), rnd32);
- r = mkdir(temp_dir, 0700);
-#endif
- if (r) {
- fprintf(stderr, "Can't create directory %s:", temp_dir);
- perror("");
- exit(1);
- }
- is_setup = 1;
- temp_dir_setup_in_pid = getpid();
-}
-
-/** Return a filename relative to our testing temporary directory */
-const char *
-get_fname(const char *name)
-{
- static char buf[1024];
- setup_directory();
- if (!name)
- return temp_dir;
- tor_snprintf(buf,sizeof(buf),"%s/%s",temp_dir,name);
- return buf;
-}
-
-/* Remove a directory and all of its subdirectories */
-static void
-rm_rf(const char *dir)
-{
- struct stat st;
- smartlist_t *elements;
-
- elements = tor_listdir(dir);
- if (elements) {
- SMARTLIST_FOREACH_BEGIN(elements, const char *, cp) {
- char *tmp = NULL;
- tor_asprintf(&tmp, "%s"PATH_SEPARATOR"%s", dir, cp);
- if (0 == stat(tmp,&st) && (st.st_mode & S_IFDIR)) {
- rm_rf(tmp);
- } else {
- if (unlink(tmp)) {
- fprintf(stderr, "Error removing %s: %s\n", tmp, strerror(errno));
- }
- }
- tor_free(tmp);
- } SMARTLIST_FOREACH_END(cp);
- SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
- smartlist_free(elements);
- }
- if (rmdir(dir))
- fprintf(stderr, "Error removing directory %s: %s\n", dir, strerror(errno));
-}
-
-/** Remove all files stored under the temporary directory, and the directory
- * itself. Called by atexit(). */
-static void
-remove_directory(void)
-{
- if (getpid() != temp_dir_setup_in_pid) {
- /* Only clean out the tempdir when the main process is exiting. */
- return;
- }
-
- rm_rf(temp_dir);
-}
-
-/** Define this if unit tests spend too much time generating public keys*/
-#undef CACHE_GENERATED_KEYS
-
-static crypto_pk_t *pregen_keys[5] = {NULL, NULL, NULL, NULL, NULL};
-#define N_PREGEN_KEYS ((int)(sizeof(pregen_keys)/sizeof(pregen_keys[0])))
-
-/** Generate and return a new keypair for use in unit tests. If we're using
- * the key cache optimization, we might reuse keys: we only guarantee that
- * keys made with distinct values for <b>idx</b> are different. The value of
- * <b>idx</b> must be at least 0, and less than N_PREGEN_KEYS. */
-crypto_pk_t *
-pk_generate(int idx)
-{
-#ifdef CACHE_GENERATED_KEYS
- tor_assert(idx < N_PREGEN_KEYS);
- if (! pregen_keys[idx]) {
- pregen_keys[idx] = crypto_pk_new();
- tor_assert(!crypto_pk_generate_key(pregen_keys[idx]));
- }
- return crypto_pk_dup_key(pregen_keys[idx]);
-#else
- crypto_pk_t *result;
- (void) idx;
- result = crypto_pk_new();
- tor_assert(!crypto_pk_generate_key(result));
- return result;
-#endif
-}
-
-/** Free all storage used for the cached key optimization. */
-static void
-free_pregenerated_keys(void)
-{
- unsigned idx;
- for (idx = 0; idx < N_PREGEN_KEYS; ++idx) {
- if (pregen_keys[idx]) {
- crypto_pk_free(pregen_keys[idx]);
- pregen_keys[idx] = NULL;
- }
- }
-}
/** Run unit tests for the onion handshake code. */
static void
-test_onion_handshake(void)
+test_onion_handshake(void *arg)
{
/* client-side */
crypto_dh_t *c_dh = NULL;
@@ -237,12 +75,13 @@ test_onion_handshake(void)
/* shared */
crypto_pk_t *pk = NULL, *pk2 = NULL;
+ (void)arg;
pk = pk_generate(0);
pk2 = pk_generate(1);
/* client handshake 1. */
memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
- test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
+ tt_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
for (i = 1; i <= 3; ++i) {
crypto_pk_t *k1, *k2;
@@ -259,16 +98,17 @@ test_onion_handshake(void)
memset(s_buf, 0, TAP_ONIONSKIN_REPLY_LEN);
memset(s_keys, 0, 40);
- test_assert(! onion_skin_TAP_server_handshake(c_buf, k1, k2,
+ tt_assert(! onion_skin_TAP_server_handshake(c_buf, k1, k2,
s_buf, s_keys, 40));
/* client handshake 2 */
memset(c_keys, 0, 40);
- test_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
+ tt_assert(! onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys,
+ 40, NULL));
- test_memeq(c_keys, s_keys, 40);
+ tt_mem_op(c_keys,OP_EQ, s_keys, 40);
memset(s_buf, 0, 40);
- test_memneq(c_keys, s_buf, 40);
+ tt_mem_op(c_keys,OP_NE, s_buf, 40);
}
done:
crypto_dh_free(c_dh);
@@ -300,7 +140,7 @@ test_bad_onion_handshake(void *arg)
memset(junk_buf, 0, sizeof(junk_buf));
crypto_pk_public_hybrid_encrypt(pk, junk_buf2, TAP_ONIONSKIN_CHALLENGE_LEN,
junk_buf, DH_KEY_LEN, PK_PKCS1_OAEP_PADDING, 1);
- tt_int_op(-1, ==,
+ tt_int_op(-1, OP_EQ,
onion_skin_TAP_server_handshake(junk_buf2, pk, NULL,
s_buf, s_keys, 40));
@@ -309,46 +149,46 @@ test_bad_onion_handshake(void *arg)
memset(junk_buf2, 0, sizeof(junk_buf2));
crypto_pk_public_encrypt(pk, junk_buf2, sizeof(junk_buf2),
junk_buf, 48, PK_PKCS1_OAEP_PADDING);
- tt_int_op(-1, ==,
+ tt_int_op(-1, OP_EQ,
onion_skin_TAP_server_handshake(junk_buf2, pk, NULL,
s_buf, s_keys, 40));
/* client handshake 1: do it straight. */
memset(c_buf, 0, TAP_ONIONSKIN_CHALLENGE_LEN);
- test_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
+ tt_assert(! onion_skin_TAP_create(pk, &c_dh, c_buf));
/* Server: Case 3: we just don't have the right key. */
- tt_int_op(-1, ==,
+ tt_int_op(-1, OP_EQ,
onion_skin_TAP_server_handshake(c_buf, pk2, NULL,
s_buf, s_keys, 40));
/* Server: Case 4: The RSA-encrypted portion is corrupt. */
c_buf[64] ^= 33;
- tt_int_op(-1, ==,
+ tt_int_op(-1, OP_EQ,
onion_skin_TAP_server_handshake(c_buf, pk, NULL,
s_buf, s_keys, 40));
c_buf[64] ^= 33;
/* (Let the server procede) */
- tt_int_op(0, ==,
+ tt_int_op(0, OP_EQ,
onion_skin_TAP_server_handshake(c_buf, pk, NULL,
s_buf, s_keys, 40));
/* Client: Case 1: The server sent back junk. */
s_buf[64] ^= 33;
- tt_int_op(-1, ==,
- onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
+ tt_int_op(-1, OP_EQ,
+ onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, NULL));
s_buf[64] ^= 33;
/* Let the client finish; make sure it can. */
- tt_int_op(0, ==,
- onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
- test_memeq(s_keys, c_keys, 40);
+ tt_int_op(0, OP_EQ,
+ onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, NULL));
+ tt_mem_op(s_keys,OP_EQ, c_keys, 40);
/* Client: Case 2: The server sent back a degenerate DH. */
memset(s_buf, 0, sizeof(s_buf));
- tt_int_op(-1, ==,
- onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40));
+ tt_int_op(-1, OP_EQ,
+ onion_skin_TAP_client_handshake(c_dh, s_buf, c_keys, 40, NULL));
done:
crypto_dh_free(c_dh);
@@ -356,7 +196,6 @@ test_bad_onion_handshake(void *arg)
crypto_pk_free(pk2);
}
-#ifdef CURVE25519_ENABLED
static void
test_ntor_handshake(void *arg)
{
@@ -385,34 +224,33 @@ test_ntor_handshake(void *arg)
/* client handshake 1. */
memset(c_buf, 0, NTOR_ONIONSKIN_LEN);
- tt_int_op(0, ==, onion_skin_ntor_create(node_id, server_pubkey,
+ tt_int_op(0, OP_EQ, onion_skin_ntor_create(node_id, server_pubkey,
&c_state, c_buf));
/* server handshake */
memset(s_buf, 0, NTOR_REPLY_LEN);
memset(s_keys, 0, 40);
- tt_int_op(0, ==, onion_skin_ntor_server_handshake(c_buf, s_keymap, NULL,
+ tt_int_op(0, OP_EQ, onion_skin_ntor_server_handshake(c_buf, s_keymap, NULL,
node_id,
s_buf, s_keys, 400));
/* client handshake 2 */
memset(c_keys, 0, 40);
- tt_int_op(0, ==, onion_skin_ntor_client_handshake(c_state, s_buf,
- c_keys, 400));
+ tt_int_op(0, OP_EQ, onion_skin_ntor_client_handshake(c_state, s_buf,
+ c_keys, 400, NULL));
- test_memeq(c_keys, s_keys, 400);
+ tt_mem_op(c_keys,OP_EQ, s_keys, 400);
memset(s_buf, 0, 40);
- test_memneq(c_keys, s_buf, 40);
+ tt_mem_op(c_keys,OP_NE, s_buf, 40);
done:
ntor_handshake_state_free(c_state);
dimap_free(s_keymap, NULL);
}
-#endif
/** Run unit tests for the onion queues. */
static void
-test_onion_queues(void)
+test_onion_queues(void *arg)
{
uint8_t buf1[TAP_ONIONSKIN_CHALLENGE_LEN] = {0};
uint8_t buf2[NTOR_ONIONSKIN_LEN] = {0};
@@ -423,6 +261,7 @@ test_onion_queues(void)
create_cell_t *onionskin = NULL, *create2_ptr;
create_cell_t *create1 = tor_malloc_zero(sizeof(create_cell_t));
create_cell_t *create2 = tor_malloc_zero(sizeof(create_cell_t));
+ (void)arg;
create2_ptr = create2; /* remember, but do not free */
create_cell_init(create1, CELL_CREATE, ONION_HANDSHAKE_TYPE_TAP,
@@ -430,24 +269,24 @@ test_onion_queues(void)
create_cell_init(create2, CELL_CREATE, ONION_HANDSHAKE_TYPE_NTOR,
NTOR_ONIONSKIN_LEN, buf2);
- test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
- test_eq(0, onion_pending_add(circ1, create1));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_pending_add(circ1, create1));
create1 = NULL;
- test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
- test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
- test_eq(0, onion_pending_add(circ2, create2));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_pending_add(circ2, create2));
create2 = NULL;
- test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
- test_eq_ptr(circ2, onion_next_task(&onionskin));
- test_eq(1, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
- test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
- tt_ptr_op(onionskin, ==, create2_ptr);
+ tt_ptr_op(circ2,OP_EQ, onion_next_task(&onionskin));
+ tt_int_op(1,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_ptr_op(onionskin, OP_EQ, create2_ptr);
clear_pending_onions();
- test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
- test_eq(0, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_TAP));
+ tt_int_op(0,OP_EQ, onion_num_pending(ONION_HANDSHAKE_TYPE_NTOR));
done:
circuit_free(TO_CIRCUIT(circ1));
@@ -458,7 +297,7 @@ test_onion_queues(void)
}
static void
-test_circuit_timeout(void)
+test_circuit_timeout(void *arg)
{
/* Plan:
* 1. Generate 1000 samples
@@ -476,6 +315,7 @@ test_circuit_timeout(void)
or_state_t *state=NULL;
int i, runs;
double close_ms;
+ (void)arg;
circuit_build_times_init(&initial);
circuit_build_times_init(&estimate);
circuit_build_times_init(&final);
@@ -510,11 +350,11 @@ test_circuit_timeout(void)
} while (fabs(circuit_build_times_cdf(&initial, timeout0) -
circuit_build_times_cdf(&initial, timeout1)) > 0.02);
- test_assert(estimate.total_build_times <= CBT_NCIRCUITS_TO_OBSERVE);
+ tt_assert(estimate.total_build_times <= CBT_NCIRCUITS_TO_OBSERVE);
circuit_build_times_update_state(&estimate, state);
circuit_build_times_free_timeouts(&final);
- test_assert(circuit_build_times_parse_state(&final, state) == 0);
+ tt_assert(circuit_build_times_parse_state(&final, state) == 0);
circuit_build_times_update_alpha(&final);
timeout2 = circuit_build_times_calculate_timeout(&final,
@@ -524,7 +364,7 @@ test_circuit_timeout(void)
log_notice(LD_CIRC, "Timeout2 is %f, Xm is %d", timeout2, final.Xm);
/* 5% here because some accuracy is lost due to histogram conversion */
- test_assert(fabs(circuit_build_times_cdf(&initial, timeout0) -
+ tt_assert(fabs(circuit_build_times_cdf(&initial, timeout0) -
circuit_build_times_cdf(&initial, timeout2)) < 0.05);
for (runs = 0; runs < 50; runs++) {
@@ -547,8 +387,8 @@ test_circuit_timeout(void)
CBT_DEFAULT_QUANTILE_CUTOFF/100.0));
}
- test_assert(!circuit_build_times_network_check_changed(&estimate));
- test_assert(!circuit_build_times_network_check_changed(&final));
+ tt_assert(!circuit_build_times_network_check_changed(&estimate));
+ tt_assert(!circuit_build_times_network_check_changed(&final));
/* Reset liveness to be non-live */
final.liveness.network_last_live = 0;
@@ -557,27 +397,27 @@ test_circuit_timeout(void)
build_times_idx = estimate.build_times_idx;
total_build_times = estimate.total_build_times;
- test_assert(circuit_build_times_network_check_live(&estimate));
- test_assert(circuit_build_times_network_check_live(&final));
+ tt_assert(circuit_build_times_network_check_live(&estimate));
+ tt_assert(circuit_build_times_network_check_live(&final));
circuit_build_times_count_close(&estimate, 0,
(time_t)(approx_time()-estimate.close_ms/1000.0-1));
circuit_build_times_count_close(&final, 0,
(time_t)(approx_time()-final.close_ms/1000.0-1));
- test_assert(!circuit_build_times_network_check_live(&estimate));
- test_assert(!circuit_build_times_network_check_live(&final));
+ tt_assert(!circuit_build_times_network_check_live(&estimate));
+ tt_assert(!circuit_build_times_network_check_live(&final));
log_info(LD_CIRC, "idx: %d %d, tot: %d %d",
build_times_idx, estimate.build_times_idx,
total_build_times, estimate.total_build_times);
/* Check rollback index. Should match top of loop. */
- test_assert(build_times_idx == estimate.build_times_idx);
+ tt_assert(build_times_idx == estimate.build_times_idx);
// This can fail if estimate.total_build_times == 1000, because
// in that case, rewind actually causes us to lose timeouts
if (total_build_times != CBT_NCIRCUITS_TO_OBSERVE)
- test_assert(total_build_times == estimate.total_build_times);
+ tt_assert(total_build_times == estimate.total_build_times);
/* Now simulate that the network has become live and we need
* a change */
@@ -592,14 +432,22 @@ test_circuit_timeout(void)
}
}
- test_assert(estimate.liveness.after_firsthop_idx == 0);
- test_assert(final.liveness.after_firsthop_idx ==
+ tt_assert(estimate.liveness.after_firsthop_idx == 0);
+ tt_assert(final.liveness.after_firsthop_idx ==
CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT-1);
- test_assert(circuit_build_times_network_check_live(&estimate));
- test_assert(circuit_build_times_network_check_live(&final));
+ tt_assert(circuit_build_times_network_check_live(&estimate));
+ tt_assert(circuit_build_times_network_check_live(&final));
circuit_build_times_count_timeout(&final, 1);
+
+ /* Ensure return value for degenerate cases are clamped correctly */
+ initial.alpha = INT32_MAX;
+ tt_assert(circuit_build_times_calculate_timeout(&initial, .99999999) <=
+ INT32_MAX);
+ initial.alpha = 0;
+ tt_assert(circuit_build_times_calculate_timeout(&initial, .5) <=
+ INT32_MAX);
}
done:
@@ -611,7 +459,7 @@ test_circuit_timeout(void)
/** Test encoding and parsing of rendezvous service descriptors. */
static void
-test_rend_fns(void)
+test_rend_fns(void *arg)
{
rend_service_descriptor_t *generated = NULL, *parsed = NULL;
char service_id[DIGEST_LEN];
@@ -634,16 +482,17 @@ test_rend_fns(void)
char address6[] = "foo.bar.abcdefghijklmnop.onion";
char address7[] = ".abcdefghijklmnop.onion";
- test_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
- test_assert(ONION_HOSTNAME == parse_extended_hostname(address2));
- test_streq(address2, "aaaaaaaaaaaaaaaa");
- test_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
- test_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
- test_assert(ONION_HOSTNAME == parse_extended_hostname(address5));
- test_streq(address5, "abcdefghijklmnop");
- test_assert(ONION_HOSTNAME == parse_extended_hostname(address6));
- test_streq(address6, "abcdefghijklmnop");
- test_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
+ (void)arg;
+ tt_assert(BAD_HOSTNAME == parse_extended_hostname(address1));
+ tt_assert(ONION_HOSTNAME == parse_extended_hostname(address2));
+ tt_str_op(address2,OP_EQ, "aaaaaaaaaaaaaaaa");
+ tt_assert(EXIT_HOSTNAME == parse_extended_hostname(address3));
+ tt_assert(NORMAL_HOSTNAME == parse_extended_hostname(address4));
+ tt_assert(ONION_HOSTNAME == parse_extended_hostname(address5));
+ tt_str_op(address5,OP_EQ, "abcdefghijklmnop");
+ tt_assert(ONION_HOSTNAME == parse_extended_hostname(address6));
+ tt_str_op(address6,OP_EQ, "abcdefghijklmnop");
+ tt_assert(BAD_HOSTNAME == parse_extended_hostname(address7));
pk1 = pk_generate(0);
pk2 = pk_generate(1);
@@ -676,40 +525,41 @@ test_rend_fns(void)
intro->intro_key = crypto_pk_dup_key(pk2);
smartlist_add(generated->intro_nodes, intro);
}
- test_assert(rend_encode_v2_descriptors(descs, generated, now, 0,
+ tt_assert(rend_encode_v2_descriptors(descs, generated, now, 0,
REND_NO_AUTH, NULL, NULL) > 0);
- test_assert(rend_compute_v2_desc_id(computed_desc_id, service_id_base32,
+ tt_assert(rend_compute_v2_desc_id(computed_desc_id, service_id_base32,
NULL, now, 0) == 0);
- test_memeq(((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0))->desc_id, computed_desc_id, DIGEST_LEN);
- test_assert(rend_parse_v2_service_descriptor(&parsed, parsed_desc_id,
- &intro_points_encrypted,
- &intro_points_size,
- &encoded_size,
- &next_desc,
- ((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0))->desc_str) == 0);
- test_assert(parsed);
- test_memeq(((rend_encoded_v2_service_descriptor_t *)
- smartlist_get(descs, 0))->desc_id, parsed_desc_id, DIGEST_LEN);
- test_eq(rend_parse_introduction_points(parsed, intro_points_encrypted,
- intro_points_size), 3);
- test_assert(!crypto_pk_cmp_keys(generated->pk, parsed->pk));
- test_eq(parsed->timestamp, now);
- test_eq(parsed->version, 2);
- test_eq(parsed->protocols, 42);
- test_eq(smartlist_len(parsed->intro_nodes), 3);
+ tt_mem_op(((rend_encoded_v2_service_descriptor_t *)
+ smartlist_get(descs, 0))->desc_id, OP_EQ,
+ computed_desc_id, DIGEST_LEN);
+ tt_assert(rend_parse_v2_service_descriptor(&parsed, parsed_desc_id,
+ &intro_points_encrypted,
+ &intro_points_size,
+ &encoded_size,
+ &next_desc,
+ ((rend_encoded_v2_service_descriptor_t *)
+ smartlist_get(descs, 0))->desc_str, 1) == 0);
+ tt_assert(parsed);
+ tt_mem_op(((rend_encoded_v2_service_descriptor_t *)
+ smartlist_get(descs, 0))->desc_id,OP_EQ, parsed_desc_id, DIGEST_LEN);
+ tt_int_op(rend_parse_introduction_points(parsed, intro_points_encrypted,
+ intro_points_size),OP_EQ, 3);
+ tt_assert(!crypto_pk_cmp_keys(generated->pk, parsed->pk));
+ tt_int_op(parsed->timestamp,OP_EQ, now);
+ tt_int_op(parsed->version,OP_EQ, 2);
+ tt_int_op(parsed->protocols,OP_EQ, 42);
+ tt_int_op(smartlist_len(parsed->intro_nodes),OP_EQ, 3);
for (i = 0; i < smartlist_len(parsed->intro_nodes); i++) {
rend_intro_point_t *par_intro = smartlist_get(parsed->intro_nodes, i),
*gen_intro = smartlist_get(generated->intro_nodes, i);
extend_info_t *par_info = par_intro->extend_info;
extend_info_t *gen_info = gen_intro->extend_info;
- test_assert(!crypto_pk_cmp_keys(gen_info->onion_key, par_info->onion_key));
- test_memeq(gen_info->identity_digest, par_info->identity_digest,
+ tt_assert(!crypto_pk_cmp_keys(gen_info->onion_key, par_info->onion_key));
+ tt_mem_op(gen_info->identity_digest,OP_EQ, par_info->identity_digest,
DIGEST_LEN);
- test_streq(gen_info->nickname, par_info->nickname);
- test_assert(tor_addr_eq(&gen_info->addr, &par_info->addr));
- test_eq(gen_info->port, par_info->port);
+ tt_str_op(gen_info->nickname,OP_EQ, par_info->nickname);
+ tt_assert(tor_addr_eq(&gen_info->addr, &par_info->addr));
+ tt_int_op(gen_info->port,OP_EQ, par_info->port);
}
rend_service_descriptor_free(parsed);
@@ -753,17 +603,17 @@ test_rend_fns(void)
} while (0)
#define CHECK_COUNTRY(country, val) do { \
/* test ipv4 country lookup */ \
- test_streq(country, \
+ tt_str_op(country, OP_EQ, \
geoip_get_country_name(geoip_get_country_by_ipv4(val))); \
/* test ipv6 country lookup */ \
SET_TEST_IPV6(val); \
- test_streq(country, \
+ tt_str_op(country, OP_EQ, \
geoip_get_country_name(geoip_get_country_by_ipv6(&in6))); \
} while (0)
/** Run unit tests for GeoIP code. */
static void
-test_geoip(void)
+test_geoip(void *arg)
{
int i, j;
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
@@ -817,23 +667,24 @@ test_geoip(void)
/* Populate the DB a bit. Add these in order, since we can't do the final
* 'sort' step. These aren't very good IP addresses, but they're perfectly
* fine uint32_t values. */
- test_eq(0, geoip_parse_entry("10,50,AB", AF_INET));
- test_eq(0, geoip_parse_entry("52,90,XY", AF_INET));
- test_eq(0, geoip_parse_entry("95,100,AB", AF_INET));
- test_eq(0, geoip_parse_entry("\"105\",\"140\",\"ZZ\"", AF_INET));
- test_eq(0, geoip_parse_entry("\"150\",\"190\",\"XY\"", AF_INET));
- test_eq(0, geoip_parse_entry("\"200\",\"250\",\"AB\"", AF_INET));
+ (void)arg;
+ tt_int_op(0,OP_EQ, geoip_parse_entry("10,50,AB", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("52,90,XY", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("95,100,AB", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("\"105\",\"140\",\"ZZ\"", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("\"150\",\"190\",\"XY\"", AF_INET));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("\"200\",\"250\",\"AB\"", AF_INET));
/* Populate the IPv6 DB equivalently with fake IPs in the same range */
- test_eq(0, geoip_parse_entry("::a,::32,AB", AF_INET6));
- test_eq(0, geoip_parse_entry("::34,::5a,XY", AF_INET6));
- test_eq(0, geoip_parse_entry("::5f,::64,AB", AF_INET6));
- test_eq(0, geoip_parse_entry("::69,::8c,ZZ", AF_INET6));
- test_eq(0, geoip_parse_entry("::96,::be,XY", AF_INET6));
- test_eq(0, geoip_parse_entry("::c8,::fa,AB", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::a,::32,AB", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::34,::5a,XY", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::5f,::64,AB", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::69,::8c,ZZ", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::96,::be,XY", AF_INET6));
+ tt_int_op(0,OP_EQ, geoip_parse_entry("::c8,::fa,AB", AF_INET6));
/* We should have 4 countries: ??, ab, xy, zz. */
- test_eq(4, geoip_get_n_countries());
+ tt_int_op(4,OP_EQ, geoip_get_n_countries());
memset(&in6, 0, sizeof(in6));
CHECK_COUNTRY("??", 3);
@@ -844,9 +695,9 @@ test_geoip(void)
CHECK_COUNTRY("xy", 190);
CHECK_COUNTRY("??", 2000);
- test_eq(0, geoip_get_country_by_ipv4(3));
+ tt_int_op(0,OP_EQ, geoip_get_country_by_ipv4(3));
SET_TEST_IPV6(3);
- test_eq(0, geoip_get_country_by_ipv6(&in6));
+ tt_int_op(0,OP_EQ, geoip_get_country_by_ipv6(&in6));
get_options_mutable()->BridgeRelay = 1;
get_options_mutable()->BridgeRecordUsageByCountry = 1;
@@ -869,41 +720,41 @@ test_geoip(void)
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
}
geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
- test_assert(s);
- test_assert(v);
- test_streq("zz=24,ab=16,xy=8", s);
- test_streq("v4=16,v6=16", v);
+ tt_assert(s);
+ tt_assert(v);
+ tt_str_op("zz=24,ab=16,xy=8",OP_EQ, s);
+ tt_str_op("v4=16,v6=16",OP_EQ, v);
tor_free(s);
tor_free(v);
/* Now clear out all the AB observations. */
geoip_remove_old_clients(now-6000);
geoip_get_client_history(GEOIP_CLIENT_CONNECT, &s, &v);
- test_assert(s);
- test_assert(v);
- test_streq("zz=24,xy=8", s);
- test_streq("v4=16,v6=16", v);
+ tt_assert(s);
+ tt_assert(v);
+ tt_str_op("zz=24,xy=8",OP_EQ, s);
+ tt_str_op("v4=16,v6=16",OP_EQ, v);
tor_free(s);
tor_free(v);
/* Start testing bridge statistics by making sure that we don't output
* bridge stats without initializing them. */
s = geoip_format_bridge_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Initialize stats and generate the bridge-stats history string out of
* the connecting clients added above. */
geoip_bridge_stats_init(now);
s = geoip_format_bridge_stats(now + 86400);
- test_assert(s);
- test_streq(bridge_stats_1, s);
+ tt_assert(s);
+ tt_str_op(bridge_stats_1,OP_EQ, s);
tor_free(s);
/* Stop collecting bridge stats and make sure we don't write a history
* string anymore. */
geoip_bridge_stats_term();
s = geoip_format_bridge_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Stop being a bridge and start being a directory mirror that gathers
* directory request statistics. */
@@ -917,7 +768,7 @@ test_geoip(void)
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Initialize stats, note one connecting client, and generate the
* dirreq-stats history string. */
@@ -925,7 +776,7 @@ test_geoip(void)
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
- test_streq(dirreq_stats_1, s);
+ tt_str_op(dirreq_stats_1,OP_EQ, s);
tor_free(s);
/* Stop collecting stats, add another connecting client, and ensure we
@@ -934,7 +785,7 @@ test_geoip(void)
SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
s = geoip_format_dirreq_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
@@ -943,20 +794,20 @@ test_geoip(void)
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, NULL, now);
geoip_reset_dirreq_stats(now);
s = geoip_format_dirreq_stats(now + 86400);
- test_streq(dirreq_stats_2, s);
+ tt_str_op(dirreq_stats_2,OP_EQ, s);
tor_free(s);
/* Note a successful network status response and make sure that it
* appears in the history string. */
geoip_note_ns_response(GEOIP_SUCCESS);
s = geoip_format_dirreq_stats(now + 86400);
- test_streq(dirreq_stats_3, s);
+ tt_str_op(dirreq_stats_3,OP_EQ, s);
tor_free(s);
/* Start a tunneled directory request. */
geoip_start_dirreq((uint64_t) 1, 1024, DIRREQ_TUNNELED);
s = geoip_format_dirreq_stats(now + 86400);
- test_streq(dirreq_stats_4, s);
+ tt_str_op(dirreq_stats_4,OP_EQ, s);
tor_free(s);
/* Stop collecting directory request statistics and start gathering
@@ -970,7 +821,7 @@ test_geoip(void)
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Initialize stats, note one connecting client, and generate the
* entry-stats history string. */
@@ -978,7 +829,7 @@ test_geoip(void)
SET_TEST_ADDRESS(100);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
- test_streq(entry_stats_1, s);
+ tt_str_op(entry_stats_1,OP_EQ, s);
tor_free(s);
/* Stop collecting stats, add another connecting client, and ensure we
@@ -987,7 +838,7 @@ test_geoip(void)
SET_TEST_ADDRESS(101);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
s = geoip_format_entry_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
@@ -996,7 +847,7 @@ test_geoip(void)
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &addr, NULL, now);
geoip_reset_entry_stats(now);
s = geoip_format_entry_stats(now + 86400);
- test_streq(entry_stats_2, s);
+ tt_str_op(entry_stats_2,OP_EQ, s);
tor_free(s);
/* Stop collecting entry statistics. */
@@ -1009,7 +860,7 @@ test_geoip(void)
}
static void
-test_geoip_with_pt(void)
+test_geoip_with_pt(void *arg)
{
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
char *s = NULL;
@@ -1017,6 +868,7 @@ test_geoip_with_pt(void)
tor_addr_t addr;
struct in6_addr in6;
+ (void)arg;
get_options_mutable()->BridgeRelay = 1;
get_options_mutable()->BridgeRecordUsageByCountry = 1;
@@ -1068,7 +920,7 @@ test_geoip_with_pt(void)
/* Test the transport history string. */
s = geoip_get_transport_history();
tor_assert(s);
- test_streq(s, "<OR>=8,alpha=16,beta=8,charlie=16,ddr=136,"
+ tt_str_op(s,OP_EQ, "<OR>=8,alpha=16,beta=8,charlie=16,ddr=136,"
"entropy=8,fire=8,google=8");
/* Stop collecting entry statistics. */
@@ -1085,7 +937,7 @@ test_geoip_with_pt(void)
/** Run unit tests for stats code. */
static void
-test_stats(void)
+test_stats(void *arg)
{
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
char *s = NULL;
@@ -1093,10 +945,11 @@ test_stats(void)
/* Start with testing exit port statistics; we shouldn't collect exit
* stats without initializing them. */
+ (void)arg;
rep_hist_note_exit_stream_opened(80);
rep_hist_note_exit_bytes(80, 100, 10000);
s = rep_hist_format_exit_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Initialize stats, note some streams and bytes, and generate history
* string. */
@@ -1107,10 +960,10 @@ test_stats(void)
rep_hist_note_exit_bytes(443, 100, 10000);
rep_hist_note_exit_bytes(443, 100, 10000);
s = rep_hist_format_exit_stats(now + 86400);
- test_streq("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"exit-kibibytes-written 80=1,443=1,other=0\n"
"exit-kibibytes-read 80=10,443=20,other=0\n"
- "exit-streams-opened 80=4,443=4,other=0\n", s);
+ "exit-streams-opened 80=4,443=4,other=0\n",OP_EQ, s);
tor_free(s);
/* Add a few bytes on 10 more ports and ensure that only the top 10
@@ -1120,13 +973,13 @@ test_stats(void)
rep_hist_note_exit_stream_opened(i);
}
s = rep_hist_format_exit_stats(now + 86400);
- test_streq("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"exit-kibibytes-written 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
"59=1,80=1,443=1,other=1\n"
"exit-kibibytes-read 52=1,53=1,54=1,55=1,56=1,57=1,58=1,"
"59=1,80=10,443=20,other=1\n"
"exit-streams-opened 52=4,53=4,54=4,55=4,56=4,57=4,58=4,"
- "59=4,80=4,443=4,other=4\n", s);
+ "59=4,80=4,443=4,other=4\n",OP_EQ, s);
tor_free(s);
/* Stop collecting stats, add some bytes, and ensure we don't generate
@@ -1134,7 +987,7 @@ test_stats(void)
rep_hist_exit_stats_term();
rep_hist_note_exit_bytes(80, 100, 10000);
s = rep_hist_format_exit_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Re-start stats, add some bytes, reset stats, and see what history we
* get when observing no streams or bytes at all. */
@@ -1143,17 +996,17 @@ test_stats(void)
rep_hist_note_exit_bytes(80, 100, 10000);
rep_hist_reset_exit_stats(now);
s = rep_hist_format_exit_stats(now + 86400);
- test_streq("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ tt_str_op("exit-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"exit-kibibytes-written other=0\n"
"exit-kibibytes-read other=0\n"
- "exit-streams-opened other=0\n", s);
+ "exit-streams-opened other=0\n",OP_EQ, s);
tor_free(s);
/* Continue with testing connection statistics; we shouldn't collect
* conn stats without initializing them. */
rep_hist_note_or_conn_bytes(1, 20, 400, now);
s = rep_hist_format_conn_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Initialize stats, note bytes, and generate history string. */
rep_hist_conn_stats_init(now);
@@ -1162,7 +1015,7 @@ test_stats(void)
rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
s = rep_hist_format_conn_stats(now + 86400);
- test_streq("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n", s);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n",OP_EQ, s);
tor_free(s);
/* Stop collecting stats, add some bytes, and ensure we don't generate
@@ -1170,7 +1023,7 @@ test_stats(void)
rep_hist_conn_stats_term();
rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
s = rep_hist_format_conn_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Re-start stats, add some bytes, reset stats, and see what history we
* get when observing no bytes at all. */
@@ -1181,26 +1034,26 @@ test_stats(void)
rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
rep_hist_reset_conn_stats(now);
s = rep_hist_format_conn_stats(now + 86400);
- test_streq("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n", s);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",OP_EQ, s);
tor_free(s);
/* Continue with testing buffer statistics; we shouldn't collect buffer
* stats without initializing them. */
rep_hist_add_buffer_stats(2.0, 2.0, 20);
s = rep_hist_format_buffer_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Initialize stats, add statistics for a single circuit, and generate
* the history string. */
rep_hist_buffer_stats_init(now);
rep_hist_add_buffer_stats(2.0, 2.0, 20);
s = rep_hist_format_buffer_stats(now + 86400);
- test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"cell-processed-cells 20,0,0,0,0,0,0,0,0,0\n"
"cell-queued-cells 2.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
"0.00,0.00\n"
"cell-time-in-queue 2,0,0,0,0,0,0,0,0,0\n"
- "cell-circuits-per-decile 1\n", s);
+ "cell-circuits-per-decile 1\n",OP_EQ, s);
tor_free(s);
/* Add nineteen more circuit statistics to the one that's already in the
@@ -1210,12 +1063,12 @@ test_stats(void)
for (i = 20; i < 30; i++)
rep_hist_add_buffer_stats(3.5, 3.5, i);
s = rep_hist_format_buffer_stats(now + 86400);
- test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"cell-processed-cells 29,28,27,26,25,24,23,22,21,20\n"
"cell-queued-cells 2.75,2.75,2.75,2.75,2.75,2.75,2.75,2.75,"
"2.75,2.75\n"
"cell-time-in-queue 3,3,3,3,3,3,3,3,3,3\n"
- "cell-circuits-per-decile 2\n", s);
+ "cell-circuits-per-decile 2\n",OP_EQ, s);
tor_free(s);
/* Stop collecting stats, add statistics for one circuit, and ensure we
@@ -1223,7 +1076,7 @@ test_stats(void)
rep_hist_buffer_stats_term();
rep_hist_add_buffer_stats(2.0, 2.0, 20);
s = rep_hist_format_buffer_stats(now + 86400);
- test_assert(!s);
+ tt_assert(!s);
/* Re-start stats, add statistics for one circuit, reset stats, and make
* sure that the history has all zeros. */
@@ -1231,54 +1084,27 @@ test_stats(void)
rep_hist_add_buffer_stats(2.0, 2.0, 20);
rep_hist_reset_buffer_stats(now);
s = rep_hist_format_buffer_stats(now + 86400);
- test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
+ tt_str_op("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"cell-processed-cells 0,0,0,0,0,0,0,0,0,0\n"
"cell-queued-cells 0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
"0.00,0.00\n"
"cell-time-in-queue 0,0,0,0,0,0,0,0,0,0\n"
- "cell-circuits-per-decile 0\n", s);
+ "cell-circuits-per-decile 0\n",OP_EQ, s);
done:
tor_free(s);
}
-static void *
-legacy_test_setup(const struct testcase_t *testcase)
-{
- return testcase->setup_data;
-}
-
-void
-legacy_test_helper(void *data)
-{
- void (*fn)(void) = data;
- fn();
-}
-
-static int
-legacy_test_cleanup(const struct testcase_t *testcase, void *ptr)
-{
- (void)ptr;
- (void)testcase;
- return 1;
-}
-
-const struct testcase_setup_t legacy_setup = {
- legacy_test_setup, legacy_test_cleanup
-};
-
#define ENT(name) \
- { #name, legacy_test_helper, 0, &legacy_setup, test_ ## name }
+ { #name, test_ ## name , 0, NULL, NULL }
#define FORK(name) \
- { #name, legacy_test_helper, TT_FORK, &legacy_setup, test_ ## name }
+ { #name, test_ ## name , TT_FORK, NULL, NULL }
static struct testcase_t test_array[] = {
ENT(onion_handshake),
{ "bad_onion_handshake", test_bad_onion_handshake, 0, NULL, NULL },
ENT(onion_queues),
-#ifdef CURVE25519_ENABLED
{ "ntor_handshake", test_ntor_handshake, 0, NULL, NULL },
-#endif
ENT(circuit_timeout),
ENT(rend_fns),
ENT(geoip),
@@ -1288,145 +1114,90 @@ static struct testcase_t test_array[] = {
END_OF_TESTCASES
};
+extern struct testcase_t accounting_tests[];
extern struct testcase_t addr_tests[];
+extern struct testcase_t address_tests[];
extern struct testcase_t buffer_tests[];
-extern struct testcase_t crypto_tests[];
-extern struct testcase_t container_tests[];
-extern struct testcase_t util_tests[];
-extern struct testcase_t dir_tests[];
-extern struct testcase_t microdesc_tests[];
-extern struct testcase_t pt_tests[];
-extern struct testcase_t config_tests[];
-extern struct testcase_t introduce_tests[];
-extern struct testcase_t replaycache_tests[];
-extern struct testcase_t relaycell_tests[];
extern struct testcase_t cell_format_tests[];
+extern struct testcase_t cell_queue_tests[];
+extern struct testcase_t channel_tests[];
+extern struct testcase_t channeltls_tests[];
+extern struct testcase_t checkdir_tests[];
extern struct testcase_t circuitlist_tests[];
extern struct testcase_t circuitmux_tests[];
-extern struct testcase_t cell_queue_tests[];
-extern struct testcase_t options_tests[];
-extern struct testcase_t socks_tests[];
-extern struct testcase_t extorport_tests[];
+extern struct testcase_t config_tests[];
+extern struct testcase_t container_tests[];
extern struct testcase_t controller_event_tests[];
-extern struct testcase_t logging_tests[];
+extern struct testcase_t crypto_tests[];
+extern struct testcase_t dir_tests[];
+extern struct testcase_t entryconn_tests[];
+extern struct testcase_t entrynodes_tests[];
+extern struct testcase_t guardfraction_tests[];
+extern struct testcase_t extorport_tests[];
extern struct testcase_t hs_tests[];
+extern struct testcase_t introduce_tests[];
+extern struct testcase_t logging_tests[];
+extern struct testcase_t microdesc_tests[];
extern struct testcase_t nodelist_tests[];
-extern struct testcase_t routerkeys_tests[];
extern struct testcase_t oom_tests[];
+extern struct testcase_t options_tests[];
extern struct testcase_t policy_tests[];
+extern struct testcase_t pt_tests[];
+extern struct testcase_t relay_tests[];
+extern struct testcase_t relaycell_tests[];
+extern struct testcase_t replaycache_tests[];
+extern struct testcase_t router_tests[];
+extern struct testcase_t routerkeys_tests[];
+extern struct testcase_t routerlist_tests[];
+extern struct testcase_t routerset_tests[];
+extern struct testcase_t scheduler_tests[];
+extern struct testcase_t socks_tests[];
extern struct testcase_t status_tests[];
+extern struct testcase_t thread_tests[];
+extern struct testcase_t util_tests[];
-static struct testgroup_t testgroups[] = {
+struct testgroup_t testgroups[] = {
{ "", test_array },
- { "buffer/", buffer_tests },
- { "socks/", socks_tests },
+ { "accounting/", accounting_tests },
{ "addr/", addr_tests },
- { "crypto/", crypto_tests },
- { "container/", container_tests },
- { "util/", util_tests },
- { "util/logging/", logging_tests },
+ { "address/", address_tests },
+ { "buffer/", buffer_tests },
{ "cellfmt/", cell_format_tests },
{ "cellqueue/", cell_queue_tests },
- { "dir/", dir_tests },
- { "dir/md/", microdesc_tests },
- { "pt/", pt_tests },
- { "config/", config_tests },
- { "replaycache/", replaycache_tests },
- { "relaycell/", relaycell_tests },
- { "introduce/", introduce_tests },
+ { "channel/", channel_tests },
+ { "channeltls/", channeltls_tests },
+ { "checkdir/", checkdir_tests },
{ "circuitlist/", circuitlist_tests },
{ "circuitmux/", circuitmux_tests },
- { "options/", options_tests },
- { "extorport/", extorport_tests },
+ { "config/", config_tests },
+ { "container/", container_tests },
{ "control/", controller_event_tests },
+ { "crypto/", crypto_tests },
+ { "dir/", dir_tests },
+ { "dir/md/", microdesc_tests },
+ { "entryconn/", entryconn_tests },
+ { "entrynodes/", entrynodes_tests },
+ { "guardfraction/", guardfraction_tests },
+ { "extorport/", extorport_tests },
{ "hs/", hs_tests },
+ { "introduce/", introduce_tests },
{ "nodelist/", nodelist_tests },
- { "routerkeys/", routerkeys_tests },
{ "oom/", oom_tests },
+ { "options/", options_tests },
{ "policy/" , policy_tests },
+ { "pt/", pt_tests },
+ { "relay/" , relay_tests },
+ { "relaycell/", relaycell_tests },
+ { "replaycache/", replaycache_tests },
+ { "routerkeys/", routerkeys_tests },
+ { "routerlist/", routerlist_tests },
+ { "routerset/" , routerset_tests },
+ { "scheduler/", scheduler_tests },
+ { "socks/", socks_tests },
{ "status/" , status_tests },
+ { "util/", util_tests },
+ { "util/logging/", logging_tests },
+ { "util/thread/", thread_tests },
END_OF_GROUPS
};
-/** Main entry point for unit test code: parse the command line, and run
- * some unit tests. */
-int
-main(int c, const char **v)
-{
- or_options_t *options;
- char *errmsg = NULL;
- int i, i_out;
- int loglevel = LOG_ERR;
- int accel_crypto = 0;
-
-#ifdef USE_DMALLOC
- {
- int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
- tor_assert(r);
- }
-#endif
-
- update_approx_time(time(NULL));
- options = options_new();
- tor_threads_init();
- init_logging();
-
- for (i_out = i = 1; i < c; ++i) {
- if (!strcmp(v[i], "--warn")) {
- loglevel = LOG_WARN;
- } else if (!strcmp(v[i], "--notice")) {
- loglevel = LOG_NOTICE;
- } else if (!strcmp(v[i], "--info")) {
- loglevel = LOG_INFO;
- } else if (!strcmp(v[i], "--debug")) {
- loglevel = LOG_DEBUG;
- } else if (!strcmp(v[i], "--accel")) {
- accel_crypto = 1;
- } else {
- v[i_out++] = v[i];
- }
- }
- c = i_out;
-
- {
- log_severity_list_t s;
- memset(&s, 0, sizeof(s));
- set_log_severity_config(loglevel, LOG_ERR, &s);
- add_stream_log(&s, "", fileno(stdout));
- }
-
- options->command = CMD_RUN_UNITTESTS;
- if (crypto_global_init(accel_crypto, NULL, NULL)) {
- printf("Can't initialize crypto subsystem; exiting.\n");
- return 1;
- }
- crypto_set_tls_dh_prime(NULL);
- crypto_seed_rng(1);
- rep_hist_init();
- network_init();
- setup_directory();
- options_init(options);
- options->DataDirectory = tor_strdup(temp_dir);
- options->EntryStatistics = 1;
- if (set_options(options, &errmsg) < 0) {
- printf("Failed to set initial options: %s\n", errmsg);
- tor_free(errmsg);
- return 1;
- }
-
- atexit(remove_directory);
-
- have_failed = (tinytest_main(c, v, testgroups) != 0);
-
- free_pregenerated_keys();
-#ifdef USE_DMALLOC
- tor_free_all(0);
- dmalloc_log_unfreed();
-#endif
-
- if (have_failed)
- return 1;
- else
- return 0;
-}
-
diff --git a/src/test/test.h b/src/test/test.h
index b9e4d5bdb4..b0c0946ac4 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2003, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#ifndef TOR_TEST_H
@@ -22,25 +22,6 @@
#define PRETTY_FUNCTION ""
#endif
-#define test_fail_msg(msg) TT_DIE((msg))
-
-#define test_fail() test_fail_msg("Assertion failed.")
-
-#define test_assert(expr) tt_assert(expr)
-
-#define test_eq(expr1, expr2) tt_int_op((expr1), ==, (expr2))
-#define test_eq_ptr(expr1, expr2) tt_ptr_op((expr1), ==, (expr2))
-#define test_neq(expr1, expr2) tt_int_op((expr1), !=, (expr2))
-#define test_neq_ptr(expr1, expr2) tt_ptr_op((expr1), !=, (expr2))
-#define test_streq(expr1, expr2) tt_str_op((expr1), ==, (expr2))
-#define test_strneq(expr1, expr2) tt_str_op((expr1), !=, (expr2))
-
-#define test_mem_op(expr1, op, expr2, len) \
- tt_mem_op((expr1), op, (expr2), (len))
-
-#define test_memeq(expr1, expr2, len) test_mem_op((expr1), ==, (expr2), len)
-#define test_memneq(expr1, expr2, len) test_mem_op((expr1), !=, (expr2), len)
-
/* As test_mem_op, but decodes 'hex' before comparing. There must be a
* local char* variable called mem_op_hex_tmp for this to work. */
#define test_mem_op_hex(expr1, op, hex) \
@@ -50,13 +31,13 @@
mem_op_hex_tmp = tor_malloc(length/2); \
tor_assert((length&1)==0); \
base16_decode(mem_op_hex_tmp, length/2, hex, length); \
- test_mem_op(expr1, op, mem_op_hex_tmp, length/2); \
+ tt_mem_op(expr1, op, mem_op_hex_tmp, length/2); \
STMT_END
-#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, ==, hex)
+#define test_memeq_hex(expr1, hex) test_mem_op_hex(expr1, OP_EQ, hex)
#define tt_double_op(a,op,b) \
- tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%f", \
+ tt_assert_test_type(a,b,#a" "#op" "#b,double,(val1_ op val2_),"%g", \
TT_EXIT_TEST_FUNCTION)
#ifdef _MSC_VER
@@ -85,9 +66,6 @@
const char *get_fname(const char *name);
crypto_pk_t *pk_generate(int idx);
-void legacy_test_helper(void *data);
-extern const struct testcase_setup_t legacy_setup;
-
#define US2_CONCAT_2__(a, b) a ## __ ## b
#define US_CONCAT_2__(a, b) a ## _ ## b
#define US_CONCAT_3__(a, b, c) a ## _ ## b ## _ ## c
@@ -180,5 +158,7 @@ extern const struct testcase_setup_t legacy_setup;
#define NS_MOCK(name) MOCK(name, NS(name))
#define NS_UNMOCK(name) UNMOCK(name)
+extern const struct testcase_setup_t passthrough_setup;
+
#endif
diff --git a/src/test/test_accounting.c b/src/test/test_accounting.c
new file mode 100644
index 0000000000..25908e942c
--- /dev/null
+++ b/src/test/test_accounting.c
@@ -0,0 +1,76 @@
+#include "or.h"
+#include "test.h"
+#define HIBERNATE_PRIVATE
+#include "hibernate.h"
+#include "config.h"
+#define STATEFILE_PRIVATE
+#include "statefile.h"
+
+#define NS_MODULE accounting
+
+#define NS_SUBMODULE limits
+
+/*
+ * Test to make sure accounting triggers hibernation
+ * correctly with both sum or max rules set
+ */
+
+static or_state_t *or_state;
+NS_DECL(or_state_t *, get_or_state, (void));
+static or_state_t *
+NS(get_or_state)(void)
+{
+ return or_state;
+}
+
+static void
+test_accounting_limits(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ time_t fake_time = time(NULL);
+ (void) arg;
+
+ NS_MOCK(get_or_state);
+ or_state = or_state_new();
+
+ options->AccountingMax = 100;
+ options->AccountingRule = ACCT_MAX;
+
+ tor_assert(accounting_is_enabled(options));
+ configure_accounting(fake_time);
+
+ accounting_add_bytes(10, 0, 1);
+ fake_time += 1;
+ consider_hibernation(fake_time);
+ tor_assert(we_are_hibernating() == 0);
+
+ accounting_add_bytes(90, 0, 1);
+ fake_time += 1;
+ consider_hibernation(fake_time);
+ tor_assert(we_are_hibernating() == 1);
+
+ options->AccountingMax = 200;
+ options->AccountingRule = ACCT_SUM;
+
+ accounting_add_bytes(0, 10, 1);
+ fake_time += 1;
+ consider_hibernation(fake_time);
+ tor_assert(we_are_hibernating() == 0);
+
+ accounting_add_bytes(0, 90, 1);
+ fake_time += 1;
+ consider_hibernation(fake_time);
+ tor_assert(we_are_hibernating() == 1);
+ goto done;
+ done:
+ NS_UNMOCK(get_or_state);
+ or_state_free(or_state);
+}
+
+#undef NS_SUBMODULE
+
+struct testcase_t accounting_tests[] = {
+ { "bwlimits", test_accounting_limits, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 2c126e6d14..0f77e73630 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define ADDRESSMAP_PRIVATE
@@ -10,49 +10,50 @@
#include "addressmap.h"
static void
-test_addr_basic(void)
+test_addr_basic(void *arg)
{
uint32_t u32;
uint16_t u16;
char *cp;
/* Test addr_port_lookup */
+ (void)arg;
cp = NULL; u32 = 3; u16 = 3;
- test_assert(!addr_port_lookup(LOG_WARN, "1.2.3.4", &cp, &u32, &u16));
- test_streq(cp, "1.2.3.4");
- test_eq(u32, 0x01020304u);
- test_eq(u16, 0);
+ tt_assert(!addr_port_lookup(LOG_WARN, "1.2.3.4", &cp, &u32, &u16));
+ tt_str_op(cp,OP_EQ, "1.2.3.4");
+ tt_int_op(u32,OP_EQ, 0x01020304u);
+ tt_int_op(u16,OP_EQ, 0);
tor_free(cp);
- test_assert(!addr_port_lookup(LOG_WARN, "4.3.2.1:99", &cp, &u32, &u16));
- test_streq(cp, "4.3.2.1");
- test_eq(u32, 0x04030201u);
- test_eq(u16, 99);
+ tt_assert(!addr_port_lookup(LOG_WARN, "4.3.2.1:99", &cp, &u32, &u16));
+ tt_str_op(cp,OP_EQ, "4.3.2.1");
+ tt_int_op(u32,OP_EQ, 0x04030201u);
+ tt_int_op(u16,OP_EQ, 99);
tor_free(cp);
- test_assert(!addr_port_lookup(LOG_WARN, "nonexistent.address:4040",
+ tt_assert(!addr_port_lookup(LOG_WARN, "nonexistent.address:4040",
&cp, NULL, &u16));
- test_streq(cp, "nonexistent.address");
- test_eq(u16, 4040);
+ tt_str_op(cp,OP_EQ, "nonexistent.address");
+ tt_int_op(u16,OP_EQ, 4040);
tor_free(cp);
- test_assert(!addr_port_lookup(LOG_WARN, "localhost:9999", &cp, &u32, &u16));
- test_streq(cp, "localhost");
- test_eq(u32, 0x7f000001u);
- test_eq(u16, 9999);
+ tt_assert(!addr_port_lookup(LOG_WARN, "localhost:9999", &cp, &u32, &u16));
+ tt_str_op(cp,OP_EQ, "localhost");
+ tt_int_op(u32,OP_EQ, 0x7f000001u);
+ tt_int_op(u16,OP_EQ, 9999);
tor_free(cp);
u32 = 3;
- test_assert(!addr_port_lookup(LOG_WARN, "localhost", NULL, &u32, &u16));
- test_eq_ptr(cp, NULL);
- test_eq(u32, 0x7f000001u);
- test_eq(u16, 0);
+ tt_assert(!addr_port_lookup(LOG_WARN, "localhost", NULL, &u32, &u16));
+ tt_ptr_op(cp,OP_EQ, NULL);
+ tt_int_op(u32,OP_EQ, 0x7f000001u);
+ tt_int_op(u16,OP_EQ, 0);
tor_free(cp);
- test_assert(addr_port_lookup(LOG_WARN, "localhost:3", &cp, &u32, NULL));
+ tt_assert(addr_port_lookup(LOG_WARN, "localhost:3", &cp, &u32, NULL));
tor_free(cp);
- test_eq(0, addr_mask_get_bits(0x0u));
- test_eq(32, addr_mask_get_bits(0xFFFFFFFFu));
- test_eq(16, addr_mask_get_bits(0xFFFF0000u));
- test_eq(31, addr_mask_get_bits(0xFFFFFFFEu));
- test_eq(1, addr_mask_get_bits(0x80000000u));
+ tt_int_op(0,OP_EQ, addr_mask_get_bits(0x0u));
+ tt_int_op(32,OP_EQ, addr_mask_get_bits(0xFFFFFFFFu));
+ tt_int_op(16,OP_EQ, addr_mask_get_bits(0xFFFF0000u));
+ tt_int_op(31,OP_EQ, addr_mask_get_bits(0xFFFFFFFEu));
+ tt_int_op(1,OP_EQ, addr_mask_get_bits(0x80000000u));
/* Test inet_ntop */
{
@@ -61,15 +62,16 @@ test_addr_basic(void)
struct in_addr in;
/* good round trip */
- test_eq(tor_inet_pton(AF_INET, ip, &in), 1);
- test_eq_ptr(tor_inet_ntop(AF_INET, &in, tmpbuf, sizeof(tmpbuf)), &tmpbuf);
- test_streq(tmpbuf, ip);
+ tt_int_op(tor_inet_pton(AF_INET, ip, &in), OP_EQ, 1);
+ tt_ptr_op(tor_inet_ntop(AF_INET, &in, tmpbuf, sizeof(tmpbuf)),
+ OP_EQ, &tmpbuf);
+ tt_str_op(tmpbuf,OP_EQ, ip);
/* just enough buffer length */
- test_streq(tor_inet_ntop(AF_INET, &in, tmpbuf, strlen(ip) + 1), ip);
+ tt_str_op(tor_inet_ntop(AF_INET, &in, tmpbuf, strlen(ip) + 1), OP_EQ, ip);
/* too short buffer */
- test_eq_ptr(tor_inet_ntop(AF_INET, &in, tmpbuf, strlen(ip)), NULL);
+ tt_ptr_op(tor_inet_ntop(AF_INET, &in, tmpbuf, strlen(ip)),OP_EQ, NULL);
}
done:
@@ -96,67 +98,68 @@ test_addr_basic(void)
/** Helper: Assert that two strings both decode as IPv6 addresses with
* tor_inet_pton(), and both decode to the same address. */
-#define test_pton6_same(a,b) STMT_BEGIN \
- test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
- test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
- test_op_ip6_(&a1,==,&a2,#a,#b); \
+#define test_pton6_same(a,b) STMT_BEGIN \
+ tt_int_op(tor_inet_pton(AF_INET6, a, &a1), OP_EQ, 1); \
+ tt_int_op(tor_inet_pton(AF_INET6, b, &a2), OP_EQ, 1); \
+ test_op_ip6_(&a1,OP_EQ,&a2,#a,#b); \
STMT_END
/** Helper: Assert that <b>a</b> is recognized as a bad IPv6 address by
* tor_inet_pton(). */
#define test_pton6_bad(a) \
- test_eq(0, tor_inet_pton(AF_INET6, a, &a1))
+ tt_int_op(0, OP_EQ, tor_inet_pton(AF_INET6, a, &a1))
/** Helper: assert that <b>a</b>, when parsed by tor_inet_pton() and displayed
* with tor_inet_ntop(), yields <b>b</b>. Also assert that <b>b</b> parses to
* the same value as <b>a</b>. */
-#define test_ntop6_reduces(a,b) STMT_BEGIN \
- test_eq(tor_inet_pton(AF_INET6, a, &a1), 1); \
- test_streq(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), b); \
- test_eq(tor_inet_pton(AF_INET6, b, &a2), 1); \
- test_op_ip6_(&a1, ==, &a2, a, b); \
+#define test_ntop6_reduces(a,b) STMT_BEGIN \
+ tt_int_op(tor_inet_pton(AF_INET6, a, &a1), OP_EQ, 1); \
+ tt_str_op(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), OP_EQ, b); \
+ tt_int_op(tor_inet_pton(AF_INET6, b, &a2), OP_EQ, 1); \
+ test_op_ip6_(&a1, OP_EQ, &a2, a, b); \
STMT_END
/** Helper: assert that <b>a</b> parses by tor_inet_pton() into a address that
* passes tor_addr_is_internal() with <b>for_listening</b>. */
#define test_internal_ip(a,for_listening) STMT_BEGIN \
- test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \
+ tt_int_op(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), OP_EQ, 1); \
t1.family = AF_INET6; \
if (!tor_addr_is_internal(&t1, for_listening)) \
- test_fail_msg( a "was not internal."); \
+ TT_DIE(("%s was not internal", a)); \
STMT_END
/** Helper: assert that <b>a</b> parses by tor_inet_pton() into a address that
* does not pass tor_addr_is_internal() with <b>for_listening</b>. */
#define test_external_ip(a,for_listening) STMT_BEGIN \
- test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \
+ tt_int_op(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), OP_EQ, 1); \
t1.family = AF_INET6; \
if (tor_addr_is_internal(&t1, for_listening)) \
- test_fail_msg(a "was not external."); \
+ TT_DIE(("%s was not internal", a)); \
STMT_END
/** Helper: Assert that <b>a</b> and <b>b</b>, when parsed by
* tor_inet_pton(), give addresses that compare in the order defined by
* <b>op</b> with tor_addr_compare(). */
#define test_addr_compare(a, op, b) STMT_BEGIN \
- test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \
- test_eq(tor_inet_pton(AF_INET6, b, &t2.addr.in6_addr), 1); \
+ tt_int_op(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), OP_EQ, 1); \
+ tt_int_op(tor_inet_pton(AF_INET6, b, &t2.addr.in6_addr), OP_EQ, 1); \
t1.family = t2.family = AF_INET6; \
r = tor_addr_compare(&t1,&t2,CMP_SEMANTIC); \
if (!(r op 0)) \
- test_fail_msg("failed: tor_addr_compare("a","b") "#op" 0"); \
+ TT_DIE(("Failed: tor_addr_compare(%s,%s) %s 0", a, b, #op));\
STMT_END
/** Helper: Assert that <b>a</b> and <b>b</b>, when parsed by
* tor_inet_pton(), give addresses that compare in the order defined by
* <b>op</b> with tor_addr_compare_masked() with <b>m</b> masked. */
#define test_addr_compare_masked(a, op, b, m) STMT_BEGIN \
- test_eq(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), 1); \
- test_eq(tor_inet_pton(AF_INET6, b, &t2.addr.in6_addr), 1); \
+ tt_int_op(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), OP_EQ, 1); \
+ tt_int_op(tor_inet_pton(AF_INET6, b, &t2.addr.in6_addr), OP_EQ, 1); \
t1.family = t2.family = AF_INET6; \
r = tor_addr_compare_masked(&t1,&t2,m,CMP_SEMANTIC); \
if (!(r op 0)) \
- test_fail_msg("failed: tor_addr_compare_masked("a","b","#m") "#op" 0"); \
+ TT_DIE(("Failed: tor_addr_compare_masked(%s,%s,%d) %s 0", \
+ a, b, m, #op)); \
STMT_END
/** Helper: assert that <b>xx</b> is parseable as a masked IPv6 address with
@@ -165,21 +168,21 @@ test_addr_basic(void)
* as <b>pt1..pt2</b>. */
#define test_addr_mask_ports_parse(xx, f, ip1, ip2, ip3, ip4, mm, pt1, pt2) \
STMT_BEGIN \
- test_eq(tor_addr_parse_mask_ports(xx, 0, &t1, &mask, &port1, &port2), \
- f); \
+ tt_int_op(tor_addr_parse_mask_ports(xx, 0, &t1, &mask, &port1, &port2), \
+ OP_EQ, f); \
p1=tor_inet_ntop(AF_INET6, &t1.addr.in6_addr, bug, sizeof(bug)); \
- test_eq(htonl(ip1), tor_addr_to_in6_addr32(&t1)[0]); \
- test_eq(htonl(ip2), tor_addr_to_in6_addr32(&t1)[1]); \
- test_eq(htonl(ip3), tor_addr_to_in6_addr32(&t1)[2]); \
- test_eq(htonl(ip4), tor_addr_to_in6_addr32(&t1)[3]); \
- test_eq(mask, mm); \
- test_eq(port1, pt1); \
- test_eq(port2, pt2); \
+ tt_int_op(htonl(ip1), OP_EQ, tor_addr_to_in6_addr32(&t1)[0]); \
+ tt_int_op(htonl(ip2), OP_EQ, tor_addr_to_in6_addr32(&t1)[1]); \
+ tt_int_op(htonl(ip3), OP_EQ, tor_addr_to_in6_addr32(&t1)[2]); \
+ tt_int_op(htonl(ip4), OP_EQ, tor_addr_to_in6_addr32(&t1)[3]); \
+ tt_int_op(mask, OP_EQ, mm); \
+ tt_uint_op(port1, OP_EQ, pt1); \
+ tt_uint_op(port2, OP_EQ, pt2); \
STMT_END
/** Run unit tests for IPv6 encoding/decoding/manipulation functions. */
static void
-test_addr_ip6_helpers(void)
+test_addr_ip6_helpers(void *arg)
{
char buf[TOR_ADDR_BUF_LEN], bug[TOR_ADDR_BUF_LEN];
char rbuf[REVERSE_LOOKUP_NAME_BUF_LEN];
@@ -194,28 +197,29 @@ test_addr_ip6_helpers(void)
struct sockaddr_in6 *sin6;
/* Test tor_inet_ntop and tor_inet_pton: IPv6 */
+ (void)arg;
{
const char *ip = "2001::1234";
const char *ip_ffff = "::ffff:192.168.1.2";
/* good round trip */
- test_eq(tor_inet_pton(AF_INET6, ip, &a1), 1);
- test_eq_ptr(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)), &buf);
- test_streq(buf, ip);
+ tt_int_op(tor_inet_pton(AF_INET6, ip, &a1),OP_EQ, 1);
+ tt_ptr_op(tor_inet_ntop(AF_INET6, &a1, buf, sizeof(buf)),OP_EQ, &buf);
+ tt_str_op(buf,OP_EQ, ip);
/* good round trip - ::ffff:0:0 style */
- test_eq(tor_inet_pton(AF_INET6, ip_ffff, &a2), 1);
- test_eq_ptr(tor_inet_ntop(AF_INET6, &a2, buf, sizeof(buf)), &buf);
- test_streq(buf, ip_ffff);
+ tt_int_op(tor_inet_pton(AF_INET6, ip_ffff, &a2),OP_EQ, 1);
+ tt_ptr_op(tor_inet_ntop(AF_INET6, &a2, buf, sizeof(buf)),OP_EQ, &buf);
+ tt_str_op(buf,OP_EQ, ip_ffff);
/* just long enough buffer (remember \0) */
- test_streq(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)+1), ip);
- test_streq(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)+1),
+ tt_str_op(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)+1),OP_EQ, ip);
+ tt_str_op(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)+1),OP_EQ,
ip_ffff);
/* too short buffer (remember \0) */
- test_eq_ptr(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)), NULL);
- test_eq_ptr(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)), NULL);
+ tt_ptr_op(tor_inet_ntop(AF_INET6, &a1, buf, strlen(ip)),OP_EQ, NULL);
+ tt_ptr_op(tor_inet_ntop(AF_INET6, &a2, buf, strlen(ip_ffff)),OP_EQ, NULL);
}
/* ==== Converting to and from sockaddr_t. */
@@ -224,16 +228,16 @@ test_addr_ip6_helpers(void)
sin->sin_port = htons(9090);
sin->sin_addr.s_addr = htonl(0x7f7f0102); /*127.127.1.2*/
tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, &port1);
- test_eq(tor_addr_family(&t1), AF_INET);
- test_eq(tor_addr_to_ipv4h(&t1), 0x7f7f0102);
- tt_int_op(port1, ==, 9090);
+ tt_int_op(tor_addr_family(&t1),OP_EQ, AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ, 0x7f7f0102);
+ tt_int_op(port1, OP_EQ, 9090);
memset(&sa_storage, 0, sizeof(sa_storage));
- test_eq(sizeof(struct sockaddr_in),
+ tt_int_op(sizeof(struct sockaddr_in),OP_EQ,
tor_addr_to_sockaddr(&t1, 1234, (struct sockaddr *)&sa_storage,
sizeof(sa_storage)));
- test_eq(1234, ntohs(sin->sin_port));
- test_eq(0x7f7f0102, ntohl(sin->sin_addr.s_addr));
+ tt_int_op(1234,OP_EQ, ntohs(sin->sin_port));
+ tt_int_op(0x7f7f0102,OP_EQ, ntohl(sin->sin_addr.s_addr));
memset(&sa_storage, 0, sizeof(sa_storage));
sin6 = (struct sockaddr_in6 *)&sa_storage;
@@ -241,37 +245,37 @@ test_addr_ip6_helpers(void)
sin6->sin6_port = htons(7070);
sin6->sin6_addr.s6_addr[0] = 128;
tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin6, &port1);
- test_eq(tor_addr_family(&t1), AF_INET6);
- tt_int_op(port1, ==, 7070);
+ tt_int_op(tor_addr_family(&t1),OP_EQ, AF_INET6);
+ tt_int_op(port1, OP_EQ, 7070);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
- test_streq(p1, "8000::");
+ tt_str_op(p1,OP_EQ, "8000::");
memset(&sa_storage, 0, sizeof(sa_storage));
- test_eq(sizeof(struct sockaddr_in6),
+ tt_int_op(sizeof(struct sockaddr_in6),OP_EQ,
tor_addr_to_sockaddr(&t1, 9999, (struct sockaddr *)&sa_storage,
sizeof(sa_storage)));
- test_eq(AF_INET6, sin6->sin6_family);
- test_eq(9999, ntohs(sin6->sin6_port));
- test_eq(0x80000000, ntohl(S6_ADDR32(sin6->sin6_addr)[0]));
+ tt_int_op(AF_INET6,OP_EQ, sin6->sin6_family);
+ tt_int_op(9999,OP_EQ, ntohs(sin6->sin6_port));
+ tt_int_op(0x80000000,OP_EQ, ntohl(S6_ADDR32(sin6->sin6_addr)[0]));
/* ==== tor_addr_lookup: static cases. (Can't test dns without knowing we
* have a good resolver. */
- test_eq(0, tor_addr_lookup("127.128.129.130", AF_UNSPEC, &t1));
- test_eq(AF_INET, tor_addr_family(&t1));
- test_eq(tor_addr_to_ipv4h(&t1), 0x7f808182);
+ tt_int_op(0,OP_EQ, tor_addr_lookup("127.128.129.130", AF_UNSPEC, &t1));
+ tt_int_op(AF_INET,OP_EQ, tor_addr_family(&t1));
+ tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ, 0x7f808182);
- test_eq(0, tor_addr_lookup("9000::5", AF_UNSPEC, &t1));
- test_eq(AF_INET6, tor_addr_family(&t1));
- test_eq(0x90, tor_addr_to_in6_addr8(&t1)[0]);
- test_assert(tor_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14));
- test_eq(0x05, tor_addr_to_in6_addr8(&t1)[15]);
+ tt_int_op(0,OP_EQ, tor_addr_lookup("9000::5", AF_UNSPEC, &t1));
+ tt_int_op(AF_INET6,OP_EQ, tor_addr_family(&t1));
+ tt_int_op(0x90,OP_EQ, tor_addr_to_in6_addr8(&t1)[0]);
+ tt_assert(tor_mem_is_zero((char*)tor_addr_to_in6_addr8(&t1)+1, 14));
+ tt_int_op(0x05,OP_EQ, tor_addr_to_in6_addr8(&t1)[15]);
/* === Test pton: valid af_inet6 */
/* Simple, valid parsing. */
r = tor_inet_pton(AF_INET6,
"0102:0304:0506:0708:090A:0B0C:0D0E:0F10", &a1);
- test_assert(r==1);
- for (i=0;i<16;++i) { test_eq(i+1, (int)a1.s6_addr[i]); }
+ tt_int_op(r, OP_EQ, 1);
+ for (i=0;i<16;++i) { tt_int_op(i+1,OP_EQ, (int)a1.s6_addr[i]); }
/* ipv4 ending. */
test_pton6_same("0102:0304:0506:0708:090A:0B0C:0D0E:0F10",
"0102:0304:0506:0708:090A:0B0C:13.14.15.16");
@@ -311,7 +315,7 @@ test_addr_ip6_helpers(void)
"1000:1:0:7::");
/* Bad af param */
- test_eq(tor_inet_pton(AF_UNSPEC, 0, 0), -1);
+ tt_int_op(tor_inet_pton(AF_UNSPEC, 0, 0),OP_EQ, -1);
/* === Test pton: invalid in6. */
test_pton6_bad("foobar.");
@@ -416,132 +420,134 @@ test_addr_ip6_helpers(void)
test_external_ip("::ffff:169.255.0.0", 0);
/* tor_addr_compare(tor_addr_t x2) */
- test_addr_compare("ffff::", ==, "ffff::0");
- test_addr_compare("0::3:2:1", <, "0::ffff:0.3.2.1");
- test_addr_compare("0::2:2:1", <, "0::ffff:0.3.2.1");
- test_addr_compare("0::ffff:0.3.2.1", >, "0::0:0:0");
- test_addr_compare("0::ffff:5.2.2.1", <, "::ffff:6.0.0.0"); /* XXXX wrong. */
+ test_addr_compare("ffff::", OP_EQ, "ffff::0");
+ test_addr_compare("0::3:2:1", OP_LT, "0::ffff:0.3.2.1");
+ test_addr_compare("0::2:2:1", OP_LT, "0::ffff:0.3.2.1");
+ test_addr_compare("0::ffff:0.3.2.1", OP_GT, "0::0:0:0");
+ test_addr_compare("0::ffff:5.2.2.1", OP_LT,
+ "::ffff:6.0.0.0"); /* XXXX wrong. */
tor_addr_parse_mask_ports("[::ffff:2.3.4.5]", 0, &t1, NULL, NULL, NULL);
tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
- test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) == 0);
+ tt_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) == 0);
tor_addr_parse_mask_ports("[::ffff:2.3.4.4]", 0, &t1, NULL, NULL, NULL);
tor_addr_parse_mask_ports("2.3.4.5", 0, &t2, NULL, NULL, NULL);
- test_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) < 0);
+ tt_assert(tor_addr_compare(&t1, &t2, CMP_SEMANTIC) < 0);
/* test compare_masked */
- test_addr_compare_masked("ffff::", ==, "ffff::0", 128);
- test_addr_compare_masked("ffff::", ==, "ffff::0", 64);
- test_addr_compare_masked("0::2:2:1", <, "0::8000:2:1", 81);
- test_addr_compare_masked("0::2:2:1", ==, "0::8000:2:1", 80);
+ test_addr_compare_masked("ffff::", OP_EQ, "ffff::0", 128);
+ test_addr_compare_masked("ffff::", OP_EQ, "ffff::0", 64);
+ test_addr_compare_masked("0::2:2:1", OP_LT, "0::8000:2:1", 81);
+ test_addr_compare_masked("0::2:2:1", OP_EQ, "0::8000:2:1", 80);
/* Test undecorated tor_addr_to_str */
- test_eq(AF_INET6, tor_addr_parse(&t1, "[123:45:6789::5005:11]"));
+ tt_int_op(AF_INET6,OP_EQ, tor_addr_parse(&t1, "[123:45:6789::5005:11]"));
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
- test_streq(p1, "123:45:6789::5005:11");
- test_eq(AF_INET, tor_addr_parse(&t1, "18.0.0.1"));
+ tt_str_op(p1,OP_EQ, "123:45:6789::5005:11");
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&t1, "18.0.0.1"));
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 0);
- test_streq(p1, "18.0.0.1");
+ tt_str_op(p1,OP_EQ, "18.0.0.1");
/* Test decorated tor_addr_to_str */
- test_eq(AF_INET6, tor_addr_parse(&t1, "[123:45:6789::5005:11]"));
+ tt_int_op(AF_INET6,OP_EQ, tor_addr_parse(&t1, "[123:45:6789::5005:11]"));
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
- test_streq(p1, "[123:45:6789::5005:11]");
- test_eq(AF_INET, tor_addr_parse(&t1, "18.0.0.1"));
+ tt_str_op(p1,OP_EQ, "[123:45:6789::5005:11]");
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&t1, "18.0.0.1"));
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
- test_streq(p1, "18.0.0.1");
+ tt_str_op(p1,OP_EQ, "18.0.0.1");
/* Test buffer bounds checking of tor_addr_to_str */
- test_eq(AF_INET6, tor_addr_parse(&t1, "::")); /* 2 + \0 */
- test_eq_ptr(tor_addr_to_str(buf, &t1, 2, 0), NULL); /* too short buf */
- test_streq(tor_addr_to_str(buf, &t1, 3, 0), "::");
- test_eq_ptr(tor_addr_to_str(buf, &t1, 4, 1), NULL); /* too short buf */
- test_streq(tor_addr_to_str(buf, &t1, 5, 1), "[::]");
-
- test_eq(AF_INET6, tor_addr_parse(&t1, "2000::1337")); /* 10 + \0 */
- test_eq_ptr(tor_addr_to_str(buf, &t1, 10, 0), NULL); /* too short buf */
- test_streq(tor_addr_to_str(buf, &t1, 11, 0), "2000::1337");
- test_eq_ptr(tor_addr_to_str(buf, &t1, 12, 1), NULL); /* too short buf */
- test_streq(tor_addr_to_str(buf, &t1, 13, 1), "[2000::1337]");
-
- test_eq(AF_INET, tor_addr_parse(&t1, "1.2.3.4")); /* 7 + \0 */
- test_eq_ptr(tor_addr_to_str(buf, &t1, 7, 0), NULL); /* too short buf */
- test_streq(tor_addr_to_str(buf, &t1, 8, 0), "1.2.3.4");
-
- test_eq(AF_INET, tor_addr_parse(&t1, "255.255.255.255")); /* 15 + \0 */
- test_eq_ptr(tor_addr_to_str(buf, &t1, 15, 0), NULL); /* too short buf */
- test_streq(tor_addr_to_str(buf, &t1, 16, 0), "255.255.255.255");
- test_eq_ptr(tor_addr_to_str(buf, &t1, 15, 1), NULL); /* too short buf */
- test_streq(tor_addr_to_str(buf, &t1, 16, 1), "255.255.255.255");
+ tt_int_op(AF_INET6,OP_EQ, tor_addr_parse(&t1, "::")); /* 2 + \0 */
+ tt_ptr_op(tor_addr_to_str(buf, &t1, 2, 0),OP_EQ, NULL); /* too short buf */
+ tt_str_op(tor_addr_to_str(buf, &t1, 3, 0),OP_EQ, "::");
+ tt_ptr_op(tor_addr_to_str(buf, &t1, 4, 1),OP_EQ, NULL); /* too short buf */
+ tt_str_op(tor_addr_to_str(buf, &t1, 5, 1),OP_EQ, "[::]");
+
+ tt_int_op(AF_INET6,OP_EQ, tor_addr_parse(&t1, "2000::1337")); /* 10 + \0 */
+ tt_ptr_op(tor_addr_to_str(buf, &t1, 10, 0),OP_EQ, NULL); /* too short buf */
+ tt_str_op(tor_addr_to_str(buf, &t1, 11, 0),OP_EQ, "2000::1337");
+ tt_ptr_op(tor_addr_to_str(buf, &t1, 12, 1),OP_EQ, NULL); /* too short buf */
+ tt_str_op(tor_addr_to_str(buf, &t1, 13, 1),OP_EQ, "[2000::1337]");
+
+ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&t1, "1.2.3.4")); /* 7 + \0 */
+ tt_ptr_op(tor_addr_to_str(buf, &t1, 7, 0),OP_EQ, NULL); /* too short buf */
+ tt_str_op(tor_addr_to_str(buf, &t1, 8, 0),OP_EQ, "1.2.3.4");
+
+ tt_int_op(AF_INET, OP_EQ,
+ tor_addr_parse(&t1, "255.255.255.255")); /* 15 + \0 */
+ tt_ptr_op(tor_addr_to_str(buf, &t1, 15, 0),OP_EQ, NULL); /* too short buf */
+ tt_str_op(tor_addr_to_str(buf, &t1, 16, 0),OP_EQ, "255.255.255.255");
+ tt_ptr_op(tor_addr_to_str(buf, &t1, 15, 1),OP_EQ, NULL); /* too short buf */
+ tt_str_op(tor_addr_to_str(buf, &t1, 16, 1),OP_EQ, "255.255.255.255");
t1.family = AF_UNSPEC;
- test_eq_ptr(tor_addr_to_str(buf, &t1, sizeof(buf), 0), NULL);
+ tt_ptr_op(tor_addr_to_str(buf, &t1, sizeof(buf), 0),OP_EQ, NULL);
/* Test tor_addr_parse_PTR_name */
i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 0);
- test_eq(0, i);
+ tt_int_op(0,OP_EQ, i);
i = tor_addr_parse_PTR_name(&t1, "Foobar.baz", AF_UNSPEC, 1);
- test_eq(0, i);
+ tt_int_op(0,OP_EQ, i);
i = tor_addr_parse_PTR_name(&t1, "9999999999999999999999999999.in-addr.arpa",
AF_UNSPEC, 1);
- test_eq(-1, i);
+ tt_int_op(-1,OP_EQ, i);
i = tor_addr_parse_PTR_name(&t1, "1.0.168.192.in-addr.arpa",
AF_UNSPEC, 1);
- test_eq(1, i);
- test_eq(tor_addr_family(&t1), AF_INET);
+ tt_int_op(1,OP_EQ, i);
+ tt_int_op(tor_addr_family(&t1),OP_EQ, AF_INET);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
- test_streq(p1, "192.168.0.1");
+ tt_str_op(p1,OP_EQ, "192.168.0.1");
i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 0);
- test_eq(0, i);
+ tt_int_op(0,OP_EQ, i);
i = tor_addr_parse_PTR_name(&t1, "192.168.0.99", AF_UNSPEC, 1);
- test_eq(1, i);
+ tt_int_op(1,OP_EQ, i);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
- test_streq(p1, "192.168.0.99");
+ tt_str_op(p1,OP_EQ, "192.168.0.99");
memset(&t1, 0, sizeof(t1));
i = tor_addr_parse_PTR_name(&t1,
"0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
- test_eq(1, i);
+ tt_int_op(1,OP_EQ, i);
p1 = tor_addr_to_str(buf, &t1, sizeof(buf), 1);
- test_streq(p1, "[9dee:effe:ebe1:beef:fedc:ba98:7654:3210]");
+ tt_str_op(p1,OP_EQ, "[9dee:effe:ebe1:beef:fedc:ba98:7654:3210]");
/* Failing cases. */
i = tor_addr_parse_PTR_name(&t1,
"6.7.8.9.a.b.c.d.e.f."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
- test_eq(i, -1);
+ tt_int_op(i,OP_EQ, -1);
i = tor_addr_parse_PTR_name(&t1,
"6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.f.0."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
- test_eq(i, -1);
+ tt_int_op(i,OP_EQ, -1);
i = tor_addr_parse_PTR_name(&t1,
"6.7.8.9.a.b.c.d.e.f.X.0.0.0.0.9."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_UNSPEC, 0);
- test_eq(i, -1);
+ tt_int_op(i,OP_EQ, -1);
i = tor_addr_parse_PTR_name(&t1, "32.1.1.in-addr.arpa",
AF_UNSPEC, 0);
- test_eq(i, -1);
+ tt_int_op(i,OP_EQ, -1);
i = tor_addr_parse_PTR_name(&t1, ".in-addr.arpa",
AF_UNSPEC, 0);
- test_eq(i, -1);
+ tt_int_op(i,OP_EQ, -1);
i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa",
AF_UNSPEC, 0);
- test_eq(i, -1);
+ tt_int_op(i,OP_EQ, -1);
i = tor_addr_parse_PTR_name(&t1, "1.2.3.4.5.in-addr.arpa",
AF_INET6, 0);
- test_eq(i, -1);
+ tt_int_op(i,OP_EQ, -1);
i = tor_addr_parse_PTR_name(&t1,
"6.7.8.9.a.b.c.d.e.f.a.b.c.d.e.0."
"f.e.e.b.1.e.b.e.e.f.f.e.e.e.d.9."
"ip6.ARPA",
AF_INET, 0);
- test_eq(i, -1);
+ tt_int_op(i,OP_EQ, -1);
/* === Test tor_addr_to_PTR_name */
@@ -553,19 +559,19 @@ test_addr_ip6_helpers(void)
tor_addr_from_sockaddr(&t1, (struct sockaddr *)sin, NULL);
/* Check IPv4 PTR - too short buffer */
- test_eq(tor_addr_to_PTR_name(rbuf, 1, &t1), -1);
- test_eq(tor_addr_to_PTR_name(rbuf,
+ tt_int_op(tor_addr_to_PTR_name(rbuf, 1, &t1),OP_EQ, -1);
+ tt_int_op(tor_addr_to_PTR_name(rbuf,
strlen("3.2.1.127.in-addr.arpa") - 1,
- &t1), -1);
+ &t1),OP_EQ, -1);
/* Check IPv4 PTR - valid addr */
- test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),
+ tt_int_op(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),OP_EQ,
strlen("3.2.1.127.in-addr.arpa"));
- test_streq(rbuf, "3.2.1.127.in-addr.arpa");
+ tt_str_op(rbuf,OP_EQ, "3.2.1.127.in-addr.arpa");
/* Invalid addr family */
t1.family = AF_UNSPEC;
- test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1), -1);
+ tt_int_op(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),OP_EQ, -1);
/* Stage IPv6 addr */
memset(&sa_storage, 0, sizeof(sa_storage));
@@ -582,153 +588,152 @@ test_addr_ip6_helpers(void)
"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.ip6.arpa";
/* Check IPv6 PTR - too short buffer */
- test_eq(tor_addr_to_PTR_name(rbuf, 0, &t1), -1);
- test_eq(tor_addr_to_PTR_name(rbuf, strlen(addr_PTR) - 1, &t1), -1);
+ tt_int_op(tor_addr_to_PTR_name(rbuf, 0, &t1),OP_EQ, -1);
+ tt_int_op(tor_addr_to_PTR_name(rbuf, strlen(addr_PTR) - 1, &t1),OP_EQ, -1);
/* Check IPv6 PTR - valid addr */
- test_eq(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),
+ tt_int_op(tor_addr_to_PTR_name(rbuf, sizeof(rbuf), &t1),OP_EQ,
strlen(addr_PTR));
- test_streq(rbuf, addr_PTR);
+ tt_str_op(rbuf,OP_EQ, addr_PTR);
}
/* XXXX turn this into a separate function; it's not all IPv6. */
/* test tor_addr_parse_mask_ports */
test_addr_mask_ports_parse("[::f]/17:47-95", AF_INET6,
0, 0, 0, 0x0000000f, 17, 47, 95);
- test_streq(p1, "::f");
+ tt_str_op(p1,OP_EQ, "::f");
//test_addr_parse("[::fefe:4.1.1.7/120]:999-1000");
//test_addr_parse_check("::fefe:401:107", 120, 999, 1000);
test_addr_mask_ports_parse("[::ffff:4.1.1.7]/120:443", AF_INET6,
0, 0, 0x0000ffff, 0x04010107, 120, 443, 443);
- test_streq(p1, "::ffff:4.1.1.7");
+ tt_str_op(p1,OP_EQ, "::ffff:4.1.1.7");
test_addr_mask_ports_parse("[abcd:2::44a:0]:2-65000", AF_INET6,
0xabcd0002, 0, 0, 0x044a0000, 128, 2, 65000);
- test_streq(p1, "abcd:2::44a:0");
+ tt_str_op(p1,OP_EQ, "abcd:2::44a:0");
/* Try some long addresses. */
r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111]",
0, &t1, NULL, NULL, NULL);
- test_assert(r == AF_INET6);
+ tt_assert(r == AF_INET6);
r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:11111]",
0, &t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("[ffff:1111:1111:1111:1111:1111:1111:1111:1]",
0, &t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports(
"[ffff:1111:1111:1111:1111:1111:1111:ffff:"
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]",
0, &t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* Try some failing cases. */
r=tor_addr_parse_mask_ports("[fefef::]/112", 0, &t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("[fefe::/112", 0, &t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("[fefe::", 0, &t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("[fefe::X]", 0, &t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("efef::/112", 0, &t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f::]",0,&t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("[::f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("[f:f:f:f:f:f:f:f:f]",0,&t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/fred",0,&t1,&mask, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("[f:f:f:f:f::]/255.255.0.0",
0,&t1, NULL, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* This one will get rejected because it isn't a pure prefix. */
r=tor_addr_parse_mask_ports("1.1.2.3/255.255.64.0",0,&t1, &mask,NULL,NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* Test for V4-mapped address with mask < 96. (arguably not valid) */
r=tor_addr_parse_mask_ports("[::ffff:1.1.2.2/33]",0,&t1, &mask, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("1.1.2.2/33",0,&t1, &mask, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* Try extended wildcard addresses with out TAPMP_EXTENDED_STAR*/
r=tor_addr_parse_mask_ports("*4",0,&t1, &mask, NULL, NULL);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r=tor_addr_parse_mask_ports("*6",0,&t1, &mask, NULL, NULL);
- test_assert(r == -1);
-#if 0
+ tt_int_op(r, OP_EQ, -1);
+ tt_assert(r == -1);
/* Try a mask with a wildcard. */
r=tor_addr_parse_mask_ports("*/16",0,&t1, &mask, NULL, NULL);
- test_assert(r == -1);
+ tt_assert(r == -1);
r=tor_addr_parse_mask_ports("*4/16",TAPMP_EXTENDED_STAR,
&t1, &mask, NULL, NULL);
- test_assert(r == -1);
+ tt_assert(r == -1);
r=tor_addr_parse_mask_ports("*6/30",TAPMP_EXTENDED_STAR,
&t1, &mask, NULL, NULL);
- test_assert(r == -1);
-#endif
+ tt_assert(r == -1);
/* Basic mask tests*/
r=tor_addr_parse_mask_ports("1.1.2.2/31",0,&t1, &mask, NULL, NULL);
- test_assert(r == AF_INET);
- tt_int_op(mask,==,31);
- tt_int_op(tor_addr_family(&t1),==,AF_INET);
- tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010202);
+ tt_assert(r == AF_INET);
+ tt_int_op(mask,OP_EQ,31);
+ tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x01010202);
r=tor_addr_parse_mask_ports("3.4.16.032:1-2",0,&t1, &mask, &port1, &port2);
- test_assert(r == AF_INET);
- tt_int_op(mask,==,32);
- tt_int_op(tor_addr_family(&t1),==,AF_INET);
- tt_int_op(tor_addr_to_ipv4h(&t1),==,0x03041020);
- test_assert(port1 == 1);
- test_assert(port2 == 2);
+ tt_assert(r == AF_INET);
+ tt_int_op(mask,OP_EQ,32);
+ tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x03041020);
+ tt_assert(port1 == 1);
+ tt_assert(port2 == 2);
r=tor_addr_parse_mask_ports("1.1.2.3/255.255.128.0",0,&t1, &mask,NULL,NULL);
- test_assert(r == AF_INET);
- tt_int_op(mask,==,17);
- tt_int_op(tor_addr_family(&t1),==,AF_INET);
- tt_int_op(tor_addr_to_ipv4h(&t1),==,0x01010203);
+ tt_assert(r == AF_INET);
+ tt_int_op(mask,OP_EQ,17);
+ tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0x01010203);
r=tor_addr_parse_mask_ports("[efef::]/112",0,&t1, &mask, &port1, &port2);
- test_assert(r == AF_INET6);
- test_assert(port1 == 1);
- test_assert(port2 == 65535);
+ tt_assert(r == AF_INET6);
+ tt_assert(port1 == 1);
+ tt_assert(port2 == 65535);
/* Try regular wildcard behavior without TAPMP_EXTENDED_STAR */
r=tor_addr_parse_mask_ports("*:80-443",0,&t1,&mask,&port1,&port2);
- tt_int_op(r,==,AF_INET); /* Old users of this always get inet */
- tt_int_op(tor_addr_family(&t1),==,AF_INET);
- tt_int_op(tor_addr_to_ipv4h(&t1),==,0);
- tt_int_op(mask,==,0);
- tt_int_op(port1,==,80);
- tt_int_op(port2,==,443);
+ tt_int_op(r,OP_EQ,AF_INET); /* Old users of this always get inet */
+ tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0);
+ tt_int_op(mask,OP_EQ,0);
+ tt_int_op(port1,OP_EQ,80);
+ tt_int_op(port2,OP_EQ,443);
/* Now try wildcards *with* TAPMP_EXTENDED_STAR */
r=tor_addr_parse_mask_ports("*:8000-9000",TAPMP_EXTENDED_STAR,
&t1,&mask,&port1,&port2);
- tt_int_op(r,==,AF_UNSPEC);
- tt_int_op(tor_addr_family(&t1),==,AF_UNSPEC);
- tt_int_op(mask,==,0);
- tt_int_op(port1,==,8000);
- tt_int_op(port2,==,9000);
+ tt_int_op(r,OP_EQ,AF_UNSPEC);
+ tt_int_op(tor_addr_family(&t1),OP_EQ,AF_UNSPEC);
+ tt_int_op(mask,OP_EQ,0);
+ tt_int_op(port1,OP_EQ,8000);
+ tt_int_op(port2,OP_EQ,9000);
r=tor_addr_parse_mask_ports("*4:6667",TAPMP_EXTENDED_STAR,
&t1,&mask,&port1,&port2);
- tt_int_op(r,==,AF_INET);
- tt_int_op(tor_addr_family(&t1),==,AF_INET);
- tt_int_op(tor_addr_to_ipv4h(&t1),==,0);
- tt_int_op(mask,==,0);
- tt_int_op(port1,==,6667);
- tt_int_op(port2,==,6667);
+ tt_int_op(r,OP_EQ,AF_INET);
+ tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET);
+ tt_int_op(tor_addr_to_ipv4h(&t1),OP_EQ,0);
+ tt_int_op(mask,OP_EQ,0);
+ tt_int_op(port1,OP_EQ,6667);
+ tt_int_op(port2,OP_EQ,6667);
r=tor_addr_parse_mask_ports("*6",TAPMP_EXTENDED_STAR,
&t1,&mask,&port1,&port2);
- tt_int_op(r,==,AF_INET6);
- tt_int_op(tor_addr_family(&t1),==,AF_INET6);
+ tt_int_op(r,OP_EQ,AF_INET6);
+ tt_int_op(tor_addr_family(&t1),OP_EQ,AF_INET6);
tt_assert(tor_mem_is_zero((const char*)tor_addr_to_in6_addr32(&t1), 16));
- tt_int_op(mask,==,0);
- tt_int_op(port1,==,1);
- tt_int_op(port2,==,65535);
+ tt_int_op(mask,OP_EQ,0);
+ tt_int_op(port1,OP_EQ,1);
+ tt_int_op(port2,OP_EQ,65535);
/* make sure inet address lengths >= max */
- test_assert(INET_NTOA_BUF_LEN >= sizeof("255.255.255.255"));
- test_assert(TOR_ADDR_BUF_LEN >=
+ tt_assert(INET_NTOA_BUF_LEN >= sizeof("255.255.255.255"));
+ tt_assert(TOR_ADDR_BUF_LEN >=
sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"));
- test_assert(sizeof(tor_addr_t) >= sizeof(struct in6_addr));
+ tt_assert(sizeof(tor_addr_t) >= sizeof(struct in6_addr));
/* get interface addresses */
r = get_interface_address6(LOG_DEBUG, AF_INET, &t1);
@@ -745,7 +750,7 @@ test_addr_ip6_helpers(void)
/** Test tor_addr_port_parse(). */
static void
-test_addr_parse(void)
+test_addr_parse(void *arg)
{
int r;
tor_addr_t addr;
@@ -753,90 +758,91 @@ test_addr_parse(void)
uint16_t port = 0;
/* Correct call. */
+ (void)arg;
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.1:1234",
&addr, &port, -1);
- test_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- test_streq(buf, "192.0.2.1");
- test_eq(port, 1234);
+ tt_str_op(buf,OP_EQ, "192.0.2.1");
+ tt_int_op(port,OP_EQ, 1234);
r= tor_addr_port_parse(LOG_DEBUG,
"[::1]:1234",
&addr, &port, -1);
- test_assert(r == 0);
+ tt_int_op(r, OP_EQ, 0);
tor_addr_to_str(buf, &addr, sizeof(buf), 0);
- test_streq(buf, "::1");
- test_eq(port, 1234);
+ tt_str_op(buf,OP_EQ, "::1");
+ tt_int_op(port,OP_EQ, 1234);
/* Domain name. */
r= tor_addr_port_parse(LOG_DEBUG,
"torproject.org:1234",
&addr, &port, -1);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* Only IP. */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.2",
&addr, &port, -1);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.2",
&addr, &port, 200);
- test_assert(r == 0);
- tt_int_op(port,==,200);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(port,OP_EQ,200);
r= tor_addr_port_parse(LOG_DEBUG,
"[::1]",
&addr, &port, -1);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r= tor_addr_port_parse(LOG_DEBUG,
"[::1]",
&addr, &port, 400);
- test_assert(r == 0);
- tt_int_op(port,==,400);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(port,OP_EQ,400);
/* Bad port. */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.2:66666",
&addr, &port, -1);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.2:66666",
&addr, &port, 200);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* Only domain name */
r= tor_addr_port_parse(LOG_DEBUG,
"torproject.org",
&addr, &port, -1);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
r= tor_addr_port_parse(LOG_DEBUG,
"torproject.org",
&addr, &port, 200);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* Bad IP address */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2:1234",
&addr, &port, -1);
- test_assert(r == -1);
+ tt_int_op(r, OP_EQ, -1);
/* Make sure that the default port has lower priority than the real
one */
r= tor_addr_port_parse(LOG_DEBUG,
"192.0.2.2:1337",
&addr, &port, 200);
- test_assert(r == 0);
- tt_int_op(port,==,1337);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(port,OP_EQ,1337);
r= tor_addr_port_parse(LOG_DEBUG,
"[::1]:1369",
&addr, &port, 200);
- test_assert(r == 0);
- tt_int_op(port,==,1369);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(port,OP_EQ,1369);
done:
;
@@ -891,7 +897,7 @@ test_virtaddrmap(void *data)
get_random_virtual_addr(&cfg[ipv6], &a);
//printf("%s\n", fmt_addr(&a));
/* Make sure that the first b bits match the configured network */
- tt_int_op(0, ==, tor_addr_compare_masked(&a, &cfg[ipv6].addr,
+ tt_int_op(0, OP_EQ, tor_addr_compare_masked(&a, &cfg[ipv6].addr,
bits, CMP_EXACT));
/* And track which bits have been different between pairs of
@@ -935,7 +941,7 @@ test_addr_dup_ip(void *arg)
(void)arg;
#define CHECK(ip, s) do { \
v = tor_dup_ip(ip); \
- tt_str_op(v,==,(s)); \
+ tt_str_op(v,OP_EQ,(s)); \
tor_free(v); \
} while (0)
@@ -961,7 +967,7 @@ test_addr_sockaddr_to_str(void *arg)
#endif
#define CHECK(sa, s) do { \
v = tor_sockaddr_to_str((const struct sockaddr*) &(sa)); \
- tt_str_op(v,==,(s)); \
+ tt_str_op(v,OP_EQ,(s)); \
tor_free(v); \
} while (0)
(void)arg;
@@ -1018,12 +1024,13 @@ test_addr_is_loopback(void *data)
(void)data;
for (i=0; loopback_items[i].name; ++i) {
- tt_int_op(tor_addr_parse(&addr, loopback_items[i].name), >=, 0);
- tt_int_op(tor_addr_is_loopback(&addr), ==, loopback_items[i].is_loopback);
+ tt_int_op(tor_addr_parse(&addr, loopback_items[i].name), OP_GE, 0);
+ tt_int_op(tor_addr_is_loopback(&addr), OP_EQ,
+ loopback_items[i].is_loopback);
}
tor_addr_make_unspec(&addr);
- tt_int_op(tor_addr_is_loopback(&addr), ==, 0);
+ tt_int_op(tor_addr_is_loopback(&addr), OP_EQ, 0);
done:
;
@@ -1038,25 +1045,25 @@ test_addr_make_null(void *data)
(void) data;
/* Ensure that before tor_addr_make_null, addr != 0's */
memset(addr, 1, sizeof(*addr));
- tt_int_op(memcmp(addr, zeros, sizeof(*addr)), !=, 0);
+ tt_int_op(memcmp(addr, zeros, sizeof(*addr)), OP_NE, 0);
/* Test with AF == AF_INET */
zeros->family = AF_INET;
tor_addr_make_null(addr, AF_INET);
- tt_int_op(memcmp(addr, zeros, sizeof(*addr)), ==, 0);
- tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), ==, "0.0.0.0");
+ tt_int_op(memcmp(addr, zeros, sizeof(*addr)), OP_EQ, 0);
+ tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), OP_EQ, "0.0.0.0");
/* Test with AF == AF_INET6 */
memset(addr, 1, sizeof(*addr));
zeros->family = AF_INET6;
tor_addr_make_null(addr, AF_INET6);
- tt_int_op(memcmp(addr, zeros, sizeof(*addr)), ==, 0);
- tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), ==, "::");
+ tt_int_op(memcmp(addr, zeros, sizeof(*addr)), OP_EQ, 0);
+ tt_str_op(tor_addr_to_str(buf, addr, sizeof(buf), 0), OP_EQ, "::");
done:
tor_free(addr);
tor_free(zeros);
}
#define ADDR_LEGACY(name) \
- { #name, legacy_test_helper, 0, &legacy_setup, test_addr_ ## name }
+ { #name, test_addr_ ## name , 0, NULL, NULL }
struct testcase_t addr_tests[] = {
ADDR_LEGACY(basic),
diff --git a/src/test/test_address.c b/src/test/test_address.c
new file mode 100644
index 0000000000..424a6352b0
--- /dev/null
+++ b/src/test/test_address.c
@@ -0,0 +1,473 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define ADDRESS_PRIVATE
+
+#ifdef _WIN32
+#include <winsock2.h>
+/* For access to structs needed by GetAdaptersAddresses */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#include <iphlpapi.h>
+#endif
+
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+#include <net/if.h>
+#include <ifaddrs.h>
+#endif
+
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <net/if.h>
+#endif
+
+#include "or.h"
+#include "address.h"
+#include "test.h"
+
+/** Return 1 iff <b>sockaddr1</b> and <b>sockaddr2</b> represent
+ * the same IP address and port combination. Otherwise, return 0.
+ */
+static uint8_t
+sockaddr_in_are_equal(struct sockaddr_in *sockaddr1,
+ struct sockaddr_in *sockaddr2)
+{
+ return ((sockaddr1->sin_family == sockaddr2->sin_family) &&
+ (sockaddr1->sin_port == sockaddr2->sin_port) &&
+ (sockaddr1->sin_addr.s_addr == sockaddr2->sin_addr.s_addr));
+}
+
+/** Return 1 iff <b>sockaddr1</b> and <b>sockaddr2</b> represent
+ * the same IP address and port combination. Otherwise, return 0.
+ */
+static uint8_t
+sockaddr_in6_are_equal(struct sockaddr_in6 *sockaddr1,
+ struct sockaddr_in6 *sockaddr2)
+{
+ return ((sockaddr1->sin6_family == sockaddr2->sin6_family) &&
+ (sockaddr1->sin6_port == sockaddr2->sin6_port) &&
+ (tor_memeq(sockaddr1->sin6_addr.s6_addr,
+ sockaddr2->sin6_addr.s6_addr,16)));
+}
+
+/** Create a sockaddr_in structure from IP address string <b>ip_str</b>.
+ *
+ * If <b>out</b> is not NULL, write the result
+ * to the memory address in <b>out</b>. Otherwise, allocate the memory
+ * for result. On success, return pointer to result. Otherwise, return
+ * NULL.
+ */
+static struct sockaddr_in *
+sockaddr_in_from_string(const char *ip_str, struct sockaddr_in *out)
+{
+ // [FIXME: add some error checking?]
+ if (!out)
+ out = tor_malloc_zero(sizeof(struct sockaddr_in));
+
+ out->sin_family = AF_INET;
+ out->sin_port = 0;
+ tor_inet_pton(AF_INET,ip_str,&(out->sin_addr));
+
+ return out;
+}
+
+/** Return 1 iff <b>smartlist</b> contains a tor_addr_t structure
+ * that points to 127.0.0.1. Otherwise, return 0.
+ */
+static int
+smartlist_contains_localhost_tor_addr(smartlist_t *smartlist)
+{
+ int found_localhost = 0;
+
+ struct sockaddr_in *sockaddr_localhost;
+ struct sockaddr_storage *sockaddr_to_check;
+
+ sockaddr_localhost = sockaddr_in_from_string("127.0.0.1",NULL);
+
+ sockaddr_to_check = tor_malloc(sizeof(struct sockaddr_in));
+
+ SMARTLIST_FOREACH_BEGIN(smartlist, tor_addr_t *, tor_addr) {
+ tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+ sizeof(struct sockaddr_in));
+
+ if (sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check,
+ sockaddr_localhost)) {
+ found_localhost = 1;
+ break;
+ }
+ } SMARTLIST_FOREACH_END(tor_addr);
+
+ tor_free(sockaddr_localhost);
+ tor_free(sockaddr_to_check);
+
+ return found_localhost;
+}
+
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+static void
+test_address_ifaddrs_to_smartlist(void *arg)
+{
+ struct ifaddrs *ifa = NULL;
+ struct ifaddrs *ifa_ipv4 = NULL;
+ struct ifaddrs *ifa_ipv6 = NULL;
+ struct sockaddr_in *ipv4_sockaddr_local = NULL;
+ struct sockaddr_in *netmask_slash8 = NULL;
+ struct sockaddr_in *ipv4_sockaddr_remote = NULL;
+ struct sockaddr_in6 *ipv6_sockaddr = NULL;
+ smartlist_t *smartlist = NULL;
+ tor_addr_t *tor_addr = NULL;
+ struct sockaddr *sockaddr_to_check = NULL;
+ socklen_t addr_len;
+
+ (void)arg;
+
+ netmask_slash8 = sockaddr_in_from_string("255.0.0.0",NULL);
+ ipv4_sockaddr_local = sockaddr_in_from_string("127.0.0.1",NULL);
+ ipv4_sockaddr_remote = sockaddr_in_from_string("128.52.160.20",NULL);
+
+ ipv6_sockaddr = tor_malloc(sizeof(struct sockaddr_in6));
+ ipv6_sockaddr->sin6_family = AF_INET6;
+ ipv6_sockaddr->sin6_port = 0;
+ inet_pton(AF_INET6, "2001:db8:8714:3a90::12",
+ &(ipv6_sockaddr->sin6_addr));
+
+ ifa = tor_malloc(sizeof(struct ifaddrs));
+ ifa_ipv4 = tor_malloc(sizeof(struct ifaddrs));
+ ifa_ipv6 = tor_malloc(sizeof(struct ifaddrs));
+
+ ifa->ifa_next = ifa_ipv4;
+ ifa->ifa_name = tor_strdup("eth0");
+ ifa->ifa_flags = IFF_UP | IFF_RUNNING;
+ ifa->ifa_addr = (struct sockaddr *)ipv4_sockaddr_local;
+ ifa->ifa_netmask = (struct sockaddr *)netmask_slash8;
+ ifa->ifa_dstaddr = NULL;
+ ifa->ifa_data = NULL;
+
+ ifa_ipv4->ifa_next = ifa_ipv6;
+ ifa_ipv4->ifa_name = tor_strdup("eth1");
+ ifa_ipv4->ifa_flags = IFF_UP | IFF_RUNNING;
+ ifa_ipv4->ifa_addr = (struct sockaddr *)ipv4_sockaddr_remote;
+ ifa_ipv4->ifa_netmask = (struct sockaddr *)netmask_slash8;
+ ifa_ipv4->ifa_dstaddr = NULL;
+ ifa_ipv4->ifa_data = NULL;
+
+ ifa_ipv6->ifa_next = NULL;
+ ifa_ipv6->ifa_name = tor_strdup("eth2");
+ ifa_ipv6->ifa_flags = IFF_UP | IFF_RUNNING;
+ ifa_ipv6->ifa_addr = (struct sockaddr *)ipv6_sockaddr;
+ ifa_ipv6->ifa_netmask = NULL;
+ ifa_ipv6->ifa_dstaddr = NULL;
+ ifa_ipv6->ifa_data = NULL;
+
+ smartlist = ifaddrs_to_smartlist(ifa);
+
+ tt_assert(smartlist);
+ tt_assert(smartlist_len(smartlist) == 3);
+
+ sockaddr_to_check = tor_malloc(sizeof(struct sockaddr_in6));
+
+ tor_addr = smartlist_get(smartlist,0);
+ addr_len =
+ tor_addr_to_sockaddr(tor_addr,0,sockaddr_to_check,
+ sizeof(struct sockaddr_in));
+
+ tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_assert(sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check,
+ ipv4_sockaddr_local));
+
+ tor_addr = smartlist_get(smartlist,1);
+ addr_len =
+ tor_addr_to_sockaddr(tor_addr,0,sockaddr_to_check,
+ sizeof(struct sockaddr_in));
+
+ tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_assert(sockaddr_in_are_equal((struct sockaddr_in *)sockaddr_to_check,
+ ipv4_sockaddr_remote));
+
+ tor_addr = smartlist_get(smartlist,2);
+ addr_len =
+ tor_addr_to_sockaddr(tor_addr,0,sockaddr_to_check,
+ sizeof(struct sockaddr_in6));
+
+ tt_int_op(addr_len,==,sizeof(struct sockaddr_in6));
+ tt_assert(sockaddr_in6_are_equal((struct sockaddr_in6*)sockaddr_to_check,
+ ipv6_sockaddr));
+
+ done:
+ tor_free(netmask_slash8);
+ tor_free(ipv4_sockaddr_local);
+ tor_free(ipv4_sockaddr_remote);
+ tor_free(ipv6_sockaddr);
+ tor_free(ifa->ifa_name);
+ tor_free(ifa_ipv4->ifa_name);
+ tor_free(ifa_ipv6->ifa_name);
+ tor_free(ifa);
+ tor_free(ifa_ipv4);
+ tor_free(ifa_ipv6);
+ tor_free(sockaddr_to_check);
+ if (smartlist) {
+ SMARTLIST_FOREACH(smartlist, tor_addr_t *, t, tor_free(t));
+ smartlist_free(smartlist);
+ }
+ return;
+}
+
+static void
+test_address_get_if_addrs_ifaddrs(void *arg)
+{
+
+ smartlist_t *results = NULL;
+
+ (void)arg;
+
+ results = get_interface_addresses_ifaddrs(0);
+
+ tt_int_op(smartlist_len(results),>=,1);
+ tt_assert(smartlist_contains_localhost_tor_addr(results));
+
+ done:
+ SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
+ smartlist_free(results);
+ return;
+}
+
+#endif
+
+#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
+
+static void
+test_address_get_if_addrs_win32(void *arg)
+{
+
+ smartlist_t *results = NULL;
+
+ (void)arg;
+
+ results = get_interface_addresses_win32(0);
+
+ tt_int_op(smartlist_len(results),>=,1);
+ tt_assert(smartlist_contains_localhost_tor_addr(results));
+
+ done:
+ SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
+ tor_free(results);
+ return;
+}
+
+static void
+test_address_ip_adapter_addresses_to_smartlist(void *arg)
+{
+
+ IP_ADAPTER_ADDRESSES *addrs1;
+ IP_ADAPTER_ADDRESSES *addrs2;
+
+ IP_ADAPTER_UNICAST_ADDRESS *unicast11;
+ IP_ADAPTER_UNICAST_ADDRESS *unicast12;
+ IP_ADAPTER_UNICAST_ADDRESS *unicast21;
+
+ smartlist_t *result = NULL;
+
+ struct sockaddr_in *sockaddr_test1;
+ struct sockaddr_in *sockaddr_test2;
+ struct sockaddr_in *sockaddr_localhost;
+ struct sockaddr_in *sockaddr_to_check;
+
+ tor_addr_t *tor_addr;
+
+ (void)arg;
+ (void)sockaddr_in6_are_equal;
+
+ sockaddr_to_check = tor_malloc_zero(sizeof(struct sockaddr_in));
+
+ addrs1 =
+ tor_malloc_zero(sizeof(IP_ADAPTER_ADDRESSES));
+
+ addrs1->FirstUnicastAddress =
+ unicast11 = tor_malloc_zero(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
+ sockaddr_test1 = sockaddr_in_from_string("86.59.30.40",NULL);
+ unicast11->Address.lpSockaddr = (LPSOCKADDR)sockaddr_test1;
+
+ unicast11->Next = unicast12 =
+ tor_malloc_zero(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
+ sockaddr_test2 = sockaddr_in_from_string("93.95.227.222", NULL);
+ unicast12->Address.lpSockaddr = (LPSOCKADDR)sockaddr_test2;
+
+ addrs1->Next = addrs2 =
+ tor_malloc_zero(sizeof(IP_ADAPTER_ADDRESSES));
+
+ addrs2->FirstUnicastAddress =
+ unicast21 = tor_malloc_zero(sizeof(IP_ADAPTER_UNICAST_ADDRESS));
+ sockaddr_localhost = sockaddr_in_from_string("127.0.0.1", NULL);
+ unicast21->Address.lpSockaddr = (LPSOCKADDR)sockaddr_localhost;
+
+ result = ip_adapter_addresses_to_smartlist(addrs1);
+
+ tt_assert(result);
+ tt_assert(smartlist_len(result) == 3);
+
+ tor_addr = smartlist_get(result,0);
+
+ tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+ sizeof(struct sockaddr_in));
+
+ tt_assert(sockaddr_in_are_equal(sockaddr_test1,sockaddr_to_check));
+
+ tor_addr = smartlist_get(result,1);
+
+ tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+ sizeof(struct sockaddr_in));
+
+ tt_assert(sockaddr_in_are_equal(sockaddr_test2,sockaddr_to_check));
+
+ tor_addr = smartlist_get(result,2);
+
+ tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+ sizeof(struct sockaddr_in));
+
+ tt_assert(sockaddr_in_are_equal(sockaddr_localhost,sockaddr_to_check));
+
+ done:
+ SMARTLIST_FOREACH(result, tor_addr_t *, t, tor_free(t));
+ smartlist_free(result);
+ tor_free(addrs1);
+ tor_free(addrs2);
+ tor_free(unicast11->Address.lpSockaddr);
+ tor_free(unicast11);
+ tor_free(unicast12->Address.lpSockaddr);
+ tor_free(unicast12);
+ tor_free(unicast21->Address.lpSockaddr);
+ tor_free(unicast21);
+ tor_free(sockaddr_to_check);
+ return;
+}
+#endif
+
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+
+static void
+test_address_ifreq_to_smartlist(void *arg)
+{
+ smartlist_t *results = NULL;
+ const tor_addr_t *tor_addr = NULL;
+ struct sockaddr_in *sockaddr = NULL;
+ struct sockaddr_in *sockaddr_eth1 = NULL;
+ struct sockaddr_in *sockaddr_to_check = NULL;
+
+ struct ifconf *ifc;
+ struct ifreq *ifr;
+ struct ifreq *ifr_next;
+
+ socklen_t addr_len;
+
+ (void)arg;
+
+ sockaddr_to_check = tor_malloc(sizeof(struct sockaddr_in));
+
+ ifr = tor_malloc(sizeof(struct ifreq));
+ memset(ifr,0,sizeof(struct ifreq));
+ strlcpy(ifr->ifr_name,"lo",3);
+ sockaddr = (struct sockaddr_in *) &(ifr->ifr_ifru.ifru_addr);
+ sockaddr_in_from_string("127.0.0.1",sockaddr);
+
+ ifc = tor_malloc(sizeof(struct ifconf));
+ memset(ifc,0,sizeof(struct ifconf));
+ ifc->ifc_len = sizeof(struct ifreq);
+ ifc->ifc_ifcu.ifcu_req = ifr;
+
+ results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
+ tt_int_op(smartlist_len(results),==,1);
+
+ tor_addr = smartlist_get(results, 0);
+ addr_len =
+ tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+ sizeof(struct sockaddr_in));
+
+ tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_assert(sockaddr_in_are_equal(sockaddr,sockaddr_to_check));
+
+ ifr = tor_realloc(ifr,2*sizeof(struct ifreq));
+ ifr_next = ifr+1;
+ strlcpy(ifr_next->ifr_name,"eth1",5);
+ ifc->ifc_len = 2*sizeof(struct ifreq);
+ ifc->ifc_ifcu.ifcu_req = ifr;
+ sockaddr = (struct sockaddr_in *) &(ifr->ifr_ifru.ifru_addr);
+
+ sockaddr_eth1 = (struct sockaddr_in *) &(ifr_next->ifr_ifru.ifru_addr);
+ sockaddr_in_from_string("192.168.10.55",sockaddr_eth1);
+ SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
+ smartlist_free(results);
+
+ results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
+ tt_int_op(smartlist_len(results),==,2);
+
+ tor_addr = smartlist_get(results, 0);
+ addr_len =
+ tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+ sizeof(struct sockaddr_in));
+
+ tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_assert(sockaddr_in_are_equal(sockaddr,sockaddr_to_check));
+
+ tor_addr = smartlist_get(results, 1);
+ addr_len =
+ tor_addr_to_sockaddr(tor_addr,0,(struct sockaddr *)sockaddr_to_check,
+ sizeof(struct sockaddr_in));
+
+ tt_int_op(addr_len,==,sizeof(struct sockaddr_in));
+ tt_assert(sockaddr_in_are_equal(sockaddr_eth1,sockaddr_to_check));
+
+ done:
+ tor_free(sockaddr_to_check);
+ SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
+ smartlist_free(results);
+ tor_free(ifc);
+ tor_free(ifr);
+ return;
+}
+
+static void
+test_address_get_if_addrs_ioctl(void *arg)
+{
+
+ smartlist_t *result = NULL;
+
+ (void)arg;
+
+ result = get_interface_addresses_ioctl(LOG_ERR);
+
+ tt_assert(result);
+ tt_int_op(smartlist_len(result),>=,1);
+
+ tt_assert(smartlist_contains_localhost_tor_addr(result));
+
+ done:
+ if (result) {
+ SMARTLIST_FOREACH(result, tor_addr_t *, t, tor_free(t));
+ smartlist_free(result);
+ }
+ return;
+}
+
+#endif
+
+#define ADDRESS_TEST(name, flags) \
+ { #name, test_address_ ## name, flags, NULL, NULL }
+
+struct testcase_t address_tests[] = {
+#ifdef HAVE_IFADDRS_TO_SMARTLIST
+ ADDRESS_TEST(get_if_addrs_ifaddrs, TT_FORK),
+ ADDRESS_TEST(ifaddrs_to_smartlist, 0),
+#endif
+#ifdef HAVE_IP_ADAPTER_TO_SMARTLIST
+ ADDRESS_TEST(get_if_addrs_win32, TT_FORK),
+ ADDRESS_TEST(ip_adapter_addresses_to_smartlist, 0),
+#endif
+#ifdef HAVE_IFCONF_TO_SMARTLIST
+ ADDRESS_TEST(get_if_addrs_ioctl, TT_FORK),
+ ADDRESS_TEST(ifreq_to_smartlist, 0),
+#endif
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c
index 45ae82fb85..0fa0cd5c0a 100644
--- a/src/test/test_bt_cl.c
+++ b/src/test/test_bt_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -30,7 +30,12 @@ int
crash(int x)
{
if (crashtype == 0) {
+#if defined(__clang_analyzer__) || defined(__COVERITY__)
+ tor_assert(1 == 0); /* Avert your eyes, clangalyzer and coverity! You
+ * don't need to see us dereference NULL. */
+#else
*(volatile int *)0 = 0;
+#endif
} else if (crashtype == 1) {
tor_assert(1 == 0);
} else if (crashtype == -1) {
@@ -91,7 +96,7 @@ main(int argc, char **argv)
return 1;
}
- init_logging();
+ init_logging(1);
set_log_severity_config(LOG_WARN, LOG_ERR, &severity);
add_stream_log(&severity, "stdout", STDOUT_FILENO);
tor_log_update_sigsafe_err_fds();
diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c
index f24b80f0b0..0ede8081d8 100644
--- a/src/test/test_buffers.c
+++ b/src/test/test_buffers.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define BUFFERS_PRIVATE
@@ -27,10 +27,10 @@ test_buffers_basic(void *arg)
* buf_new
****/
if (!(buf = buf_new()))
- test_fail();
+ TT_DIE(("Assertion failed."));
//test_eq(buf_capacity(buf), 4096);
- test_eq(buf_datalen(buf), 0);
+ tt_int_op(buf_datalen(buf),OP_EQ, 0);
/****
* General pointer frobbing
@@ -40,16 +40,16 @@ test_buffers_basic(void *arg)
}
write_to_buf(str, 256, buf);
write_to_buf(str, 256, buf);
- test_eq(buf_datalen(buf), 512);
+ tt_int_op(buf_datalen(buf),OP_EQ, 512);
fetch_from_buf(str2, 200, buf);
- test_memeq(str, str2, 200);
- test_eq(buf_datalen(buf), 312);
+ tt_mem_op(str,OP_EQ, str2, 200);
+ tt_int_op(buf_datalen(buf),OP_EQ, 312);
memset(str2, 0, sizeof(str2));
fetch_from_buf(str2, 256, buf);
- test_memeq(str+200, str2, 56);
- test_memeq(str, str2+56, 200);
- test_eq(buf_datalen(buf), 56);
+ tt_mem_op(str+200,OP_EQ, str2, 56);
+ tt_mem_op(str,OP_EQ, str2+56, 200);
+ tt_int_op(buf_datalen(buf),OP_EQ, 56);
memset(str2, 0, sizeof(str2));
/* Okay, now we should be 512 bytes into the 4096-byte buffer. If we add
* another 3584 bytes, we hit the end. */
@@ -57,16 +57,16 @@ test_buffers_basic(void *arg)
write_to_buf(str, 256, buf);
}
assert_buf_ok(buf);
- test_eq(buf_datalen(buf), 3896);
+ tt_int_op(buf_datalen(buf),OP_EQ, 3896);
fetch_from_buf(str2, 56, buf);
- test_eq(buf_datalen(buf), 3840);
- test_memeq(str+200, str2, 56);
+ tt_int_op(buf_datalen(buf),OP_EQ, 3840);
+ tt_mem_op(str+200,OP_EQ, str2, 56);
for (j=0;j<15;++j) {
memset(str2, 0, sizeof(str2));
fetch_from_buf(str2, 256, buf);
- test_memeq(str, str2, 256);
+ tt_mem_op(str,OP_EQ, str2, 256);
}
- test_eq(buf_datalen(buf), 0);
+ tt_int_op(buf_datalen(buf),OP_EQ, 0);
buf_free(buf);
buf = NULL;
@@ -76,7 +76,7 @@ test_buffers_basic(void *arg)
write_to_buf(str+1, 255, buf);
//test_eq(buf_capacity(buf), 256);
fetch_from_buf(str2, 254, buf);
- test_memeq(str+1, str2, 254);
+ tt_mem_op(str+1,OP_EQ, str2, 254);
//test_eq(buf_capacity(buf), 256);
assert_buf_ok(buf);
write_to_buf(str, 32, buf);
@@ -85,15 +85,15 @@ test_buffers_basic(void *arg)
write_to_buf(str, 256, buf);
assert_buf_ok(buf);
//test_eq(buf_capacity(buf), 512);
- test_eq(buf_datalen(buf), 33+256);
+ tt_int_op(buf_datalen(buf),OP_EQ, 33+256);
fetch_from_buf(str2, 33, buf);
- test_eq(*str2, str[255]);
+ tt_int_op(*str2,OP_EQ, str[255]);
- test_memeq(str2+1, str, 32);
+ tt_mem_op(str2+1,OP_EQ, str, 32);
//test_eq(buf_capacity(buf), 512);
- test_eq(buf_datalen(buf), 256);
+ tt_int_op(buf_datalen(buf),OP_EQ, 256);
fetch_from_buf(str2, 256, buf);
- test_memeq(str, str2, 256);
+ tt_mem_op(str,OP_EQ, str2, 256);
/* now try shrinking: case 1. */
buf_free(buf);
@@ -102,10 +102,10 @@ test_buffers_basic(void *arg)
write_to_buf(str,255, buf);
}
//test_eq(buf_capacity(buf), 33668);
- test_eq(buf_datalen(buf), 17085);
+ tt_int_op(buf_datalen(buf),OP_EQ, 17085);
for (j=0; j < 40; ++j) {
fetch_from_buf(str2, 255,buf);
- test_memeq(str2, str, 255);
+ tt_mem_op(str2,OP_EQ, str, 255);
}
/* now try shrinking: case 2. */
@@ -116,7 +116,7 @@ test_buffers_basic(void *arg)
}
for (j=0; j < 20; ++j) {
fetch_from_buf(str2, 255,buf);
- test_memeq(str2, str, 255);
+ tt_mem_op(str2,OP_EQ, str, 255);
}
for (j=0;j<80;++j) {
write_to_buf(str,255, buf);
@@ -124,7 +124,7 @@ test_buffers_basic(void *arg)
//test_eq(buf_capacity(buf),33668);
for (j=0; j < 120; ++j) {
fetch_from_buf(str2, 255,buf);
- test_memeq(str2, str, 255);
+ tt_mem_op(str2,OP_EQ, str, 255);
}
/* Move from buf to buf. */
@@ -133,27 +133,27 @@ test_buffers_basic(void *arg)
buf2 = buf_new_with_capacity(4096);
for (j=0;j<100;++j)
write_to_buf(str, 255, buf);
- test_eq(buf_datalen(buf), 25500);
+ tt_int_op(buf_datalen(buf),OP_EQ, 25500);
for (j=0;j<100;++j) {
r = 10;
move_buf_to_buf(buf2, buf, &r);
- test_eq(r, 0);
+ tt_int_op(r,OP_EQ, 0);
}
- test_eq(buf_datalen(buf), 24500);
- test_eq(buf_datalen(buf2), 1000);
+ tt_int_op(buf_datalen(buf),OP_EQ, 24500);
+ tt_int_op(buf_datalen(buf2),OP_EQ, 1000);
for (j=0;j<3;++j) {
fetch_from_buf(str2, 255, buf2);
- test_memeq(str2, str, 255);
+ tt_mem_op(str2,OP_EQ, str, 255);
}
r = 8192; /*big move*/
move_buf_to_buf(buf2, buf, &r);
- test_eq(r, 0);
+ tt_int_op(r,OP_EQ, 0);
r = 30000; /* incomplete move */
move_buf_to_buf(buf2, buf, &r);
- test_eq(r, 13692);
+ tt_int_op(r,OP_EQ, 13692);
for (j=0;j<97;++j) {
fetch_from_buf(str2, 255, buf2);
- test_memeq(str2, str, 255);
+ tt_mem_op(str2,OP_EQ, str, 255);
}
buf_free(buf);
buf_free(buf2);
@@ -163,16 +163,16 @@ test_buffers_basic(void *arg)
cp = "Testing. This is a moderately long Testing string.";
for (j = 0; cp[j]; j++)
write_to_buf(cp+j, 1, buf);
- test_eq(0, buf_find_string_offset(buf, "Testing", 7));
- test_eq(1, buf_find_string_offset(buf, "esting", 6));
- test_eq(1, buf_find_string_offset(buf, "est", 3));
- test_eq(39, buf_find_string_offset(buf, "ing str", 7));
- test_eq(35, buf_find_string_offset(buf, "Testing str", 11));
- test_eq(32, buf_find_string_offset(buf, "ng ", 3));
- test_eq(43, buf_find_string_offset(buf, "string.", 7));
- test_eq(-1, buf_find_string_offset(buf, "shrdlu", 6));
- test_eq(-1, buf_find_string_offset(buf, "Testing thing", 13));
- test_eq(-1, buf_find_string_offset(buf, "ngx", 3));
+ tt_int_op(0,OP_EQ, buf_find_string_offset(buf, "Testing", 7));
+ tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "esting", 6));
+ tt_int_op(1,OP_EQ, buf_find_string_offset(buf, "est", 3));
+ tt_int_op(39,OP_EQ, buf_find_string_offset(buf, "ing str", 7));
+ tt_int_op(35,OP_EQ, buf_find_string_offset(buf, "Testing str", 11));
+ tt_int_op(32,OP_EQ, buf_find_string_offset(buf, "ng ", 3));
+ tt_int_op(43,OP_EQ, buf_find_string_offset(buf, "string.", 7));
+ tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "shrdlu", 6));
+ tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "Testing thing", 13));
+ tt_int_op(-1,OP_EQ, buf_find_string_offset(buf, "ngx", 3));
buf_free(buf);
buf = NULL;
@@ -183,7 +183,7 @@ test_buffers_basic(void *arg)
write_to_buf(cp, 65536, buf);
tor_free(cp);
- tt_int_op(buf_datalen(buf), ==, 65536);
+ tt_int_op(buf_datalen(buf), OP_EQ, 65536);
buf_free(buf);
buf = NULL;
}
@@ -193,7 +193,6 @@ test_buffers_basic(void *arg)
buf_free(buf);
if (buf2)
buf_free(buf2);
- buf_shrink_freelists(1);
}
static void
@@ -213,19 +212,19 @@ test_buffer_pullup(void *arg)
buf = buf_new_with_capacity(3000); /* rounds up to next power of 2. */
tt_assert(buf);
- tt_int_op(buf_get_default_chunk_size(buf), ==, 4096);
+ tt_int_op(buf_get_default_chunk_size(buf), OP_EQ, 4096);
- tt_int_op(buf_get_total_allocation(), ==, 0);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
/* There are a bunch of cases for pullup. One is the trivial case. Let's
mess around with an empty buffer. */
buf_pullup(buf, 16, 1);
buf_get_first_chunk_data(buf, &cp, &sz);
- tt_ptr_op(cp, ==, NULL);
- tt_uint_op(sz, ==, 0);
+ tt_ptr_op(cp, OP_EQ, NULL);
+ tt_uint_op(sz, OP_EQ, 0);
/* Let's make sure nothing got allocated */
- tt_int_op(buf_get_total_allocation(), ==, 0);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
/* Case 1: everything puts into the first chunk with some moving. */
@@ -234,22 +233,22 @@ test_buffer_pullup(void *arg)
write_to_buf(stuff, 3000, buf);
write_to_buf(stuff+3000, 3000, buf);
buf_get_first_chunk_data(buf, &cp, &sz);
- tt_ptr_op(cp, !=, NULL);
- tt_int_op(sz, <=, 4096);
+ tt_ptr_op(cp, OP_NE, NULL);
+ tt_int_op(sz, OP_LE, 4096);
/* Make room for 3000 bytes in the first chunk, so that the pullup-move code
* can get tested. */
- tt_int_op(fetch_from_buf(tmp, 3000, buf), ==, 3000);
- test_memeq(tmp, stuff, 3000);
+ tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 3000);
+ tt_mem_op(tmp,OP_EQ, stuff, 3000);
buf_pullup(buf, 2048, 0);
assert_buf_ok(buf);
buf_get_first_chunk_data(buf, &cp, &sz);
- tt_ptr_op(cp, !=, NULL);
- tt_int_op(sz, >=, 2048);
- test_memeq(cp, stuff+3000, 2048);
- tt_int_op(3000, ==, buf_datalen(buf));
- tt_int_op(fetch_from_buf(tmp, 3000, buf), ==, 0);
- test_memeq(tmp, stuff+3000, 2048);
+ tt_ptr_op(cp, OP_NE, NULL);
+ tt_int_op(sz, OP_GE, 2048);
+ tt_mem_op(cp,OP_EQ, stuff+3000, 2048);
+ tt_int_op(3000, OP_EQ, buf_datalen(buf));
+ tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 0);
+ tt_mem_op(tmp,OP_EQ, stuff+3000, 2048);
buf_free(buf);
@@ -259,26 +258,26 @@ test_buffer_pullup(void *arg)
write_to_buf(stuff+4000, 4000, buf);
write_to_buf(stuff+8000, 4000, buf);
write_to_buf(stuff+12000, 4000, buf);
- tt_int_op(buf_datalen(buf), ==, 16000);
+ tt_int_op(buf_datalen(buf), OP_EQ, 16000);
buf_get_first_chunk_data(buf, &cp, &sz);
- tt_ptr_op(cp, !=, NULL);
- tt_int_op(sz, <=, 4096);
+ tt_ptr_op(cp, OP_NE, NULL);
+ tt_int_op(sz, OP_LE, 4096);
buf_pullup(buf, 12500, 0);
assert_buf_ok(buf);
buf_get_first_chunk_data(buf, &cp, &sz);
- tt_ptr_op(cp, !=, NULL);
- tt_int_op(sz, >=, 12500);
- test_memeq(cp, stuff, 12500);
- tt_int_op(buf_datalen(buf), ==, 16000);
+ tt_ptr_op(cp, OP_NE, NULL);
+ tt_int_op(sz, OP_GE, 12500);
+ tt_mem_op(cp,OP_EQ, stuff, 12500);
+ tt_int_op(buf_datalen(buf), OP_EQ, 16000);
fetch_from_buf(tmp, 12400, buf);
- test_memeq(tmp, stuff, 12400);
- tt_int_op(buf_datalen(buf), ==, 3600);
+ tt_mem_op(tmp,OP_EQ, stuff, 12400);
+ tt_int_op(buf_datalen(buf), OP_EQ, 3600);
fetch_from_buf(tmp, 3500, buf);
- test_memeq(tmp, stuff+12400, 3500);
+ tt_mem_op(tmp,OP_EQ, stuff+12400, 3500);
fetch_from_buf(tmp, 100, buf);
- test_memeq(tmp, stuff+15900, 10);
+ tt_mem_op(tmp,OP_EQ, stuff+15900, 10);
buf_free(buf);
@@ -290,19 +289,16 @@ test_buffer_pullup(void *arg)
buf_pullup(buf, 16000, 0); /* Way too much. */
assert_buf_ok(buf);
buf_get_first_chunk_data(buf, &cp, &sz);
- tt_ptr_op(cp, !=, NULL);
- tt_int_op(sz, ==, 7900);
- test_memeq(cp, stuff+100, 7900);
+ tt_ptr_op(cp, OP_NE, NULL);
+ tt_int_op(sz, OP_EQ, 7900);
+ tt_mem_op(cp,OP_EQ, stuff+100, 7900);
buf_free(buf);
buf = NULL;
- buf_shrink_freelists(1);
-
- tt_int_op(buf_get_total_allocation(), ==, 0);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
done:
buf_free(buf);
- buf_shrink_freelists(1);
tor_free(stuff);
tor_free(tmp);
}
@@ -321,31 +317,31 @@ test_buffer_copy(void *arg)
tt_assert(buf);
/* Copy an empty buffer. */
- tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(0, OP_EQ, generic_buffer_set_to_copy(&buf2, buf));
tt_assert(buf2);
- tt_int_op(0, ==, generic_buffer_len(buf2));
+ tt_int_op(0, OP_EQ, generic_buffer_len(buf2));
/* Now try with a short buffer. */
s = "And now comes an act of enormous enormance!";
len = strlen(s);
generic_buffer_add(buf, s, len);
- tt_int_op(len, ==, generic_buffer_len(buf));
+ tt_int_op(len, OP_EQ, generic_buffer_len(buf));
/* Add junk to buf2 so we can test replacing.*/
generic_buffer_add(buf2, "BLARG", 5);
- tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
- tt_int_op(len, ==, generic_buffer_len(buf2));
+ tt_int_op(0, OP_EQ, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(len, OP_EQ, generic_buffer_len(buf2));
generic_buffer_get(buf2, b, len);
- test_mem_op(b, ==, s, len);
+ tt_mem_op(b, OP_EQ, s, len);
/* Now free buf2 and retry so we can test allocating */
generic_buffer_free(buf2);
buf2 = NULL;
- tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
- tt_int_op(len, ==, generic_buffer_len(buf2));
+ tt_int_op(0, OP_EQ, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(len, OP_EQ, generic_buffer_len(buf2));
generic_buffer_get(buf2, b, len);
- test_mem_op(b, ==, s, len);
+ tt_mem_op(b, OP_EQ, s, len);
/* Clear buf for next test */
generic_buffer_get(buf, b, len);
- tt_int_op(generic_buffer_len(buf),==,0);
+ tt_int_op(generic_buffer_len(buf),OP_EQ,0);
/* Okay, now let's try a bigger buffer. */
s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit "
@@ -357,12 +353,12 @@ test_buffer_copy(void *arg)
generic_buffer_add(buf, b, 1);
generic_buffer_add(buf, s, len);
}
- tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
- tt_int_op(generic_buffer_len(buf2), ==, generic_buffer_len(buf));
+ tt_int_op(0, OP_EQ, generic_buffer_set_to_copy(&buf2, buf));
+ tt_int_op(generic_buffer_len(buf2), OP_EQ, generic_buffer_len(buf));
for (i = 0; i < 256; ++i) {
generic_buffer_get(buf2, b, len+1);
- tt_int_op((unsigned char)b[0],==,i);
- test_mem_op(b+1, ==, s, len);
+ tt_int_op((unsigned char)b[0],OP_EQ,i);
+ tt_mem_op(b+1, OP_EQ, s, len);
}
done:
@@ -370,7 +366,6 @@ test_buffer_copy(void *arg)
generic_buffer_free(buf);
if (buf2)
generic_buffer_free(buf2);
- buf_shrink_freelists(1);
}
static void
@@ -382,62 +377,62 @@ test_buffer_ext_or_cmd(void *arg)
(void) arg;
/* Empty -- should give "not there. */
- tt_int_op(0, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
- tt_ptr_op(NULL, ==, cmd);
+ tt_int_op(0, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, OP_EQ, cmd);
/* Three bytes: shouldn't work. */
generic_buffer_add(buf, "\x00\x20\x00", 3);
- tt_int_op(0, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
- tt_ptr_op(NULL, ==, cmd);
- tt_int_op(3, ==, generic_buffer_len(buf));
+ tt_int_op(0, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, OP_EQ, cmd);
+ tt_int_op(3, OP_EQ, generic_buffer_len(buf));
/* 0020 0000: That's a nil command. It should work. */
generic_buffer_add(buf, "\x00", 1);
- tt_int_op(1, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
- tt_ptr_op(NULL, !=, cmd);
- tt_int_op(0x20, ==, cmd->cmd);
- tt_int_op(0, ==, cmd->len);
- tt_int_op(0, ==, generic_buffer_len(buf));
+ tt_int_op(1, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0x20, OP_EQ, cmd->cmd);
+ tt_int_op(0, OP_EQ, cmd->len);
+ tt_int_op(0, OP_EQ, generic_buffer_len(buf));
ext_or_cmd_free(cmd);
cmd = NULL;
/* Now try a length-6 command with one byte missing. */
generic_buffer_add(buf, "\x10\x21\x00\x06""abcde", 9);
- tt_int_op(0, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
- tt_ptr_op(NULL, ==, cmd);
+ tt_int_op(0, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, OP_EQ, cmd);
generic_buffer_add(buf, "f", 1);
- tt_int_op(1, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
- tt_ptr_op(NULL, !=, cmd);
- tt_int_op(0x1021, ==, cmd->cmd);
- tt_int_op(6, ==, cmd->len);
- test_mem_op("abcdef", ==, cmd->body, 6);
- tt_int_op(0, ==, generic_buffer_len(buf));
+ tt_int_op(1, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0x1021, OP_EQ, cmd->cmd);
+ tt_int_op(6, OP_EQ, cmd->len);
+ tt_mem_op("abcdef", OP_EQ, cmd->body, 6);
+ tt_int_op(0, OP_EQ, generic_buffer_len(buf));
ext_or_cmd_free(cmd);
cmd = NULL;
/* Now try a length-10 command with 4 extra bytes. */
generic_buffer_add(buf, "\xff\xff\x00\x0a"
"loremipsum\x10\x00\xff\xff", 18);
- tt_int_op(1, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
- tt_ptr_op(NULL, !=, cmd);
- tt_int_op(0xffff, ==, cmd->cmd);
- tt_int_op(10, ==, cmd->len);
- test_mem_op("loremipsum", ==, cmd->body, 10);
- tt_int_op(4, ==, generic_buffer_len(buf));
+ tt_int_op(1, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0xffff, OP_EQ, cmd->cmd);
+ tt_int_op(10, OP_EQ, cmd->len);
+ tt_mem_op("loremipsum", OP_EQ, cmd->body, 10);
+ tt_int_op(4, OP_EQ, generic_buffer_len(buf));
ext_or_cmd_free(cmd);
cmd = NULL;
/* Finally, let's try a maximum-length command. We already have the header
* waiting. */
- tt_int_op(0, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_int_op(0, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
tmp = tor_malloc_zero(65535);
generic_buffer_add(buf, tmp, 65535);
- tt_int_op(1, ==, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
- tt_ptr_op(NULL, !=, cmd);
- tt_int_op(0x1000, ==, cmd->cmd);
- tt_int_op(0xffff, ==, cmd->len);
- test_mem_op(tmp, ==, cmd->body, 65535);
- tt_int_op(0, ==, generic_buffer_len(buf));
+ tt_int_op(1, OP_EQ, generic_buffer_fetch_ext_or_cmd(buf, &cmd));
+ tt_ptr_op(NULL, OP_NE, cmd);
+ tt_int_op(0x1000, OP_EQ, cmd->cmd);
+ tt_int_op(0xffff, OP_EQ, cmd->len);
+ tt_mem_op(tmp, OP_EQ, cmd->body, 65535);
+ tt_int_op(0, OP_EQ, generic_buffer_len(buf));
ext_or_cmd_free(cmd);
cmd = NULL;
@@ -445,7 +440,6 @@ test_buffer_ext_or_cmd(void *arg)
ext_or_cmd_free(cmd);
generic_buffer_free(buf);
tor_free(tmp);
- buf_shrink_freelists(1);
}
static void
@@ -458,70 +452,61 @@ test_buffer_allocation_tracking(void *arg)
(void)arg;
crypto_rand(junk, 16384);
- tt_int_op(buf_get_total_allocation(), ==, 0);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
buf1 = buf_new();
tt_assert(buf1);
buf2 = buf_new();
tt_assert(buf2);
- tt_int_op(buf_allocation(buf1), ==, 0);
- tt_int_op(buf_get_total_allocation(), ==, 0);
+ tt_int_op(buf_allocation(buf1), OP_EQ, 0);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
write_to_buf(junk, 4000, buf1);
write_to_buf(junk, 4000, buf1);
write_to_buf(junk, 4000, buf1);
write_to_buf(junk, 4000, buf1);
- tt_int_op(buf_allocation(buf1), ==, 16384);
+ tt_int_op(buf_allocation(buf1), OP_EQ, 16384);
fetch_from_buf(junk, 100, buf1);
- tt_int_op(buf_allocation(buf1), ==, 16384); /* still 4 4k chunks */
+ tt_int_op(buf_allocation(buf1), OP_EQ, 16384); /* still 4 4k chunks */
- tt_int_op(buf_get_total_allocation(), ==, 16384);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 16384);
fetch_from_buf(junk, 4096, buf1); /* drop a 1k chunk... */
- tt_int_op(buf_allocation(buf1), ==, 3*4096); /* now 3 4k chunks */
+ tt_int_op(buf_allocation(buf1), OP_EQ, 3*4096); /* now 3 4k chunks */
-#ifdef ENABLE_BUF_FREELISTS
- tt_int_op(buf_get_total_allocation(), ==, 16384); /* that chunk went onto
- the freelist. */
-#else
- tt_int_op(buf_get_total_allocation(), ==, 12288); /* that chunk was really
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 12288); /* that chunk was really
freed. */
-#endif
write_to_buf(junk, 4000, buf2);
- tt_int_op(buf_allocation(buf2), ==, 4096); /* another 4k chunk. */
+ tt_int_op(buf_allocation(buf2), OP_EQ, 4096); /* another 4k chunk. */
/*
- * If we're using freelists, size stays at 16384 because we just pulled a
- * chunk from the freelist. If we aren't, we bounce back up to 16384 by
- * allocating a new chunk.
+ * We bounce back up to 16384 by allocating a new chunk.
*/
- tt_int_op(buf_get_total_allocation(), ==, 16384);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 16384);
write_to_buf(junk, 4000, buf2);
- tt_int_op(buf_allocation(buf2), ==, 8192); /* another 4k chunk. */
- tt_int_op(buf_get_total_allocation(), ==, 5*4096); /* that chunk was new. */
+ tt_int_op(buf_allocation(buf2), OP_EQ, 8192); /* another 4k chunk. */
+ tt_int_op(buf_get_total_allocation(),
+ OP_EQ, 5*4096); /* that chunk was new. */
/* Make a really huge buffer */
for (i = 0; i < 1000; ++i) {
write_to_buf(junk, 4000, buf2);
}
- tt_int_op(buf_allocation(buf2), >=, 4008000);
- tt_int_op(buf_get_total_allocation(), >=, 4008000);
+ tt_int_op(buf_allocation(buf2), OP_GE, 4008000);
+ tt_int_op(buf_get_total_allocation(), OP_GE, 4008000);
buf_free(buf2);
buf2 = NULL;
- tt_int_op(buf_get_total_allocation(), <, 4008000);
- buf_shrink_freelists(1);
- tt_int_op(buf_get_total_allocation(), ==, buf_allocation(buf1));
+ tt_int_op(buf_get_total_allocation(), OP_LT, 4008000);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, buf_allocation(buf1));
buf_free(buf1);
buf1 = NULL;
- buf_shrink_freelists(1);
- tt_int_op(buf_get_total_allocation(), ==, 0);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
done:
buf_free(buf1);
buf_free(buf2);
- buf_shrink_freelists(1);
tor_free(junk);
}
@@ -545,37 +530,38 @@ test_buffer_time_tracking(void *arg)
tt_assert(buf);
/* Empty buffer means the timestamp is 0. */
- tt_int_op(0, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC));
- tt_int_op(0, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000));
+ tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC));
+ tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000));
tor_gettimeofday_cache_set(&tv0);
write_to_buf("ABCDEFG", 7, buf);
- tt_int_op(1000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000));
+ tt_int_op(1000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+1000));
buf2 = buf_copy(buf);
tt_assert(buf2);
- tt_int_op(1234, ==, buf_get_oldest_chunk_timestamp(buf2, START_MSEC+1234));
+ tt_int_op(1234, OP_EQ,
+ buf_get_oldest_chunk_timestamp(buf2, START_MSEC+1234));
/* Now add more bytes; enough to overflow the first chunk. */
tv0.tv_usec += 123 * 1000;
tor_gettimeofday_cache_set(&tv0);
for (i = 0; i < 600; ++i)
write_to_buf("ABCDEFG", 7, buf);
- tt_int_op(4207, ==, buf_datalen(buf));
+ tt_int_op(4207, OP_EQ, buf_datalen(buf));
/* The oldest bytes are still in the front. */
- tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000));
+ tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000));
/* Once those bytes are dropped, the chunk is still on the first
* timestamp. */
fetch_from_buf(tmp, 100, buf);
- tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000));
+ tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2000));
/* But once we discard the whole first chunk, we get the data in the second
* chunk. */
fetch_from_buf(tmp, 4000, buf);
- tt_int_op(107, ==, buf_datalen(buf));
- tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123));
+ tt_int_op(107, OP_EQ, buf_datalen(buf));
+ tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123));
/* This time we'll be grabbing a chunk from the freelist, and making sure
its time gets updated */
@@ -584,13 +570,13 @@ test_buffer_time_tracking(void *arg)
tor_gettimeofday_cache_set(&tv0);
for (i = 0; i < 600; ++i)
write_to_buf("ABCDEFG", 7, buf);
- tt_int_op(4307, ==, buf_datalen(buf));
+ tt_int_op(4307, OP_EQ, buf_datalen(buf));
- tt_int_op(2000, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123));
+ tt_int_op(2000, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+2123));
fetch_from_buf(tmp, 4000, buf);
fetch_from_buf(tmp, 306, buf);
- tt_int_op(0, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+5617));
- tt_int_op(383, ==, buf_get_oldest_chunk_timestamp(buf, START_MSEC+6000));
+ tt_int_op(0, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+5617));
+ tt_int_op(383, OP_EQ, buf_get_oldest_chunk_timestamp(buf, START_MSEC+6000));
done:
buf_free(buf);
@@ -609,35 +595,35 @@ test_buffers_zlib_impl(int finalize_with_nil)
int done;
buf = buf_new_with_capacity(128); /* will round up */
- zlib_state = tor_zlib_new(1, ZLIB_METHOD);
+ zlib_state = tor_zlib_new(1, ZLIB_METHOD, HIGH_COMPRESSION);
msg = tor_malloc(512);
crypto_rand(msg, 512);
- tt_int_op(write_to_buf_zlib(buf, zlib_state, msg, 128, 0), ==, 0);
- tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+128, 128, 0), ==, 0);
- tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+256, 256, 0), ==, 0);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, msg, 128, 0), OP_EQ, 0);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+128, 128, 0), OP_EQ, 0);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, msg+256, 256, 0), OP_EQ, 0);
done = !finalize_with_nil;
- tt_int_op(write_to_buf_zlib(buf, zlib_state, "all done", 9, done), ==, 0);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, "all done", 9, done), OP_EQ, 0);
if (finalize_with_nil) {
- tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), ==, 0);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), OP_EQ, 0);
}
in_len = buf_datalen(buf);
contents = tor_malloc(in_len);
- tt_int_op(fetch_from_buf(contents, in_len, buf), ==, 0);
+ tt_int_op(fetch_from_buf(contents, in_len, buf), OP_EQ, 0);
- tt_int_op(0, ==, tor_gzip_uncompress(&expanded, &out_len,
+ tt_int_op(0, OP_EQ, tor_gzip_uncompress(&expanded, &out_len,
contents, in_len,
ZLIB_METHOD, 1,
LOG_WARN));
- tt_int_op(out_len, >=, 128);
- tt_mem_op(msg, ==, expanded, 128);
- tt_int_op(out_len, >=, 512);
- tt_mem_op(msg, ==, expanded, 512);
- tt_int_op(out_len, ==, 512+9);
- tt_mem_op("all done", ==, expanded+512, 9);
+ tt_int_op(out_len, OP_GE, 128);
+ tt_mem_op(msg, OP_EQ, expanded, 128);
+ tt_int_op(out_len, OP_GE, 512);
+ tt_mem_op(msg, OP_EQ, expanded, 512);
+ tt_int_op(out_len, OP_EQ, 512+9);
+ tt_mem_op("all done", OP_EQ, expanded+512, 9);
done:
buf_free(buf);
@@ -680,28 +666,28 @@ test_buffers_zlib_fin_at_chunk_end(void *arg)
tt_assert(buf->head);
/* Fill up the chunk so the zlib stuff won't fit in one chunk. */
- tt_uint_op(buf->head->memlen, <, sz);
+ tt_uint_op(buf->head->memlen, OP_LT, sz);
headerjunk = buf->head->memlen - 7;
write_to_buf(msg, headerjunk-1, buf);
- tt_uint_op(buf->head->datalen, ==, headerjunk);
- tt_uint_op(buf_datalen(buf), ==, headerjunk);
+ tt_uint_op(buf->head->datalen, OP_EQ, headerjunk);
+ tt_uint_op(buf_datalen(buf), OP_EQ, headerjunk);
/* Write an empty string, with finalization on. */
- zlib_state = tor_zlib_new(1, ZLIB_METHOD);
- tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), ==, 0);
+ zlib_state = tor_zlib_new(1, ZLIB_METHOD, HIGH_COMPRESSION);
+ tt_int_op(write_to_buf_zlib(buf, zlib_state, "", 0, 1), OP_EQ, 0);
in_len = buf_datalen(buf);
contents = tor_malloc(in_len);
- tt_int_op(fetch_from_buf(contents, in_len, buf), ==, 0);
+ tt_int_op(fetch_from_buf(contents, in_len, buf), OP_EQ, 0);
- tt_uint_op(in_len, >, headerjunk);
+ tt_uint_op(in_len, OP_GT, headerjunk);
- tt_int_op(0, ==, tor_gzip_uncompress(&expanded, &out_len,
+ tt_int_op(0, OP_EQ, tor_gzip_uncompress(&expanded, &out_len,
contents + headerjunk, in_len - headerjunk,
ZLIB_METHOD, 1,
LOG_WARN));
- tt_int_op(out_len, ==, 0);
+ tt_int_op(out_len, OP_EQ, 0);
tt_assert(expanded);
done:
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index d7f60680c2..e86dc0934f 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -30,16 +30,16 @@ test_cfmt_relay_header(void *arg)
uint8_t hdr_out[RELAY_HEADER_SIZE];
(void)arg;
- tt_int_op(sizeof(hdr_1), ==, RELAY_HEADER_SIZE);
+ tt_int_op(sizeof(hdr_1), OP_EQ, RELAY_HEADER_SIZE);
relay_header_unpack(&rh, hdr_1);
- tt_int_op(rh.command, ==, 3);
- tt_int_op(rh.recognized, ==, 0);
- tt_int_op(rh.stream_id, ==, 0x2122);
- test_mem_op(rh.integrity, ==, "ABCD", 4);
- tt_int_op(rh.length, ==, 0x103);
+ tt_int_op(rh.command, OP_EQ, 3);
+ tt_int_op(rh.recognized, OP_EQ, 0);
+ tt_int_op(rh.stream_id, OP_EQ, 0x2122);
+ tt_mem_op(rh.integrity, OP_EQ, "ABCD", 4);
+ tt_int_op(rh.length, OP_EQ, 0x103);
relay_header_pack(hdr_out, &rh);
- test_mem_op(hdr_out, ==, hdr_1, RELAY_HEADER_SIZE);
+ tt_mem_op(hdr_out, OP_EQ, hdr_1, RELAY_HEADER_SIZE);
done:
;
@@ -74,32 +74,32 @@ test_cfmt_begin_cells(void *arg)
/* Try begindir. */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "", 0);
- tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
- tt_ptr_op(NULL, ==, bcell.address);
- tt_int_op(0, ==, bcell.flags);
- tt_int_op(0, ==, bcell.port);
- tt_int_op(5, ==, bcell.stream_id);
- tt_int_op(1, ==, bcell.is_begindir);
+ tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_ptr_op(NULL, OP_EQ, bcell.address);
+ tt_int_op(0, OP_EQ, bcell.flags);
+ tt_int_op(0, OP_EQ, bcell.port);
+ tt_int_op(5, OP_EQ, bcell.stream_id);
+ tt_int_op(1, OP_EQ, bcell.is_begindir);
/* A Begindir with extra stuff. */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN_DIR, "12345", 5);
- tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
- tt_ptr_op(NULL, ==, bcell.address);
- tt_int_op(0, ==, bcell.flags);
- tt_int_op(0, ==, bcell.port);
- tt_int_op(5, ==, bcell.stream_id);
- tt_int_op(1, ==, bcell.is_begindir);
+ tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_ptr_op(NULL, OP_EQ, bcell.address);
+ tt_int_op(0, OP_EQ, bcell.flags);
+ tt_int_op(0, OP_EQ, bcell.port);
+ tt_int_op(5, OP_EQ, bcell.stream_id);
+ tt_int_op(1, OP_EQ, bcell.is_begindir);
/* A short but valid begin cell */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:9", 6);
- tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
- tt_str_op("a.b", ==, bcell.address);
- tt_int_op(0, ==, bcell.flags);
- tt_int_op(9, ==, bcell.port);
- tt_int_op(5, ==, bcell.stream_id);
- tt_int_op(0, ==, bcell.is_begindir);
+ tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("a.b", OP_EQ, bcell.address);
+ tt_int_op(0, OP_EQ, bcell.flags);
+ tt_int_op(9, OP_EQ, bcell.port);
+ tt_int_op(5, OP_EQ, bcell.stream_id);
+ tt_int_op(0, OP_EQ, bcell.is_begindir);
tor_free(bcell.address);
/* A significantly loner begin cell */
@@ -108,35 +108,35 @@ test_cfmt_begin_cells(void *arg)
const char c[] = "here-is-a-nice-long.hostname.com:65535";
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, strlen(c)+1);
}
- tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
- tt_str_op("here-is-a-nice-long.hostname.com", ==, bcell.address);
- tt_int_op(0, ==, bcell.flags);
- tt_int_op(65535, ==, bcell.port);
- tt_int_op(5, ==, bcell.stream_id);
- tt_int_op(0, ==, bcell.is_begindir);
+ tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("here-is-a-nice-long.hostname.com", OP_EQ, bcell.address);
+ tt_int_op(0, OP_EQ, bcell.flags);
+ tt_int_op(65535, OP_EQ, bcell.port);
+ tt_int_op(5, OP_EQ, bcell.stream_id);
+ tt_int_op(0, OP_EQ, bcell.is_begindir);
tor_free(bcell.address);
/* An IPv4 begin cell. */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "18.9.22.169:80", 15);
- tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
- tt_str_op("18.9.22.169", ==, bcell.address);
- tt_int_op(0, ==, bcell.flags);
- tt_int_op(80, ==, bcell.port);
- tt_int_op(5, ==, bcell.stream_id);
- tt_int_op(0, ==, bcell.is_begindir);
+ tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("18.9.22.169", OP_EQ, bcell.address);
+ tt_int_op(0, OP_EQ, bcell.flags);
+ tt_int_op(80, OP_EQ, bcell.port);
+ tt_int_op(5, OP_EQ, bcell.stream_id);
+ tt_int_op(0, OP_EQ, bcell.is_begindir);
tor_free(bcell.address);
/* An IPv6 begin cell. Let's make sure we handle colons*/
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN,
"[2620::6b0:b:1a1a:0:26e5:480e]:80", 34);
- tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
- tt_str_op("[2620::6b0:b:1a1a:0:26e5:480e]", ==, bcell.address);
- tt_int_op(0, ==, bcell.flags);
- tt_int_op(80, ==, bcell.port);
- tt_int_op(5, ==, bcell.stream_id);
- tt_int_op(0, ==, bcell.is_begindir);
+ tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("[2620::6b0:b:1a1a:0:26e5:480e]", OP_EQ, bcell.address);
+ tt_int_op(0, OP_EQ, bcell.flags);
+ tt_int_op(80, OP_EQ, bcell.port);
+ tt_int_op(5, OP_EQ, bcell.stream_id);
+ tt_int_op(0, OP_EQ, bcell.is_begindir);
tor_free(bcell.address);
/* a begin cell with extra junk but not enough for flags. */
@@ -145,12 +145,12 @@ test_cfmt_begin_cells(void *arg)
const char c[] = "another.example.com:80\x00\x01\x02";
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
}
- tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
- tt_str_op("another.example.com", ==, bcell.address);
- tt_int_op(0, ==, bcell.flags);
- tt_int_op(80, ==, bcell.port);
- tt_int_op(5, ==, bcell.stream_id);
- tt_int_op(0, ==, bcell.is_begindir);
+ tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("another.example.com", OP_EQ, bcell.address);
+ tt_int_op(0, OP_EQ, bcell.flags);
+ tt_int_op(80, OP_EQ, bcell.port);
+ tt_int_op(5, OP_EQ, bcell.stream_id);
+ tt_int_op(0, OP_EQ, bcell.is_begindir);
tor_free(bcell.address);
/* a begin cell with flags. */
@@ -159,12 +159,12 @@ test_cfmt_begin_cells(void *arg)
const char c[] = "another.example.com:443\x00\x01\x02\x03\x04";
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
}
- tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
- tt_str_op("another.example.com", ==, bcell.address);
- tt_int_op(0x1020304, ==, bcell.flags);
- tt_int_op(443, ==, bcell.port);
- tt_int_op(5, ==, bcell.stream_id);
- tt_int_op(0, ==, bcell.is_begindir);
+ tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("another.example.com", OP_EQ, bcell.address);
+ tt_int_op(0x1020304, OP_EQ, bcell.flags);
+ tt_int_op(443, OP_EQ, bcell.port);
+ tt_int_op(5, OP_EQ, bcell.stream_id);
+ tt_int_op(0, OP_EQ, bcell.is_begindir);
tor_free(bcell.address);
/* a begin cell with flags and even more cruft after that. */
@@ -173,12 +173,12 @@ test_cfmt_begin_cells(void *arg)
const char c[] = "a-further.example.com:22\x00\xee\xaa\x00\xffHi mom";
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, c, sizeof(c)-1);
}
- tt_int_op(0, ==, begin_cell_parse(&cell, &bcell, &end_reason));
- tt_str_op("a-further.example.com", ==, bcell.address);
- tt_int_op(0xeeaa00ff, ==, bcell.flags);
- tt_int_op(22, ==, bcell.port);
- tt_int_op(5, ==, bcell.stream_id);
- tt_int_op(0, ==, bcell.is_begindir);
+ tt_int_op(0, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_str_op("a-further.example.com", OP_EQ, bcell.address);
+ tt_int_op(0xeeaa00ff, OP_EQ, bcell.flags);
+ tt_int_op(22, OP_EQ, bcell.port);
+ tt_int_op(5, OP_EQ, bcell.stream_id);
+ tt_int_op(0, OP_EQ, bcell.is_begindir);
tor_free(bcell.address);
/* bad begin cell: impossible length. */
@@ -189,42 +189,42 @@ test_cfmt_begin_cells(void *arg)
{
relay_header_t rh;
relay_header_unpack(&rh, cell.payload);
- tt_int_op(rh.length, ==, 510);
+ tt_int_op(rh.length, OP_EQ, 510);
}
- tt_int_op(-2, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_int_op(-2, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
/* Bad begin cell: no body. */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0);
- tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
/* bad begin cell: no body. */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "", 0);
- tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
/* bad begin cell: no colon */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b", 4);
- tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
/* bad begin cell: no ports */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:", 5);
- tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
/* bad begin cell: bad port */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:xyz", 8);
- tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:100000", 11);
- tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
/* bad begin cell: no nul */
memset(&bcell, 0x7f, sizeof(bcell));
make_relay_cell(&cell, RELAY_COMMAND_BEGIN, "a.b:80", 6);
- tt_int_op(-1, ==, begin_cell_parse(&cell, &bcell, &end_reason));
+ tt_int_op(-1, OP_EQ, begin_cell_parse(&cell, &bcell, &end_reason));
done:
tor_free(bcell.address);
@@ -244,47 +244,47 @@ test_cfmt_connected_cells(void *arg)
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "", 0);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, 0);
- tt_int_op(tor_addr_family(&addr), ==, AF_UNSPEC);
- tt_int_op(ttl, ==, -1);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(tor_addr_family(&addr), OP_EQ, AF_UNSPEC);
+ tt_int_op(ttl, OP_EQ, -1);
/* A slightly less oldschool one: only an IPv4 address */
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x20\x30\x40\x50", 4);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, 0);
- tt_int_op(tor_addr_family(&addr), ==, AF_INET);
- tt_str_op(fmt_addr(&addr), ==, "32.48.64.80");
- tt_int_op(ttl, ==, -1);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET);
+ tt_str_op(fmt_addr(&addr), OP_EQ, "32.48.64.80");
+ tt_int_op(ttl, OP_EQ, -1);
/* Bogus but understandable: truncated TTL */
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED, "\x11\x12\x13\x14\x15", 5);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, 0);
- tt_int_op(tor_addr_family(&addr), ==, AF_INET);
- tt_str_op(fmt_addr(&addr), ==, "17.18.19.20");
- tt_int_op(ttl, ==, -1);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET);
+ tt_str_op(fmt_addr(&addr), OP_EQ, "17.18.19.20");
+ tt_int_op(ttl, OP_EQ, -1);
/* Regular IPv4 one: address and TTL */
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
"\x02\x03\x04\x05\x00\x00\x0e\x10", 8);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, 0);
- tt_int_op(tor_addr_family(&addr), ==, AF_INET);
- tt_str_op(fmt_addr(&addr), ==, "2.3.4.5");
- tt_int_op(ttl, ==, 3600);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET);
+ tt_str_op(fmt_addr(&addr), OP_EQ, "2.3.4.5");
+ tt_int_op(ttl, OP_EQ, 3600);
/* IPv4 with too-big TTL */
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
"\x02\x03\x04\x05\xf0\x00\x00\x00", 8);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, 0);
- tt_int_op(tor_addr_family(&addr), ==, AF_INET);
- tt_str_op(fmt_addr(&addr), ==, "2.3.4.5");
- tt_int_op(ttl, ==, -1);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET);
+ tt_str_op(fmt_addr(&addr), OP_EQ, "2.3.4.5");
+ tt_int_op(ttl, OP_EQ, -1);
/* IPv6 (ttl is mandatory) */
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
@@ -294,10 +294,10 @@ test_cfmt_connected_cells(void *arg)
"\x00\x00\x02\x58", 25);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, 0);
- tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
- tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68");
- tt_int_op(ttl, ==, 600);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET6);
+ tt_str_op(fmt_addr(&addr), OP_EQ, "2607:f8b0:400c:c02::68");
+ tt_int_op(ttl, OP_EQ, 600);
/* IPv6 (ttl too big) */
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
@@ -307,17 +307,17 @@ test_cfmt_connected_cells(void *arg)
"\x90\x00\x02\x58", 25);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, 0);
- tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
- tt_str_op(fmt_addr(&addr), ==, "2607:f8b0:400c:c02::68");
- tt_int_op(ttl, ==, -1);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET6);
+ tt_str_op(fmt_addr(&addr), OP_EQ, "2607:f8b0:400c:c02::68");
+ tt_int_op(ttl, OP_EQ, -1);
/* Bogus size: 3. */
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
"\x00\x01\x02", 3);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, -1);
+ tt_int_op(r, OP_EQ, -1);
/* Bogus family: 7. */
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
@@ -327,7 +327,7 @@ test_cfmt_connected_cells(void *arg)
"\x90\x00\x02\x58", 25);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, -1);
+ tt_int_op(r, OP_EQ, -1);
/* Truncated IPv6. */
make_relay_cell(&cell, RELAY_COMMAND_CONNECTED,
@@ -337,7 +337,7 @@ test_cfmt_connected_cells(void *arg)
"\x00\x00\x02", 24);
relay_header_unpack(&rh, cell.payload);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, -1);
+ tt_int_op(r, OP_EQ, -1);
/* Now make sure we can generate connected cells correctly. */
/* Try an IPv4 address */
@@ -346,16 +346,16 @@ test_cfmt_connected_cells(void *arg)
tor_addr_parse(&addr, "30.40.50.60");
rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
&addr, 128);
- tt_int_op(rh.length, ==, 8);
+ tt_int_op(rh.length, OP_EQ, 8);
test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000080");
/* Try parsing it. */
tor_addr_make_unspec(&addr);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, 0);
- tt_int_op(tor_addr_family(&addr), ==, AF_INET);
- tt_str_op(fmt_addr(&addr), ==, "30.40.50.60");
- tt_int_op(ttl, ==, 128);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET);
+ tt_str_op(fmt_addr(&addr), OP_EQ, "30.40.50.60");
+ tt_int_op(ttl, OP_EQ, 128);
/* Try an IPv6 address */
memset(&rh, 0, sizeof(rh));
@@ -363,7 +363,7 @@ test_cfmt_connected_cells(void *arg)
tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e");
rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
&addr, 3600);
- tt_int_op(rh.length, ==, 25);
+ tt_int_op(rh.length, OP_EQ, 25);
test_memeq_hex(cell.payload + RELAY_HEADER_SIZE,
"00000000" "06"
"2620000006b0000b1a1a000026e5480e" "00000e10");
@@ -371,10 +371,10 @@ test_cfmt_connected_cells(void *arg)
/* Try parsing it. */
tor_addr_make_unspec(&addr);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
- tt_int_op(r, ==, 0);
- tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
- tt_str_op(fmt_addr(&addr), ==, "2620:0:6b0:b:1a1a:0:26e5:480e");
- tt_int_op(ttl, ==, 3600);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(tor_addr_family(&addr), OP_EQ, AF_INET6);
+ tt_str_op(fmt_addr(&addr), OP_EQ, "2620:0:6b0:b:1a1a:0:26e5:480e");
+ tt_int_op(ttl, OP_EQ, 3600);
done:
tor_free(mem_op_hex_tmp);
@@ -398,14 +398,14 @@ test_cfmt_create_cells(void *arg)
crypto_rand((char*)b, TAP_ONIONSKIN_CHALLENGE_LEN);
cell.command = CELL_CREATE;
memcpy(cell.payload, b, TAP_ONIONSKIN_CHALLENGE_LEN);
- tt_int_op(0, ==, create_cell_parse(&cc, &cell));
- tt_int_op(CELL_CREATE, ==, cc.cell_type);
- tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type);
- tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len);
- test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
- tt_int_op(0, ==, create_cell_format(&cell2, &cc));
- tt_int_op(cell.command, ==, cell2.command);
- test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+ tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE, OP_EQ, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_TAP, OP_EQ, cc.handshake_type);
+ tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, OP_EQ, cc.handshake_len);
+ tt_mem_op(cc.onionskin,OP_EQ, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
+ tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, OP_EQ, cell2.command);
+ tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
/* A valid create_fast cell. */
memset(&cell, 0, sizeof(cell));
@@ -413,14 +413,14 @@ test_cfmt_create_cells(void *arg)
crypto_rand((char*)b, CREATE_FAST_LEN);
cell.command = CELL_CREATE_FAST;
memcpy(cell.payload, b, CREATE_FAST_LEN);
- tt_int_op(0, ==, create_cell_parse(&cc, &cell));
- tt_int_op(CELL_CREATE_FAST, ==, cc.cell_type);
- tt_int_op(ONION_HANDSHAKE_TYPE_FAST, ==, cc.handshake_type);
- tt_int_op(CREATE_FAST_LEN, ==, cc.handshake_len);
- test_memeq(cc.onionskin, b, CREATE_FAST_LEN + 10);
- tt_int_op(0, ==, create_cell_format(&cell2, &cc));
- tt_int_op(cell.command, ==, cell2.command);
- test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+ tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE_FAST, OP_EQ, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_FAST, OP_EQ, cc.handshake_type);
+ tt_int_op(CREATE_FAST_LEN, OP_EQ, cc.handshake_len);
+ tt_mem_op(cc.onionskin,OP_EQ, b, CREATE_FAST_LEN + 10);
+ tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, OP_EQ, cell2.command);
+ tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
/* A valid create2 cell with a TAP payload */
memset(&cell, 0, sizeof(cell));
@@ -429,14 +429,14 @@ test_cfmt_create_cells(void *arg)
cell.command = CELL_CREATE2;
memcpy(cell.payload, "\x00\x00\x00\xBA", 4); /* TAP, 186 bytes long */
memcpy(cell.payload+4, b, TAP_ONIONSKIN_CHALLENGE_LEN);
- tt_int_op(0, ==, create_cell_parse(&cc, &cell));
- tt_int_op(CELL_CREATE2, ==, cc.cell_type);
- tt_int_op(ONION_HANDSHAKE_TYPE_TAP, ==, cc.handshake_type);
- tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, ==, cc.handshake_len);
- test_memeq(cc.onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
- tt_int_op(0, ==, create_cell_format(&cell2, &cc));
- tt_int_op(cell.command, ==, cell2.command);
- test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+ tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE2, OP_EQ, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_TAP, OP_EQ, cc.handshake_type);
+ tt_int_op(TAP_ONIONSKIN_CHALLENGE_LEN, OP_EQ, cc.handshake_len);
+ tt_mem_op(cc.onionskin,OP_EQ, b, TAP_ONIONSKIN_CHALLENGE_LEN + 10);
+ tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, OP_EQ, cell2.command);
+ tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
/* A valid create2 cell with an ntor payload */
memset(&cell, 0, sizeof(cell));
@@ -445,18 +445,14 @@ test_cfmt_create_cells(void *arg)
cell.command = CELL_CREATE2;
memcpy(cell.payload, "\x00\x02\x00\x54", 4); /* ntor, 84 bytes long */
memcpy(cell.payload+4, b, NTOR_ONIONSKIN_LEN);
-#ifdef CURVE25519_ENABLED
- tt_int_op(0, ==, create_cell_parse(&cc, &cell));
- tt_int_op(CELL_CREATE2, ==, cc.cell_type);
- tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type);
- tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len);
- test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10);
- tt_int_op(0, ==, create_cell_format(&cell2, &cc));
- tt_int_op(cell.command, ==, cell2.command);
- test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
-#else
- tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
-#endif
+ tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE2, OP_EQ, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, OP_EQ, cc.handshake_type);
+ tt_int_op(NTOR_ONIONSKIN_LEN, OP_EQ, cc.handshake_len);
+ tt_mem_op(cc.onionskin,OP_EQ, b, NTOR_ONIONSKIN_LEN + 10);
+ tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, OP_EQ, cell2.command);
+ tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
/* A valid create cell with an ntor payload, in legacy format. */
memset(&cell, 0, sizeof(cell));
@@ -465,42 +461,38 @@ test_cfmt_create_cells(void *arg)
cell.command = CELL_CREATE;
memcpy(cell.payload, "ntorNTORntorNTOR", 16);
memcpy(cell.payload+16, b, NTOR_ONIONSKIN_LEN);
-#ifdef CURVE25519_ENABLED
- tt_int_op(0, ==, create_cell_parse(&cc, &cell));
- tt_int_op(CELL_CREATE, ==, cc.cell_type);
- tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, ==, cc.handshake_type);
- tt_int_op(NTOR_ONIONSKIN_LEN, ==, cc.handshake_len);
- test_memeq(cc.onionskin, b, NTOR_ONIONSKIN_LEN + 10);
- tt_int_op(0, ==, create_cell_format(&cell2, &cc));
- tt_int_op(cell.command, ==, cell2.command);
- test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
-#else
- tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
-#endif
+ tt_int_op(0, OP_EQ, create_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATE, OP_EQ, cc.cell_type);
+ tt_int_op(ONION_HANDSHAKE_TYPE_NTOR, OP_EQ, cc.handshake_type);
+ tt_int_op(NTOR_ONIONSKIN_LEN, OP_EQ, cc.handshake_len);
+ tt_mem_op(cc.onionskin,OP_EQ, b, NTOR_ONIONSKIN_LEN + 10);
+ tt_int_op(0, OP_EQ, create_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, OP_EQ, cell2.command);
+ tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
/* == Okay, now let's try to parse some impossible stuff. */
/* It has to be some kind of a create cell! */
cell.command = CELL_CREATED;
- tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(-1, OP_EQ, create_cell_parse(&cc, &cell));
/* You can't acutally make an unparseable CREATE or CREATE_FAST cell. */
/* Try some CREATE2 cells. First with a bad type. */
cell.command = CELL_CREATE2;
memcpy(cell.payload, "\x00\x50\x00\x99", 4); /* Type 0x50???? */
- tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(-1, OP_EQ, create_cell_parse(&cc, &cell));
/* Now a good type with an incorrect length. */
memcpy(cell.payload, "\x00\x00\x00\xBC", 4); /* TAP, 187 bytes.*/
- tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(-1, OP_EQ, create_cell_parse(&cc, &cell));
/* Now a good type with a ridiculous length. */
memcpy(cell.payload, "\x00\x00\x02\x00", 4); /* TAP, 512 bytes.*/
- tt_int_op(-1, ==, create_cell_parse(&cc, &cell));
+ tt_int_op(-1, OP_EQ, create_cell_parse(&cc, &cell));
/* == Time to try formatting bad cells. The important thing is that
we reject big lengths, so just check that for now. */
cc.handshake_len = 512;
- tt_int_op(-1, ==, create_cell_format(&cell2, &cc));
+ tt_int_op(-1, OP_EQ, create_cell_format(&cell2, &cc));
/* == Try formatting a create2 cell we don't understand. XXXX */
@@ -524,13 +516,13 @@ test_cfmt_created_cells(void *arg)
crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
cell.command = CELL_CREATED;
memcpy(cell.payload, b, TAP_ONIONSKIN_REPLY_LEN);
- tt_int_op(0, ==, created_cell_parse(&cc, &cell));
- tt_int_op(CELL_CREATED, ==, cc.cell_type);
- tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, cc.handshake_len);
- test_memeq(cc.reply, b, TAP_ONIONSKIN_REPLY_LEN + 10);
- tt_int_op(0, ==, created_cell_format(&cell2, &cc));
- tt_int_op(cell.command, ==, cell2.command);
- test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+ tt_int_op(0, OP_EQ, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED, OP_EQ, cc.cell_type);
+ tt_int_op(TAP_ONIONSKIN_REPLY_LEN, OP_EQ, cc.handshake_len);
+ tt_mem_op(cc.reply,OP_EQ, b, TAP_ONIONSKIN_REPLY_LEN + 10);
+ tt_int_op(0, OP_EQ, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, OP_EQ, cell2.command);
+ tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
/* A good CREATED_FAST cell */
memset(&cell, 0, sizeof(cell));
@@ -538,13 +530,13 @@ test_cfmt_created_cells(void *arg)
crypto_rand((char*)b, CREATED_FAST_LEN);
cell.command = CELL_CREATED_FAST;
memcpy(cell.payload, b, CREATED_FAST_LEN);
- tt_int_op(0, ==, created_cell_parse(&cc, &cell));
- tt_int_op(CELL_CREATED_FAST, ==, cc.cell_type);
- tt_int_op(CREATED_FAST_LEN, ==, cc.handshake_len);
- test_memeq(cc.reply, b, CREATED_FAST_LEN + 10);
- tt_int_op(0, ==, created_cell_format(&cell2, &cc));
- tt_int_op(cell.command, ==, cell2.command);
- test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+ tt_int_op(0, OP_EQ, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED_FAST, OP_EQ, cc.cell_type);
+ tt_int_op(CREATED_FAST_LEN, OP_EQ, cc.handshake_len);
+ tt_mem_op(cc.reply,OP_EQ, b, CREATED_FAST_LEN + 10);
+ tt_int_op(0, OP_EQ, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, OP_EQ, cell2.command);
+ tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
/* A good CREATED2 cell with short reply */
memset(&cell, 0, sizeof(cell));
@@ -553,13 +545,13 @@ test_cfmt_created_cells(void *arg)
cell.command = CELL_CREATED2;
memcpy(cell.payload, "\x00\x40", 2);
memcpy(cell.payload+2, b, 64);
- tt_int_op(0, ==, created_cell_parse(&cc, &cell));
- tt_int_op(CELL_CREATED2, ==, cc.cell_type);
- tt_int_op(64, ==, cc.handshake_len);
- test_memeq(cc.reply, b, 80);
- tt_int_op(0, ==, created_cell_format(&cell2, &cc));
- tt_int_op(cell.command, ==, cell2.command);
- test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+ tt_int_op(0, OP_EQ, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED2, OP_EQ, cc.cell_type);
+ tt_int_op(64, OP_EQ, cc.handshake_len);
+ tt_mem_op(cc.reply,OP_EQ, b, 80);
+ tt_int_op(0, OP_EQ, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, OP_EQ, cell2.command);
+ tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
/* A good CREATED2 cell with maximal reply */
memset(&cell, 0, sizeof(cell));
@@ -568,13 +560,13 @@ test_cfmt_created_cells(void *arg)
cell.command = CELL_CREATED2;
memcpy(cell.payload, "\x01\xF0", 2);
memcpy(cell.payload+2, b, 496);
- tt_int_op(0, ==, created_cell_parse(&cc, &cell));
- tt_int_op(CELL_CREATED2, ==, cc.cell_type);
- tt_int_op(496, ==, cc.handshake_len);
- test_memeq(cc.reply, b, 496);
- tt_int_op(0, ==, created_cell_format(&cell2, &cc));
- tt_int_op(cell.command, ==, cell2.command);
- test_memeq(cell.payload, cell2.payload, CELL_PAYLOAD_SIZE);
+ tt_int_op(0, OP_EQ, created_cell_parse(&cc, &cell));
+ tt_int_op(CELL_CREATED2, OP_EQ, cc.cell_type);
+ tt_int_op(496, OP_EQ, cc.handshake_len);
+ tt_mem_op(cc.reply,OP_EQ, b, 496);
+ tt_int_op(0, OP_EQ, created_cell_format(&cell2, &cc));
+ tt_int_op(cell.command, OP_EQ, cell2.command);
+ tt_mem_op(cell.payload,OP_EQ, cell2.payload, CELL_PAYLOAD_SIZE);
/* Bogus CREATED2 cell: too long! */
memset(&cell, 0, sizeof(cell));
@@ -582,11 +574,11 @@ test_cfmt_created_cells(void *arg)
crypto_rand((char*)b, 496);
cell.command = CELL_CREATED2;
memcpy(cell.payload, "\x01\xF1", 2);
- tt_int_op(-1, ==, created_cell_parse(&cc, &cell));
+ tt_int_op(-1, OP_EQ, created_cell_parse(&cc, &cell));
/* Unformattable CREATED2 cell: too long! */
cc.handshake_len = 497;
- tt_int_op(-1, ==, created_cell_format(&cell2, &cc));
+ tt_int_op(-1, OP_EQ, created_cell_format(&cell2, &cc));
done:
;
@@ -614,21 +606,21 @@ test_cfmt_extend_cells(void *arg)
memcpy(p, "\x12\xf4\x00\x01\x01\x02", 6); /* 18 244 0 1 : 258 */
memcpy(p+6,b,TAP_ONIONSKIN_CHALLENGE_LEN);
memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
- tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
+ tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
- tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type);
- tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
- tt_int_op(258, ==, ec.orport_ipv4.port);
- tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
- test_memeq(ec.node_id, "electroencephalogram", 20);
- tt_int_op(cc->cell_type, ==, CELL_CREATE);
- tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_TAP);
- tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_CHALLENGE_LEN);
- test_memeq(cc->onionskin, b, TAP_ONIONSKIN_CHALLENGE_LEN+20);
- tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND);
- tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
- test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
+ tt_int_op(RELAY_COMMAND_EXTEND, OP_EQ, ec.cell_type);
+ tt_str_op("18.244.0.1", OP_EQ, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(258, OP_EQ, ec.orport_ipv4.port);
+ tt_int_op(AF_UNSPEC, OP_EQ, tor_addr_family(&ec.orport_ipv6.addr));
+ tt_mem_op(ec.node_id,OP_EQ, "electroencephalogram", 20);
+ tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE);
+ tt_int_op(cc->handshake_type, OP_EQ, ONION_HANDSHAKE_TYPE_TAP);
+ tt_int_op(cc->handshake_len, OP_EQ, TAP_ONIONSKIN_CHALLENGE_LEN);
+ tt_mem_op(cc->onionskin,OP_EQ, b, TAP_ONIONSKIN_CHALLENGE_LEN+20);
+ tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND);
+ tt_int_op(p2_len, OP_EQ, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
+ tt_mem_op(p2,OP_EQ, p, RELAY_PAYLOAD_SIZE);
/* Let's do an ntor stuffed in a legacy EXTEND cell */
memset(p, 0, sizeof(p));
@@ -638,22 +630,22 @@ test_cfmt_extend_cells(void *arg)
memcpy(p+6,"ntorNTORntorNTOR", 16);
memcpy(p+22, b, NTOR_ONIONSKIN_LEN);
memcpy(p+6+TAP_ONIONSKIN_CHALLENGE_LEN, "electroencephalogram", 20);
- tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
+ tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND,
p, 26+TAP_ONIONSKIN_CHALLENGE_LEN));
- tt_int_op(RELAY_COMMAND_EXTEND, ==, ec.cell_type);
- tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
- tt_int_op(258, ==, ec.orport_ipv4.port);
- tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
- test_memeq(ec.node_id, "electroencephalogram", 20);
- tt_int_op(cc->cell_type, ==, CELL_CREATE2);
- tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR);
- tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN);
- test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20);
- tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND);
- tt_int_op(p2_len, ==, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
- test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
- tt_int_op(0, ==, create_cell_format_relayed(&cell, cc));
+ tt_int_op(RELAY_COMMAND_EXTEND, OP_EQ, ec.cell_type);
+ tt_str_op("18.244.0.1", OP_EQ, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(258, OP_EQ, ec.orport_ipv4.port);
+ tt_int_op(AF_UNSPEC, OP_EQ, tor_addr_family(&ec.orport_ipv6.addr));
+ tt_mem_op(ec.node_id,OP_EQ, "electroencephalogram", 20);
+ tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, OP_EQ, ONION_HANDSHAKE_TYPE_NTOR);
+ tt_int_op(cc->handshake_len, OP_EQ, NTOR_ONIONSKIN_LEN);
+ tt_mem_op(cc->onionskin,OP_EQ, b, NTOR_ONIONSKIN_LEN+20);
+ tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND);
+ tt_int_op(p2_len, OP_EQ, 26+TAP_ONIONSKIN_CHALLENGE_LEN);
+ tt_mem_op(p2,OP_EQ, p, RELAY_PAYLOAD_SIZE);
+ tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
/* Now let's do a minimal ntor EXTEND2 cell. */
memset(&ec, 0xff, sizeof(ec));
@@ -667,21 +659,21 @@ test_cfmt_extend_cells(void *arg)
/* Prep for the handshake: type and length */
memcpy(p+31, "\x00\x02\x00\x54", 4);
memcpy(p+35, b, NTOR_ONIONSKIN_LEN);
- tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, 35+NTOR_ONIONSKIN_LEN));
- tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type);
- tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
- tt_int_op(61681, ==, ec.orport_ipv4.port);
- tt_int_op(AF_UNSPEC, ==, tor_addr_family(&ec.orport_ipv6.addr));
- test_memeq(ec.node_id, "anarchoindividualist", 20);
- tt_int_op(cc->cell_type, ==, CELL_CREATE2);
- tt_int_op(cc->handshake_type, ==, ONION_HANDSHAKE_TYPE_NTOR);
- tt_int_op(cc->handshake_len, ==, NTOR_ONIONSKIN_LEN);
- test_memeq(cc->onionskin, b, NTOR_ONIONSKIN_LEN+20);
- tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2);
- tt_int_op(p2_len, ==, 35+NTOR_ONIONSKIN_LEN);
- test_memeq(p2, p, RELAY_PAYLOAD_SIZE);
+ tt_int_op(RELAY_COMMAND_EXTEND2, OP_EQ, ec.cell_type);
+ tt_str_op("18.244.0.1", OP_EQ, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(61681, OP_EQ, ec.orport_ipv4.port);
+ tt_int_op(AF_UNSPEC, OP_EQ, tor_addr_family(&ec.orport_ipv6.addr));
+ tt_mem_op(ec.node_id,OP_EQ, "anarchoindividualist", 20);
+ tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, OP_EQ, ONION_HANDSHAKE_TYPE_NTOR);
+ tt_int_op(cc->handshake_len, OP_EQ, NTOR_ONIONSKIN_LEN);
+ tt_mem_op(cc->onionskin,OP_EQ, b, NTOR_ONIONSKIN_LEN+20);
+ tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
+ tt_int_op(p2_len, OP_EQ, 35+NTOR_ONIONSKIN_LEN);
+ tt_mem_op(p2,OP_EQ, p, RELAY_PAYLOAD_SIZE);
/* Now let's do a fanciful EXTEND2 cell. */
memset(&ec, 0xff, sizeof(ec));
@@ -700,21 +692,21 @@ test_cfmt_extend_cells(void *arg)
/* Prep for the handshake: weird type and length */
memcpy(p+85, "\x01\x05\x00\x63", 4);
memcpy(p+89, b, 99);
- tt_int_op(0, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, 89+99));
- tt_int_op(RELAY_COMMAND_EXTEND2, ==, ec.cell_type);
- tt_str_op("18.244.0.1", ==, fmt_addr(&ec.orport_ipv4.addr));
- tt_int_op(61681, ==, ec.orport_ipv4.port);
- tt_str_op("2002::f0:c51e", ==, fmt_addr(&ec.orport_ipv6.addr));
- tt_int_op(4370, ==, ec.orport_ipv6.port);
- test_memeq(ec.node_id, "anthropomorphization", 20);
- tt_int_op(cc->cell_type, ==, CELL_CREATE2);
- tt_int_op(cc->handshake_type, ==, 0x105);
- tt_int_op(cc->handshake_len, ==, 99);
- test_memeq(cc->onionskin, b, 99+20);
- tt_int_op(0, ==, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(p2_cmd, ==, RELAY_COMMAND_EXTEND2);
+ tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2, p, 89+99));
+ tt_int_op(RELAY_COMMAND_EXTEND2, OP_EQ, ec.cell_type);
+ tt_str_op("18.244.0.1", OP_EQ, fmt_addr(&ec.orport_ipv4.addr));
+ tt_int_op(61681, OP_EQ, ec.orport_ipv4.port);
+ tt_str_op("2002::f0:c51e", OP_EQ, fmt_addr(&ec.orport_ipv6.addr));
+ tt_int_op(4370, OP_EQ, ec.orport_ipv6.port);
+ tt_mem_op(ec.node_id,OP_EQ, "anthropomorphization", 20);
+ tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, OP_EQ, 0x105);
+ tt_int_op(cc->handshake_len, OP_EQ, 99);
+ tt_mem_op(cc->onionskin,OP_EQ, b, 99+20);
+ tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
/* We'll generate it minus the IPv6 address and minus the konami code */
- tt_int_op(p2_len, ==, 89+99-34-20);
+ tt_int_op(p2_len, OP_EQ, 89+99-34-20);
test_memeq_hex(p2,
/* Two items: one that same darn IP address. */
"02000612F40001F0F1"
@@ -722,8 +714,8 @@ test_cfmt_extend_cells(void *arg)
"0214616e7468726f706f6d6f727068697a6174696f6e"
/* Now the handshake prologue */
"01050063");
- test_memeq(p2+1+8+22+4, b, 99+20);
- tt_int_op(0, ==, create_cell_format_relayed(&cell, cc));
+ tt_mem_op(p2+1+8+22+4,OP_EQ, b, 99+20);
+ tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
/* == Now try parsing some junk */
@@ -732,7 +724,7 @@ test_cfmt_extend_cells(void *arg)
memcpy(p, "\x02\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+31, "\xff\xff\x01\xd0", 4);
- tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* Try two identities. */
@@ -741,14 +733,14 @@ test_cfmt_extend_cells(void *arg)
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+31, "\x02\x14" "autodepolymerization", 22);
memcpy(p+53, "\xff\xff\x00\x10", 4);
- tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* No identities. */
memset(p, 0, sizeof(p));
memcpy(p, "\x01\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
memcpy(p+53, "\xff\xff\x00\x10", 4);
- tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* Try a bad IPv4 address (too long, too short)*/
@@ -756,13 +748,13 @@ test_cfmt_extend_cells(void *arg)
memcpy(p, "\x02\x00\x07\x12\xf4\x00\x01\xf0\xf1\xff", 10);
memcpy(p+10, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+32, "\xff\xff\x00\x10", 4);
- tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
memset(p, 0, sizeof(p));
memcpy(p, "\x02\x00\x05\x12\xf4\x00\x01\xf0", 8);
memcpy(p+8, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+30, "\xff\xff\x00\x10", 4);
- tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* IPv6 address (too long, too short, no IPv4)*/
@@ -771,28 +763,28 @@ test_cfmt_extend_cells(void *arg)
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+31, "\x01\x13" "xxxxxxxxxxxxxxxxYYZ", 19);
memcpy(p+50, "\xff\xff\x00\x20", 4);
- tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
memset(p, 0, sizeof(p));
memcpy(p, "\x03\x00\x06\x12\xf4\x00\x01\xf0\xf1", 9);
memcpy(p+9, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+31, "\x01\x11" "xxxxxxxxxxxxxxxxY", 17);
memcpy(p+48, "\xff\xff\x00\x20", 4);
- tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
memset(p, 0, sizeof(p));
memcpy(p, "\x02", 1);
memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
memcpy(p+41, "\xff\xff\x00\x20", 4);
- tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* Running out of space in specifiers */
memset(p,0,sizeof(p));
memcpy(p, "\x05\x0a\xff", 3);
memcpy(p+3+255, "\x0a\xff", 2);
- tt_int_op(-1, ==, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
/* Fuzz, because why not. */
@@ -831,16 +823,16 @@ test_cfmt_extended_cells(void *arg)
memset(b, 0, sizeof(b));
crypto_rand((char*)b, TAP_ONIONSKIN_REPLY_LEN);
memcpy(p,b,TAP_ONIONSKIN_REPLY_LEN);
- tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED, p,
+ tt_int_op(0, OP_EQ, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED, p,
TAP_ONIONSKIN_REPLY_LEN));
- tt_int_op(RELAY_COMMAND_EXTENDED, ==, ec.cell_type);
- tt_int_op(cc->cell_type, ==, CELL_CREATED);
- tt_int_op(cc->handshake_len, ==, TAP_ONIONSKIN_REPLY_LEN);
- test_memeq(cc->reply, b, TAP_ONIONSKIN_REPLY_LEN);
- tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(RELAY_COMMAND_EXTENDED, ==, p2_cmd);
- tt_int_op(TAP_ONIONSKIN_REPLY_LEN, ==, p2_len);
- test_memeq(p2, p, sizeof(p2));
+ tt_int_op(RELAY_COMMAND_EXTENDED, OP_EQ, ec.cell_type);
+ tt_int_op(cc->cell_type, OP_EQ, CELL_CREATED);
+ tt_int_op(cc->handshake_len, OP_EQ, TAP_ONIONSKIN_REPLY_LEN);
+ tt_mem_op(cc->reply,OP_EQ, b, TAP_ONIONSKIN_REPLY_LEN);
+ tt_int_op(0, OP_EQ, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(RELAY_COMMAND_EXTENDED, OP_EQ, p2_cmd);
+ tt_int_op(TAP_ONIONSKIN_REPLY_LEN, OP_EQ, p2_len);
+ tt_mem_op(p2,OP_EQ, p, sizeof(p2));
/* Try an EXTENDED2 cell */
memset(&ec, 0xff, sizeof(ec));
@@ -849,25 +841,26 @@ test_cfmt_extended_cells(void *arg)
crypto_rand((char*)b, 42);
memcpy(p,"\x00\x2a",2);
memcpy(p+2,b,42);
- tt_int_op(0, ==, extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, 2+42));
- tt_int_op(RELAY_COMMAND_EXTENDED2, ==, ec.cell_type);
- tt_int_op(cc->cell_type, ==, CELL_CREATED2);
- tt_int_op(cc->handshake_len, ==, 42);
- test_memeq(cc->reply, b, 42+10);
- tt_int_op(0, ==, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(RELAY_COMMAND_EXTENDED2, ==, p2_cmd);
- tt_int_op(2+42, ==, p2_len);
- test_memeq(p2, p, sizeof(p2));
+ tt_int_op(0, OP_EQ,
+ extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, 2+42));
+ tt_int_op(RELAY_COMMAND_EXTENDED2, OP_EQ, ec.cell_type);
+ tt_int_op(cc->cell_type, OP_EQ, CELL_CREATED2);
+ tt_int_op(cc->handshake_len, OP_EQ, 42);
+ tt_mem_op(cc->reply,OP_EQ, b, 42+10);
+ tt_int_op(0, OP_EQ, extended_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(RELAY_COMMAND_EXTENDED2, OP_EQ, p2_cmd);
+ tt_int_op(2+42, OP_EQ, p2_len);
+ tt_mem_op(p2,OP_EQ, p, sizeof(p2));
/* Try an almost-too-long EXTENDED2 cell */
memcpy(p, "\x01\xf0", 2);
- tt_int_op(0, ==,
+ tt_int_op(0, OP_EQ,
extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p)));
/* Now try a too-long extended2 cell. That's the only misparse I can think
* of. */
memcpy(p, "\x01\xf1", 2);
- tt_int_op(-1, ==,
+ tt_int_op(-1, OP_EQ,
extended_cell_parse(&ec, RELAY_COMMAND_EXTENDED2, p, sizeof(p)));
done:
@@ -911,22 +904,22 @@ test_cfmt_resolved_cells(void *arg)
/* Let's try an empty cell */
SET_CELL("");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
CLEAR_ADDRS(); /* redundant but let's be consistent */
/* Cell with one ipv4 addr */
SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00");
- tt_int_op(rh.length, ==, 10);
+ tt_int_op(rh.length, OP_EQ, 10);
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 1);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 1);
a = smartlist_get(addrs, 0);
- tt_str_op(fmt_addr(&a->addr), ==, "127.0.2.10");
- tt_ptr_op(a->hostname, ==, NULL);
- tt_int_op(a->ttl, ==, 256);
+ tt_str_op(fmt_addr(&a->addr), OP_EQ, "127.0.2.10");
+ tt_ptr_op(a->hostname, OP_EQ, NULL);
+ tt_int_op(a->ttl, OP_EQ, 256);
CLEAR_ADDRS();
/* Cell with one ipv6 addr */
@@ -934,30 +927,30 @@ test_cfmt_resolved_cells(void *arg)
"\x20\x02\x90\x90\x00\x00\x00\x00"
"\x00\x00\x00\x00\xf0\xf0\xab\xcd"
"\x02\00\x00\x01");
- tt_int_op(rh.length, ==, 22);
+ tt_int_op(rh.length, OP_EQ, 22);
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 1);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 1);
a = smartlist_get(addrs, 0);
- tt_str_op(fmt_addr(&a->addr), ==, "2002:9090::f0f0:abcd");
- tt_ptr_op(a->hostname, ==, NULL);
- tt_int_op(a->ttl, ==, 0x2000001);
+ tt_str_op(fmt_addr(&a->addr), OP_EQ, "2002:9090::f0f0:abcd");
+ tt_ptr_op(a->hostname, OP_EQ, NULL);
+ tt_int_op(a->ttl, OP_EQ, 0x2000001);
CLEAR_ADDRS();
/* Cell with one hostname */
SET_CELL("\x00\x11"
"motherbrain.zebes"
"\x00\00\x00\x00");
- tt_int_op(rh.length, ==, 23);
+ tt_int_op(rh.length, OP_EQ, 23);
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 1);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 1);
a = smartlist_get(addrs, 0);
tt_assert(tor_addr_is_null(&a->addr));
- tt_str_op(a->hostname, ==, "motherbrain.zebes");
- tt_int_op(a->ttl, ==, 0);
+ tt_str_op(a->hostname, OP_EQ, "motherbrain.zebes");
+ tt_int_op(a->ttl, OP_EQ, 0);
CLEAR_ADDRS();
#define LONG_NAME \
@@ -966,51 +959,51 @@ test_cfmt_resolved_cells(void *arg)
"function-is-already-very-full.of-copy-and-pasted-stuff.having-this-app" \
"ear-more-than-once-would-bother-me-somehow.is"
- tt_int_op(strlen(LONG_NAME), ==, 255);
+ tt_int_op(strlen(LONG_NAME), OP_EQ, 255);
SET_CELL("\x00\xff"
LONG_NAME
"\x00\01\x00\x00");
- tt_int_op(rh.length, ==, 261);
+ tt_int_op(rh.length, OP_EQ, 261);
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 1);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 1);
a = smartlist_get(addrs, 0);
tt_assert(tor_addr_is_null(&a->addr));
- tt_str_op(a->hostname, ==, LONG_NAME);
- tt_int_op(a->ttl, ==, 65536);
+ tt_str_op(a->hostname, OP_EQ, LONG_NAME);
+ tt_int_op(a->ttl, OP_EQ, 65536);
CLEAR_ADDRS();
/* Cells with an error */
SET_CELL("\xf0\x2b"
"I'm sorry, Dave. I'm afraid I can't do that"
"\x00\x11\x22\x33");
- tt_int_op(rh.length, ==, 49);
+ tt_int_op(rh.length, OP_EQ, 49);
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, RESOLVED_TYPE_ERROR_TRANSIENT);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, RESOLVED_TYPE_ERROR_TRANSIENT);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
CLEAR_ADDRS();
SET_CELL("\xf1\x40"
"This hostname is too important for me to allow you to resolve it"
"\x00\x00\x00\x00");
- tt_int_op(rh.length, ==, 70);
+ tt_int_op(rh.length, OP_EQ, 70);
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, RESOLVED_TYPE_ERROR);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, RESOLVED_TYPE_ERROR);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
CLEAR_ADDRS();
/* Cell with an unrecognized type */
SET_CELL("\xee\x16"
"fault in the AE35 unit"
"\x09\x09\x01\x01");
- tt_int_op(rh.length, ==, 28);
+ tt_int_op(rh.length, OP_EQ, 28);
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
CLEAR_ADDRS();
/* Cell with one of each */
@@ -1035,21 +1028,21 @@ test_cfmt_resolved_cells(void *arg)
"\x00\00\x00\x00"
);
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0); /* no error reported; we got answers */
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 3);
+ tt_int_op(errcode, OP_EQ, 0); /* no error reported; we got answers */
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 3);
a = smartlist_get(addrs, 0);
- tt_str_op(fmt_addr(&a->addr), ==, "2002:9090::f0f0:abcd");
- tt_ptr_op(a->hostname, ==, NULL);
- tt_int_op(a->ttl, ==, 0x2000001);
+ tt_str_op(fmt_addr(&a->addr), OP_EQ, "2002:9090::f0f0:abcd");
+ tt_ptr_op(a->hostname, OP_EQ, NULL);
+ tt_int_op(a->ttl, OP_EQ, 0x2000001);
a = smartlist_get(addrs, 1);
- tt_str_op(fmt_addr(&a->addr), ==, "127.0.2.10");
- tt_ptr_op(a->hostname, ==, NULL);
- tt_int_op(a->ttl, ==, 256);
+ tt_str_op(fmt_addr(&a->addr), OP_EQ, "127.0.2.10");
+ tt_ptr_op(a->hostname, OP_EQ, NULL);
+ tt_int_op(a->ttl, OP_EQ, 256);
a = smartlist_get(addrs, 2);
tt_assert(tor_addr_is_null(&a->addr));
- tt_str_op(a->hostname, ==, "motherbrain.zebes");
- tt_int_op(a->ttl, ==, 0);
+ tt_str_op(a->hostname, OP_EQ, "motherbrain.zebes");
+ tt_int_op(a->ttl, OP_EQ, 0);
CLEAR_ADDRS();
/* Cell with several of similar type */
@@ -1067,29 +1060,29 @@ test_cfmt_resolved_cells(void *arg)
"\x00\x00\x00\x00\x00\xfa\xca\xde"
"\x00\00\x00\x03");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 5);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 5);
a = smartlist_get(addrs, 0);
- tt_str_op(fmt_addr(&a->addr), ==, "127.0.2.10");
- tt_ptr_op(a->hostname, ==, NULL);
- tt_int_op(a->ttl, ==, 256);
+ tt_str_op(fmt_addr(&a->addr), OP_EQ, "127.0.2.10");
+ tt_ptr_op(a->hostname, OP_EQ, NULL);
+ tt_int_op(a->ttl, OP_EQ, 256);
a = smartlist_get(addrs, 1);
- tt_str_op(fmt_addr(&a->addr), ==, "8.8.8.8");
- tt_ptr_op(a->hostname, ==, NULL);
- tt_int_op(a->ttl, ==, 261);
+ tt_str_op(fmt_addr(&a->addr), OP_EQ, "8.8.8.8");
+ tt_ptr_op(a->hostname, OP_EQ, NULL);
+ tt_int_op(a->ttl, OP_EQ, 261);
a = smartlist_get(addrs, 2);
- tt_str_op(fmt_addr(&a->addr), ==, "127.176.2.176");
- tt_ptr_op(a->hostname, ==, NULL);
- tt_int_op(a->ttl, ==, 131071);
+ tt_str_op(fmt_addr(&a->addr), OP_EQ, "127.176.2.176");
+ tt_ptr_op(a->hostname, OP_EQ, NULL);
+ tt_int_op(a->ttl, OP_EQ, 131071);
a = smartlist_get(addrs, 3);
- tt_str_op(fmt_addr(&a->addr), ==, "2002:9000::cafe:f00d");
- tt_ptr_op(a->hostname, ==, NULL);
- tt_int_op(a->ttl, ==, 1);
+ tt_str_op(fmt_addr(&a->addr), OP_EQ, "2002:9000::cafe:f00d");
+ tt_ptr_op(a->hostname, OP_EQ, NULL);
+ tt_int_op(a->ttl, OP_EQ, 1);
a = smartlist_get(addrs, 4);
- tt_str_op(fmt_addr(&a->addr), ==, "2002:9001::fa:cade");
- tt_ptr_op(a->hostname, ==, NULL);
- tt_int_op(a->ttl, ==, 3);
+ tt_str_op(fmt_addr(&a->addr), OP_EQ, "2002:9001::fa:cade");
+ tt_ptr_op(a->hostname, OP_EQ, NULL);
+ tt_int_op(a->ttl, OP_EQ, 3);
CLEAR_ADDRS();
/* Full cell */
@@ -1099,22 +1092,22 @@ test_cfmt_resolved_cells(void *arg)
"g-case.to-avoid-off-by-one-errors.where-full-things-are-misreported-as" \
".overflowing-by-one.z"
- tt_int_op(strlen(LONG_NAME2), ==, 231);
+ tt_int_op(strlen(LONG_NAME2), OP_EQ, 231);
SET_CELL("\x00\xff"
LONG_NAME
"\x00\01\x00\x00"
"\x00\xe7"
LONG_NAME2
"\x00\01\x00\x00");
- tt_int_op(rh.length, ==, RELAY_PAYLOAD_SIZE);
+ tt_int_op(rh.length, OP_EQ, RELAY_PAYLOAD_SIZE);
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, 0);
- tt_int_op(smartlist_len(addrs), ==, 2);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 2);
a = smartlist_get(addrs, 0);
- tt_str_op(a->hostname, ==, LONG_NAME);
+ tt_str_op(a->hostname, OP_EQ, LONG_NAME);
a = smartlist_get(addrs, 1);
- tt_str_op(a->hostname, ==, LONG_NAME2);
+ tt_str_op(a->hostname, OP_EQ, LONG_NAME2);
CLEAR_ADDRS();
/* BAD CELLS */
@@ -1122,49 +1115,49 @@ test_cfmt_resolved_cells(void *arg)
/* Invalid length on an IPv4 */
SET_CELL("\x04\x03zzz1234");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"
"\x04\x05zzzzz1234");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
/* Invalid length on an IPv6 */
SET_CELL("\x06\x03zzz1234");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"
"\x06\x17wwwwwwwwwwwwwwwww1234");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00"
"\x06\x10xxxx");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
/* Empty hostname */
SET_CELL("\x00\x00xxxx");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
/* rh.length out of range */
CLEAR_CELL();
rh.length = 499;
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(errcode, ==, 0);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(errcode, OP_EQ, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
/* Item length extends beyond rh.length */
CLEAR_CELL();
@@ -1173,18 +1166,18 @@ test_cfmt_resolved_cells(void *arg)
"\x00\01\x00\x00");
rh.length -= 1;
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
rh.length -= 5;
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
SET_CELL("\x04\x04" "\x7f\x00\x02\x0a" "\x00\00\x01\x00");
rh.length -= 1;
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
SET_CELL("\xee\x10"
"\x20\x02\x90\x01\x00\x00\x00\x00"
@@ -1192,19 +1185,19 @@ test_cfmt_resolved_cells(void *arg)
"\x00\00\x00\x03");
rh.length -= 1;
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
/* Truncated item after first character */
SET_CELL("\x04");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
SET_CELL("\xee");
r = resolved_cell_parse(&cell, &rh, addrs, &errcode);
- tt_int_op(r, ==, -1);
- tt_int_op(smartlist_len(addrs), ==, 0);
+ tt_int_op(r, OP_EQ, -1);
+ tt_int_op(smartlist_len(addrs), OP_EQ, 0);
done:
CLEAR_ADDRS();
@@ -1232,19 +1225,19 @@ test_cfmt_is_destroy(void *arg)
cell_pack(&packed, &cell, 0);
chan->wide_circ_ids = 0;
tt_assert(! packed_cell_is_destroy(chan, &packed, &circid));
- tt_int_op(circid, ==, 0);
+ tt_int_op(circid, OP_EQ, 0);
cell_pack(&packed, &cell, 1);
chan->wide_circ_ids = 1;
tt_assert(! packed_cell_is_destroy(chan, &packed, &circid));
- tt_int_op(circid, ==, 0);
+ tt_int_op(circid, OP_EQ, 0);
cell.command = CELL_DESTROY;
cell_pack(&packed, &cell, 0);
chan->wide_circ_ids = 0;
tt_assert(packed_cell_is_destroy(chan, &packed, &circid));
- tt_int_op(circid, ==, 3003);
+ tt_int_op(circid, OP_EQ, 3003);
circid = 0;
cell_pack(&packed, &cell, 1);
diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c
index 92629823ec..ed34df2ea2 100644
--- a/src/test/test_cell_queue.c
+++ b/src/test/test_cell_queue.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CIRCUITLIST_PRIVATE
@@ -16,12 +16,8 @@ test_cq_manip(void *arg)
cell_t cell;
(void) arg;
-#ifdef ENABLE_MEMPOOLS
- init_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
-
cell_queue_init(&cq);
- tt_int_op(cq.n, ==, 0);
+ tt_int_op(cq.n, OP_EQ, 0);
pc1 = packed_cell_new();
pc2 = packed_cell_new();
@@ -29,26 +25,26 @@ test_cq_manip(void *arg)
pc4 = packed_cell_new();
tt_assert(pc1 && pc2 && pc3 && pc4);
- tt_ptr_op(NULL, ==, cell_queue_pop(&cq));
+ tt_ptr_op(NULL, OP_EQ, cell_queue_pop(&cq));
/* Add and remove a singleton. */
cell_queue_append(&cq, pc1);
- tt_int_op(cq.n, ==, 1);
- tt_ptr_op(pc1, ==, cell_queue_pop(&cq));
- tt_int_op(cq.n, ==, 0);
+ tt_int_op(cq.n, OP_EQ, 1);
+ tt_ptr_op(pc1, OP_EQ, cell_queue_pop(&cq));
+ tt_int_op(cq.n, OP_EQ, 0);
/* Add and remove four items */
cell_queue_append(&cq, pc4);
cell_queue_append(&cq, pc3);
cell_queue_append(&cq, pc2);
cell_queue_append(&cq, pc1);
- tt_int_op(cq.n, ==, 4);
- tt_ptr_op(pc4, ==, cell_queue_pop(&cq));
- tt_ptr_op(pc3, ==, cell_queue_pop(&cq));
- tt_ptr_op(pc2, ==, cell_queue_pop(&cq));
- tt_ptr_op(pc1, ==, cell_queue_pop(&cq));
- tt_int_op(cq.n, ==, 0);
- tt_ptr_op(NULL, ==, cell_queue_pop(&cq));
+ tt_int_op(cq.n, OP_EQ, 4);
+ tt_ptr_op(pc4, OP_EQ, cell_queue_pop(&cq));
+ tt_ptr_op(pc3, OP_EQ, cell_queue_pop(&cq));
+ tt_ptr_op(pc2, OP_EQ, cell_queue_pop(&cq));
+ tt_ptr_op(pc1, OP_EQ, cell_queue_pop(&cq));
+ tt_int_op(cq.n, OP_EQ, 0);
+ tt_ptr_op(NULL, OP_EQ, cell_queue_pop(&cq));
/* Try a packed copy (wide, then narrow, which is a bit of a cheat, since a
* real cell queue has only one type.) */
@@ -64,32 +60,32 @@ test_cq_manip(void *arg)
cell.circ_id = 0x2013;
cell_queue_append_packed_copy(NULL /*circ*/, &cq, 0 /*exitward*/, &cell,
0 /*wide*/, 0 /*stats*/);
- tt_int_op(cq.n, ==, 2);
+ tt_int_op(cq.n, OP_EQ, 2);
pc_tmp = cell_queue_pop(&cq);
- tt_int_op(cq.n, ==, 1);
- tt_ptr_op(pc_tmp, !=, NULL);
- test_mem_op(pc_tmp->body, ==, "\x12\x34\x56\x78\x0a", 5);
- test_mem_op(pc_tmp->body+5, ==, cell.payload, sizeof(cell.payload));
+ tt_int_op(cq.n, OP_EQ, 1);
+ tt_ptr_op(pc_tmp, OP_NE, NULL);
+ tt_mem_op(pc_tmp->body, OP_EQ, "\x12\x34\x56\x78\x0a", 5);
+ tt_mem_op(pc_tmp->body+5, OP_EQ, cell.payload, sizeof(cell.payload));
packed_cell_free(pc_tmp);
pc_tmp = cell_queue_pop(&cq);
- tt_int_op(cq.n, ==, 0);
- tt_ptr_op(pc_tmp, !=, NULL);
- test_mem_op(pc_tmp->body, ==, "\x20\x13\x0a", 3);
- test_mem_op(pc_tmp->body+3, ==, cell.payload, sizeof(cell.payload));
+ tt_int_op(cq.n, OP_EQ, 0);
+ tt_ptr_op(pc_tmp, OP_NE, NULL);
+ tt_mem_op(pc_tmp->body, OP_EQ, "\x20\x13\x0a", 3);
+ tt_mem_op(pc_tmp->body+3, OP_EQ, cell.payload, sizeof(cell.payload));
packed_cell_free(pc_tmp);
pc_tmp = NULL;
- tt_ptr_op(NULL, ==, cell_queue_pop(&cq));
+ tt_ptr_op(NULL, OP_EQ, cell_queue_pop(&cq));
/* Now make sure cell_queue_clear works. */
cell_queue_append(&cq, pc2);
cell_queue_append(&cq, pc1);
- tt_int_op(cq.n, ==, 2);
+ tt_int_op(cq.n, OP_EQ, 2);
cell_queue_clear(&cq);
pc2 = pc1 = NULL; /* prevent double-free */
- tt_int_op(cq.n, ==, 0);
+ tt_int_op(cq.n, OP_EQ, 0);
done:
packed_cell_free(pc1);
@@ -99,10 +95,6 @@ test_cq_manip(void *arg)
packed_cell_free(pc_tmp);
cell_queue_clear(&cq);
-
-#ifdef ENABLE_MEMPOOLS
- free_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
}
static void
@@ -114,10 +106,6 @@ test_circuit_n_cells(void *arg)
(void)arg;
-#ifdef ENABLE_MEMPOOLS
- init_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
-
pc1 = packed_cell_new();
pc2 = packed_cell_new();
pc3 = packed_cell_new();
@@ -129,25 +117,21 @@ test_circuit_n_cells(void *arg)
origin_c = origin_circuit_new();
origin_c->base_.purpose = CIRCUIT_PURPOSE_C_GENERAL;
- tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), ==, 0);
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), OP_EQ, 0);
cell_queue_append(&or_c->p_chan_cells, pc1);
- tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), ==, 1);
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), OP_EQ, 1);
cell_queue_append(&or_c->base_.n_chan_cells, pc2);
cell_queue_append(&or_c->base_.n_chan_cells, pc3);
- tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), ==, 3);
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(or_c)), OP_EQ, 3);
- tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), ==, 0);
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), OP_EQ, 0);
cell_queue_append(&origin_c->base_.n_chan_cells, pc4);
cell_queue_append(&origin_c->base_.n_chan_cells, pc5);
- tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), ==, 2);
+ tt_int_op(n_cells_in_circ_queues(TO_CIRCUIT(origin_c)), OP_EQ, 2);
done:
circuit_free(TO_CIRCUIT(or_c));
circuit_free(TO_CIRCUIT(origin_c));
-
-#ifdef ENABLE_MEMPOOLS
- free_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
}
struct testcase_t cell_queue_tests[] = {
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
new file mode 100644
index 0000000000..e11ac3f3cc
--- /dev/null
+++ b/src/test/test_channel.c
@@ -0,0 +1,1673 @@
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_PRIVATE_
+#include "or.h"
+#include "channel.h"
+/* For channel_note_destroy_not_pending */
+#include "circuitlist.h"
+#include "circuitmux.h"
+/* For var_cell_free */
+#include "connection_or.h"
+/* For packed_cell stuff */
+#define RELAY_PRIVATE
+#include "relay.h"
+/* For init/free stuff */
+#include "scheduler.h"
+
+/* Test suite stuff */
+#include "test.h"
+#include "fakechans.h"
+
+/* This comes from channel.c */
+extern uint64_t estimated_total_queue_size;
+
+static int test_chan_accept_cells = 0;
+static int test_chan_fixed_cells_recved = 0;
+static int test_chan_var_cells_recved = 0;
+static int test_cells_written = 0;
+static int test_destroy_not_pending_calls = 0;
+static int test_doesnt_want_writes_count = 0;
+static int test_dumpstats_calls = 0;
+static int test_has_waiting_cells_count = 0;
+static double test_overhead_estimate = 1.0f;
+static int test_releases_count = 0;
+static circuitmux_t *test_target_cmux = NULL;
+static unsigned int test_cmux_cells = 0;
+static channel_t *dump_statistics_mock_target = NULL;
+static int dump_statistics_mock_matches = 0;
+
+static void chan_test_channel_dump_statistics_mock(
+ channel_t *chan, int severity);
+static int chan_test_channel_flush_from_first_active_circuit_mock(
+ channel_t *chan, int max);
+static unsigned int chan_test_circuitmux_num_cells_mock(circuitmux_t *cmux);
+static void channel_note_destroy_not_pending_mock(channel_t *ch,
+ circid_t circid);
+static void chan_test_cell_handler(channel_t *ch,
+ cell_t *cell);
+static const char * chan_test_describe_transport(channel_t *ch);
+static void chan_test_dumpstats(channel_t *ch, int severity);
+static void chan_test_var_cell_handler(channel_t *ch,
+ var_cell_t *var_cell);
+static void chan_test_close(channel_t *ch);
+static void chan_test_error(channel_t *ch);
+static void chan_test_finish_close(channel_t *ch);
+static const char * chan_test_get_remote_descr(channel_t *ch, int flags);
+static int chan_test_is_canonical(channel_t *ch, int req);
+static size_t chan_test_num_bytes_queued(channel_t *ch);
+static int chan_test_num_cells_writeable(channel_t *ch);
+static int chan_test_write_cell(channel_t *ch, cell_t *cell);
+static int chan_test_write_packed_cell(channel_t *ch,
+ packed_cell_t *packed_cell);
+static int chan_test_write_var_cell(channel_t *ch, var_cell_t *var_cell);
+static void scheduler_channel_doesnt_want_writes_mock(channel_t *ch);
+
+static void test_channel_dumpstats(void *arg);
+static void test_channel_flush(void *arg);
+static void test_channel_flushmux(void *arg);
+static void test_channel_incoming(void *arg);
+static void test_channel_lifecycle(void *arg);
+static void test_channel_multi(void *arg);
+static void test_channel_queue_size(void *arg);
+static void test_channel_write(void *arg);
+
+static void
+channel_note_destroy_not_pending_mock(channel_t *ch,
+ circid_t circid)
+{
+ (void)ch;
+ (void)circid;
+
+ ++test_destroy_not_pending_calls;
+}
+
+static const char *
+chan_test_describe_transport(channel_t *ch)
+{
+ tt_assert(ch != NULL);
+
+ done:
+ return "Fake channel for unit tests";
+}
+
+/**
+ * Mock for channel_dump_statistics(); if the channel matches the
+ * target, bump a counter - otherwise ignore.
+ */
+
+static void
+chan_test_channel_dump_statistics_mock(channel_t *chan, int severity)
+{
+ tt_assert(chan != NULL);
+
+ (void)severity;
+
+ if (chan != NULL && chan == dump_statistics_mock_target) {
+ ++dump_statistics_mock_matches;
+ }
+
+ done:
+ return;
+}
+
+/**
+ * If the target cmux is the cmux for chan, make fake cells up to the
+ * target number of cells and write them to chan. Otherwise, invoke
+ * the real channel_flush_from_first_active_circuit().
+ */
+
+static int
+chan_test_channel_flush_from_first_active_circuit_mock(channel_t *chan,
+ int max)
+{
+ int result = 0, c = 0;
+ packed_cell_t *cell = NULL;
+
+ tt_assert(chan != NULL);
+ if (test_target_cmux != NULL &&
+ test_target_cmux == chan->cmux) {
+ while (c <= max && test_cmux_cells > 0) {
+ cell = packed_cell_new();
+ channel_write_packed_cell(chan, cell);
+ ++c;
+ --test_cmux_cells;
+ }
+ result = c;
+ } else {
+ result = channel_flush_from_first_active_circuit__real(chan, max);
+ }
+
+ done:
+ return result;
+}
+
+/**
+ * If we have a target cmux set and this matches it, lie about how
+ * many cells we have according to the number indicated; otherwise
+ * pass to the real circuitmux_num_cells().
+ */
+
+static unsigned int
+chan_test_circuitmux_num_cells_mock(circuitmux_t *cmux)
+{
+ unsigned int result = 0;
+
+ tt_assert(cmux != NULL);
+ if (cmux != NULL) {
+ if (cmux == test_target_cmux) {
+ result = test_cmux_cells;
+ } else {
+ result = circuitmux_num_cells__real(cmux);
+ }
+ }
+
+ done:
+
+ return result;
+}
+
+/*
+ * Handle an incoming fixed-size cell for unit tests
+ */
+
+static void
+chan_test_cell_handler(channel_t *ch,
+ cell_t *cell)
+{
+ tt_assert(ch);
+ tt_assert(cell);
+
+ tor_free(cell);
+ ++test_chan_fixed_cells_recved;
+
+ done:
+ return;
+}
+
+/*
+ * Fake transport-specific stats call
+ */
+
+static void
+chan_test_dumpstats(channel_t *ch, int severity)
+{
+ tt_assert(ch != NULL);
+
+ (void)severity;
+
+ ++test_dumpstats_calls;
+
+ done:
+ return;
+}
+
+/*
+ * Handle an incoming variable-size cell for unit tests
+ */
+
+static void
+chan_test_var_cell_handler(channel_t *ch,
+ var_cell_t *var_cell)
+{
+ tt_assert(ch);
+ tt_assert(var_cell);
+
+ tor_free(var_cell);
+ ++test_chan_var_cells_recved;
+
+ done:
+ return;
+}
+
+static void
+chan_test_close(channel_t *ch)
+{
+ tt_assert(ch);
+
+ done:
+ return;
+}
+
+/*
+ * Close a channel through the error path
+ */
+
+static void
+chan_test_error(channel_t *ch)
+{
+ tt_assert(ch);
+ tt_assert(!(ch->state == CHANNEL_STATE_CLOSING ||
+ ch->state == CHANNEL_STATE_ERROR ||
+ ch->state == CHANNEL_STATE_CLOSED));
+
+ channel_close_for_error(ch);
+
+ done:
+ return;
+}
+
+/*
+ * Finish closing a channel from CHANNEL_STATE_CLOSING
+ */
+
+static void
+chan_test_finish_close(channel_t *ch)
+{
+ tt_assert(ch);
+ tt_assert(ch->state == CHANNEL_STATE_CLOSING);
+
+ channel_closed(ch);
+
+ done:
+ return;
+}
+
+static const char *
+chan_test_get_remote_descr(channel_t *ch, int flags)
+{
+ tt_assert(ch);
+ tt_int_op(flags & ~(GRD_FLAG_ORIGINAL | GRD_FLAG_ADDR_ONLY), ==, 0);
+
+ done:
+ return "Fake channel for unit tests; no real endpoint";
+}
+
+static double
+chan_test_get_overhead_estimate(channel_t *ch)
+{
+ tt_assert(ch);
+
+ done:
+ return test_overhead_estimate;
+}
+
+static int
+chan_test_is_canonical(channel_t *ch, int req)
+{
+ tt_assert(ch != NULL);
+ tt_assert(req == 0 || req == 1);
+
+ done:
+ /* Fake channels are always canonical */
+ return 1;
+}
+
+static size_t
+chan_test_num_bytes_queued(channel_t *ch)
+{
+ tt_assert(ch);
+
+ done:
+ return 0;
+}
+
+static int
+chan_test_num_cells_writeable(channel_t *ch)
+{
+ tt_assert(ch);
+
+ done:
+ return 32;
+}
+
+static int
+chan_test_write_cell(channel_t *ch, cell_t *cell)
+{
+ int rv = 0;
+
+ tt_assert(ch);
+ tt_assert(cell);
+
+ if (test_chan_accept_cells) {
+ /* Free the cell and bump the counter */
+ tor_free(cell);
+ ++test_cells_written;
+ rv = 1;
+ }
+ /* else return 0, we didn't accept it */
+
+ done:
+ return rv;
+}
+
+static int
+chan_test_write_packed_cell(channel_t *ch,
+ packed_cell_t *packed_cell)
+{
+ int rv = 0;
+
+ tt_assert(ch);
+ tt_assert(packed_cell);
+
+ if (test_chan_accept_cells) {
+ /* Free the cell and bump the counter */
+ packed_cell_free(packed_cell);
+ ++test_cells_written;
+ rv = 1;
+ }
+ /* else return 0, we didn't accept it */
+
+ done:
+ return rv;
+}
+
+static int
+chan_test_write_var_cell(channel_t *ch, var_cell_t *var_cell)
+{
+ int rv = 0;
+
+ tt_assert(ch);
+ tt_assert(var_cell);
+
+ if (test_chan_accept_cells) {
+ /* Free the cell and bump the counter */
+ var_cell_free(var_cell);
+ ++test_cells_written;
+ rv = 1;
+ }
+ /* else return 0, we didn't accept it */
+
+ done:
+ return rv;
+}
+
+/**
+ * Fill out c with a new fake cell for test suite use
+ */
+
+void
+make_fake_cell(cell_t *c)
+{
+ tt_assert(c != NULL);
+
+ c->circ_id = 1;
+ c->command = CELL_RELAY;
+ memset(c->payload, 0, CELL_PAYLOAD_SIZE);
+
+ done:
+ return;
+}
+
+/**
+ * Fill out c with a new fake var_cell for test suite use
+ */
+
+void
+make_fake_var_cell(var_cell_t *c)
+{
+ tt_assert(c != NULL);
+
+ c->circ_id = 1;
+ c->command = CELL_VERSIONS;
+ c->payload_len = CELL_PAYLOAD_SIZE / 2;
+ memset(c->payload, 0, c->payload_len);
+
+ done:
+ return;
+}
+
+/**
+ * Set up a new fake channel for the test suite
+ */
+
+channel_t *
+new_fake_channel(void)
+{
+ channel_t *chan = tor_malloc_zero(sizeof(channel_t));
+ channel_init(chan);
+
+ chan->close = chan_test_close;
+ chan->get_overhead_estimate = chan_test_get_overhead_estimate;
+ chan->get_remote_descr = chan_test_get_remote_descr;
+ chan->num_bytes_queued = chan_test_num_bytes_queued;
+ chan->num_cells_writeable = chan_test_num_cells_writeable;
+ chan->write_cell = chan_test_write_cell;
+ chan->write_packed_cell = chan_test_write_packed_cell;
+ chan->write_var_cell = chan_test_write_var_cell;
+ chan->state = CHANNEL_STATE_OPEN;
+
+ return chan;
+}
+
+void
+free_fake_channel(channel_t *chan)
+{
+ cell_queue_entry_t *cell, *cell_tmp;
+
+ if (! chan)
+ return;
+
+ if (chan->cmux)
+ circuitmux_free(chan->cmux);
+
+ TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->incoming_queue, next, cell_tmp) {
+ cell_queue_entry_free(cell, 0);
+ }
+ TOR_SIMPLEQ_FOREACH_SAFE(cell, &chan->outgoing_queue, next, cell_tmp) {
+ cell_queue_entry_free(cell, 0);
+ }
+
+ tor_free(chan);
+}
+
+/**
+ * Counter query for scheduler_channel_has_waiting_cells_mock()
+ */
+
+int
+get_mock_scheduler_has_waiting_cells_count(void)
+{
+ return test_has_waiting_cells_count;
+}
+
+/**
+ * Mock for scheduler_channel_has_waiting_cells()
+ */
+
+void
+scheduler_channel_has_waiting_cells_mock(channel_t *ch)
+{
+ (void)ch;
+
+ /* Increment counter */
+ ++test_has_waiting_cells_count;
+
+ return;
+}
+
+static void
+scheduler_channel_doesnt_want_writes_mock(channel_t *ch)
+{
+ (void)ch;
+
+ /* Increment counter */
+ ++test_doesnt_want_writes_count;
+
+ return;
+}
+
+/**
+ * Counter query for scheduler_release_channel_mock()
+ */
+
+int
+get_mock_scheduler_release_channel_count(void)
+{
+ return test_releases_count;
+}
+
+/**
+ * Mock for scheduler_release_channel()
+ */
+
+void
+scheduler_release_channel_mock(channel_t *ch)
+{
+ (void)ch;
+
+ /* Increment counter */
+ ++test_releases_count;
+
+ return;
+}
+
+/**
+ * Test for channel_dumpstats() and limited test for
+ * channel_dump_statistics()
+ */
+
+static void
+test_channel_dumpstats(void *arg)
+{
+ channel_t *ch = NULL;
+ cell_t *cell = NULL;
+ int old_count;
+
+ (void)arg;
+
+ /* Mock these for duration of the test */
+ MOCK(scheduler_channel_doesnt_want_writes,
+ scheduler_channel_doesnt_want_writes_mock);
+ MOCK(scheduler_release_channel,
+ scheduler_release_channel_mock);
+
+ /* Set up a new fake channel */
+ ch = new_fake_channel();
+ tt_assert(ch);
+ ch->cmux = circuitmux_alloc();
+
+ /* Try to register it */
+ channel_register(ch);
+ tt_assert(ch->registered);
+
+ /* Set up mock */
+ dump_statistics_mock_target = ch;
+ dump_statistics_mock_matches = 0;
+ MOCK(channel_dump_statistics,
+ chan_test_channel_dump_statistics_mock);
+
+ /* Call channel_dumpstats() */
+ channel_dumpstats(LOG_DEBUG);
+
+ /* Assert that we hit the mock */
+ tt_int_op(dump_statistics_mock_matches, ==, 1);
+
+ /* Close the channel */
+ channel_mark_for_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ chan_test_finish_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+
+ /* Try again and hit the finished channel */
+ channel_dumpstats(LOG_DEBUG);
+ tt_int_op(dump_statistics_mock_matches, ==, 2);
+
+ channel_run_cleanup();
+ ch = NULL;
+
+ /* Now we should hit nothing */
+ channel_dumpstats(LOG_DEBUG);
+ tt_int_op(dump_statistics_mock_matches, ==, 2);
+
+ /* Unmock */
+ UNMOCK(channel_dump_statistics);
+ dump_statistics_mock_target = NULL;
+ dump_statistics_mock_matches = 0;
+
+ /* Now make another channel */
+ ch = new_fake_channel();
+ tt_assert(ch);
+ ch->cmux = circuitmux_alloc();
+ channel_register(ch);
+ tt_assert(ch->registered);
+ /* Lie about its age so dumpstats gets coverage for rate calculations */
+ ch->timestamp_created = time(NULL) - 30;
+ tt_assert(ch->timestamp_created > 0);
+ tt_assert(time(NULL) > ch->timestamp_created);
+
+ /* Put cells through it both ways to make the counters non-zero */
+ cell = tor_malloc_zero(sizeof(*cell));
+ make_fake_cell(cell);
+ test_chan_accept_cells = 1;
+ old_count = test_cells_written;
+ channel_write_cell(ch, cell);
+ cell = NULL;
+ tt_int_op(test_cells_written, ==, old_count + 1);
+ tt_assert(ch->n_bytes_xmitted > 0);
+ tt_assert(ch->n_cells_xmitted > 0);
+
+ /* Receive path */
+ channel_set_cell_handlers(ch,
+ chan_test_cell_handler,
+ chan_test_var_cell_handler);
+ tt_ptr_op(channel_get_cell_handler(ch), ==, chan_test_cell_handler);
+ tt_ptr_op(channel_get_var_cell_handler(ch), ==, chan_test_var_cell_handler);
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ old_count = test_chan_fixed_cells_recved;
+ channel_queue_cell(ch, cell);
+ cell = NULL;
+ tt_int_op(test_chan_fixed_cells_recved, ==, old_count + 1);
+ tt_assert(ch->n_bytes_recved > 0);
+ tt_assert(ch->n_cells_recved > 0);
+
+ /* Test channel_dump_statistics */
+ ch->describe_transport = chan_test_describe_transport;
+ ch->dumpstats = chan_test_dumpstats;
+ ch->is_canonical = chan_test_is_canonical;
+ old_count = test_dumpstats_calls;
+ channel_dump_statistics(ch, LOG_DEBUG);
+ tt_int_op(test_dumpstats_calls, ==, old_count + 1);
+
+ /* Close the channel */
+ channel_mark_for_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ chan_test_finish_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ channel_run_cleanup();
+ ch = NULL;
+
+ done:
+ tor_free(cell);
+ free_fake_channel(ch);
+
+ UNMOCK(scheduler_channel_doesnt_want_writes);
+ UNMOCK(scheduler_release_channel);
+
+ return;
+}
+
+static void
+test_channel_flush(void *arg)
+{
+ channel_t *ch = NULL;
+ cell_t *cell = NULL;
+ packed_cell_t *p_cell = NULL;
+ var_cell_t *v_cell = NULL;
+ int init_count;
+
+ (void)arg;
+
+ ch = new_fake_channel();
+ tt_assert(ch);
+
+ /* Cache the original count */
+ init_count = test_cells_written;
+
+ /* Stop accepting so we can queue some */
+ test_chan_accept_cells = 0;
+
+ /* Queue a regular cell */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ channel_write_cell(ch, cell);
+ /* It should be queued, so assert that we didn't write it */
+ tt_int_op(test_cells_written, ==, init_count);
+
+ /* Queue a var cell */
+ v_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
+ make_fake_var_cell(v_cell);
+ channel_write_var_cell(ch, v_cell);
+ /* It should be queued, so assert that we didn't write it */
+ tt_int_op(test_cells_written, ==, init_count);
+
+ /* Try a packed cell now */
+ p_cell = packed_cell_new();
+ tt_assert(p_cell);
+ channel_write_packed_cell(ch, p_cell);
+ /* It should be queued, so assert that we didn't write it */
+ tt_int_op(test_cells_written, ==, init_count);
+
+ /* Now allow writes through again */
+ test_chan_accept_cells = 1;
+
+ /* ...and flush */
+ channel_flush_cells(ch);
+
+ /* All three should have gone through */
+ tt_int_op(test_cells_written, ==, init_count + 3);
+
+ done:
+ tor_free(ch);
+
+ return;
+}
+
+/**
+ * Channel flush tests that require cmux mocking
+ */
+
+static void
+test_channel_flushmux(void *arg)
+{
+ channel_t *ch = NULL;
+ int old_count, q_len_before, q_len_after;
+ ssize_t result;
+
+ (void)arg;
+
+ /* Install mocks we need for this test */
+ MOCK(channel_flush_from_first_active_circuit,
+ chan_test_channel_flush_from_first_active_circuit_mock);
+ MOCK(circuitmux_num_cells,
+ chan_test_circuitmux_num_cells_mock);
+
+ ch = new_fake_channel();
+ tt_assert(ch);
+ ch->cmux = circuitmux_alloc();
+
+ old_count = test_cells_written;
+
+ test_target_cmux = ch->cmux;
+ test_cmux_cells = 1;
+
+ /* Enable cell acceptance */
+ test_chan_accept_cells = 1;
+
+ result = channel_flush_some_cells(ch, 1);
+
+ tt_int_op(result, ==, 1);
+ tt_int_op(test_cells_written, ==, old_count + 1);
+ tt_int_op(test_cmux_cells, ==, 0);
+
+ /* Now try it without accepting to force them into the queue */
+ test_chan_accept_cells = 0;
+ test_cmux_cells = 1;
+ q_len_before = chan_cell_queue_len(&(ch->outgoing_queue));
+
+ result = channel_flush_some_cells(ch, 1);
+
+ /* We should not have actually flushed any */
+ tt_int_op(result, ==, 0);
+ tt_int_op(test_cells_written, ==, old_count + 1);
+ /* But we should have gotten to the fake cellgen loop */
+ tt_int_op(test_cmux_cells, ==, 0);
+ /* ...and we should have a queued cell */
+ q_len_after = chan_cell_queue_len(&(ch->outgoing_queue));
+ tt_int_op(q_len_after, ==, q_len_before + 1);
+
+ /* Now accept cells again and drain the queue */
+ test_chan_accept_cells = 1;
+ channel_flush_cells(ch);
+ tt_int_op(test_cells_written, ==, old_count + 2);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+
+ test_target_cmux = NULL;
+ test_cmux_cells = 0;
+
+ done:
+ if (ch)
+ circuitmux_free(ch->cmux);
+ tor_free(ch);
+
+ UNMOCK(channel_flush_from_first_active_circuit);
+ UNMOCK(circuitmux_num_cells);
+
+ test_chan_accept_cells = 0;
+
+ return;
+}
+
+static void
+test_channel_incoming(void *arg)
+{
+ channel_t *ch = NULL;
+ cell_t *cell = NULL;
+ var_cell_t *var_cell = NULL;
+ int old_count;
+
+ (void)arg;
+
+ /* Mock these for duration of the test */
+ MOCK(scheduler_channel_doesnt_want_writes,
+ scheduler_channel_doesnt_want_writes_mock);
+ MOCK(scheduler_release_channel,
+ scheduler_release_channel_mock);
+
+ /* Accept cells to lower layer */
+ test_chan_accept_cells = 1;
+ /* Use default overhead factor */
+ test_overhead_estimate = 1.0f;
+
+ ch = new_fake_channel();
+ tt_assert(ch);
+ /* Start it off in OPENING */
+ ch->state = CHANNEL_STATE_OPENING;
+ /* We'll need a cmux */
+ ch->cmux = circuitmux_alloc();
+
+ /* Install incoming cell handlers */
+ channel_set_cell_handlers(ch,
+ chan_test_cell_handler,
+ chan_test_var_cell_handler);
+ /* Test cell handler getters */
+ tt_ptr_op(channel_get_cell_handler(ch), ==, chan_test_cell_handler);
+ tt_ptr_op(channel_get_var_cell_handler(ch), ==, chan_test_var_cell_handler);
+
+ /* Try to register it */
+ channel_register(ch);
+ tt_assert(ch->registered);
+
+ /* Open it */
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_OPEN);
+
+ /* Receive a fixed cell */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ old_count = test_chan_fixed_cells_recved;
+ channel_queue_cell(ch, cell);
+ cell = NULL;
+ tt_int_op(test_chan_fixed_cells_recved, ==, old_count + 1);
+
+ /* Receive a variable-size cell */
+ var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
+ make_fake_var_cell(var_cell);
+ old_count = test_chan_var_cells_recved;
+ channel_queue_var_cell(ch, var_cell);
+ var_cell = NULL;
+ tt_int_op(test_chan_var_cells_recved, ==, old_count + 1);
+
+ /* Close it */
+ channel_mark_for_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ chan_test_finish_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ channel_run_cleanup();
+ ch = NULL;
+
+ done:
+ free_fake_channel(ch);
+ tor_free(cell);
+ tor_free(var_cell);
+
+ UNMOCK(scheduler_channel_doesnt_want_writes);
+ UNMOCK(scheduler_release_channel);
+
+ return;
+}
+
+/**
+ * Normal channel lifecycle test:
+ *
+ * OPENING->OPEN->MAINT->OPEN->CLOSING->CLOSED
+ */
+
+static void
+test_channel_lifecycle(void *arg)
+{
+ channel_t *ch1 = NULL, *ch2 = NULL;
+ cell_t *cell = NULL;
+ int old_count, init_doesnt_want_writes_count;
+ int init_releases_count;
+
+ (void)arg;
+
+ /* Mock these for the whole lifecycle test */
+ MOCK(scheduler_channel_doesnt_want_writes,
+ scheduler_channel_doesnt_want_writes_mock);
+ MOCK(scheduler_release_channel,
+ scheduler_release_channel_mock);
+
+ /* Cache some initial counter values */
+ init_doesnt_want_writes_count = test_doesnt_want_writes_count;
+ init_releases_count = test_releases_count;
+
+ /* Accept cells to lower layer */
+ test_chan_accept_cells = 1;
+ /* Use default overhead factor */
+ test_overhead_estimate = 1.0f;
+
+ ch1 = new_fake_channel();
+ tt_assert(ch1);
+ /* Start it off in OPENING */
+ ch1->state = CHANNEL_STATE_OPENING;
+ /* We'll need a cmux */
+ ch1->cmux = circuitmux_alloc();
+
+ /* Try to register it */
+ channel_register(ch1);
+ tt_assert(ch1->registered);
+
+ /* Try to write a cell through (should queue) */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ old_count = test_cells_written;
+ channel_write_cell(ch1, cell);
+ tt_int_op(old_count, ==, test_cells_written);
+
+ /* Move it to OPEN and flush */
+ channel_change_state(ch1, CHANNEL_STATE_OPEN);
+
+ /* Queue should drain */
+ tt_int_op(old_count + 1, ==, test_cells_written);
+
+ /* Get another one */
+ ch2 = new_fake_channel();
+ tt_assert(ch2);
+ ch2->state = CHANNEL_STATE_OPENING;
+ ch2->cmux = circuitmux_alloc();
+
+ /* Register */
+ channel_register(ch2);
+ tt_assert(ch2->registered);
+
+ /* Check counters */
+ tt_int_op(test_doesnt_want_writes_count, ==, init_doesnt_want_writes_count);
+ tt_int_op(test_releases_count, ==, init_releases_count);
+
+ /* Move ch1 to MAINT */
+ channel_change_state(ch1, CHANNEL_STATE_MAINT);
+ tt_int_op(test_doesnt_want_writes_count, ==,
+ init_doesnt_want_writes_count + 1);
+ tt_int_op(test_releases_count, ==, init_releases_count);
+
+ /* Move ch2 to OPEN */
+ channel_change_state(ch2, CHANNEL_STATE_OPEN);
+ tt_int_op(test_doesnt_want_writes_count, ==,
+ init_doesnt_want_writes_count + 1);
+ tt_int_op(test_releases_count, ==, init_releases_count);
+
+ /* Move ch1 back to OPEN */
+ channel_change_state(ch1, CHANNEL_STATE_OPEN);
+ tt_int_op(test_doesnt_want_writes_count, ==,
+ init_doesnt_want_writes_count + 1);
+ tt_int_op(test_releases_count, ==, init_releases_count);
+
+ /* Mark ch2 for close */
+ channel_mark_for_close(ch2);
+ tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSING);
+ tt_int_op(test_doesnt_want_writes_count, ==,
+ init_doesnt_want_writes_count + 1);
+ tt_int_op(test_releases_count, ==, init_releases_count + 1);
+
+ /* Shut down channels */
+ channel_free_all();
+ ch1 = ch2 = NULL;
+ tt_int_op(test_doesnt_want_writes_count, ==,
+ init_doesnt_want_writes_count + 1);
+ /* channel_free() calls scheduler_release_channel() */
+ tt_int_op(test_releases_count, ==, init_releases_count + 4);
+
+ done:
+ free_fake_channel(ch1);
+ free_fake_channel(ch2);
+
+ UNMOCK(scheduler_channel_doesnt_want_writes);
+ UNMOCK(scheduler_release_channel);
+
+ return;
+}
+
+/**
+ * Weird channel lifecycle test:
+ *
+ * OPENING->CLOSING->CLOSED
+ * OPENING->OPEN->CLOSING->ERROR
+ * OPENING->OPEN->MAINT->CLOSING->CLOSED
+ * OPENING->OPEN->MAINT->CLOSING->ERROR
+ */
+
+static void
+test_channel_lifecycle_2(void *arg)
+{
+ channel_t *ch = NULL;
+
+ (void)arg;
+
+ /* Mock these for the whole lifecycle test */
+ MOCK(scheduler_channel_doesnt_want_writes,
+ scheduler_channel_doesnt_want_writes_mock);
+ MOCK(scheduler_release_channel,
+ scheduler_release_channel_mock);
+
+ /* Accept cells to lower layer */
+ test_chan_accept_cells = 1;
+ /* Use default overhead factor */
+ test_overhead_estimate = 1.0f;
+
+ ch = new_fake_channel();
+ tt_assert(ch);
+ /* Start it off in OPENING */
+ ch->state = CHANNEL_STATE_OPENING;
+ /* The full lifecycle test needs a cmux */
+ ch->cmux = circuitmux_alloc();
+
+ /* Try to register it */
+ channel_register(ch);
+ tt_assert(ch->registered);
+
+ /* Try to close it */
+ channel_mark_for_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+
+ /* Finish closing it */
+ chan_test_finish_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ channel_run_cleanup();
+ ch = NULL;
+
+ /* Now try OPENING->OPEN->CLOSING->ERROR */
+ ch = new_fake_channel();
+ tt_assert(ch);
+ ch->state = CHANNEL_STATE_OPENING;
+ ch->cmux = circuitmux_alloc();
+ channel_register(ch);
+ tt_assert(ch->registered);
+
+ /* Finish opening it */
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+
+ /* Error exit from lower layer */
+ chan_test_error(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+ chan_test_finish_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_ERROR);
+ channel_run_cleanup();
+ ch = NULL;
+
+ /* OPENING->OPEN->MAINT->CLOSING->CLOSED close from maintenance state */
+ ch = new_fake_channel();
+ tt_assert(ch);
+ ch->state = CHANNEL_STATE_OPENING;
+ ch->cmux = circuitmux_alloc();
+ channel_register(ch);
+ tt_assert(ch->registered);
+
+ /* Finish opening it */
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_OPEN);
+
+ /* Go to maintenance state */
+ channel_change_state(ch, CHANNEL_STATE_MAINT);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_MAINT);
+
+ /* Lower layer close */
+ channel_mark_for_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+
+ /* Finish */
+ chan_test_finish_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ channel_run_cleanup();
+ ch = NULL;
+
+ /*
+ * OPENING->OPEN->MAINT->CLOSING->CLOSED lower-layer close during
+ * maintenance state
+ */
+ ch = new_fake_channel();
+ tt_assert(ch);
+ ch->state = CHANNEL_STATE_OPENING;
+ ch->cmux = circuitmux_alloc();
+ channel_register(ch);
+ tt_assert(ch->registered);
+
+ /* Finish opening it */
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_OPEN);
+
+ /* Go to maintenance state */
+ channel_change_state(ch, CHANNEL_STATE_MAINT);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_MAINT);
+
+ /* Lower layer close */
+ channel_close_from_lower_layer(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+
+ /* Finish */
+ chan_test_finish_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSED);
+ channel_run_cleanup();
+ ch = NULL;
+
+ /* OPENING->OPEN->MAINT->CLOSING->ERROR */
+ ch = new_fake_channel();
+ tt_assert(ch);
+ ch->state = CHANNEL_STATE_OPENING;
+ ch->cmux = circuitmux_alloc();
+ channel_register(ch);
+ tt_assert(ch->registered);
+
+ /* Finish opening it */
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_OPEN);
+
+ /* Go to maintenance state */
+ channel_change_state(ch, CHANNEL_STATE_MAINT);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_MAINT);
+
+ /* Lower layer close */
+ chan_test_error(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_CLOSING);
+
+ /* Finish */
+ chan_test_finish_close(ch);
+ tt_int_op(ch->state, ==, CHANNEL_STATE_ERROR);
+ channel_run_cleanup();
+ ch = NULL;
+
+ /* Shut down channels */
+ channel_free_all();
+
+ done:
+ tor_free(ch);
+
+ UNMOCK(scheduler_channel_doesnt_want_writes);
+ UNMOCK(scheduler_release_channel);
+
+ return;
+}
+
+static void
+test_channel_multi(void *arg)
+{
+ channel_t *ch1 = NULL, *ch2 = NULL;
+ uint64_t global_queue_estimate;
+ cell_t *cell = NULL;
+
+ (void)arg;
+
+ /* Accept cells to lower layer */
+ test_chan_accept_cells = 1;
+ /* Use default overhead factor */
+ test_overhead_estimate = 1.0f;
+
+ ch1 = new_fake_channel();
+ tt_assert(ch1);
+ ch2 = new_fake_channel();
+ tt_assert(ch2);
+
+ /* Initial queue size update */
+ channel_update_xmit_queue_size(ch1);
+ tt_u64_op(ch1->bytes_queued_for_xmit, ==, 0);
+ channel_update_xmit_queue_size(ch2);
+ tt_u64_op(ch2->bytes_queued_for_xmit, ==, 0);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 0);
+
+ /* Queue some cells, check queue estimates */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ channel_write_cell(ch1, cell);
+
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ channel_write_cell(ch2, cell);
+
+ channel_update_xmit_queue_size(ch1);
+ channel_update_xmit_queue_size(ch2);
+ tt_u64_op(ch1->bytes_queued_for_xmit, ==, 0);
+ tt_u64_op(ch2->bytes_queued_for_xmit, ==, 0);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 0);
+
+ /* Stop accepting cells at lower layer */
+ test_chan_accept_cells = 0;
+
+ /* Queue some cells and check queue estimates */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ channel_write_cell(ch1, cell);
+
+ channel_update_xmit_queue_size(ch1);
+ tt_u64_op(ch1->bytes_queued_for_xmit, ==, 512);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 512);
+
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ channel_write_cell(ch2, cell);
+
+ channel_update_xmit_queue_size(ch2);
+ tt_u64_op(ch2->bytes_queued_for_xmit, ==, 512);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 1024);
+
+ /* Allow cells through again */
+ test_chan_accept_cells = 1;
+
+ /* Flush chan 2 */
+ channel_flush_cells(ch2);
+
+ /* Update and check queue sizes */
+ channel_update_xmit_queue_size(ch1);
+ channel_update_xmit_queue_size(ch2);
+ tt_u64_op(ch1->bytes_queued_for_xmit, ==, 512);
+ tt_u64_op(ch2->bytes_queued_for_xmit, ==, 0);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 512);
+
+ /* Flush chan 1 */
+ channel_flush_cells(ch1);
+
+ /* Update and check queue sizes */
+ channel_update_xmit_queue_size(ch1);
+ channel_update_xmit_queue_size(ch2);
+ tt_u64_op(ch1->bytes_queued_for_xmit, ==, 0);
+ tt_u64_op(ch2->bytes_queued_for_xmit, ==, 0);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 0);
+
+ /* Now block again */
+ test_chan_accept_cells = 0;
+
+ /* Queue some cells */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ channel_write_cell(ch1, cell);
+
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ channel_write_cell(ch2, cell);
+ cell = NULL;
+
+ /* Check the estimates */
+ channel_update_xmit_queue_size(ch1);
+ channel_update_xmit_queue_size(ch2);
+ tt_u64_op(ch1->bytes_queued_for_xmit, ==, 512);
+ tt_u64_op(ch2->bytes_queued_for_xmit, ==, 512);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 1024);
+
+ /* Now close channel 2; it should be subtracted from the global queue */
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
+ channel_mark_for_close(ch2);
+ UNMOCK(scheduler_release_channel);
+
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 512);
+
+ /*
+ * Since the fake channels aren't registered, channel_free_all() can't
+ * see them properly.
+ */
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
+ channel_mark_for_close(ch1);
+ UNMOCK(scheduler_release_channel);
+
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 0);
+
+ /* Now free everything */
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
+ channel_free_all();
+ UNMOCK(scheduler_release_channel);
+
+ done:
+ free_fake_channel(ch1);
+ free_fake_channel(ch2);
+
+ return;
+}
+
+/**
+ * Check some hopefully-impossible edge cases in the channel queue we
+ * can only trigger by doing evil things to the queue directly.
+ */
+
+static void
+test_channel_queue_impossible(void *arg)
+{
+ channel_t *ch = NULL;
+ cell_t *cell = NULL;
+ packed_cell_t *packed_cell = NULL;
+ var_cell_t *var_cell = NULL;
+ int old_count;
+ cell_queue_entry_t *q = NULL;
+ uint64_t global_queue_estimate;
+ uintptr_t cellintptr;
+
+ /* Cache the global queue size (see below) */
+ global_queue_estimate = channel_get_global_queue_estimate();
+
+ (void)arg;
+
+ ch = new_fake_channel();
+ tt_assert(ch);
+
+ /* We test queueing here; tell it not to accept cells */
+ test_chan_accept_cells = 0;
+ /* ...and keep it from trying to flush the queue */
+ ch->state = CHANNEL_STATE_MAINT;
+
+ /* Cache the cell written count */
+ old_count = test_cells_written;
+
+ /* Assert that the queue is initially empty */
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+
+ /* Get a fresh cell and write it to the channel*/
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ cellintptr = (uintptr_t)(void*)cell;
+ channel_write_cell(ch, cell);
+
+ /* Now it should be queued */
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 1);
+ q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue));
+ tt_assert(q);
+ if (q) {
+ tt_int_op(q->type, ==, CELL_QUEUE_FIXED);
+ tt_assert((uintptr_t)q->u.fixed.cell == cellintptr);
+ }
+ /* Do perverse things to it */
+ tor_free(q->u.fixed.cell);
+ q->u.fixed.cell = NULL;
+
+ /*
+ * Now change back to open with channel_change_state() and assert that it
+ * gets thrown away properly.
+ */
+ test_chan_accept_cells = 1;
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tt_assert(test_cells_written == old_count);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+
+ /* Same thing but for a var_cell */
+
+ test_chan_accept_cells = 0;
+ ch->state = CHANNEL_STATE_MAINT;
+ var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
+ make_fake_var_cell(var_cell);
+ cellintptr = (uintptr_t)(void*)var_cell;
+ channel_write_var_cell(ch, var_cell);
+
+ /* Check that it's queued */
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 1);
+ q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue));
+ tt_assert(q);
+ if (q) {
+ tt_int_op(q->type, ==, CELL_QUEUE_VAR);
+ tt_assert((uintptr_t)q->u.var.var_cell == cellintptr);
+ }
+
+ /* Remove the cell from the queue entry */
+ tor_free(q->u.var.var_cell);
+ q->u.var.var_cell = NULL;
+
+ /* Let it drain and check that the bad entry is discarded */
+ test_chan_accept_cells = 1;
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tt_assert(test_cells_written == old_count);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+
+ /* Same thing with a packed_cell */
+
+ test_chan_accept_cells = 0;
+ ch->state = CHANNEL_STATE_MAINT;
+ packed_cell = packed_cell_new();
+ tt_assert(packed_cell);
+ cellintptr = (uintptr_t)(void*)packed_cell;
+ channel_write_packed_cell(ch, packed_cell);
+
+ /* Check that it's queued */
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 1);
+ q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue));
+ tt_assert(q);
+ if (q) {
+ tt_int_op(q->type, ==, CELL_QUEUE_PACKED);
+ tt_assert((uintptr_t)q->u.packed.packed_cell == cellintptr);
+ }
+
+ /* Remove the cell from the queue entry */
+ packed_cell_free(q->u.packed.packed_cell);
+ q->u.packed.packed_cell = NULL;
+
+ /* Let it drain and check that the bad entry is discarded */
+ test_chan_accept_cells = 1;
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tt_assert(test_cells_written == old_count);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+
+ /* Unknown cell type case */
+ test_chan_accept_cells = 0;
+ ch->state = CHANNEL_STATE_MAINT;
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ cellintptr = (uintptr_t)(void*)cell;
+ channel_write_cell(ch, cell);
+
+ /* Check that it's queued */
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 1);
+ q = TOR_SIMPLEQ_FIRST(&(ch->outgoing_queue));
+ tt_assert(q);
+ if (q) {
+ tt_int_op(q->type, ==, CELL_QUEUE_FIXED);
+ tt_assert((uintptr_t)q->u.fixed.cell == cellintptr);
+ }
+ /* Clobber it, including the queue entry type */
+ tor_free(q->u.fixed.cell);
+ q->u.fixed.cell = NULL;
+ q->type = CELL_QUEUE_PACKED + 1;
+
+ /* Let it drain and check that the bad entry is discarded */
+ test_chan_accept_cells = 1;
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tt_assert(test_cells_written == old_count);
+ tt_int_op(chan_cell_queue_len(&(ch->outgoing_queue)), ==, 0);
+
+ done:
+ free_fake_channel(ch);
+
+ /*
+ * Doing that meant that we couldn't correctly adjust the queue size
+ * for the var cell, so manually reset the global queue size estimate
+ * so the next test doesn't break if we run with --no-fork.
+ */
+ estimated_total_queue_size = global_queue_estimate;
+
+ return;
+}
+
+static void
+test_channel_queue_size(void *arg)
+{
+ channel_t *ch = NULL;
+ cell_t *cell = NULL;
+ int n, old_count;
+ uint64_t global_queue_estimate;
+
+ (void)arg;
+
+ ch = new_fake_channel();
+ tt_assert(ch);
+
+ /* Initial queue size update */
+ channel_update_xmit_queue_size(ch);
+ tt_u64_op(ch->bytes_queued_for_xmit, ==, 0);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 0);
+
+ /* Test the call-through to our fake lower layer */
+ n = channel_num_cells_writeable(ch);
+ /* chan_test_num_cells_writeable() always returns 32 */
+ tt_int_op(n, ==, 32);
+
+ /*
+ * Now we queue some cells and check that channel_num_cells_writeable()
+ * adjusts properly
+ */
+
+ /* tell it not to accept cells */
+ test_chan_accept_cells = 0;
+ /* ...and keep it from trying to flush the queue */
+ ch->state = CHANNEL_STATE_MAINT;
+
+ /* Get a fresh cell */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+
+ old_count = test_cells_written;
+ channel_write_cell(ch, cell);
+ /* Assert that it got queued, not written through, correctly */
+ tt_int_op(test_cells_written, ==, old_count);
+
+ /* Now check chan_test_num_cells_writeable() again */
+ n = channel_num_cells_writeable(ch);
+ tt_int_op(n, ==, 0); /* Should return 0 since we're in CHANNEL_STATE_MAINT */
+
+ /* Update queue size estimates */
+ channel_update_xmit_queue_size(ch);
+ /* One cell, times an overhead factor of 1.0 */
+ tt_u64_op(ch->bytes_queued_for_xmit, ==, 512);
+ /* Try a different overhead factor */
+ test_overhead_estimate = 0.5f;
+ /* This one should be ignored since it's below 1.0 */
+ channel_update_xmit_queue_size(ch);
+ tt_u64_op(ch->bytes_queued_for_xmit, ==, 512);
+ /* Now try a larger one */
+ test_overhead_estimate = 2.0f;
+ channel_update_xmit_queue_size(ch);
+ tt_u64_op(ch->bytes_queued_for_xmit, ==, 1024);
+ /* Go back to 1.0 */
+ test_overhead_estimate = 1.0f;
+ channel_update_xmit_queue_size(ch);
+ tt_u64_op(ch->bytes_queued_for_xmit, ==, 512);
+ /* Check the global estimate too */
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 512);
+
+ /* Go to open */
+ old_count = test_cells_written;
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+
+ /*
+ * It should try to write, but we aren't accepting cells right now, so
+ * it'll requeue
+ */
+ tt_int_op(test_cells_written, ==, old_count);
+
+ /* Check the queue size again */
+ channel_update_xmit_queue_size(ch);
+ tt_u64_op(ch->bytes_queued_for_xmit, ==, 512);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 512);
+
+ /*
+ * Now the cell is in the queue, and we're open, so we should get 31
+ * writeable cells.
+ */
+ n = channel_num_cells_writeable(ch);
+ tt_int_op(n, ==, 31);
+
+ /* Accept cells again */
+ test_chan_accept_cells = 1;
+ /* ...and re-process the queue */
+ old_count = test_cells_written;
+ channel_flush_cells(ch);
+ tt_int_op(test_cells_written, ==, old_count + 1);
+
+ /* Should have 32 writeable now */
+ n = channel_num_cells_writeable(ch);
+ tt_int_op(n, ==, 32);
+
+ /* Should have queue size estimate of zero */
+ channel_update_xmit_queue_size(ch);
+ tt_u64_op(ch->bytes_queued_for_xmit, ==, 0);
+ global_queue_estimate = channel_get_global_queue_estimate();
+ tt_u64_op(global_queue_estimate, ==, 0);
+
+ /* Okay, now we're done with this one */
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
+ channel_mark_for_close(ch);
+ UNMOCK(scheduler_release_channel);
+
+ done:
+ free_fake_channel(ch);
+
+ return;
+}
+
+static void
+test_channel_write(void *arg)
+{
+ channel_t *ch = NULL;
+ cell_t *cell = tor_malloc_zero(sizeof(cell_t));
+ packed_cell_t *packed_cell = NULL;
+ var_cell_t *var_cell =
+ tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
+ int old_count;
+
+ (void)arg;
+
+ packed_cell = packed_cell_new();
+ tt_assert(packed_cell);
+
+ ch = new_fake_channel();
+ tt_assert(ch);
+ make_fake_cell(cell);
+ make_fake_var_cell(var_cell);
+
+ /* Tell it to accept cells */
+ test_chan_accept_cells = 1;
+
+ old_count = test_cells_written;
+ channel_write_cell(ch, cell);
+ cell = NULL;
+ tt_assert(test_cells_written == old_count + 1);
+
+ channel_write_var_cell(ch, var_cell);
+ var_cell = NULL;
+ tt_assert(test_cells_written == old_count + 2);
+
+ channel_write_packed_cell(ch, packed_cell);
+ packed_cell = NULL;
+ tt_assert(test_cells_written == old_count + 3);
+
+ /* Now we test queueing; tell it not to accept cells */
+ test_chan_accept_cells = 0;
+ /* ...and keep it from trying to flush the queue */
+ ch->state = CHANNEL_STATE_MAINT;
+
+ /* Get a fresh cell */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+
+ old_count = test_cells_written;
+ channel_write_cell(ch, cell);
+ tt_assert(test_cells_written == old_count);
+
+ /*
+ * Now change back to open with channel_change_state() and assert that it
+ * gets drained from the queue.
+ */
+ test_chan_accept_cells = 1;
+ channel_change_state(ch, CHANNEL_STATE_OPEN);
+ tt_assert(test_cells_written == old_count + 1);
+
+ /*
+ * Check the note destroy case
+ */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ cell->command = CELL_DESTROY;
+
+ /* Set up the mock */
+ MOCK(channel_note_destroy_not_pending,
+ channel_note_destroy_not_pending_mock);
+
+ old_count = test_destroy_not_pending_calls;
+ channel_write_cell(ch, cell);
+ tt_assert(test_destroy_not_pending_calls == old_count + 1);
+
+ /* Now send a non-destroy and check we don't call it */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ channel_write_cell(ch, cell);
+ tt_assert(test_destroy_not_pending_calls == old_count + 1);
+
+ UNMOCK(channel_note_destroy_not_pending);
+
+ /*
+ * Now switch it to CLOSING so we can test the discard-cells case
+ * in the channel_write_*() functions.
+ */
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
+ channel_mark_for_close(ch);
+ UNMOCK(scheduler_release_channel);
+
+ /* Send cells that will drop in the closing state */
+ old_count = test_cells_written;
+
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+ channel_write_cell(ch, cell);
+ cell = NULL;
+ tt_assert(test_cells_written == old_count);
+
+ var_cell = tor_malloc_zero(sizeof(var_cell_t) + CELL_PAYLOAD_SIZE);
+ make_fake_var_cell(var_cell);
+ channel_write_var_cell(ch, var_cell);
+ var_cell = NULL;
+ tt_assert(test_cells_written == old_count);
+
+ packed_cell = packed_cell_new();
+ channel_write_packed_cell(ch, packed_cell);
+ packed_cell = NULL;
+ tt_assert(test_cells_written == old_count);
+
+ done:
+ free_fake_channel(ch);
+ tor_free(var_cell);
+ tor_free(cell);
+ packed_cell_free(packed_cell);
+ return;
+}
+
+struct testcase_t channel_tests[] = {
+ { "dumpstats", test_channel_dumpstats, TT_FORK, NULL, NULL },
+ { "flush", test_channel_flush, TT_FORK, NULL, NULL },
+ { "flushmux", test_channel_flushmux, TT_FORK, NULL, NULL },
+ { "incoming", test_channel_incoming, TT_FORK, NULL, NULL },
+ { "lifecycle", test_channel_lifecycle, TT_FORK, NULL, NULL },
+ { "lifecycle_2", test_channel_lifecycle_2, TT_FORK, NULL, NULL },
+ { "multi", test_channel_multi, TT_FORK, NULL, NULL },
+ { "queue_impossible", test_channel_queue_impossible, TT_FORK, NULL, NULL },
+ { "queue_size", test_channel_queue_size, TT_FORK, NULL, NULL },
+ { "write", test_channel_write, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
new file mode 100644
index 0000000000..016e504ab3
--- /dev/null
+++ b/src/test/test_channeltls.c
@@ -0,0 +1,333 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include <math.h>
+
+#define TOR_CHANNEL_INTERNAL_
+#include "or.h"
+#include "address.h"
+#include "buffers.h"
+#include "channel.h"
+#include "channeltls.h"
+#include "connection_or.h"
+#include "config.h"
+/* For init/free stuff */
+#include "scheduler.h"
+#include "tortls.h"
+
+/* Test suite stuff */
+#include "test.h"
+#include "fakechans.h"
+
+/* The channeltls unit tests */
+static void test_channeltls_create(void *arg);
+static void test_channeltls_num_bytes_queued(void *arg);
+static void test_channeltls_overhead_estimate(void *arg);
+
+/* Mocks used by channeltls unit tests */
+static size_t tlschan_buf_datalen_mock(const buf_t *buf);
+static or_connection_t * tlschan_connection_or_connect_mock(
+ const tor_addr_t *addr,
+ uint16_t port,
+ const char *digest,
+ channel_tls_t *tlschan);
+static int tlschan_is_local_addr_mock(const tor_addr_t *addr);
+
+/* Fake close method */
+static void tlschan_fake_close_method(channel_t *chan);
+
+/* Flags controlling behavior of channeltls unit test mocks */
+static int tlschan_local = 0;
+static const buf_t * tlschan_buf_datalen_mock_target = NULL;
+static size_t tlschan_buf_datalen_mock_size = 0;
+
+/* Thing to cast to fake tor_tls_t * to appease assert_connection_ok() */
+static int fake_tortls = 0; /* Bleh... */
+
+static void
+test_channeltls_create(void *arg)
+{
+ tor_addr_t test_addr;
+ channel_t *ch = NULL;
+ const char test_digest[DIGEST_LEN] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
+
+ (void)arg;
+
+ /* Set up a fake address to fake-connect to */
+ test_addr.family = AF_INET;
+ test_addr.addr.in_addr.s_addr = htonl(0x01020304);
+
+ /* For this test we always want the address to be treated as non-local */
+ tlschan_local = 0;
+ /* Install is_local_addr() mock */
+ MOCK(is_local_addr, tlschan_is_local_addr_mock);
+
+ /* Install mock for connection_or_connect() */
+ MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
+
+ /* Try connecting */
+ ch = channel_tls_connect(&test_addr, 567, test_digest);
+ tt_assert(ch != NULL);
+
+ done:
+ if (ch) {
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
+ /*
+ * Use fake close method that doesn't try to do too much to fake
+ * orconn
+ */
+ ch->close = tlschan_fake_close_method;
+ channel_mark_for_close(ch);
+ free_fake_channel(ch);
+ UNMOCK(scheduler_release_channel);
+ }
+
+ UNMOCK(connection_or_connect);
+ UNMOCK(is_local_addr);
+
+ return;
+}
+
+static void
+test_channeltls_num_bytes_queued(void *arg)
+{
+ tor_addr_t test_addr;
+ channel_t *ch = NULL;
+ const char test_digest[DIGEST_LEN] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
+ channel_tls_t *tlschan = NULL;
+ size_t len;
+ int fake_outbuf = 0, n;
+
+ (void)arg;
+
+ /* Set up a fake address to fake-connect to */
+ test_addr.family = AF_INET;
+ test_addr.addr.in_addr.s_addr = htonl(0x01020304);
+
+ /* For this test we always want the address to be treated as non-local */
+ tlschan_local = 0;
+ /* Install is_local_addr() mock */
+ MOCK(is_local_addr, tlschan_is_local_addr_mock);
+
+ /* Install mock for connection_or_connect() */
+ MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
+
+ /* Try connecting */
+ ch = channel_tls_connect(&test_addr, 567, test_digest);
+ tt_assert(ch != NULL);
+
+ /*
+ * Next, we have to test ch->num_bytes_queued, which is
+ * channel_tls_num_bytes_queued_method. We can't mock
+ * connection_get_outbuf_len() directly because it's static INLINE
+ * in connection.h, but we can mock buf_datalen(). Note that
+ * if bufferevents ever work, this will break with them enabled.
+ */
+
+ tt_assert(ch->num_bytes_queued != NULL);
+ tlschan = BASE_CHAN_TO_TLS(ch);
+ tt_assert(tlschan != NULL);
+ if (TO_CONN(tlschan->conn)->outbuf == NULL) {
+ /* We need an outbuf to make sure buf_datalen() gets called */
+ fake_outbuf = 1;
+ TO_CONN(tlschan->conn)->outbuf = buf_new();
+ }
+ tlschan_buf_datalen_mock_target = TO_CONN(tlschan->conn)->outbuf;
+ tlschan_buf_datalen_mock_size = 1024;
+ MOCK(buf_datalen, tlschan_buf_datalen_mock);
+ len = ch->num_bytes_queued(ch);
+ tt_int_op(len, ==, tlschan_buf_datalen_mock_size);
+ /*
+ * We also cover num_cells_writeable here; since wide_circ_ids = 0 on
+ * the fake tlschans, cell_network_size returns 512, and so with
+ * tlschan_buf_datalen_mock_size == 1024, we should be able to write
+ * ceil((OR_CONN_HIGHWATER - 1024) / 512) = ceil(OR_CONN_HIGHWATER / 512)
+ * - 2 cells.
+ */
+ n = ch->num_cells_writeable(ch);
+ tt_int_op(n, ==, CEIL_DIV(OR_CONN_HIGHWATER, 512) - 2);
+ UNMOCK(buf_datalen);
+ tlschan_buf_datalen_mock_target = NULL;
+ tlschan_buf_datalen_mock_size = 0;
+ if (fake_outbuf) {
+ buf_free(TO_CONN(tlschan->conn)->outbuf);
+ TO_CONN(tlschan->conn)->outbuf = NULL;
+ }
+
+ done:
+ if (ch) {
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
+ /*
+ * Use fake close method that doesn't try to do too much to fake
+ * orconn
+ */
+ ch->close = tlschan_fake_close_method;
+ channel_mark_for_close(ch);
+ free_fake_channel(ch);
+ UNMOCK(scheduler_release_channel);
+ }
+
+ UNMOCK(connection_or_connect);
+ UNMOCK(is_local_addr);
+
+ return;
+}
+
+static void
+test_channeltls_overhead_estimate(void *arg)
+{
+ tor_addr_t test_addr;
+ channel_t *ch = NULL;
+ const char test_digest[DIGEST_LEN] = {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14 };
+ float r;
+ channel_tls_t *tlschan = NULL;
+
+ (void)arg;
+
+ /* Set up a fake address to fake-connect to */
+ test_addr.family = AF_INET;
+ test_addr.addr.in_addr.s_addr = htonl(0x01020304);
+
+ /* For this test we always want the address to be treated as non-local */
+ tlschan_local = 0;
+ /* Install is_local_addr() mock */
+ MOCK(is_local_addr, tlschan_is_local_addr_mock);
+
+ /* Install mock for connection_or_connect() */
+ MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
+
+ /* Try connecting */
+ ch = channel_tls_connect(&test_addr, 567, test_digest);
+ tt_assert(ch != NULL);
+
+ /* First case: silly low ratios should get clamped to 1.0f */
+ tlschan = BASE_CHAN_TO_TLS(ch);
+ tt_assert(tlschan != NULL);
+ tlschan->conn->bytes_xmitted = 128;
+ tlschan->conn->bytes_xmitted_by_tls = 64;
+ r = ch->get_overhead_estimate(ch);
+ tt_assert(fabsf(r - 1.0f) < 1E-12);
+
+ tlschan->conn->bytes_xmitted_by_tls = 127;
+ r = ch->get_overhead_estimate(ch);
+ tt_assert(fabsf(r - 1.0f) < 1E-12);
+
+ /* Now middle of the range */
+ tlschan->conn->bytes_xmitted_by_tls = 192;
+ r = ch->get_overhead_estimate(ch);
+ tt_assert(fabsf(r - 1.5f) < 1E-12);
+
+ /* Now above the 2.0f clamp */
+ tlschan->conn->bytes_xmitted_by_tls = 257;
+ r = ch->get_overhead_estimate(ch);
+ tt_assert(fabsf(r - 2.0f) < 1E-12);
+
+ tlschan->conn->bytes_xmitted_by_tls = 512;
+ r = ch->get_overhead_estimate(ch);
+ tt_assert(fabsf(r - 2.0f) < 1E-12);
+
+ done:
+ if (ch) {
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
+ /*
+ * Use fake close method that doesn't try to do too much to fake
+ * orconn
+ */
+ ch->close = tlschan_fake_close_method;
+ channel_mark_for_close(ch);
+ free_fake_channel(ch);
+ UNMOCK(scheduler_release_channel);
+ }
+
+ UNMOCK(connection_or_connect);
+ UNMOCK(is_local_addr);
+
+ return;
+}
+
+static size_t
+tlschan_buf_datalen_mock(const buf_t *buf)
+{
+ if (buf != NULL && buf == tlschan_buf_datalen_mock_target) {
+ return tlschan_buf_datalen_mock_size;
+ } else {
+ return buf_datalen__real(buf);
+ }
+}
+
+static or_connection_t *
+tlschan_connection_or_connect_mock(const tor_addr_t *addr,
+ uint16_t port,
+ const char *digest,
+ channel_tls_t *tlschan)
+{
+ or_connection_t *result = NULL;
+
+ tt_assert(addr != NULL);
+ tt_assert(port != 0);
+ tt_assert(digest != NULL);
+ tt_assert(tlschan != NULL);
+
+ /* Make a fake orconn */
+ result = tor_malloc_zero(sizeof(*result));
+ result->base_.magic = OR_CONNECTION_MAGIC;
+ result->base_.state = OR_CONN_STATE_OPEN;
+ result->base_.type = CONN_TYPE_OR;
+ result->base_.socket_family = addr->family;
+ result->base_.address = tor_strdup("<fake>");
+ memcpy(&(result->base_.addr), addr, sizeof(tor_addr_t));
+ result->base_.port = port;
+ memcpy(result->identity_digest, digest, DIGEST_LEN);
+ result->chan = tlschan;
+ memcpy(&(result->real_addr), addr, sizeof(tor_addr_t));
+ result->tls = (tor_tls_t *)((void *)(&fake_tortls));
+
+ done:
+ return result;
+}
+
+static void
+tlschan_fake_close_method(channel_t *chan)
+{
+ channel_tls_t *tlschan = NULL;
+
+ tt_assert(chan != NULL);
+ tt_int_op(chan->magic, ==, TLS_CHAN_MAGIC);
+
+ tlschan = BASE_CHAN_TO_TLS(chan);
+ tt_assert(tlschan != NULL);
+
+ /* Just free the fake orconn */
+ tor_free(tlschan->conn->base_.address);
+ tor_free(tlschan->conn);
+
+ channel_closed(chan);
+
+ done:
+ return;
+}
+
+static int
+tlschan_is_local_addr_mock(const tor_addr_t *addr)
+{
+ tt_assert(addr != NULL);
+
+ done:
+ return tlschan_local;
+}
+
+struct testcase_t channeltls_tests[] = {
+ { "create", test_channeltls_create, TT_FORK, NULL, NULL },
+ { "num_bytes_queued", test_channeltls_num_bytes_queued,
+ TT_FORK, NULL, NULL },
+ { "overhead_estimate", test_channeltls_overhead_estimate,
+ TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c
new file mode 100644
index 0000000000..ae859449cb
--- /dev/null
+++ b/src/test/test_checkdir.c
@@ -0,0 +1,143 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "or.h"
+#include <dirent.h>
+#include "config.h"
+#include "test.h"
+#include "util.h"
+
+#ifdef _WIN32
+#define mkdir(a,b) mkdir(a)
+#define tt_int_op_nowin(a,op,b) do { (void)(a); (void)(b); } while (0)
+#define umask(mask) ((void)0)
+#else
+#define tt_int_op_nowin(a,op,b) tt_int_op((a),op,(b))
+#endif
+
+/** Run unit tests for private dir permission enforcement logic. */
+static void
+test_checkdir_perms(void *testdata)
+{
+ (void)testdata;
+ or_options_t *options = get_options_mutable();
+ const char *subdir = "test_checkdir";
+ char *testdir = NULL;
+ cpd_check_t cpd_chkopts;
+ cpd_check_t unix_create_opts;
+ cpd_check_t unix_verify_optsmask;
+ struct stat st;
+
+ umask(022);
+
+ /* setup data directory before tests. */
+ tor_free(options->DataDirectory);
+ options->DataDirectory = tor_strdup(get_fname(subdir));
+ tt_int_op(mkdir(options->DataDirectory, 0750), OP_EQ, 0);
+
+ /* test: create new dir, no flags. */
+ testdir = get_datadir_fname("checkdir_new_none");
+ cpd_chkopts = CPD_CREATE;
+ unix_verify_optsmask = 0077;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ tt_int_op(0, OP_EQ, stat(testdir, &st));
+ tt_int_op_nowin(0, OP_EQ, (st.st_mode & unix_verify_optsmask));
+ tor_free(testdir);
+
+ /* test: create new dir, CPD_GROUP_OK option set. */
+ testdir = get_datadir_fname("checkdir_new_groupok");
+ cpd_chkopts = CPD_CREATE|CPD_GROUP_OK;
+ unix_verify_optsmask = 0077;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ tt_int_op(0, OP_EQ, stat(testdir, &st));
+ tt_int_op_nowin(0, OP_EQ, (st.st_mode & unix_verify_optsmask));
+ tor_free(testdir);
+
+ /* test: should get an error on existing dir with
+ wrong perms */
+ testdir = get_datadir_fname("checkdir_new_groupok_err");
+ tt_int_op(0, OP_EQ, mkdir(testdir, 027));
+ cpd_chkopts = CPD_CHECK_MODE_ONLY|CPD_CREATE|CPD_GROUP_OK;
+ tt_int_op_nowin(-1, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ tor_free(testdir);
+
+ /* test: create new dir, CPD_GROUP_READ option set. */
+ testdir = get_datadir_fname("checkdir_new_groupread");
+ cpd_chkopts = CPD_CREATE|CPD_GROUP_READ;
+ unix_verify_optsmask = 0027;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ tt_int_op(0, OP_EQ, stat(testdir, &st));
+ tt_int_op_nowin(0, OP_EQ, (st.st_mode & unix_verify_optsmask));
+ tor_free(testdir);
+
+ /* test: check existing dir created with defaults,
+ and verify with CPD_CREATE only. */
+ testdir = get_datadir_fname("checkdir_exists_none");
+ cpd_chkopts = CPD_CREATE;
+ unix_create_opts = 0700;
+ (void)unix_create_opts;
+ unix_verify_optsmask = 0077;
+ tt_int_op(0, OP_EQ, mkdir(testdir, unix_create_opts));
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ tt_int_op(0, OP_EQ, stat(testdir, &st));
+ tt_int_op_nowin(0, OP_EQ, (st.st_mode & unix_verify_optsmask));
+ tor_free(testdir);
+
+ /* test: check existing dir created with defaults,
+ and verify with CPD_GROUP_OK option set. */
+ testdir = get_datadir_fname("checkdir_exists_groupok");
+ cpd_chkopts = CPD_CREATE;
+ unix_verify_optsmask = 0077;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ cpd_chkopts = CPD_GROUP_OK;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ tt_int_op(0, OP_EQ, stat(testdir, &st));
+ tt_int_op_nowin(0, OP_EQ, (st.st_mode & unix_verify_optsmask));
+ tor_free(testdir);
+
+ /* test: check existing dir created with defaults,
+ and verify with CPD_GROUP_READ option set. */
+ testdir = get_datadir_fname("checkdir_exists_groupread");
+ cpd_chkopts = CPD_CREATE;
+ unix_verify_optsmask = 0027;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ cpd_chkopts = CPD_GROUP_READ;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ tt_int_op(0, OP_EQ, stat(testdir, &st));
+ tt_int_op_nowin(0, OP_EQ, (st.st_mode & unix_verify_optsmask));
+ tor_free(testdir);
+
+ /* test: check existing dir created with CPD_GROUP_READ,
+ and verify with CPD_GROUP_OK option set. */
+ testdir = get_datadir_fname("checkdir_existsread_groupok");
+ cpd_chkopts = CPD_CREATE|CPD_GROUP_READ;
+ unix_verify_optsmask = 0027;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ cpd_chkopts = CPD_GROUP_OK;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ tt_int_op(0, OP_EQ, stat(testdir, &st));
+ tt_int_op_nowin(0, OP_EQ, (st.st_mode & unix_verify_optsmask));
+ tor_free(testdir);
+
+ /* test: check existing dir created with CPD_GROUP_READ,
+ and verify with CPD_GROUP_READ option set. */
+ testdir = get_datadir_fname("checkdir_existsread_groupread");
+ cpd_chkopts = CPD_CREATE|CPD_GROUP_READ;
+ unix_verify_optsmask = 0027;
+ tt_int_op(0, OP_EQ, check_private_dir(testdir, cpd_chkopts, NULL));
+ tt_int_op(0, OP_EQ, stat(testdir, &st));
+ tt_int_op_nowin(0, OP_EQ, (st.st_mode & unix_verify_optsmask));
+
+ done:
+ tor_free(testdir);
+}
+
+#define CHECKDIR(name,flags) \
+ { #name, test_checkdir_##name, (flags), NULL, NULL }
+
+struct testcase_t checkdir_tests[] = {
+ CHECKDIR(perms, TT_FORK),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c
index b19edd1fd4..0760accfc1 100644
--- a/src/test/test_circuitlist.c
+++ b/src/test/test_circuitlist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TOR_CHANNEL_INTERNAL_
@@ -50,17 +50,17 @@ circuitmux_detach_mock(circuitmux_t *cmux, circuit_t *circ)
}
#define GOT_CMUX_ATTACH(mux_, circ_, dir_) do { \
- tt_int_op(cam.ncalls, ==, 1); \
- tt_ptr_op(cam.cmux, ==, (mux_)); \
- tt_ptr_op(cam.circ, ==, (circ_)); \
- tt_int_op(cam.dir, ==, (dir_)); \
+ tt_int_op(cam.ncalls, OP_EQ, 1); \
+ tt_ptr_op(cam.cmux, OP_EQ, (mux_)); \
+ tt_ptr_op(cam.circ, OP_EQ, (circ_)); \
+ tt_int_op(cam.dir, OP_EQ, (dir_)); \
memset(&cam, 0, sizeof(cam)); \
} while (0)
#define GOT_CMUX_DETACH(mux_, circ_) do { \
- tt_int_op(cdm.ncalls, ==, 1); \
- tt_ptr_op(cdm.cmux, ==, (mux_)); \
- tt_ptr_op(cdm.circ, ==, (circ_)); \
+ tt_int_op(cdm.ncalls, OP_EQ, 1); \
+ tt_ptr_op(cdm.cmux, OP_EQ, (mux_)); \
+ tt_ptr_op(cdm.circ, OP_EQ, (circ_)); \
memset(&cdm, 0, sizeof(cdm)); \
} while (0)
@@ -79,21 +79,25 @@ test_clist_maps(void *arg)
memset(&cam, 0, sizeof(cam));
memset(&cdm, 0, sizeof(cdm));
- ch1->cmux = (void*)0x1001;
- ch2->cmux = (void*)0x1002;
- ch3->cmux = (void*)0x1003;
+ tt_assert(ch1);
+ tt_assert(ch2);
+ tt_assert(ch3);
+
+ ch1->cmux = tor_malloc(1);
+ ch2->cmux = tor_malloc(1);
+ ch3->cmux = tor_malloc(1);
or_c1 = or_circuit_new(100, ch2);
tt_assert(or_c1);
GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN);
- tt_int_op(or_c1->p_circ_id, ==, 100);
- tt_ptr_op(or_c1->p_chan, ==, ch2);
+ tt_int_op(or_c1->p_circ_id, OP_EQ, 100);
+ tt_ptr_op(or_c1->p_chan, OP_EQ, ch2);
or_c2 = or_circuit_new(100, ch1);
tt_assert(or_c2);
GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN);
- tt_int_op(or_c2->p_circ_id, ==, 100);
- tt_ptr_op(or_c2->p_chan, ==, ch1);
+ tt_int_op(or_c2->p_circ_id, OP_EQ, 100);
+ tt_ptr_op(or_c2->p_chan, OP_EQ, ch1);
circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1);
GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT);
@@ -101,11 +105,11 @@ test_clist_maps(void *arg)
circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2);
GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT);
- tt_ptr_op(circuit_get_by_circid_channel(200, ch1), ==, TO_CIRCUIT(or_c1));
- tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
- tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch1), OP_EQ, TO_CIRCUIT(or_c1));
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
/* Try the same thing again, to test the "fast" path. */
- tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
tt_assert(circuit_id_in_use_on_channel(100, ch2));
tt_assert(! circuit_id_in_use_on_channel(101, ch2));
@@ -113,9 +117,9 @@ test_clist_maps(void *arg)
circuit_set_p_circid_chan(or_c1, 500, ch3);
GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1));
GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN);
- tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, NULL);
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, NULL);
tt_assert(! circuit_id_in_use_on_channel(100, ch2));
- tt_ptr_op(circuit_get_by_circid_channel(500, ch3), ==, TO_CIRCUIT(or_c1));
+ tt_ptr_op(circuit_get_by_circid_channel(500, ch3), OP_EQ, TO_CIRCUIT(or_c1));
/* Now let's see about destroy handling. */
tt_assert(! circuit_id_in_use_on_channel(205, ch2));
@@ -128,26 +132,26 @@ test_clist_maps(void *arg)
tt_assert(circuit_id_in_use_on_channel(100, ch1));
tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0);
- tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
- tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, TO_CIRCUIT(or_c2));
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, TO_CIRCUIT(or_c2));
/* Okay, now free ch2 and make sure that the circuit ID is STILL not
* usable, because we haven't declared the destroy to be nonpending */
- tt_int_op(cdm.ncalls, ==, 0);
+ tt_int_op(cdm.ncalls, OP_EQ, 0);
circuit_free(TO_CIRCUIT(or_c2));
or_c2 = NULL; /* prevent free */
- tt_int_op(cdm.ncalls, ==, 2);
+ tt_int_op(cdm.ncalls, OP_EQ, 2);
memset(&cdm, 0, sizeof(cdm));
tt_assert(circuit_id_in_use_on_channel(200, ch2));
tt_assert(circuit_id_in_use_on_channel(100, ch1));
- tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
- tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);
/* Now say that the destroy is nonpending */
channel_note_destroy_not_pending(ch2, 200);
- tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
channel_note_destroy_not_pending(ch1, 100);
- tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);
tt_assert(! circuit_id_in_use_on_channel(200, ch2));
tt_assert(! circuit_id_in_use_on_channel(100, ch1));
@@ -156,6 +160,12 @@ test_clist_maps(void *arg)
circuit_free(TO_CIRCUIT(or_c1));
if (or_c2)
circuit_free(TO_CIRCUIT(or_c2));
+ if (ch1)
+ tor_free(ch1->cmux);
+ if (ch2)
+ tor_free(ch2->cmux);
+ if (ch3)
+ tor_free(ch3->cmux);
tor_free(ch1);
tor_free(ch2);
tor_free(ch3);
@@ -180,73 +190,73 @@ test_rend_token_maps(void *arg)
c4 = or_circuit_new(0, NULL);
/* Make sure we really filled up the tok* variables */
- tt_int_op(tok1[REND_TOKEN_LEN-1], ==, 'y');
- tt_int_op(tok2[REND_TOKEN_LEN-1], ==, ' ');
- tt_int_op(tok3[REND_TOKEN_LEN-1], ==, '.');
+ tt_int_op(tok1[REND_TOKEN_LEN-1], OP_EQ, 'y');
+ tt_int_op(tok2[REND_TOKEN_LEN-1], OP_EQ, ' ');
+ tt_int_op(tok3[REND_TOKEN_LEN-1], OP_EQ, '.');
/* No maps; nothing there. */
- tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
- tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1));
circuit_set_rendezvous_cookie(c1, tok1);
circuit_set_intro_point_digest(c2, tok2);
- tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok3));
- tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3));
- tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2));
- tt_ptr_op(NULL, ==, circuit_get_intro_point(tok1));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok3));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok1));
/* Without purpose set, we don't get the circuits */
- tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
- tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2));
c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
/* Okay, make sure they show up now. */
- tt_ptr_op(c1, ==, circuit_get_rendezvous(tok1));
- tt_ptr_op(c2, ==, circuit_get_intro_point(tok2));
+ tt_ptr_op(c1, OP_EQ, circuit_get_rendezvous(tok1));
+ tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2));
/* Two items at the same place with the same token. */
c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
circuit_set_rendezvous_cookie(c3, tok2);
- tt_ptr_op(c2, ==, circuit_get_intro_point(tok2));
- tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2));
+ tt_ptr_op(c2, OP_EQ, circuit_get_intro_point(tok2));
+ tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2));
/* Marking a circuit makes it not get returned any more */
circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED);
- tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok1));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok1));
circuit_free(TO_CIRCUIT(c1));
c1 = NULL;
/* Freeing a circuit makes it not get returned any more. */
circuit_free(TO_CIRCUIT(c2));
c2 = NULL;
- tt_ptr_op(NULL, ==, circuit_get_intro_point(tok2));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok2));
/* c3 -- are you still there? */
- tt_ptr_op(c3, ==, circuit_get_rendezvous(tok2));
+ tt_ptr_op(c3, OP_EQ, circuit_get_rendezvous(tok2));
/* Change its cookie. This never happens in Tor per se, but hey. */
c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
circuit_set_intro_point_digest(c3, tok3);
- tt_ptr_op(NULL, ==, circuit_get_rendezvous(tok2));
- tt_ptr_op(c3, ==, circuit_get_intro_point(tok3));
+ tt_ptr_op(NULL, OP_EQ, circuit_get_rendezvous(tok2));
+ tt_ptr_op(c3, OP_EQ, circuit_get_intro_point(tok3));
/* Now replace c3 with c4. */
c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
circuit_set_intro_point_digest(c4, tok3);
- tt_ptr_op(c4, ==, circuit_get_intro_point(tok3));
+ tt_ptr_op(c4, OP_EQ, circuit_get_intro_point(tok3));
- tt_ptr_op(c3->rendinfo, ==, NULL);
- tt_ptr_op(c4->rendinfo, !=, NULL);
- test_mem_op(c4->rendinfo, ==, tok3, REND_TOKEN_LEN);
+ tt_ptr_op(c3->rendinfo, OP_EQ, NULL);
+ tt_ptr_op(c4->rendinfo, OP_NE, NULL);
+ tt_mem_op(c4->rendinfo, OP_EQ, tok3, REND_TOKEN_LEN);
/* Now clear c4's cookie. */
circuit_set_intro_point_digest(c4, NULL);
- tt_ptr_op(c4->rendinfo, ==, NULL);
- tt_ptr_op(NULL, ==, circuit_get_intro_point(tok3));
+ tt_ptr_op(c4->rendinfo, OP_EQ, NULL);
+ tt_ptr_op(NULL, OP_EQ, circuit_get_intro_point(tok3));
done:
if (c1)
@@ -273,32 +283,32 @@ test_pick_circid(void *arg)
chan2->wide_circ_ids = 1;
chan1->circ_id_type = CIRC_ID_TYPE_NEITHER;
- tt_int_op(0, ==, get_unique_circ_id_by_chan(chan1));
+ tt_int_op(0, OP_EQ, get_unique_circ_id_by_chan(chan1));
/* Basic tests, with no collisions */
chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
for (i = 0; i < 50; ++i) {
circid = get_unique_circ_id_by_chan(chan1);
- tt_uint_op(0, <, circid);
- tt_uint_op(circid, <, (1<<15));
+ tt_uint_op(0, OP_LT, circid);
+ tt_uint_op(circid, OP_LT, (1<<15));
}
chan1->circ_id_type = CIRC_ID_TYPE_HIGHER;
for (i = 0; i < 50; ++i) {
circid = get_unique_circ_id_by_chan(chan1);
- tt_uint_op((1<<15), <, circid);
- tt_uint_op(circid, <, (1<<16));
+ tt_uint_op((1<<15), OP_LT, circid);
+ tt_uint_op(circid, OP_LT, (1<<16));
}
chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
for (i = 0; i < 50; ++i) {
circid = get_unique_circ_id_by_chan(chan2);
- tt_uint_op(0, <, circid);
- tt_uint_op(circid, <, (1u<<31));
+ tt_uint_op(0, OP_LT, circid);
+ tt_uint_op(circid, OP_LT, (1u<<31));
}
chan2->circ_id_type = CIRC_ID_TYPE_HIGHER;
for (i = 0; i < 50; ++i) {
circid = get_unique_circ_id_by_chan(chan2);
- tt_uint_op((1u<<31), <, circid);
+ tt_uint_op((1u<<31), OP_LT, circid);
}
/* Now make sure that we can behave well when we are full up on circuits */
@@ -309,20 +319,20 @@ test_pick_circid(void *arg)
for (i = 0; i < (1<<15); ++i) {
circid = get_unique_circ_id_by_chan(chan1);
if (circid == 0) {
- tt_int_op(i, >, (1<<14));
+ tt_int_op(i, OP_GT, (1<<14));
break;
}
- tt_uint_op(circid, <, (1<<15));
+ tt_uint_op(circid, OP_LT, (1<<15));
tt_assert(! bitarray_is_set(ba, circid));
bitarray_set(ba, circid);
channel_mark_circid_unusable(chan1, circid);
}
- tt_int_op(i, <, (1<<15));
+ tt_int_op(i, OP_LT, (1<<15));
/* Make sure that being full on chan1 does not interfere with chan2 */
for (i = 0; i < 100; ++i) {
circid = get_unique_circ_id_by_chan(chan2);
- tt_uint_op(circid, >, 0);
- tt_uint_op(circid, <, (1<<15));
+ tt_uint_op(circid, OP_GT, 0);
+ tt_uint_op(circid, OP_LT, (1<<15));
channel_mark_circid_unusable(chan2, circid);
}
diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c
index b9c0436ebf..6d93731eea 100644
--- a/src/test/test_circuitmux.c
+++ b/src/test/test_circuitmux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define TOR_CHANNEL_INTERNAL_
@@ -8,6 +8,7 @@
#include "channel.h"
#include "circuitmux.h"
#include "relay.h"
+#include "scheduler.h"
#include "test.h"
/* XXXX duplicated function from test_circuitlist.c */
@@ -35,10 +36,13 @@ test_cmux_destroy_cell_queue(void *arg)
circuit_t *circ = NULL;
cell_queue_t *cq = NULL;
packed_cell_t *pc = NULL;
+ tor_libevent_cfg cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+
+ tor_libevent_initialize(&cfg);
+ scheduler_init();
-#ifdef ENABLE_MEMPOOLS
- init_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
(void) arg;
cmux = circuitmux_alloc();
@@ -55,30 +59,26 @@ test_cmux_destroy_cell_queue(void *arg)
circuitmux_append_destroy_cell(ch, cmux, 190, 6);
circuitmux_append_destroy_cell(ch, cmux, 30, 1);
- tt_int_op(circuitmux_num_cells(cmux), ==, 3);
+ tt_int_op(circuitmux_num_cells(cmux), OP_EQ, 3);
circ = circuitmux_get_first_active_circuit(cmux, &cq);
tt_assert(!circ);
tt_assert(cq);
- tt_int_op(cq->n, ==, 3);
+ tt_int_op(cq->n, OP_EQ, 3);
pc = cell_queue_pop(cq);
tt_assert(pc);
- test_mem_op(pc->body, ==, "\x00\x00\x00\x64\x04\x0a\x00\x00\x00", 9);
+ tt_mem_op(pc->body, OP_EQ, "\x00\x00\x00\x64\x04\x0a\x00\x00\x00", 9);
packed_cell_free(pc);
pc = NULL;
- tt_int_op(circuitmux_num_cells(cmux), ==, 2);
+ tt_int_op(circuitmux_num_cells(cmux), OP_EQ, 2);
done:
circuitmux_free(cmux);
channel_free(ch);
packed_cell_free(pc);
-
-#ifdef ENABLE_MEMPOOLS
- free_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
}
struct testcase_t circuitmux_tests[] = {
diff --git a/src/test/test_cmdline_args.py b/src/test/test_cmdline_args.py
index 55d1cdb805..57641974db 100755
--- a/src/test/test_cmdline_args.py
+++ b/src/test/test_cmdline_args.py
@@ -49,22 +49,25 @@ def contents(fn):
finally:
f.close()
-def run_tor(args, failure=False):
- p = subprocess.Popen([TOR] + args, stdout=subprocess.PIPE)
- output, _ = p.communicate()
+def run_tor(args, failure=False, stdin=None):
+ kwargs = {}
+ if stdin != None:
+ kwargs['stdin'] = subprocess.PIPE
+ p = subprocess.Popen([TOR] + args, stdout=subprocess.PIPE, **kwargs)
+ output, _ = p.communicate(input=stdin)
result = p.poll()
if result and not failure:
raise UnexpectedFailure()
elif not result and failure:
raise UnexpectedSuccess()
- return b2s(output)
+ return b2s(output.replace('\r\n','\n'))
def spaceify_fp(fp):
for i in range(0, len(fp), 4):
yield fp[i:i+4]
def lines(s):
- out = s.split("\n")
+ out = s.splitlines()
if out and out[-1] == '':
del out[-1]
return out
@@ -151,7 +154,7 @@ class CmdlineTests(unittest.TestCase):
if os.stat(TOR).st_mtime < os.stat(main_c).st_mtime:
self.skipTest(TOR+" not up to date")
out = run_tor(["--digests"])
- main_line = [ l for l in lines(out) if l.endswith("/main.c") ]
+ main_line = [ l for l in lines(out) if l.endswith("/main.c") or l.endswith(" main.c") ]
digest, name = main_line[0].split()
f = open(main_c, 'rb')
actual = hashlib.sha1(f.read()).hexdigest()
@@ -234,20 +237,26 @@ class CmdlineTests(unittest.TestCase):
def test_cmdline_args(self):
default_torrc = NamedTemporaryFile()
torrc = NamedTemporaryFile()
- torrc.write("SocksPort 9999\n")
- torrc.write("SocksPort 9998\n")
- torrc.write("ORPort 9000\n")
- torrc.write("ORPort 9001\n")
- torrc.write("Nickname eleventeen\n")
- torrc.write("ControlPort 9500\n")
- torrc.close()
+ contents = ("SocksPort 9999\n"
+ "SocksPort 9998\n"
+ "ORPort 9000\n"
+ "ORPort 9001\n"
+ "Nickname eleventeen\n"
+ "ControlPort 9500\n")
+ torrc.write(contents)
default_torrc.write("")
default_torrc.close()
+ torrc.close()
out_sh = out_nb = out_fl = None
+
+ opts_stdin = [ "-f", "-",
+ "--defaults-torrc", default_torrc.name,
+ "--dump-config", "short" ]
opts = [ "-f", torrc.name,
"--defaults-torrc", default_torrc.name,
"--dump-config", "short" ]
try:
+ out_0 = run_tor(opts_stdin,stdin=contents)
out_1 = run_tor(opts)
out_2 = run_tor(opts+["+ORPort", "9003",
"SocksPort", "9090",
@@ -258,9 +267,18 @@ class CmdlineTests(unittest.TestCase):
os.unlink(torrc.name)
os.unlink(default_torrc.name)
+ out_0 = [ l for l in lines(out_0) if not l.startswith("DataDir") ]
out_1 = [ l for l in lines(out_1) if not l.startswith("DataDir") ]
out_2 = [ l for l in lines(out_2) if not l.startswith("DataDir") ]
+ self.assertEqual(out_0,
+ ["ControlPort 9500",
+ "Nickname eleventeen",
+ "ORPort 9000",
+ "ORPort 9001",
+ "SocksPort 9999",
+ "SocksPort 9998"])
+
self.assertEqual(out_1,
["ControlPort 9500",
"Nickname eleventeen",
@@ -268,6 +286,7 @@ class CmdlineTests(unittest.TestCase):
"ORPort 9001",
"SocksPort 9999",
"SocksPort 9998"])
+
self.assertEqual(out_2,
["ExtORPort 9005",
"Nickname eleventeen",
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 94ac4dca13..0444062722 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -1,11 +1,12 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define CONFIG_PRIVATE
+#define PT_PRIVATE
#include "or.h"
#include "addressmap.h"
#include "config.h"
@@ -14,6 +15,8 @@
#include "test.h"
#include "util.h"
#include "address.h"
+#include "entrynodes.h"
+#include "transports.h"
static void
test_config_addressmap(void *arg)
@@ -48,62 +51,61 @@ test_config_addressmap(void *arg)
/* Use old interface for now, so we don't need to rewrite the unit tests */
#define addressmap_rewrite(a,s,eo,ao) \
- addressmap_rewrite((a),(s),AMR_FLAG_USE_IPV4_DNS|AMR_FLAG_USE_IPV6_DNS, \
- (eo),(ao))
+ addressmap_rewrite((a),(s), ~0, (eo),(ao))
/* MapAddress .invalidwildcard.com .torserver.exit - no match */
strlcpy(address, "www.invalidwildcard.com", sizeof(address));
- test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
/* MapAddress *invalidasterisk.com .torserver.exit - no match */
strlcpy(address, "www.invalidasterisk.com", sizeof(address));
- test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
/* Where no mapping for FQDN match on top-level domain */
/* MapAddress .google.com .torserver.exit */
strlcpy(address, "reader.google.com", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "reader.torserver.exit");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "reader.torserver.exit");
/* MapAddress *.yahoo.com *.google.com.torserver.exit */
strlcpy(address, "reader.yahoo.com", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "reader.google.com.torserver.exit");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "reader.google.com.torserver.exit");
/*MapAddress *.cnn.com www.cnn.com */
strlcpy(address, "cnn.com", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "www.cnn.com");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "www.cnn.com");
/* MapAddress .cn.com www.cnn.com */
strlcpy(address, "www.cn.com", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "www.cnn.com");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "www.cnn.com");
/* MapAddress ex.com www.cnn.com - no match */
strlcpy(address, "www.ex.com", sizeof(address));
- test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
/* MapAddress ey.com *.cnn.com - invalid expression */
strlcpy(address, "ey.com", sizeof(address));
- test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
/* Where mapping for FQDN match on FQDN */
strlcpy(address, "www.google.com", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "3.3.3.3");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "3.3.3.3");
strlcpy(address, "www.torproject.org", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "1.1.1.1");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "1.1.1.1");
strlcpy(address, "other.torproject.org", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "this.torproject.org.otherserver.exit");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "this.torproject.org.otherserver.exit");
strlcpy(address, "test.torproject.org", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "2.2.2.2");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "2.2.2.2");
/* Test a chain of address mappings and the order in which they were added:
"MapAddress www.example.org 4.4.4.4"
@@ -111,17 +113,17 @@ test_config_addressmap(void *arg)
"MapAddress 4.4.4.4 5.5.5.5"
*/
strlcpy(address, "www.example.org", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "5.5.5.5");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "5.5.5.5");
/* Test infinite address mapping results in no change */
strlcpy(address, "www.infiniteloop.org", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "www.infiniteloop.org");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "www.infiniteloop.org");
/* Test we don't find false positives */
strlcpy(address, "www.example.com", sizeof(address));
- test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
/* Test top-level-domain matching a bit harder */
config_free_lines(get_options_mutable()->AddressMap);
@@ -134,24 +136,24 @@ test_config_addressmap(void *arg)
config_register_addressmaps(get_options());
strlcpy(address, "www.abc.com", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "www.abc.torserver.exit");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "www.abc.torserver.exit");
strlcpy(address, "www.def.com", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "www.def.torserver.exit");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "www.def.torserver.exit");
strlcpy(address, "www.torproject.org", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "1.1.1.1");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "1.1.1.1");
strlcpy(address, "test.torproject.org", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "1.1.1.1");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "1.1.1.1");
strlcpy(address, "torproject.net", sizeof(address));
- test_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
- test_streq(address, "2.2.2.2");
+ tt_assert(addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_str_op(address,OP_EQ, "2.2.2.2");
/* We don't support '*' as a mapping directive */
config_free_lines(get_options_mutable()->AddressMap);
@@ -161,19 +163,20 @@ test_config_addressmap(void *arg)
config_register_addressmaps(get_options());
strlcpy(address, "www.abc.com", sizeof(address));
- test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
strlcpy(address, "www.def.net", sizeof(address));
- test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
strlcpy(address, "www.torproject.org", sizeof(address));
- test_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
+ tt_assert(!addressmap_rewrite(address, sizeof(address), &expires, NULL));
#undef addressmap_rewrite
done:
config_free_lines(get_options_mutable()->AddressMap);
get_options_mutable()->AddressMap = NULL;
+ addressmap_free_all();
}
static int
@@ -184,7 +187,7 @@ is_private_dir(const char* path)
if (r) {
return 0;
}
-#if !defined (_WIN32) || defined (WINCE)
+#if !defined (_WIN32)
if ((st.st_mode & (S_IFDIR | 0777)) != (S_IFDIR | 0700)) {
return 0;
}
@@ -201,7 +204,7 @@ test_config_check_or_create_data_subdir(void *arg)
char *subpath;
struct stat st;
int r;
-#if !defined (_WIN32) || defined (WINCE)
+#if !defined (_WIN32)
unsigned group_permission;
#endif
(void)arg;
@@ -210,30 +213,30 @@ test_config_check_or_create_data_subdir(void *arg)
datadir = options->DataDirectory = tor_strdup(get_fname("datadir-0"));
subpath = get_datadir_fname(subdir);
-#if defined (_WIN32) && !defined (WINCE)
- tt_int_op(mkdir(options->DataDirectory), ==, 0);
+#if defined (_WIN32)
+ tt_int_op(mkdir(options->DataDirectory), OP_EQ, 0);
#else
- tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0);
+ tt_int_op(mkdir(options->DataDirectory, 0700), OP_EQ, 0);
#endif
r = stat(subpath, &st);
// The subdirectory shouldn't exist yet,
// but should be created by the call to check_or_create_data_subdir.
- test_assert(r && (errno == ENOENT));
- test_assert(!check_or_create_data_subdir(subdir));
- test_assert(is_private_dir(subpath));
+ tt_assert(r && (errno == ENOENT));
+ tt_assert(!check_or_create_data_subdir(subdir));
+ tt_assert(is_private_dir(subpath));
// The check should return 0, if the directory already exists
// and is private to the user.
- test_assert(!check_or_create_data_subdir(subdir));
+ tt_assert(!check_or_create_data_subdir(subdir));
r = stat(subpath, &st);
if (r) {
tt_abort_perror("stat");
}
-#if !defined (_WIN32) || defined (WINCE)
+#if !defined (_WIN32)
group_permission = st.st_mode | 0070;
r = chmod(subpath, group_permission);
@@ -243,9 +246,9 @@ test_config_check_or_create_data_subdir(void *arg)
// If the directory exists, but its mode is too permissive
// a call to check_or_create_data_subdir should reset the mode.
- test_assert(!is_private_dir(subpath));
- test_assert(!check_or_create_data_subdir(subdir));
- test_assert(is_private_dir(subpath));
+ tt_assert(!is_private_dir(subpath));
+ tt_assert(!check_or_create_data_subdir(subdir));
+ tt_assert(is_private_dir(subpath));
#endif
done:
@@ -284,27 +287,27 @@ test_config_write_to_data_subdir(void *arg)
datadir = options->DataDirectory = tor_strdup(get_fname("datadir-1"));
filepath = get_datadir_fname2(subdir, fname);
-#if defined (_WIN32) && !defined (WINCE)
- tt_int_op(mkdir(options->DataDirectory), ==, 0);
+#if defined (_WIN32)
+ tt_int_op(mkdir(options->DataDirectory), OP_EQ, 0);
#else
- tt_int_op(mkdir(options->DataDirectory, 0700), ==, 0);
+ tt_int_op(mkdir(options->DataDirectory, 0700), OP_EQ, 0);
#endif
// Write attempt shoudl fail, if subdirectory doesn't exist.
- test_assert(write_to_data_subdir(subdir, fname, str, NULL));
- test_assert(! check_or_create_data_subdir(subdir));
+ tt_assert(write_to_data_subdir(subdir, fname, str, NULL));
+ tt_assert(! check_or_create_data_subdir(subdir));
// Content of file after write attempt should be
// equal to the original string.
- test_assert(!write_to_data_subdir(subdir, fname, str, NULL));
+ tt_assert(!write_to_data_subdir(subdir, fname, str, NULL));
cp = read_file_to_str(filepath, 0, NULL);
- test_streq(cp, str);
+ tt_str_op(cp,OP_EQ, str);
tor_free(cp);
// A second write operation should overwrite the old content.
- test_assert(!write_to_data_subdir(subdir, fname, str, NULL));
+ tt_assert(!write_to_data_subdir(subdir, fname, str, NULL));
cp = read_file_to_str(filepath, 0, NULL);
- test_streq(cp, str);
+ tt_str_op(cp,OP_EQ, str);
tor_free(cp);
done:
@@ -325,48 +328,48 @@ good_bridge_line_test(const char *string, const char *test_addrport,
{
char *tmp = NULL;
bridge_line_t *bridge_line = parse_bridge_line(string);
- test_assert(bridge_line);
+ tt_assert(bridge_line);
/* test addrport */
tmp = tor_strdup(fmt_addrport(&bridge_line->addr, bridge_line->port));
- test_streq(test_addrport, tmp);
+ tt_str_op(test_addrport,OP_EQ, tmp);
tor_free(tmp);
/* If we were asked to validate a digest, but we did not get a
digest after parsing, we failed. */
if (test_digest && tor_digest_is_zero(bridge_line->digest))
- test_assert(0);
+ tt_assert(0);
/* If we were not asked to validate a digest, and we got a digest
after parsing, we failed again. */
if (!test_digest && !tor_digest_is_zero(bridge_line->digest))
- test_assert(0);
+ tt_assert(0);
/* If we were asked to validate a digest, and we got a digest after
parsing, make sure it's correct. */
if (test_digest) {
tmp = tor_strdup(hex_str(bridge_line->digest, DIGEST_LEN));
tor_strlower(tmp);
- test_streq(test_digest, tmp);
+ tt_str_op(test_digest,OP_EQ, tmp);
tor_free(tmp);
}
/* If we were asked to validate a transport name, make sure tha it
matches with the transport name that was parsed. */
if (test_transport && !bridge_line->transport_name)
- test_assert(0);
+ tt_assert(0);
if (!test_transport && bridge_line->transport_name)
- test_assert(0);
+ tt_assert(0);
if (test_transport)
- test_streq(test_transport, bridge_line->transport_name);
+ tt_str_op(test_transport,OP_EQ, bridge_line->transport_name);
/* Validate the SOCKS argument smartlist. */
if (test_socks_args && !bridge_line->socks_args)
- test_assert(0);
+ tt_assert(0);
if (!test_socks_args && bridge_line->socks_args)
- test_assert(0);
+ tt_assert(0);
if (test_socks_args)
- test_assert(smartlist_strings_eq(test_socks_args,
+ tt_assert(smartlist_strings_eq(test_socks_args,
bridge_line->socks_args));
done:
@@ -382,7 +385,7 @@ bad_bridge_line_test(const char *string)
bridge_line_t *bridge_line = parse_bridge_line(string);
if (bridge_line)
TT_FAIL(("%s was supposed to fail, but it didn't.", string));
- test_assert(!bridge_line);
+ tt_assert(!bridge_line);
done:
bridge_line_free(bridge_line);
@@ -490,18 +493,18 @@ test_config_parse_transport_options_line(void *arg)
{ /* too small line */
options_sl = get_options_from_transport_options_line("valley", NULL);
- test_assert(!options_sl);
+ tt_assert(!options_sl);
}
{ /* no k=v values */
options_sl = get_options_from_transport_options_line("hit it!", NULL);
- test_assert(!options_sl);
+ tt_assert(!options_sl);
}
{ /* correct line, but wrong transport specified */
options_sl =
get_options_from_transport_options_line("trebuchet k=v", "rook");
- test_assert(!options_sl);
+ tt_assert(!options_sl);
}
{ /* correct -- no transport specified */
@@ -512,8 +515,8 @@ test_config_parse_transport_options_line(void *arg)
options_sl =
get_options_from_transport_options_line("rook ladi=dadi weliketo=party",
NULL);
- test_assert(options_sl);
- test_assert(smartlist_strings_eq(options_sl, sl_tmp));
+ tt_assert(options_sl);
+ tt_assert(smartlist_strings_eq(options_sl, sl_tmp));
SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
smartlist_free(sl_tmp);
@@ -531,8 +534,8 @@ test_config_parse_transport_options_line(void *arg)
options_sl =
get_options_from_transport_options_line("rook ladi=dadi weliketo=party",
"rook");
- test_assert(options_sl);
- test_assert(smartlist_strings_eq(options_sl, sl_tmp));
+ tt_assert(options_sl);
+ tt_assert(smartlist_strings_eq(options_sl, sl_tmp));
SMARTLIST_FOREACH(sl_tmp, char *, s, tor_free(s));
smartlist_free(sl_tmp);
sl_tmp = NULL;
@@ -552,6 +555,269 @@ test_config_parse_transport_options_line(void *arg)
}
}
+/* Mocks needed for the transport plugin line test */
+
+static void pt_kickstart_proxy_mock(const smartlist_t *transport_list,
+ char **proxy_argv, int is_server);
+static int transport_add_from_config_mock(const tor_addr_t *addr,
+ uint16_t port, const char *name,
+ int socks_ver);
+static int transport_is_needed_mock(const char *transport_name);
+
+static int pt_kickstart_proxy_mock_call_count = 0;
+static int transport_add_from_config_mock_call_count = 0;
+static int transport_is_needed_mock_call_count = 0;
+static int transport_is_needed_mock_return = 0;
+
+static void
+pt_kickstart_proxy_mock(const smartlist_t *transport_list,
+ char **proxy_argv, int is_server)
+{
+ (void) transport_list;
+ (void) proxy_argv;
+ (void) is_server;
+ /* XXXX check that args are as expected. */
+
+ ++pt_kickstart_proxy_mock_call_count;
+
+ free_execve_args(proxy_argv);
+}
+
+static int
+transport_add_from_config_mock(const tor_addr_t *addr,
+ uint16_t port, const char *name,
+ int socks_ver)
+{
+ (void) addr;
+ (void) port;
+ (void) name;
+ (void) socks_ver;
+ /* XXXX check that args are as expected. */
+
+ ++transport_add_from_config_mock_call_count;
+
+ return 0;
+}
+
+static int
+transport_is_needed_mock(const char *transport_name)
+{
+ (void) transport_name;
+ /* XXXX check that arg is as expected. */
+
+ ++transport_is_needed_mock_call_count;
+
+ return transport_is_needed_mock_return;
+}
+
+/**
+ * Test parsing for the ClientTransportPlugin and ServerTransportPlugin config
+ * options.
+ */
+
+static void
+test_config_parse_transport_plugin_line(void *arg)
+{
+ (void)arg;
+
+ or_options_t *options = get_options_mutable();
+ int r, tmp;
+ int old_pt_kickstart_proxy_mock_call_count;
+ int old_transport_add_from_config_mock_call_count;
+ int old_transport_is_needed_mock_call_count;
+
+ /* Bad transport lines - too short */
+ r = parse_transport_line(options, "bad", 1, 0);
+ tt_assert(r < 0);
+ r = parse_transport_line(options, "bad", 1, 1);
+ tt_assert(r < 0);
+ r = parse_transport_line(options, "bad bad", 1, 0);
+ tt_assert(r < 0);
+ r = parse_transport_line(options, "bad bad", 1, 1);
+ tt_assert(r < 0);
+
+ /* Test transport list parsing */
+ r = parse_transport_line(options,
+ "transport_1 exec /usr/bin/fake-transport", 1, 0);
+ tt_assert(r == 0);
+ r = parse_transport_line(options,
+ "transport_1 exec /usr/bin/fake-transport", 1, 1);
+ tt_assert(r == 0);
+ r = parse_transport_line(options,
+ "transport_1,transport_2 exec /usr/bin/fake-transport", 1, 0);
+ tt_assert(r == 0);
+ r = parse_transport_line(options,
+ "transport_1,transport_2 exec /usr/bin/fake-transport", 1, 1);
+ tt_assert(r == 0);
+ /* Bad transport identifiers */
+ r = parse_transport_line(options,
+ "transport_* exec /usr/bin/fake-transport", 1, 0);
+ tt_assert(r < 0);
+ r = parse_transport_line(options,
+ "transport_* exec /usr/bin/fake-transport", 1, 1);
+ tt_assert(r < 0);
+
+ /* Check SOCKS cases for client transport */
+ r = parse_transport_line(options,
+ "transport_1 socks4 1.2.3.4:567", 1, 0);
+ tt_assert(r == 0);
+ r = parse_transport_line(options,
+ "transport_1 socks5 1.2.3.4:567", 1, 0);
+ tt_assert(r == 0);
+ /* Proxy case for server transport */
+ r = parse_transport_line(options,
+ "transport_1 proxy 1.2.3.4:567", 1, 1);
+ tt_assert(r == 0);
+ /* Multiple-transport error exit */
+ r = parse_transport_line(options,
+ "transport_1,transport_2 socks5 1.2.3.4:567", 1, 0);
+ tt_assert(r < 0);
+ r = parse_transport_line(options,
+ "transport_1,transport_2 proxy 1.2.3.4:567", 1, 1);
+ /* No port error exit */
+ r = parse_transport_line(options,
+ "transport_1 socks5 1.2.3.4", 1, 0);
+ tt_assert(r < 0);
+ r = parse_transport_line(options,
+ "transport_1 proxy 1.2.3.4", 1, 1);
+ tt_assert(r < 0);
+ /* Unparsable address error exit */
+ r = parse_transport_line(options,
+ "transport_1 socks5 1.2.3:6x7", 1, 0);
+ tt_assert(r < 0);
+ r = parse_transport_line(options,
+ "transport_1 proxy 1.2.3:6x7", 1, 1);
+ tt_assert(r < 0);
+
+ /* "Strange {Client|Server}TransportPlugin field" error exit */
+ r = parse_transport_line(options,
+ "transport_1 foo bar", 1, 0);
+ tt_assert(r < 0);
+ r = parse_transport_line(options,
+ "transport_1 foo bar", 1, 1);
+ tt_assert(r < 0);
+
+ /* No sandbox mode error exit */
+ tmp = options->Sandbox;
+ options->Sandbox = 1;
+ r = parse_transport_line(options,
+ "transport_1 exec /usr/bin/fake-transport", 1, 0);
+ tt_assert(r < 0);
+ r = parse_transport_line(options,
+ "transport_1 exec /usr/bin/fake-transport", 1, 1);
+ tt_assert(r < 0);
+ options->Sandbox = tmp;
+
+ /*
+ * These final test cases cover code paths that only activate without
+ * validate_only, so they need mocks in place.
+ */
+ MOCK(pt_kickstart_proxy, pt_kickstart_proxy_mock);
+ old_pt_kickstart_proxy_mock_call_count =
+ pt_kickstart_proxy_mock_call_count;
+ r = parse_transport_line(options,
+ "transport_1 exec /usr/bin/fake-transport", 0, 1);
+ tt_assert(r == 0);
+ tt_assert(pt_kickstart_proxy_mock_call_count ==
+ old_pt_kickstart_proxy_mock_call_count + 1);
+ UNMOCK(pt_kickstart_proxy);
+
+ /* This one hits a log line in the !validate_only case only */
+ r = parse_transport_line(options,
+ "transport_1 proxy 1.2.3.4:567", 0, 1);
+ tt_assert(r == 0);
+
+ /* Check mocked client transport cases */
+ MOCK(pt_kickstart_proxy, pt_kickstart_proxy_mock);
+ MOCK(transport_add_from_config, transport_add_from_config_mock);
+ MOCK(transport_is_needed, transport_is_needed_mock);
+
+ /* Unnecessary transport case */
+ transport_is_needed_mock_return = 0;
+ old_pt_kickstart_proxy_mock_call_count =
+ pt_kickstart_proxy_mock_call_count;
+ old_transport_add_from_config_mock_call_count =
+ transport_add_from_config_mock_call_count;
+ old_transport_is_needed_mock_call_count =
+ transport_is_needed_mock_call_count;
+ r = parse_transport_line(options,
+ "transport_1 exec /usr/bin/fake-transport", 0, 0);
+ /* Should have succeeded */
+ tt_assert(r == 0);
+ /* transport_is_needed() should have been called */
+ tt_assert(transport_is_needed_mock_call_count ==
+ old_transport_is_needed_mock_call_count + 1);
+ /*
+ * pt_kickstart_proxy() and transport_add_from_config() should
+ * not have been called.
+ */
+ tt_assert(pt_kickstart_proxy_mock_call_count ==
+ old_pt_kickstart_proxy_mock_call_count);
+ tt_assert(transport_add_from_config_mock_call_count ==
+ old_transport_add_from_config_mock_call_count);
+
+ /* Necessary transport case */
+ transport_is_needed_mock_return = 1;
+ old_pt_kickstart_proxy_mock_call_count =
+ pt_kickstart_proxy_mock_call_count;
+ old_transport_add_from_config_mock_call_count =
+ transport_add_from_config_mock_call_count;
+ old_transport_is_needed_mock_call_count =
+ transport_is_needed_mock_call_count;
+ r = parse_transport_line(options,
+ "transport_1 exec /usr/bin/fake-transport", 0, 0);
+ /* Should have succeeded */
+ tt_assert(r == 0);
+ /*
+ * transport_is_needed() and pt_kickstart_proxy() should have been
+ * called.
+ */
+ tt_assert(pt_kickstart_proxy_mock_call_count ==
+ old_pt_kickstart_proxy_mock_call_count + 1);
+ tt_assert(transport_is_needed_mock_call_count ==
+ old_transport_is_needed_mock_call_count + 1);
+ /* transport_add_from_config() should not have been called. */
+ tt_assert(transport_add_from_config_mock_call_count ==
+ old_transport_add_from_config_mock_call_count);
+
+ /* proxy case */
+ transport_is_needed_mock_return = 1;
+ old_pt_kickstart_proxy_mock_call_count =
+ pt_kickstart_proxy_mock_call_count;
+ old_transport_add_from_config_mock_call_count =
+ transport_add_from_config_mock_call_count;
+ old_transport_is_needed_mock_call_count =
+ transport_is_needed_mock_call_count;
+ r = parse_transport_line(options,
+ "transport_1 socks5 1.2.3.4:567", 0, 0);
+ /* Should have succeeded */
+ tt_assert(r == 0);
+ /*
+ * transport_is_needed() and transport_add_from_config() should have
+ * been called.
+ */
+ tt_assert(transport_add_from_config_mock_call_count ==
+ old_transport_add_from_config_mock_call_count + 1);
+ tt_assert(transport_is_needed_mock_call_count ==
+ old_transport_is_needed_mock_call_count + 1);
+ /* pt_kickstart_proxy() should not have been called. */
+ tt_assert(pt_kickstart_proxy_mock_call_count ==
+ old_pt_kickstart_proxy_mock_call_count);
+
+ /* Done with mocked client transport cases */
+ UNMOCK(transport_is_needed);
+ UNMOCK(transport_add_from_config);
+ UNMOCK(pt_kickstart_proxy);
+
+ done:
+ /* Make sure we undo all mocks */
+ UNMOCK(pt_kickstart_proxy);
+ UNMOCK(transport_add_from_config);
+ UNMOCK(transport_is_needed);
+
+ return;
+}
+
// Tests if an options with MyFamily fingerprints missing '$' normalises
// them correctly and also ensure it also works with multiple fingerprints
static void
@@ -576,7 +842,8 @@ test_config_fix_my_family(void *arg)
TT_FAIL(("options_validate failed: %s", err));
}
- test_streq(options->MyFamily, "$1111111111111111111111111111111111111111, "
+ tt_str_op(options->MyFamily,OP_EQ,
+ "$1111111111111111111111111111111111111111, "
"$1111111111111111111111111111111111111112, "
"$1111111111111111111111111111111111111113");
@@ -589,13 +856,602 @@ test_config_fix_my_family(void *arg)
or_options_free(defaults);
}
+static int n_hostname_01010101 = 0;
+
+/** This mock function is meant to replace tor_lookup_hostname().
+ * It answers with 1.1.1.1 as IP adddress that resulted from lookup.
+ * This function increments <b>n_hostname_01010101</b> counter by one
+ * every time it is called.
+ */
+static int
+tor_lookup_hostname_01010101(const char *name, uint32_t *addr)
+{
+ n_hostname_01010101++;
+
+ if (name && addr) {
+ *addr = ntohl(0x01010101);
+ }
+
+ return 0;
+}
+
+static int n_hostname_localhost = 0;
+
+/** This mock function is meant to replace tor_lookup_hostname().
+ * It answers with 127.0.0.1 as IP adddress that resulted from lookup.
+ * This function increments <b>n_hostname_localhost</b> counter by one
+ * every time it is called.
+ */
+static int
+tor_lookup_hostname_localhost(const char *name, uint32_t *addr)
+{
+ n_hostname_localhost++;
+
+ if (name && addr) {
+ *addr = 0x7f000001;
+ }
+
+ return 0;
+}
+
+static int n_hostname_failure = 0;
+
+/** This mock function is meant to replace tor_lookup_hostname().
+ * It pretends to fail by returning -1 to caller. Also, this function
+ * increments <b>n_hostname_failure</b> every time it is called.
+ */
+static int
+tor_lookup_hostname_failure(const char *name, uint32_t *addr)
+{
+ (void)name;
+ (void)addr;
+
+ n_hostname_failure++;
+
+ return -1;
+}
+
+static int n_gethostname_replacement = 0;
+
+/** This mock function is meant to replace tor_gethostname(). It
+ * responds with string "onionrouter!" as hostname. This function
+ * increments <b>n_gethostname_replacement</b> by one every time
+ * it is called.
+ */
+static int
+tor_gethostname_replacement(char *name, size_t namelen)
+{
+ n_gethostname_replacement++;
+
+ if (name && namelen) {
+ strlcpy(name,"onionrouter!",namelen);
+ }
+
+ return 0;
+}
+
+static int n_gethostname_localhost = 0;
+
+/** This mock function is meant to replace tor_gethostname(). It
+ * responds with string "127.0.0.1" as hostname. This function
+ * increments <b>n_gethostname_localhost</b> by one every time
+ * it is called.
+ */
+static int
+tor_gethostname_localhost(char *name, size_t namelen)
+{
+ n_gethostname_localhost++;
+
+ if (name && namelen) {
+ strlcpy(name,"127.0.0.1",namelen);
+ }
+
+ return 0;
+}
+
+static int n_gethostname_failure = 0;
+
+/** This mock function is meant to replace tor_gethostname.
+ * It pretends to fail by returning -1. This function increments
+ * <b>n_gethostname_failure</b> by one every time it is called.
+ */
+static int
+tor_gethostname_failure(char *name, size_t namelen)
+{
+ (void)name;
+ (void)namelen;
+ n_gethostname_failure++;
+
+ return -1;
+}
+
+static int n_get_interface_address = 0;
+
+/** This mock function is meant to replace get_interface_address().
+ * It answers with address 8.8.8.8. This function increments
+ * <b>n_get_interface_address</b> by one every time it is called.
+ */
+static int
+get_interface_address_08080808(int severity, uint32_t *addr)
+{
+ (void)severity;
+
+ n_get_interface_address++;
+
+ if (addr) {
+ *addr = ntohl(0x08080808);
+ }
+
+ return 0;
+}
+
+static int n_get_interface_address6 = 0;
+static sa_family_t last_address6_family;
+
+/** This mock function is meant to replace get_interface_address6().
+ * It answers with IP address 9.9.9.9 iff both of the following are true:
+ * - <b>family</b> is AF_INET
+ * - <b>addr</b> pointer is not NULL.
+ * This function increments <b>n_get_interface_address6</b> by one every
+ * time it is called.
+ */
+static int
+get_interface_address6_replacement(int severity, sa_family_t family,
+ tor_addr_t *addr)
+{
+ (void)severity;
+
+ last_address6_family = family;
+ n_get_interface_address6++;
+
+ if ((family != AF_INET) || !addr) {
+ return -1;
+ }
+
+ tor_addr_from_ipv4h(addr,0x09090909);
+
+ return 0;
+}
+
+static int n_get_interface_address_failure = 0;
+
+/**
+ * This mock function is meant to replace get_interface_address().
+ * It pretends to fail getting interface address by returning -1.
+ * <b>n_get_interface_address_failure</b> is incremented by one
+ * every time this function is called.
+ */
+static int
+get_interface_address_failure(int severity, uint32_t *addr)
+{
+ (void)severity;
+ (void)addr;
+
+ n_get_interface_address_failure++;
+
+ return -1;
+}
+
+static int n_get_interface_address6_failure = 0;
+
+/**
+ * This mock function is meant to replace get_interface_addres6().
+ * It will pretent to fail by return -1.
+ * <b>n_get_interface_address6_failure</b> is incremented by one
+ * every time this function is called and <b>last_address6_family</b>
+ * is assigned the value of <b>family</b> argument.
+ */
+static int
+get_interface_address6_failure(int severity, sa_family_t family,
+ tor_addr_t *addr)
+{
+ (void)severity;
+ (void)addr;
+ n_get_interface_address6_failure++;
+ last_address6_family = family;
+
+ return -1;
+}
+
+static void
+test_config_resolve_my_address(void *arg)
+{
+ or_options_t *options;
+ uint32_t resolved_addr;
+ const char *method_used;
+ char *hostname_out = NULL;
+ int retval;
+ int prev_n_hostname_01010101;
+ int prev_n_hostname_localhost;
+ int prev_n_hostname_failure;
+ int prev_n_gethostname_replacement;
+ int prev_n_gethostname_failure;
+ int prev_n_gethostname_localhost;
+ int prev_n_get_interface_address;
+ int prev_n_get_interface_address_failure;
+ int prev_n_get_interface_address6;
+ int prev_n_get_interface_address6_failure;
+
+ (void)arg;
+
+ options = options_new();
+
+ options_init(options);
+
+ /*
+ * CASE 1:
+ * If options->Address is a valid IPv4 address string, we want
+ * the corresponding address to be parsed and returned.
+ */
+
+ options->Address = tor_strdup("128.52.128.105");
+
+ retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(retval == 0);
+ tt_want_str_op(method_used,==,"CONFIGURED");
+ tt_want(hostname_out == NULL);
+ tt_assert(resolved_addr == 0x80348069);
+
+ tor_free(options->Address);
+
+/*
+ * CASE 2:
+ * If options->Address is a valid DNS address, we want resolve_my_address()
+ * function to ask tor_lookup_hostname() for help with resolving it
+ * and return the address that was resolved (in host order).
+ */
+
+ MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101);
+
+ tor_free(options->Address);
+ options->Address = tor_strdup("www.torproject.org");
+
+ prev_n_hostname_01010101 = n_hostname_01010101;
+
+ retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(retval == 0);
+ tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
+ tt_want_str_op(method_used,==,"RESOLVED");
+ tt_want_str_op(hostname_out,==,"www.torproject.org");
+ tt_assert(resolved_addr == 0x01010101);
+
+ UNMOCK(tor_lookup_hostname);
+
+ tor_free(options->Address);
+ tor_free(hostname_out);
+
+/*
+ * CASE 3:
+ * Given that options->Address is NULL, we want resolve_my_address()
+ * to try and use tor_gethostname() to get hostname AND use
+ * tor_lookup_hostname() to get IP address.
+ */
+
+ resolved_addr = 0;
+ tor_free(options->Address);
+ options->Address = NULL;
+
+ MOCK(tor_gethostname,tor_gethostname_replacement);
+ MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101);
+
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_hostname_01010101 = n_hostname_01010101;
+
+ retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(retval == 0);
+ tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
+ tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
+ tt_want_str_op(method_used,==,"GETHOSTNAME");
+ tt_want_str_op(hostname_out,==,"onionrouter!");
+ tt_assert(resolved_addr == 0x01010101);
+
+ UNMOCK(tor_gethostname);
+ UNMOCK(tor_lookup_hostname);
+
+ tor_free(hostname_out);
+
+/*
+ * CASE 4:
+ * Given that options->Address is a local host address, we want
+ * resolve_my_address() function to fail.
+ */
+
+ resolved_addr = 0;
+ tor_free(options->Address);
+ options->Address = tor_strdup("127.0.0.1");
+
+ retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(resolved_addr == 0);
+ tt_assert(retval == -1);
+
+ tor_free(options->Address);
+ tor_free(hostname_out);
+
+/*
+ * CASE 5:
+ * We want resolve_my_address() to fail if DNS address in options->Address
+ * cannot be resolved.
+ */
+
+ MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
+
+ prev_n_hostname_failure = n_hostname_failure;
+
+ tor_free(options->Address);
+ options->Address = tor_strdup("www.tor-project.org");
+
+ retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
+ tt_assert(retval == -1);
+
+ UNMOCK(tor_lookup_hostname);
+
+ tor_free(options->Address);
+ tor_free(hostname_out);
+
+/*
+ * CASE 6:
+ * If options->Address is NULL AND gettting local hostname fails, we want
+ * resolve_my_address() to fail as well.
+ */
+
+ MOCK(tor_gethostname,tor_gethostname_failure);
+
+ prev_n_gethostname_failure = n_gethostname_failure;
+
+ retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(n_gethostname_failure == prev_n_gethostname_failure + 1);
+ tt_assert(retval == -1);
+
+ UNMOCK(tor_gethostname);
+ tor_free(hostname_out);
+
+/*
+ * CASE 7:
+ * We want resolve_my_address() to try and get network interface address via
+ * get_interface_address() if hostname returned by tor_gethostname() cannot be
+ * resolved into IP address.
+ */
+
+ MOCK(tor_gethostname,tor_gethostname_replacement);
+ MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
+ MOCK(get_interface_address,get_interface_address_08080808);
+
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_get_interface_address = n_get_interface_address;
+
+ retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(retval == 0);
+ tt_want_int_op(n_gethostname_replacement, ==,
+ prev_n_gethostname_replacement + 1);
+ tt_want_int_op(n_get_interface_address, ==,
+ prev_n_get_interface_address + 1);
+ tt_want_str_op(method_used,==,"INTERFACE");
+ tt_want(hostname_out == NULL);
+ tt_assert(resolved_addr == 0x08080808);
+
+ UNMOCK(get_interface_address);
+ tor_free(hostname_out);
+
+/*
+ * CASE 8:
+ * Suppose options->Address is NULL AND hostname returned by tor_gethostname()
+ * is unresolvable. We want resolve_my_address to fail if
+ * get_interface_address() fails.
+ */
+
+ MOCK(get_interface_address,get_interface_address_failure);
+
+ prev_n_get_interface_address_failure = n_get_interface_address_failure;
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+
+ retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(n_get_interface_address_failure ==
+ prev_n_get_interface_address_failure + 1);
+ tt_want(n_gethostname_replacement ==
+ prev_n_gethostname_replacement + 1);
+ tt_assert(retval == -1);
+
+ UNMOCK(get_interface_address);
+ tor_free(hostname_out);
+
+/*
+ * CASE 9:
+ * Given that options->Address is NULL AND tor_lookup_hostname()
+ * fails AND hostname returned by gethostname() resolves
+ * to local IP address, we want resolve_my_address() function to
+ * call get_interface_address6(.,AF_INET,.) and return IP address
+ * the latter function has found.
+ */
+
+ MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
+ MOCK(tor_gethostname,tor_gethostname_replacement);
+ MOCK(get_interface_address6,get_interface_address6_replacement);
+
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_hostname_failure = n_hostname_failure;
+ prev_n_get_interface_address6 = n_get_interface_address6;
+
+ retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(last_address6_family == AF_INET);
+ tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1);
+ tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
+ tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
+ tt_want(retval == 0);
+ tt_want_str_op(method_used,==,"INTERFACE");
+ tt_assert(resolved_addr == 0x09090909);
+
+ UNMOCK(tor_lookup_hostname);
+ UNMOCK(tor_gethostname);
+ UNMOCK(get_interface_address6);
+
+ tor_free(hostname_out);
+
+ /*
+ * CASE 10: We want resolve_my_address() to fail if all of the following
+ * are true:
+ * 1. options->Address is not NULL
+ * 2. ... but it cannot be converted to struct in_addr by
+ * tor_inet_aton()
+ * 3. ... and tor_lookup_hostname() fails to resolve the
+ * options->Address
+ */
+
+ MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
+
+ prev_n_hostname_failure = n_hostname_failure;
+
+ tor_free(options->Address);
+ options->Address = tor_strdup("some_hostname");
+
+ retval = resolve_my_address(LOG_NOTICE, options, &resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
+ tt_assert(retval == -1);
+
+ UNMOCK(tor_gethostname);
+ UNMOCK(tor_lookup_hostname);
+
+ tor_free(hostname_out);
+
+ /*
+ * CASE 11:
+ * Suppose the following sequence of events:
+ * 1. options->Address is NULL
+ * 2. tor_gethostname() succeeds to get hostname of machine Tor
+ * if running on.
+ * 3. Hostname from previous step cannot be converted to
+ * address by using tor_inet_aton() function.
+ * 4. However, tor_lookup_hostname() succeds in resolving the
+ * hostname from step 2.
+ * 5. Unfortunately, tor_addr_is_internal() deems this address
+ * to be internal.
+ * 6. get_interface_address6(.,AF_INET,.) returns non-internal
+ * IPv4
+ *
+ * We want resolve_my_addr() to succeed with method "INTERFACE"
+ * and address from step 6.
+ */
+
+ tor_free(options->Address);
+ options->Address = NULL;
+
+ MOCK(tor_gethostname,tor_gethostname_replacement);
+ MOCK(tor_lookup_hostname,tor_lookup_hostname_localhost);
+ MOCK(get_interface_address6,get_interface_address6_replacement);
+
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_hostname_localhost = n_hostname_localhost;
+ prev_n_get_interface_address6 = n_get_interface_address6;
+
+ retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
+ tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1);
+ tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1);
+
+ tt_str_op(method_used,==,"INTERFACE");
+ tt_assert(!hostname_out);
+ tt_assert(retval == 0);
+
+ /*
+ * CASE 11b:
+ * 1-5 as above.
+ * 6. get_interface_address6() fails.
+ *
+ * In this subcase, we want resolve_my_address() to fail.
+ */
+
+ UNMOCK(get_interface_address6);
+ MOCK(get_interface_address6,get_interface_address6_failure);
+
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_hostname_localhost = n_hostname_localhost;
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+
+ retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
+ tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1);
+ tt_want(n_get_interface_address6_failure ==
+ prev_n_get_interface_address6_failure + 1);
+
+ tt_assert(retval == -1);
+
+ UNMOCK(tor_gethostname);
+ UNMOCK(tor_lookup_hostname);
+ UNMOCK(get_interface_address6);
+
+ /* CASE 12:
+ * Suppose the following happens:
+ * 1. options->Address is NULL AND options->DirAuthorities is 1.
+ * 2. tor_gethostname() succeeds in getting hostname of a machine ...
+ * 3. ... which is successfully parsed by tor_inet_aton() ...
+ * 4. into IPv4 address that tor_addr_is_inernal() considers to be
+ * internal.
+ *
+ * In this case, we want resolve_my_address() to fail.
+ */
+
+ tor_free(options->Address);
+ options->Address = NULL;
+ options->DirAuthorities = tor_malloc_zero(sizeof(config_line_t));
+
+ MOCK(tor_gethostname,tor_gethostname_localhost);
+
+ prev_n_gethostname_localhost = n_gethostname_localhost;
+
+ retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
+ &method_used,&hostname_out);
+
+ tt_want(n_gethostname_localhost == prev_n_gethostname_localhost + 1);
+ tt_assert(retval == -1);
+
+ UNMOCK(tor_gethostname);
+
+ done:
+ tor_free(options->Address);
+ tor_free(options->DirAuthorities);
+ or_options_free(options);
+ tor_free(hostname_out);
+
+ UNMOCK(tor_gethostname);
+ UNMOCK(tor_lookup_hostname);
+ UNMOCK(get_interface_address);
+ UNMOCK(get_interface_address6);
+ UNMOCK(tor_gethostname);
+}
+
#define CONFIG_TEST(name, flags) \
{ #name, test_config_ ## name, flags, NULL, NULL }
struct testcase_t config_tests[] = {
+ CONFIG_TEST(resolve_my_address, TT_FORK),
CONFIG_TEST(addressmap, 0),
CONFIG_TEST(parse_bridge_line, 0),
CONFIG_TEST(parse_transport_options_line, 0),
+ CONFIG_TEST(parse_transport_plugin_line, TT_FORK),
CONFIG_TEST(check_or_create_data_subdir, TT_FORK),
CONFIG_TEST(write_to_data_subdir, TT_FORK),
CONFIG_TEST(fix_my_family, 0),
diff --git a/src/test/test_containers.c b/src/test/test_containers.c
index 067c4c1907..79085a748e 100644
--- a/src/test/test_containers.c
+++ b/src/test/test_containers.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -29,7 +29,7 @@ compare_strs_for_bsearch_(const void *a, const void **b)
/** Helper: return a tristate based on comparing the strings in *<b>a</b> and
* *<b>b</b>, excluding a's first character, and ignoring case. */
static int
-compare_without_first_ch_(const void *a, const void **b)
+cmp_without_first_(const void *a, const void **b)
{
const char *s1 = a, *s2 = *b;
return strcasecmp(s1+1, s2);
@@ -37,237 +37,259 @@ compare_without_first_ch_(const void *a, const void **b)
/** Run unit tests for basic dynamic-sized array functionality. */
static void
-test_container_smartlist_basic(void)
+test_container_smartlist_basic(void *arg)
{
smartlist_t *sl;
+ char *v0 = tor_strdup("v0");
+ char *v1 = tor_strdup("v1");
+ char *v2 = tor_strdup("v2");
+ char *v3 = tor_strdup("v3");
+ char *v4 = tor_strdup("v4");
+ char *v22 = tor_strdup("v22");
+ char *v99 = tor_strdup("v99");
+ char *v555 = tor_strdup("v555");
/* XXXX test sort_digests, uniq_strings, uniq_digests */
/* Test smartlist add, del_keeporder, insert, get. */
+ (void)arg;
sl = smartlist_new();
- smartlist_add(sl, (void*)1);
- smartlist_add(sl, (void*)2);
- smartlist_add(sl, (void*)3);
- smartlist_add(sl, (void*)4);
+ smartlist_add(sl, v1);
+ smartlist_add(sl, v2);
+ smartlist_add(sl, v3);
+ smartlist_add(sl, v4);
smartlist_del_keeporder(sl, 1);
- smartlist_insert(sl, 1, (void*)22);
- smartlist_insert(sl, 0, (void*)0);
- smartlist_insert(sl, 5, (void*)555);
- test_eq_ptr((void*)0, smartlist_get(sl,0));
- test_eq_ptr((void*)1, smartlist_get(sl,1));
- test_eq_ptr((void*)22, smartlist_get(sl,2));
- test_eq_ptr((void*)3, smartlist_get(sl,3));
- test_eq_ptr((void*)4, smartlist_get(sl,4));
- test_eq_ptr((void*)555, smartlist_get(sl,5));
+ smartlist_insert(sl, 1, v22);
+ smartlist_insert(sl, 0, v0);
+ smartlist_insert(sl, 5, v555);
+ tt_ptr_op(v0,OP_EQ, smartlist_get(sl,0));
+ tt_ptr_op(v1,OP_EQ, smartlist_get(sl,1));
+ tt_ptr_op(v22,OP_EQ, smartlist_get(sl,2));
+ tt_ptr_op(v3,OP_EQ, smartlist_get(sl,3));
+ tt_ptr_op(v4,OP_EQ, smartlist_get(sl,4));
+ tt_ptr_op(v555,OP_EQ, smartlist_get(sl,5));
/* Try deleting in the middle. */
smartlist_del(sl, 1);
- test_eq_ptr((void*)555, smartlist_get(sl, 1));
+ tt_ptr_op(v555,OP_EQ, smartlist_get(sl, 1));
/* Try deleting at the end. */
smartlist_del(sl, 4);
- test_eq(4, smartlist_len(sl));
+ tt_int_op(4,OP_EQ, smartlist_len(sl));
/* test isin. */
- test_assert(smartlist_contains(sl, (void*)3));
- test_assert(!smartlist_contains(sl, (void*)99));
+ tt_assert(smartlist_contains(sl, v3));
+ tt_assert(!smartlist_contains(sl, v99));
done:
smartlist_free(sl);
+ tor_free(v0);
+ tor_free(v1);
+ tor_free(v2);
+ tor_free(v3);
+ tor_free(v4);
+ tor_free(v22);
+ tor_free(v99);
+ tor_free(v555);
}
/** Run unit tests for smartlist-of-strings functionality. */
static void
-test_container_smartlist_strings(void)
+test_container_smartlist_strings(void *arg)
{
smartlist_t *sl = smartlist_new();
char *cp=NULL, *cp_alloc=NULL;
size_t sz;
/* Test split and join */
- test_eq(0, smartlist_len(sl));
+ (void)arg;
+ tt_int_op(0,OP_EQ, smartlist_len(sl));
smartlist_split_string(sl, "abc", ":", 0, 0);
- test_eq(1, smartlist_len(sl));
- test_streq("abc", smartlist_get(sl, 0));
+ tt_int_op(1,OP_EQ, smartlist_len(sl));
+ tt_str_op("abc",OP_EQ, smartlist_get(sl, 0));
smartlist_split_string(sl, "a::bc::", "::", 0, 0);
- test_eq(4, smartlist_len(sl));
- test_streq("a", smartlist_get(sl, 1));
- test_streq("bc", smartlist_get(sl, 2));
- test_streq("", smartlist_get(sl, 3));
+ tt_int_op(4,OP_EQ, smartlist_len(sl));
+ tt_str_op("a",OP_EQ, smartlist_get(sl, 1));
+ tt_str_op("bc",OP_EQ, smartlist_get(sl, 2));
+ tt_str_op("",OP_EQ, smartlist_get(sl, 3));
cp_alloc = smartlist_join_strings(sl, "", 0, NULL);
- test_streq(cp_alloc, "abcabc");
+ tt_str_op(cp_alloc,OP_EQ, "abcabc");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "!", 0, NULL);
- test_streq(cp_alloc, "abc!a!bc!");
+ tt_str_op(cp_alloc,OP_EQ, "abc!a!bc!");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL);
- test_streq(cp_alloc, "abcXYaXYbcXY");
+ tt_str_op(cp_alloc,OP_EQ, "abcXYaXYbcXY");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL);
- test_streq(cp_alloc, "abcXYaXYbcXYXY");
+ tt_str_op(cp_alloc,OP_EQ, "abcXYaXYbcXYXY");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "", 1, NULL);
- test_streq(cp_alloc, "abcabc");
+ tt_str_op(cp_alloc,OP_EQ, "abcabc");
tor_free(cp_alloc);
smartlist_split_string(sl, "/def/ /ghijk", "/", 0, 0);
- test_eq(8, smartlist_len(sl));
- test_streq("", smartlist_get(sl, 4));
- test_streq("def", smartlist_get(sl, 5));
- test_streq(" ", smartlist_get(sl, 6));
- test_streq("ghijk", smartlist_get(sl, 7));
+ tt_int_op(8,OP_EQ, smartlist_len(sl));
+ tt_str_op("",OP_EQ, smartlist_get(sl, 4));
+ tt_str_op("def",OP_EQ, smartlist_get(sl, 5));
+ tt_str_op(" ",OP_EQ, smartlist_get(sl, 6));
+ tt_str_op("ghijk",OP_EQ, smartlist_get(sl, 7));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
smartlist_split_string(sl, "a,bbd,cdef", ",", SPLIT_SKIP_SPACE, 0);
- test_eq(3, smartlist_len(sl));
- test_streq("a", smartlist_get(sl,0));
- test_streq("bbd", smartlist_get(sl,1));
- test_streq("cdef", smartlist_get(sl,2));
+ tt_int_op(3,OP_EQ, smartlist_len(sl));
+ tt_str_op("a",OP_EQ, smartlist_get(sl,0));
+ tt_str_op("bbd",OP_EQ, smartlist_get(sl,1));
+ tt_str_op("cdef",OP_EQ, smartlist_get(sl,2));
smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>",
SPLIT_SKIP_SPACE, 0);
- test_eq(8, smartlist_len(sl));
- test_streq("z", smartlist_get(sl,3));
- test_streq("zhasd", smartlist_get(sl,4));
- test_streq("", smartlist_get(sl,5));
- test_streq("bnud", smartlist_get(sl,6));
- test_streq("", smartlist_get(sl,7));
+ tt_int_op(8,OP_EQ, smartlist_len(sl));
+ tt_str_op("z",OP_EQ, smartlist_get(sl,3));
+ tt_str_op("zhasd",OP_EQ, smartlist_get(sl,4));
+ tt_str_op("",OP_EQ, smartlist_get(sl,5));
+ tt_str_op("bnud",OP_EQ, smartlist_get(sl,6));
+ tt_str_op("",OP_EQ, smartlist_get(sl,7));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
smartlist_split_string(sl, " ab\tc \td ef ", NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- test_eq(4, smartlist_len(sl));
- test_streq("ab", smartlist_get(sl,0));
- test_streq("c", smartlist_get(sl,1));
- test_streq("d", smartlist_get(sl,2));
- test_streq("ef", smartlist_get(sl,3));
+ tt_int_op(4,OP_EQ, smartlist_len(sl));
+ tt_str_op("ab",OP_EQ, smartlist_get(sl,0));
+ tt_str_op("c",OP_EQ, smartlist_get(sl,1));
+ tt_str_op("d",OP_EQ, smartlist_get(sl,2));
+ tt_str_op("ef",OP_EQ, smartlist_get(sl,3));
smartlist_split_string(sl, "ghi\tj", NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- test_eq(6, smartlist_len(sl));
- test_streq("ghi", smartlist_get(sl,4));
- test_streq("j", smartlist_get(sl,5));
+ tt_int_op(6,OP_EQ, smartlist_len(sl));
+ tt_str_op("ghi",OP_EQ, smartlist_get(sl,4));
+ tt_str_op("j",OP_EQ, smartlist_get(sl,5));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
cp_alloc = smartlist_join_strings(sl, "XY", 0, NULL);
- test_streq(cp_alloc, "");
+ tt_str_op(cp_alloc,OP_EQ, "");
tor_free(cp_alloc);
cp_alloc = smartlist_join_strings(sl, "XY", 1, NULL);
- test_streq(cp_alloc, "XY");
+ tt_str_op(cp_alloc,OP_EQ, "XY");
tor_free(cp_alloc);
smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- test_eq(3, smartlist_len(sl));
- test_streq("z", smartlist_get(sl, 0));
- test_streq("zhasd", smartlist_get(sl, 1));
- test_streq("bnud", smartlist_get(sl, 2));
+ tt_int_op(3,OP_EQ, smartlist_len(sl));
+ tt_str_op("z",OP_EQ, smartlist_get(sl, 0));
+ tt_str_op("zhasd",OP_EQ, smartlist_get(sl, 1));
+ tt_str_op("bnud",OP_EQ, smartlist_get(sl, 2));
smartlist_split_string(sl, " z <> zhasd <> <> bnud<> ", "<>",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
- test_eq(5, smartlist_len(sl));
- test_streq("z", smartlist_get(sl, 3));
- test_streq("zhasd <> <> bnud<>", smartlist_get(sl, 4));
+ tt_int_op(5,OP_EQ, smartlist_len(sl));
+ tt_str_op("z",OP_EQ, smartlist_get(sl, 3));
+ tt_str_op("zhasd <> <> bnud<>",OP_EQ, smartlist_get(sl, 4));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
smartlist_split_string(sl, "abcd\n", "\n",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- test_eq(1, smartlist_len(sl));
- test_streq("abcd", smartlist_get(sl, 0));
+ tt_int_op(1,OP_EQ, smartlist_len(sl));
+ tt_str_op("abcd",OP_EQ, smartlist_get(sl, 0));
smartlist_split_string(sl, "efgh", "\n",
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
- test_eq(2, smartlist_len(sl));
- test_streq("efgh", smartlist_get(sl, 1));
+ tt_int_op(2,OP_EQ, smartlist_len(sl));
+ tt_str_op("efgh",OP_EQ, smartlist_get(sl, 1));
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* Test swapping, shuffling, and sorting. */
smartlist_split_string(sl, "the,onion,router,by,arma,and,nickm", ",", 0, 0);
- test_eq(7, smartlist_len(sl));
+ tt_int_op(7,OP_EQ, smartlist_len(sl));
smartlist_sort(sl, compare_strs_);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
- test_streq(cp_alloc,"and,arma,by,nickm,onion,router,the");
+ tt_str_op(cp_alloc,OP_EQ, "and,arma,by,nickm,onion,router,the");
tor_free(cp_alloc);
smartlist_swap(sl, 1, 5);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
- test_streq(cp_alloc,"and,router,by,nickm,onion,arma,the");
+ tt_str_op(cp_alloc,OP_EQ, "and,router,by,nickm,onion,arma,the");
tor_free(cp_alloc);
smartlist_shuffle(sl);
- test_eq(7, smartlist_len(sl));
- test_assert(smartlist_contains_string(sl, "and"));
- test_assert(smartlist_contains_string(sl, "router"));
- test_assert(smartlist_contains_string(sl, "by"));
- test_assert(smartlist_contains_string(sl, "nickm"));
- test_assert(smartlist_contains_string(sl, "onion"));
- test_assert(smartlist_contains_string(sl, "arma"));
- test_assert(smartlist_contains_string(sl, "the"));
+ tt_int_op(7,OP_EQ, smartlist_len(sl));
+ tt_assert(smartlist_contains_string(sl, "and"));
+ tt_assert(smartlist_contains_string(sl, "router"));
+ tt_assert(smartlist_contains_string(sl, "by"));
+ tt_assert(smartlist_contains_string(sl, "nickm"));
+ tt_assert(smartlist_contains_string(sl, "onion"));
+ tt_assert(smartlist_contains_string(sl, "arma"));
+ tt_assert(smartlist_contains_string(sl, "the"));
/* Test bsearch. */
smartlist_sort(sl, compare_strs_);
- test_streq("nickm", smartlist_bsearch(sl, "zNicKM",
- compare_without_first_ch_));
- test_streq("and", smartlist_bsearch(sl, " AND", compare_without_first_ch_));
- test_eq_ptr(NULL, smartlist_bsearch(sl, " ANz", compare_without_first_ch_));
+ tt_str_op("nickm",OP_EQ, smartlist_bsearch(sl, "zNicKM",
+ cmp_without_first_));
+ tt_str_op("and",OP_EQ,
+ smartlist_bsearch(sl, " AND", cmp_without_first_));
+ tt_ptr_op(NULL,OP_EQ, smartlist_bsearch(sl, " ANz", cmp_without_first_));
/* Test bsearch_idx */
{
int f;
smartlist_t *tmp = NULL;
- test_eq(0, smartlist_bsearch_idx(sl," aaa",compare_without_first_ch_,&f));
- test_eq(f, 0);
- test_eq(0, smartlist_bsearch_idx(sl," and",compare_without_first_ch_,&f));
- test_eq(f, 1);
- test_eq(1, smartlist_bsearch_idx(sl," arm",compare_without_first_ch_,&f));
- test_eq(f, 0);
- test_eq(1, smartlist_bsearch_idx(sl," arma",compare_without_first_ch_,&f));
- test_eq(f, 1);
- test_eq(2, smartlist_bsearch_idx(sl," armb",compare_without_first_ch_,&f));
- test_eq(f, 0);
- test_eq(7, smartlist_bsearch_idx(sl," zzzz",compare_without_first_ch_,&f));
- test_eq(f, 0);
+ tt_int_op(0,OP_EQ,smartlist_bsearch_idx(sl," aaa",cmp_without_first_,&f));
+ tt_int_op(f,OP_EQ, 0);
+ tt_int_op(0,OP_EQ, smartlist_bsearch_idx(sl," and",cmp_without_first_,&f));
+ tt_int_op(f,OP_EQ, 1);
+ tt_int_op(1,OP_EQ, smartlist_bsearch_idx(sl," arm",cmp_without_first_,&f));
+ tt_int_op(f,OP_EQ, 0);
+ tt_int_op(1,OP_EQ,
+ smartlist_bsearch_idx(sl," arma",cmp_without_first_,&f));
+ tt_int_op(f,OP_EQ, 1);
+ tt_int_op(2,OP_EQ,
+ smartlist_bsearch_idx(sl," armb",cmp_without_first_,&f));
+ tt_int_op(f,OP_EQ, 0);
+ tt_int_op(7,OP_EQ,
+ smartlist_bsearch_idx(sl," zzzz",cmp_without_first_,&f));
+ tt_int_op(f,OP_EQ, 0);
/* Test trivial cases for list of length 0 or 1 */
tmp = smartlist_new();
- test_eq(0, smartlist_bsearch_idx(tmp, "foo",
+ tt_int_op(0,OP_EQ, smartlist_bsearch_idx(tmp, "foo",
compare_strs_for_bsearch_, &f));
- test_eq(f, 0);
+ tt_int_op(f,OP_EQ, 0);
smartlist_insert(tmp, 0, (void *)("bar"));
- test_eq(1, smartlist_bsearch_idx(tmp, "foo",
+ tt_int_op(1,OP_EQ, smartlist_bsearch_idx(tmp, "foo",
compare_strs_for_bsearch_, &f));
- test_eq(f, 0);
- test_eq(0, smartlist_bsearch_idx(tmp, "aaa",
+ tt_int_op(f,OP_EQ, 0);
+ tt_int_op(0,OP_EQ, smartlist_bsearch_idx(tmp, "aaa",
compare_strs_for_bsearch_, &f));
- test_eq(f, 0);
- test_eq(0, smartlist_bsearch_idx(tmp, "bar",
+ tt_int_op(f,OP_EQ, 0);
+ tt_int_op(0,OP_EQ, smartlist_bsearch_idx(tmp, "bar",
compare_strs_for_bsearch_, &f));
- test_eq(f, 1);
+ tt_int_op(f,OP_EQ, 1);
/* ... and one for length 2 */
smartlist_insert(tmp, 1, (void *)("foo"));
- test_eq(1, smartlist_bsearch_idx(tmp, "foo",
+ tt_int_op(1,OP_EQ, smartlist_bsearch_idx(tmp, "foo",
compare_strs_for_bsearch_, &f));
- test_eq(f, 1);
- test_eq(2, smartlist_bsearch_idx(tmp, "goo",
+ tt_int_op(f,OP_EQ, 1);
+ tt_int_op(2,OP_EQ, smartlist_bsearch_idx(tmp, "goo",
compare_strs_for_bsearch_, &f));
- test_eq(f, 0);
+ tt_int_op(f,OP_EQ, 0);
smartlist_free(tmp);
}
/* Test reverse() and pop_last() */
smartlist_reverse(sl);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
- test_streq(cp_alloc,"the,router,onion,nickm,by,arma,and");
+ tt_str_op(cp_alloc,OP_EQ, "the,router,onion,nickm,by,arma,and");
tor_free(cp_alloc);
cp_alloc = smartlist_pop_last(sl);
- test_streq(cp_alloc, "and");
+ tt_str_op(cp_alloc,OP_EQ, "and");
tor_free(cp_alloc);
- test_eq(smartlist_len(sl), 6);
+ tt_int_op(smartlist_len(sl),OP_EQ, 6);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
cp_alloc = smartlist_pop_last(sl);
- test_eq_ptr(cp_alloc, NULL);
+ tt_ptr_op(cp_alloc,OP_EQ, NULL);
/* Test uniq() */
smartlist_split_string(sl,
@@ -276,16 +298,16 @@ test_container_smartlist_strings(void)
smartlist_sort(sl, compare_strs_);
smartlist_uniq(sl, compare_strs_, tor_free_);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
- test_streq(cp_alloc, "50,a,canal,man,noon,panama,plan,radar");
+ tt_str_op(cp_alloc,OP_EQ, "50,a,canal,man,noon,panama,plan,radar");
tor_free(cp_alloc);
/* Test contains_string, contains_string_case and contains_int_as_string */
- test_assert(smartlist_contains_string(sl, "noon"));
- test_assert(!smartlist_contains_string(sl, "noonoon"));
- test_assert(smartlist_contains_string_case(sl, "nOOn"));
- test_assert(!smartlist_contains_string_case(sl, "nooNooN"));
- test_assert(smartlist_contains_int_as_string(sl, 50));
- test_assert(!smartlist_contains_int_as_string(sl, 60));
+ tt_assert(smartlist_contains_string(sl, "noon"));
+ tt_assert(!smartlist_contains_string(sl, "noonoon"));
+ tt_assert(smartlist_contains_string_case(sl, "nOOn"));
+ tt_assert(!smartlist_contains_string_case(sl, "nooNooN"));
+ tt_assert(smartlist_contains_int_as_string(sl, 50));
+ tt_assert(!smartlist_contains_int_as_string(sl, 60));
/* Test smartlist_choose */
{
@@ -293,7 +315,7 @@ test_container_smartlist_strings(void)
int allsame = 1;
int allin = 1;
void *first = smartlist_choose(sl);
- test_assert(smartlist_contains(sl, first));
+ tt_assert(smartlist_contains(sl, first));
for (i = 0; i < 100; ++i) {
void *second = smartlist_choose(sl);
if (second != first)
@@ -301,8 +323,8 @@ test_container_smartlist_strings(void)
if (!smartlist_contains(sl, second))
allin = 0;
}
- test_assert(!allsame);
- test_assert(allin);
+ tt_assert(!allsame);
+ tt_assert(allin);
}
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
@@ -312,17 +334,17 @@ test_container_smartlist_strings(void)
"Some say the Earth will end in ice and some in fire",
" ", 0, 0);
cp = smartlist_get(sl, 4);
- test_streq(cp, "will");
+ tt_str_op(cp,OP_EQ, "will");
smartlist_add(sl, cp);
smartlist_remove(sl, cp);
tor_free(cp);
cp_alloc = smartlist_join_strings(sl, ",", 0, NULL);
- test_streq(cp_alloc, "Some,say,the,Earth,fire,end,in,ice,and,some,in");
+ tt_str_op(cp_alloc,OP_EQ, "Some,say,the,Earth,fire,end,in,ice,and,some,in");
tor_free(cp_alloc);
smartlist_string_remove(sl, "in");
cp_alloc = smartlist_join_strings2(sl, "+XX", 1, 0, &sz);
- test_streq(cp_alloc, "Some+say+the+Earth+fire+end+some+ice+and");
- test_eq((int)sz, 40);
+ tt_str_op(cp_alloc,OP_EQ, "Some+say+the+Earth+fire+end+some+ice+and");
+ tt_int_op((int)sz,OP_EQ, 40);
done:
@@ -333,7 +355,7 @@ test_container_smartlist_strings(void)
/** Run unit tests for smartlist set manipulation functions. */
static void
-test_container_smartlist_overlap(void)
+test_container_smartlist_overlap(void *arg)
{
smartlist_t *sl = smartlist_new();
smartlist_t *ints = smartlist_new();
@@ -341,6 +363,7 @@ test_container_smartlist_overlap(void)
smartlist_t *evens = smartlist_new();
smartlist_t *primes = smartlist_new();
int i;
+ (void)arg;
for (i=1; i < 10; i += 2)
smartlist_add(odds, (void*)(uintptr_t)i);
for (i=0; i < 10; i += 2)
@@ -349,7 +372,7 @@ test_container_smartlist_overlap(void)
/* add_all */
smartlist_add_all(ints, odds);
smartlist_add_all(ints, evens);
- test_eq(smartlist_len(ints), 10);
+ tt_int_op(smartlist_len(ints),OP_EQ, 10);
smartlist_add(primes, (void*)2);
smartlist_add(primes, (void*)3);
@@ -357,24 +380,24 @@ test_container_smartlist_overlap(void)
smartlist_add(primes, (void*)7);
/* overlap */
- test_assert(smartlist_overlap(ints, odds));
- test_assert(smartlist_overlap(odds, primes));
- test_assert(smartlist_overlap(evens, primes));
- test_assert(!smartlist_overlap(odds, evens));
+ tt_assert(smartlist_overlap(ints, odds));
+ tt_assert(smartlist_overlap(odds, primes));
+ tt_assert(smartlist_overlap(evens, primes));
+ tt_assert(!smartlist_overlap(odds, evens));
/* intersect */
smartlist_add_all(sl, odds);
smartlist_intersect(sl, primes);
- test_eq(smartlist_len(sl), 3);
- test_assert(smartlist_contains(sl, (void*)3));
- test_assert(smartlist_contains(sl, (void*)5));
- test_assert(smartlist_contains(sl, (void*)7));
+ tt_int_op(smartlist_len(sl),OP_EQ, 3);
+ tt_assert(smartlist_contains(sl, (void*)3));
+ tt_assert(smartlist_contains(sl, (void*)5));
+ tt_assert(smartlist_contains(sl, (void*)7));
/* subtract */
smartlist_add_all(sl, primes);
smartlist_subtract(sl, odds);
- test_eq(smartlist_len(sl), 1);
- test_assert(smartlist_contains(sl, (void*)2));
+ tt_int_op(smartlist_len(sl),OP_EQ, 1);
+ tt_assert(smartlist_contains(sl, (void*)2));
done:
smartlist_free(odds);
@@ -386,31 +409,32 @@ test_container_smartlist_overlap(void)
/** Run unit tests for smartlist-of-digests functions. */
static void
-test_container_smartlist_digests(void)
+test_container_smartlist_digests(void *arg)
{
smartlist_t *sl = smartlist_new();
/* contains_digest */
+ (void)arg;
smartlist_add(sl, tor_memdup("AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN));
smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN));
smartlist_add(sl, tor_memdup("\00090AAB2AAAAaasdAAAAA", DIGEST_LEN));
- test_eq(0, smartlist_contains_digest(NULL, "AAAAAAAAAAAAAAAAAAAA"));
- test_assert(smartlist_contains_digest(sl, "AAAAAAAAAAAAAAAAAAAA"));
- test_assert(smartlist_contains_digest(sl, "\00090AAB2AAAAaasdAAAAA"));
- test_eq(0, smartlist_contains_digest(sl, "\00090AAB2AAABaasdAAAAA"));
+ tt_int_op(0,OP_EQ, smartlist_contains_digest(NULL, "AAAAAAAAAAAAAAAAAAAA"));
+ tt_assert(smartlist_contains_digest(sl, "AAAAAAAAAAAAAAAAAAAA"));
+ tt_assert(smartlist_contains_digest(sl, "\00090AAB2AAAAaasdAAAAA"));
+ tt_int_op(0,OP_EQ, smartlist_contains_digest(sl, "\00090AAB2AAABaasdAAAAA"));
/* sort digests */
smartlist_sort_digests(sl);
- test_memeq(smartlist_get(sl, 0), "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN);
- test_memeq(smartlist_get(sl, 1), "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN);
- test_memeq(smartlist_get(sl, 2), "AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN);
- test_eq(3, smartlist_len(sl));
+ tt_mem_op(smartlist_get(sl, 0),OP_EQ, "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN);
+ tt_mem_op(smartlist_get(sl, 1),OP_EQ, "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN);
+ tt_mem_op(smartlist_get(sl, 2),OP_EQ, "AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN);
+ tt_int_op(3,OP_EQ, smartlist_len(sl));
/* uniq_digests */
smartlist_uniq_digests(sl);
- test_eq(2, smartlist_len(sl));
- test_memeq(smartlist_get(sl, 0), "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN);
- test_memeq(smartlist_get(sl, 1), "AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN);
+ tt_int_op(2,OP_EQ, smartlist_len(sl));
+ tt_mem_op(smartlist_get(sl, 0),OP_EQ, "\00090AAB2AAAAaasdAAAAA", DIGEST_LEN);
+ tt_mem_op(smartlist_get(sl, 1),OP_EQ, "AAAAAAAAAAAAAAAAAAAA", DIGEST_LEN);
done:
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
@@ -419,13 +443,14 @@ test_container_smartlist_digests(void)
/** Run unit tests for concatenate-a-smartlist-of-strings functions. */
static void
-test_container_smartlist_join(void)
+test_container_smartlist_join(void *arg)
{
smartlist_t *sl = smartlist_new();
smartlist_t *sl2 = smartlist_new(), *sl3 = smartlist_new(),
*sl4 = smartlist_new();
char *joined=NULL;
/* unique, sorted. */
+ (void)arg;
smartlist_split_string(sl,
"Abashments Ambush Anchorman Bacon Banks Borscht "
"Bunks Inhumane Insurance Knish Know Manners "
@@ -441,21 +466,22 @@ test_container_smartlist_join(void)
sl2, char *, cp2,
strcmp(cp1,cp2),
smartlist_add(sl3, cp2)) {
- test_streq(cp1, cp2);
+ tt_str_op(cp1,OP_EQ, cp2);
smartlist_add(sl4, cp1);
} SMARTLIST_FOREACH_JOIN_END(cp1, cp2);
SMARTLIST_FOREACH(sl3, const char *, cp,
- test_assert(smartlist_contains(sl2, cp) &&
+ tt_assert(smartlist_contains(sl2, cp) &&
!smartlist_contains_string(sl, cp)));
SMARTLIST_FOREACH(sl4, const char *, cp,
- test_assert(smartlist_contains(sl, cp) &&
+ tt_assert(smartlist_contains(sl, cp) &&
smartlist_contains_string(sl2, cp)));
joined = smartlist_join_strings(sl3, ",", 0, NULL);
- test_streq(joined, "Anemias,Anemias,Crossbowmen,Work");
+ tt_str_op(joined,OP_EQ, "Anemias,Anemias,Crossbowmen,Work");
tor_free(joined);
joined = smartlist_join_strings(sl4, ",", 0, NULL);
- test_streq(joined, "Ambush,Anchorman,Anchorman,Bacon,Inhumane,Insurance,"
+ tt_str_op(joined,OP_EQ,
+ "Ambush,Anchorman,Anchorman,Bacon,Inhumane,Insurance,"
"Knish,Know,Manners,Manners,Maraschinos,Wombats,Wombats");
tor_free(joined);
@@ -516,18 +542,19 @@ test_container_smartlist_ints_eq(void *arg)
/** Run unit tests for bitarray code */
static void
-test_container_bitarray(void)
+test_container_bitarray(void *arg)
{
bitarray_t *ba = NULL;
int i, j, ok=1;
+ (void)arg;
ba = bitarray_init_zero(1);
- test_assert(ba);
- test_assert(! bitarray_is_set(ba, 0));
+ tt_assert(ba);
+ tt_assert(! bitarray_is_set(ba, 0));
bitarray_set(ba, 0);
- test_assert(bitarray_is_set(ba, 0));
+ tt_assert(bitarray_is_set(ba, 0));
bitarray_clear(ba, 0);
- test_assert(! bitarray_is_set(ba, 0));
+ tt_assert(! bitarray_is_set(ba, 0));
bitarray_free(ba);
ba = bitarray_init_zero(1023);
@@ -542,7 +569,7 @@ test_container_bitarray(void)
if (!bool_eq(bitarray_is_set(ba, j), j%i))
ok = 0;
}
- test_assert(ok);
+ tt_assert(ok);
if (i < 7)
++i;
else if (i == 28)
@@ -559,7 +586,7 @@ test_container_bitarray(void)
/** Run unit tests for digest set code (implemented as a hashtable or as a
* bloom filter) */
static void
-test_container_digestset(void)
+test_container_digestset(void *arg)
{
smartlist_t *included = smartlist_new();
char d[DIGEST_LEN];
@@ -568,6 +595,7 @@ test_container_digestset(void)
int false_positives = 0;
digestset_t *set = NULL;
+ (void)arg;
for (i = 0; i < 1000; ++i) {
crypto_rand(d, DIGEST_LEN);
smartlist_add(included, tor_memdup(d, DIGEST_LEN));
@@ -576,19 +604,19 @@ test_container_digestset(void)
SMARTLIST_FOREACH(included, const char *, cp,
if (digestset_contains(set, cp))
ok = 0);
- test_assert(ok);
+ tt_assert(ok);
SMARTLIST_FOREACH(included, const char *, cp,
digestset_add(set, cp));
SMARTLIST_FOREACH(included, const char *, cp,
if (!digestset_contains(set, cp))
ok = 0);
- test_assert(ok);
+ tt_assert(ok);
for (i = 0; i < 1000; ++i) {
crypto_rand(d, DIGEST_LEN);
if (digestset_contains(set, d))
++false_positives;
}
- test_assert(false_positives < 50); /* Should be far lower. */
+ tt_int_op(50, OP_GT, false_positives); /* Should be far lower. */
done:
if (set)
@@ -612,7 +640,7 @@ compare_strings_for_pqueue_(const void *p1, const void *p2)
/** Run unit tests for heap-based priority queue functions. */
static void
-test_container_pqueue(void)
+test_container_pqueue(void *arg)
{
smartlist_t *sl = smartlist_new();
int (*cmp)(const void *, const void*);
@@ -634,6 +662,8 @@ test_container_pqueue(void)
#define OK() smartlist_pqueue_assert_ok(sl, cmp, offset)
+ (void)arg;
+
cmp = compare_strings_for_pqueue_;
smartlist_pqueue_add(sl, cmp, offset, &cows);
smartlist_pqueue_add(sl, cmp, offset, &zebras);
@@ -649,31 +679,31 @@ test_container_pqueue(void)
OK();
- test_eq(smartlist_len(sl), 11);
- test_eq_ptr(smartlist_get(sl, 0), &apples);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &apples);
- test_eq(smartlist_len(sl), 10);
+ tt_int_op(smartlist_len(sl),OP_EQ, 11);
+ tt_ptr_op(smartlist_get(sl, 0),OP_EQ, &apples);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &apples);
+ tt_int_op(smartlist_len(sl),OP_EQ, 10);
OK();
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &cows);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &daschunds);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &cows);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &daschunds);
smartlist_pqueue_add(sl, cmp, offset, &chinchillas);
OK();
smartlist_pqueue_add(sl, cmp, offset, &fireflies);
OK();
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &chinchillas);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &eggplants);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &fireflies);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &chinchillas);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &eggplants);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &fireflies);
OK();
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &fish);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &frogs);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &lobsters);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &roquefort);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &fish);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &frogs);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &lobsters);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &roquefort);
OK();
- test_eq(smartlist_len(sl), 3);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &squid);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &weissbier);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &zebras);
- test_eq(smartlist_len(sl), 0);
+ tt_int_op(smartlist_len(sl),OP_EQ, 3);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &squid);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &weissbier);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &zebras);
+ tt_int_op(smartlist_len(sl),OP_EQ, 0);
OK();
/* Now test remove. */
@@ -683,21 +713,21 @@ test_container_pqueue(void)
smartlist_pqueue_add(sl, cmp, offset, &apples);
smartlist_pqueue_add(sl, cmp, offset, &squid);
smartlist_pqueue_add(sl, cmp, offset, &zebras);
- test_eq(smartlist_len(sl), 6);
+ tt_int_op(smartlist_len(sl),OP_EQ, 6);
OK();
smartlist_pqueue_remove(sl, cmp, offset, &zebras);
- test_eq(smartlist_len(sl), 5);
+ tt_int_op(smartlist_len(sl),OP_EQ, 5);
OK();
smartlist_pqueue_remove(sl, cmp, offset, &cows);
- test_eq(smartlist_len(sl), 4);
+ tt_int_op(smartlist_len(sl),OP_EQ, 4);
OK();
smartlist_pqueue_remove(sl, cmp, offset, &apples);
- test_eq(smartlist_len(sl), 3);
+ tt_int_op(smartlist_len(sl),OP_EQ, 3);
OK();
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &fish);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &frogs);
- test_eq_ptr(smartlist_pqueue_pop(sl, cmp, offset), &squid);
- test_eq(smartlist_len(sl), 0);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &fish);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &frogs);
+ tt_ptr_op(smartlist_pqueue_pop(sl, cmp, offset),OP_EQ, &squid);
+ tt_int_op(smartlist_len(sl),OP_EQ, 0);
OK();
#undef OK
@@ -709,7 +739,7 @@ test_container_pqueue(void)
/** Run unit tests for string-to-void* map functions */
static void
-test_container_strmap(void)
+test_container_strmap(void *arg)
{
strmap_t *map;
strmap_iter_t *iter;
@@ -717,36 +747,45 @@ test_container_strmap(void)
void *v;
char *visited = NULL;
smartlist_t *found_keys = NULL;
+ char *v1 = tor_strdup("v1");
+ char *v99 = tor_strdup("v99");
+ char *v100 = tor_strdup("v100");
+ char *v101 = tor_strdup("v101");
+ char *v102 = tor_strdup("v102");
+ char *v103 = tor_strdup("v103");
+ char *v104 = tor_strdup("v104");
+ char *v105 = tor_strdup("v105");
+ (void)arg;
map = strmap_new();
- test_assert(map);
- test_eq(strmap_size(map), 0);
- test_assert(strmap_isempty(map));
- v = strmap_set(map, "K1", (void*)99);
- test_eq_ptr(v, NULL);
- test_assert(!strmap_isempty(map));
- v = strmap_set(map, "K2", (void*)101);
- test_eq_ptr(v, NULL);
- v = strmap_set(map, "K1", (void*)100);
- test_eq_ptr(v, (void*)99);
- test_eq_ptr(strmap_get(map,"K1"), (void*)100);
- test_eq_ptr(strmap_get(map,"K2"), (void*)101);
- test_eq_ptr(strmap_get(map,"K-not-there"), NULL);
+ tt_assert(map);
+ tt_int_op(strmap_size(map),OP_EQ, 0);
+ tt_assert(strmap_isempty(map));
+ v = strmap_set(map, "K1", v99);
+ tt_ptr_op(v,OP_EQ, NULL);
+ tt_assert(!strmap_isempty(map));
+ v = strmap_set(map, "K2", v101);
+ tt_ptr_op(v,OP_EQ, NULL);
+ v = strmap_set(map, "K1", v100);
+ tt_ptr_op(v,OP_EQ, v99);
+ tt_ptr_op(strmap_get(map,"K1"),OP_EQ, v100);
+ tt_ptr_op(strmap_get(map,"K2"),OP_EQ, v101);
+ tt_ptr_op(strmap_get(map,"K-not-there"),OP_EQ, NULL);
strmap_assert_ok(map);
v = strmap_remove(map,"K2");
strmap_assert_ok(map);
- test_eq_ptr(v, (void*)101);
- test_eq_ptr(strmap_get(map,"K2"), NULL);
- test_eq_ptr(strmap_remove(map,"K2"), NULL);
-
- strmap_set(map, "K2", (void*)101);
- strmap_set(map, "K3", (void*)102);
- strmap_set(map, "K4", (void*)103);
- test_eq(strmap_size(map), 4);
+ tt_ptr_op(v,OP_EQ, v101);
+ tt_ptr_op(strmap_get(map,"K2"),OP_EQ, NULL);
+ tt_ptr_op(strmap_remove(map,"K2"),OP_EQ, NULL);
+
+ strmap_set(map, "K2", v101);
+ strmap_set(map, "K3", v102);
+ strmap_set(map, "K4", v103);
+ tt_int_op(strmap_size(map),OP_EQ, 4);
strmap_assert_ok(map);
- strmap_set(map, "K5", (void*)104);
- strmap_set(map, "K6", (void*)105);
+ strmap_set(map, "K5", v104);
+ strmap_set(map, "K6", v105);
strmap_assert_ok(map);
/* Test iterator. */
@@ -755,7 +794,7 @@ test_container_strmap(void)
while (!strmap_iter_done(iter)) {
strmap_iter_get(iter,&k,&v);
smartlist_add(found_keys, tor_strdup(k));
- test_eq_ptr(v, strmap_get(map, k));
+ tt_ptr_op(v,OP_EQ, strmap_get(map, k));
if (!strcmp(k, "K2")) {
iter = strmap_iter_next_rmv(map,iter);
@@ -765,12 +804,12 @@ test_container_strmap(void)
}
/* Make sure we removed K2, but not the others. */
- test_eq_ptr(strmap_get(map, "K2"), NULL);
- test_eq_ptr(strmap_get(map, "K5"), (void*)104);
+ tt_ptr_op(strmap_get(map, "K2"),OP_EQ, NULL);
+ tt_ptr_op(strmap_get(map, "K5"),OP_EQ, v104);
/* Make sure we visited everyone once */
smartlist_sort_strings(found_keys);
visited = smartlist_join_strings(found_keys, ":", 0, NULL);
- test_streq(visited, "K1:K2:K3:K4:K5:K6");
+ tt_str_op(visited,OP_EQ, "K1:K2:K3:K4:K5:K6");
strmap_assert_ok(map);
/* Clean up after ourselves. */
@@ -779,14 +818,14 @@ test_container_strmap(void)
/* Now try some lc functions. */
map = strmap_new();
- strmap_set_lc(map,"Ab.C", (void*)1);
- test_eq_ptr(strmap_get(map,"ab.c"), (void*)1);
+ strmap_set_lc(map,"Ab.C", v1);
+ tt_ptr_op(strmap_get(map,"ab.c"),OP_EQ, v1);
strmap_assert_ok(map);
- test_eq_ptr(strmap_get_lc(map,"AB.C"), (void*)1);
- test_eq_ptr(strmap_get(map,"AB.C"), NULL);
- test_eq_ptr(strmap_remove_lc(map,"aB.C"), (void*)1);
+ tt_ptr_op(strmap_get_lc(map,"AB.C"),OP_EQ, v1);
+ tt_ptr_op(strmap_get(map,"AB.C"),OP_EQ, NULL);
+ tt_ptr_op(strmap_remove_lc(map,"aB.C"),OP_EQ, v1);
strmap_assert_ok(map);
- test_eq_ptr(strmap_get_lc(map,"AB.C"), NULL);
+ tt_ptr_op(strmap_get_lc(map,"AB.C"),OP_EQ, NULL);
done:
if (map)
@@ -796,34 +835,67 @@ test_container_strmap(void)
smartlist_free(found_keys);
}
tor_free(visited);
+ tor_free(v1);
+ tor_free(v99);
+ tor_free(v100);
+ tor_free(v101);
+ tor_free(v102);
+ tor_free(v103);
+ tor_free(v104);
+ tor_free(v105);
}
/** Run unit tests for getting the median of a list. */
static void
-test_container_order_functions(void)
+test_container_order_functions(void *arg)
{
int lst[25], n = 0;
+ unsigned int lst2[25];
// int a=12,b=24,c=25,d=60,e=77;
#define median() median_int(lst, n)
+ (void)arg;
lst[n++] = 12;
- test_eq(12, median()); /* 12 */
+ tt_int_op(12,OP_EQ, median()); /* 12 */
lst[n++] = 77;
//smartlist_shuffle(sl);
- test_eq(12, median()); /* 12, 77 */
+ tt_int_op(12,OP_EQ, median()); /* 12, 77 */
lst[n++] = 77;
//smartlist_shuffle(sl);
- test_eq(77, median()); /* 12, 77, 77 */
+ tt_int_op(77,OP_EQ, median()); /* 12, 77, 77 */
lst[n++] = 24;
- test_eq(24, median()); /* 12,24,77,77 */
+ tt_int_op(24,OP_EQ, median()); /* 12,24,77,77 */
lst[n++] = 60;
lst[n++] = 12;
lst[n++] = 25;
//smartlist_shuffle(sl);
- test_eq(25, median()); /* 12,12,24,25,60,77,77 */
+ tt_int_op(25,OP_EQ, median()); /* 12,12,24,25,60,77,77 */
#undef median
+#define third_quartile() third_quartile_uint32(lst2, n)
+
+ n = 0;
+ lst2[n++] = 1;
+ tt_int_op(1,OP_EQ, third_quartile()); /* ~1~ */
+ lst2[n++] = 2;
+ tt_int_op(2,OP_EQ, third_quartile()); /* 1, ~2~ */
+ lst2[n++] = 3;
+ lst2[n++] = 4;
+ lst2[n++] = 5;
+ tt_int_op(4,OP_EQ, third_quartile()); /* 1, 2, 3, ~4~, 5 */
+ lst2[n++] = 6;
+ lst2[n++] = 7;
+ lst2[n++] = 8;
+ lst2[n++] = 9;
+ tt_int_op(7,OP_EQ, third_quartile()); /* 1, 2, 3, 4, 5, 6, ~7~, 8, 9 */
+ lst2[n++] = 10;
+ lst2[n++] = 11;
+ /* 1, 2, 3, 4, 5, 6, 7, 8, ~9~, 10, 11 */
+ tt_int_op(9,OP_EQ, third_quartile());
+
+#undef third_quartile
+
done:
;
}
@@ -844,26 +916,26 @@ test_container_di_map(void *arg)
(void)arg;
/* Try searching on an empty map. */
- tt_ptr_op(NULL, ==, dimap_search(map, key1, NULL));
- tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
- tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
+ tt_ptr_op(NULL, OP_EQ, dimap_search(map, key1, NULL));
+ tt_ptr_op(NULL, OP_EQ, dimap_search(map, key2, NULL));
+ tt_ptr_op(v3, OP_EQ, dimap_search(map, key2, v3));
dimap_free(map, NULL);
map = NULL;
/* Add a single entry. */
dimap_add_entry(&map, key1, v1);
- tt_ptr_op(NULL, ==, dimap_search(map, key2, NULL));
- tt_ptr_op(v3, ==, dimap_search(map, key2, v3));
- tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
+ tt_ptr_op(NULL, OP_EQ, dimap_search(map, key2, NULL));
+ tt_ptr_op(v3, OP_EQ, dimap_search(map, key2, v3));
+ tt_ptr_op(v1, OP_EQ, dimap_search(map, key1, NULL));
/* Now try it with three entries in the map. */
dimap_add_entry(&map, key2, v2);
dimap_add_entry(&map, key3, v3);
- tt_ptr_op(v1, ==, dimap_search(map, key1, NULL));
- tt_ptr_op(v2, ==, dimap_search(map, key2, NULL));
- tt_ptr_op(v3, ==, dimap_search(map, key3, NULL));
- tt_ptr_op(NULL, ==, dimap_search(map, key4, NULL));
- tt_ptr_op(v1, ==, dimap_search(map, key4, v1));
+ tt_ptr_op(v1, OP_EQ, dimap_search(map, key1, NULL));
+ tt_ptr_op(v2, OP_EQ, dimap_search(map, key2, NULL));
+ tt_ptr_op(v3, OP_EQ, dimap_search(map, key3, NULL));
+ tt_ptr_op(NULL, OP_EQ, dimap_search(map, key4, NULL));
+ tt_ptr_op(v1, OP_EQ, dimap_search(map, key4, v1));
done:
tor_free(v1);
@@ -874,18 +946,26 @@ test_container_di_map(void *arg)
/** Run unit tests for fp_pair-to-void* map functions */
static void
-test_container_fp_pair_map(void)
+test_container_fp_pair_map(void *arg)
{
fp_pair_map_t *map;
fp_pair_t fp1, fp2, fp3, fp4, fp5, fp6;
void *v;
fp_pair_map_iter_t *iter;
fp_pair_t k;
+ char *v99 = tor_strdup("99");
+ char *v100 = tor_strdup("v100");
+ char *v101 = tor_strdup("v101");
+ char *v102 = tor_strdup("v102");
+ char *v103 = tor_strdup("v103");
+ char *v104 = tor_strdup("v104");
+ char *v105 = tor_strdup("v105");
+ (void)arg;
map = fp_pair_map_new();
- test_assert(map);
- test_eq(fp_pair_map_size(map), 0);
- test_assert(fp_pair_map_isempty(map));
+ tt_assert(map);
+ tt_int_op(fp_pair_map_size(map),OP_EQ, 0);
+ tt_assert(fp_pair_map_isempty(map));
memset(fp1.first, 0x11, DIGEST_LEN);
memset(fp1.second, 0x12, DIGEST_LEN);
@@ -900,38 +980,38 @@ test_container_fp_pair_map(void)
memset(fp6.first, 0x61, DIGEST_LEN);
memset(fp6.second, 0x62, DIGEST_LEN);
- v = fp_pair_map_set(map, &fp1, (void*)99);
- tt_ptr_op(v, ==, NULL);
- test_assert(!fp_pair_map_isempty(map));
- v = fp_pair_map_set(map, &fp2, (void*)101);
- tt_ptr_op(v, ==, NULL);
- v = fp_pair_map_set(map, &fp1, (void*)100);
- tt_ptr_op(v, ==, (void*)99);
- test_eq_ptr(fp_pair_map_get(map, &fp1), (void*)100);
- test_eq_ptr(fp_pair_map_get(map, &fp2), (void*)101);
- test_eq_ptr(fp_pair_map_get(map, &fp3), NULL);
+ v = fp_pair_map_set(map, &fp1, v99);
+ tt_ptr_op(v, OP_EQ, NULL);
+ tt_assert(!fp_pair_map_isempty(map));
+ v = fp_pair_map_set(map, &fp2, v101);
+ tt_ptr_op(v, OP_EQ, NULL);
+ v = fp_pair_map_set(map, &fp1, v100);
+ tt_ptr_op(v, OP_EQ, v99);
+ tt_ptr_op(fp_pair_map_get(map, &fp1),OP_EQ, v100);
+ tt_ptr_op(fp_pair_map_get(map, &fp2),OP_EQ, v101);
+ tt_ptr_op(fp_pair_map_get(map, &fp3),OP_EQ, NULL);
fp_pair_map_assert_ok(map);
v = fp_pair_map_remove(map, &fp2);
fp_pair_map_assert_ok(map);
- test_eq_ptr(v, (void*)101);
- test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
- test_eq_ptr(fp_pair_map_remove(map, &fp2), NULL);
-
- fp_pair_map_set(map, &fp2, (void*)101);
- fp_pair_map_set(map, &fp3, (void*)102);
- fp_pair_map_set(map, &fp4, (void*)103);
- test_eq(fp_pair_map_size(map), 4);
+ tt_ptr_op(v,OP_EQ, v101);
+ tt_ptr_op(fp_pair_map_get(map, &fp2),OP_EQ, NULL);
+ tt_ptr_op(fp_pair_map_remove(map, &fp2),OP_EQ, NULL);
+
+ fp_pair_map_set(map, &fp2, v101);
+ fp_pair_map_set(map, &fp3, v102);
+ fp_pair_map_set(map, &fp4, v103);
+ tt_int_op(fp_pair_map_size(map),OP_EQ, 4);
fp_pair_map_assert_ok(map);
- fp_pair_map_set(map, &fp5, (void*)104);
- fp_pair_map_set(map, &fp6, (void*)105);
+ fp_pair_map_set(map, &fp5, v104);
+ fp_pair_map_set(map, &fp6, v105);
fp_pair_map_assert_ok(map);
/* Test iterator. */
iter = fp_pair_map_iter_init(map);
while (!fp_pair_map_iter_done(iter)) {
fp_pair_map_iter_get(iter, &k, &v);
- test_eq_ptr(v, fp_pair_map_get(map, &k));
+ tt_ptr_op(v,OP_EQ, fp_pair_map_get(map, &k));
if (tor_memeq(&fp2, &k, sizeof(fp2))) {
iter = fp_pair_map_iter_next_rmv(map, iter);
@@ -941,8 +1021,8 @@ test_container_fp_pair_map(void)
}
/* Make sure we removed fp2, but not the others. */
- test_eq_ptr(fp_pair_map_get(map, &fp2), NULL);
- test_eq_ptr(fp_pair_map_get(map, &fp5), (void*)104);
+ tt_ptr_op(fp_pair_map_get(map, &fp2),OP_EQ, NULL);
+ tt_ptr_op(fp_pair_map_get(map, &fp5),OP_EQ, v104);
fp_pair_map_assert_ok(map);
/* Clean up after ourselves. */
@@ -952,10 +1032,17 @@ test_container_fp_pair_map(void)
done:
if (map)
fp_pair_map_free(map, NULL);
+ tor_free(v99);
+ tor_free(v100);
+ tor_free(v101);
+ tor_free(v102);
+ tor_free(v103);
+ tor_free(v104);
+ tor_free(v105);
}
#define CONTAINER_LEGACY(name) \
- { #name, legacy_test_helper, 0, &legacy_setup, test_container_ ## name }
+ { #name, test_container_ ## name , 0, NULL, NULL }
#define CONTAINER(name, flags) \
{ #name, test_container_ ## name, (flags), NULL, NULL }
diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c
index b45e97a417..e36314da45 100644
--- a/src/test/test_controller_events.c
+++ b/src/test/test_controller_events.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
@@ -22,7 +22,7 @@ help_test_bucket_note_empty(uint32_t expected_msec_since_midnight,
tvnow.tv_usec = (msec_since_epoch % 1000) * 1000;
connection_buckets_note_empty_ts(&timestamp_var, tokens_before,
tokens_removed, &tvnow);
- tt_int_op(expected_msec_since_midnight, ==, timestamp_var);
+ tt_int_op(expected_msec_since_midnight, OP_EQ, timestamp_var);
done:
;
@@ -57,20 +57,20 @@ test_cntev_bucket_millis_empty(void *arg)
tvnow.tv_usec = 200000;
/* Bucket has not been refilled. */
- tt_int_op(0, ==, bucket_millis_empty(0, 42120, 0, 100, &tvnow));
- tt_int_op(0, ==, bucket_millis_empty(-10, 42120, -10, 100, &tvnow));
+ tt_int_op(0, OP_EQ, bucket_millis_empty(0, 42120, 0, 100, &tvnow));
+ tt_int_op(0, OP_EQ, bucket_millis_empty(-10, 42120, -10, 100, &tvnow));
/* Bucket was not empty. */
- tt_int_op(0, ==, bucket_millis_empty(10, 42120, 20, 100, &tvnow));
+ tt_int_op(0, OP_EQ, bucket_millis_empty(10, 42120, 20, 100, &tvnow));
/* Bucket has been emptied 80 msec ago and has just been refilled. */
- tt_int_op(80, ==, bucket_millis_empty(-20, 42120, -10, 100, &tvnow));
- tt_int_op(80, ==, bucket_millis_empty(-10, 42120, 0, 100, &tvnow));
- tt_int_op(80, ==, bucket_millis_empty(0, 42120, 10, 100, &tvnow));
+ tt_int_op(80, OP_EQ, bucket_millis_empty(-20, 42120, -10, 100, &tvnow));
+ tt_int_op(80, OP_EQ, bucket_millis_empty(-10, 42120, 0, 100, &tvnow));
+ tt_int_op(80, OP_EQ, bucket_millis_empty(0, 42120, 10, 100, &tvnow));
/* Bucket has been emptied 180 msec ago, last refill was 100 msec ago
* which was insufficient to make it positive, so cap msec at 100. */
- tt_int_op(100, ==, bucket_millis_empty(0, 42020, 1, 100, &tvnow));
+ tt_int_op(100, OP_EQ, bucket_millis_empty(0, 42020, 1, 100, &tvnow));
/* 1970-01-02 00:00:00:050000 */
tvnow.tv_sec = 86400;
@@ -78,7 +78,7 @@ test_cntev_bucket_millis_empty(void *arg)
/* Last emptied 30 msec before midnight, tvnow is 50 msec after
* midnight, that's 80 msec in total. */
- tt_int_op(80, ==, bucket_millis_empty(0, 86400000 - 30, 1, 100, &tvnow));
+ tt_int_op(80, OP_EQ, bucket_millis_empty(0, 86400000 - 30, 1, 100, &tvnow));
done:
;
@@ -118,26 +118,26 @@ test_cntev_sum_up_cell_stats(void *arg)
cell_stats = tor_malloc_zero(sizeof(cell_stats_t));
add_testing_cell_stats_entry(circ, CELL_RELAY, 0, 0, 0);
sum_up_cell_stats_by_command(circ, cell_stats);
- tt_u64_op(1, ==, cell_stats->added_cells_appward[CELL_RELAY]);
+ tt_u64_op(1, OP_EQ, cell_stats->added_cells_appward[CELL_RELAY]);
/* A single RELAY cell was added to the exitward queue. */
add_testing_cell_stats_entry(circ, CELL_RELAY, 0, 0, 1);
sum_up_cell_stats_by_command(circ, cell_stats);
- tt_u64_op(1, ==, cell_stats->added_cells_exitward[CELL_RELAY]);
+ tt_u64_op(1, OP_EQ, cell_stats->added_cells_exitward[CELL_RELAY]);
/* A single RELAY cell was removed from the appward queue where it spent
* 20 msec. */
add_testing_cell_stats_entry(circ, CELL_RELAY, 2, 1, 0);
sum_up_cell_stats_by_command(circ, cell_stats);
- tt_u64_op(20, ==, cell_stats->total_time_appward[CELL_RELAY]);
- tt_u64_op(1, ==, cell_stats->removed_cells_appward[CELL_RELAY]);
+ tt_u64_op(20, OP_EQ, cell_stats->total_time_appward[CELL_RELAY]);
+ tt_u64_op(1, OP_EQ, cell_stats->removed_cells_appward[CELL_RELAY]);
/* A single RELAY cell was removed from the exitward queue where it
* spent 30 msec. */
add_testing_cell_stats_entry(circ, CELL_RELAY, 3, 1, 1);
sum_up_cell_stats_by_command(circ, cell_stats);
- tt_u64_op(30, ==, cell_stats->total_time_exitward[CELL_RELAY]);
- tt_u64_op(1, ==, cell_stats->removed_cells_exitward[CELL_RELAY]);
+ tt_u64_op(30, OP_EQ, cell_stats->total_time_exitward[CELL_RELAY]);
+ tt_u64_op(1, OP_EQ, cell_stats->removed_cells_exitward[CELL_RELAY]);
done:
tor_free(cell_stats);
@@ -164,7 +164,7 @@ test_cntev_append_cell_stats(void *arg)
append_cell_stats_by_command(event_parts, key,
include_if_non_zero,
number_to_include);
- tt_int_op(0, ==, smartlist_len(event_parts));
+ tt_int_op(0, OP_EQ, smartlist_len(event_parts));
/* There's a RELAY cell to include, but the corresponding field in
* include_if_non_zero is still zero. */
@@ -172,7 +172,7 @@ test_cntev_append_cell_stats(void *arg)
append_cell_stats_by_command(event_parts, key,
include_if_non_zero,
number_to_include);
- tt_int_op(0, ==, smartlist_len(event_parts));
+ tt_int_op(0, OP_EQ, smartlist_len(event_parts));
/* Now include single RELAY cell. */
include_if_non_zero[CELL_RELAY] = 2;
@@ -180,7 +180,7 @@ test_cntev_append_cell_stats(void *arg)
include_if_non_zero,
number_to_include);
cp = smartlist_pop_last(event_parts);
- tt_str_op("Z=relay:1", ==, cp);
+ tt_str_op("Z=relay:1", OP_EQ, cp);
tor_free(cp);
/* Add four CREATE cells. */
@@ -190,7 +190,7 @@ test_cntev_append_cell_stats(void *arg)
include_if_non_zero,
number_to_include);
cp = smartlist_pop_last(event_parts);
- tt_str_op("Z=create:4,relay:1", ==, cp);
+ tt_str_op("Z=create:4,relay:1", OP_EQ, cp);
done:
tor_free(cp);
@@ -220,14 +220,14 @@ test_cntev_format_cell_stats(void *arg)
/* Origin circuit was completely idle. */
cell_stats = tor_malloc_zero(sizeof(cell_stats_t));
format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
- tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1", ==, event_string);
+ tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1", OP_EQ, event_string);
tor_free(event_string);
/* Origin circuit had 4 RELAY cells added to its exitward queue. */
cell_stats->added_cells_exitward[CELL_RELAY] = 4;
format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1 OutboundAdded=relay:4",
- ==, event_string);
+ OP_EQ, event_string);
tor_free(event_string);
/* Origin circuit also had 5 CREATE2 cells added to its exitward
@@ -235,7 +235,7 @@ test_cntev_format_cell_stats(void *arg)
cell_stats->added_cells_exitward[CELL_CREATE2] = 5;
format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1 OutboundAdded=relay:4,"
- "create2:5", ==, event_string);
+ "create2:5", OP_EQ, event_string);
tor_free(event_string);
/* Origin circuit also had 7 RELAY cells removed from its exitward queue
@@ -245,7 +245,7 @@ test_cntev_format_cell_stats(void *arg)
format_cell_stats(&event_string, TO_CIRCUIT(ocirc), cell_stats);
tt_str_op("ID=2 OutboundQueue=3 OutboundConn=1 OutboundAdded=relay:4,"
"create2:5 OutboundRemoved=relay:7 OutboundTime=relay:6",
- ==, event_string);
+ OP_EQ, event_string);
tor_free(event_string);
p_chan = tor_malloc_zero(sizeof(channel_tls_t));
@@ -265,14 +265,14 @@ test_cntev_format_cell_stats(void *arg)
cell_stats = tor_malloc_zero(sizeof(cell_stats_t));
format_cell_stats(&event_string, TO_CIRCUIT(or_circ), cell_stats);
tt_str_op("InboundQueue=8 InboundConn=2 OutboundQueue=9 OutboundConn=1",
- ==, event_string);
+ OP_EQ, event_string);
tor_free(event_string);
/* OR circuit had 3 RELAY cells added to its appward queue. */
cell_stats->added_cells_appward[CELL_RELAY] = 3;
format_cell_stats(&event_string, TO_CIRCUIT(or_circ), cell_stats);
tt_str_op("InboundQueue=8 InboundConn=2 InboundAdded=relay:3 "
- "OutboundQueue=9 OutboundConn=1", ==, event_string);
+ "OutboundQueue=9 OutboundConn=1", OP_EQ, event_string);
tor_free(event_string);
/* OR circuit had 7 RELAY cells removed from its appward queue which
@@ -282,7 +282,7 @@ test_cntev_format_cell_stats(void *arg)
format_cell_stats(&event_string, TO_CIRCUIT(or_circ), cell_stats);
tt_str_op("InboundQueue=8 InboundConn=2 InboundAdded=relay:3 "
"InboundRemoved=relay:7 InboundTime=relay:6 "
- "OutboundQueue=9 OutboundConn=1", ==, event_string);
+ "OutboundQueue=9 OutboundConn=1", OP_EQ, event_string);
done:
tor_free(cell_stats);
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c
index 5d8edb6550..e9fb8bf084 100644
--- a/src/test/test_crypto.c
+++ b/src/test/test_crypto.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -10,9 +10,9 @@
#include "aes.h"
#include "util.h"
#include "siphash.h"
-#ifdef CURVE25519_ENABLED
#include "crypto_curve25519.h"
-#endif
+#include "crypto_ed25519.h"
+#include "ed25519_vectors.inc"
extern const char AUTHORITY_SIGNKEY_3[];
extern const char AUTHORITY_SIGNKEY_A_DIGEST[];
@@ -20,7 +20,7 @@ extern const char AUTHORITY_SIGNKEY_A_DIGEST256[];
/** Run unit tests for Diffie-Hellman functionality. */
static void
-test_crypto_dh(void)
+test_crypto_dh(void *arg)
{
crypto_dh_t *dh1 = crypto_dh_new(DH_TYPE_CIRCUIT);
crypto_dh_t *dh2 = crypto_dh_new(DH_TYPE_CIRCUIT);
@@ -30,24 +30,25 @@ test_crypto_dh(void)
char s2[DH_BYTES];
ssize_t s1len, s2len;
- test_eq(crypto_dh_get_bytes(dh1), DH_BYTES);
- test_eq(crypto_dh_get_bytes(dh2), DH_BYTES);
+ (void)arg;
+ tt_int_op(crypto_dh_get_bytes(dh1),OP_EQ, DH_BYTES);
+ tt_int_op(crypto_dh_get_bytes(dh2),OP_EQ, DH_BYTES);
memset(p1, 0, DH_BYTES);
memset(p2, 0, DH_BYTES);
- test_memeq(p1, p2, DH_BYTES);
- test_assert(! crypto_dh_get_public(dh1, p1, DH_BYTES));
- test_memneq(p1, p2, DH_BYTES);
- test_assert(! crypto_dh_get_public(dh2, p2, DH_BYTES));
- test_memneq(p1, p2, DH_BYTES);
+ tt_mem_op(p1,OP_EQ, p2, DH_BYTES);
+ tt_assert(! crypto_dh_get_public(dh1, p1, DH_BYTES));
+ tt_mem_op(p1,OP_NE, p2, DH_BYTES);
+ tt_assert(! crypto_dh_get_public(dh2, p2, DH_BYTES));
+ tt_mem_op(p1,OP_NE, p2, DH_BYTES);
memset(s1, 0, DH_BYTES);
memset(s2, 0xFF, DH_BYTES);
s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p2, DH_BYTES, s1, 50);
s2len = crypto_dh_compute_secret(LOG_WARN, dh2, p1, DH_BYTES, s2, 50);
- test_assert(s1len > 0);
- test_eq(s1len, s2len);
- test_memeq(s1, s2, s1len);
+ tt_assert(s1len > 0);
+ tt_int_op(s1len,OP_EQ, s2len);
+ tt_mem_op(s1,OP_EQ, s2, s1len);
{
/* XXXX Now fabricate some bad values and make sure they get caught,
@@ -63,17 +64,18 @@ test_crypto_dh(void)
/** Run unit tests for our random number generation function and its wrappers.
*/
static void
-test_crypto_rng(void)
+test_crypto_rng(void *arg)
{
int i, j, allok;
char data1[100], data2[100];
double d;
/* Try out RNG. */
- test_assert(! crypto_seed_rng(0));
+ (void)arg;
+ tt_assert(! crypto_seed_rng(0));
crypto_rand(data1, 100);
crypto_rand(data2, 100);
- test_memneq(data1,data2,100);
+ tt_mem_op(data1,OP_NE, data2,100);
allok = 1;
for (i = 0; i < 100; ++i) {
uint64_t big;
@@ -88,8 +90,8 @@ test_crypto_rng(void)
if (big >= 5)
allok = 0;
d = crypto_rand_double();
- test_assert(d >= 0);
- test_assert(d < 1.0);
+ tt_assert(d >= 0);
+ tt_assert(d < 1.0);
host = crypto_random_hostname(3,8,"www.",".onion");
if (strcmpstart(host,"www.") ||
strcmpend(host,".onion") ||
@@ -98,7 +100,7 @@ test_crypto_rng(void)
allok = 0;
tor_free(host);
}
- test_assert(allok);
+ tt_assert(allok);
done:
;
}
@@ -128,15 +130,15 @@ test_crypto_aes(void *arg)
memset(data2, 0, 1024);
memset(data3, 0, 1024);
env1 = crypto_cipher_new(NULL);
- test_neq_ptr(env1, 0);
+ tt_ptr_op(env1, OP_NE, NULL);
env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
- test_neq_ptr(env2, 0);
+ tt_ptr_op(env2, OP_NE, NULL);
/* Try encrypting 512 chars. */
crypto_cipher_encrypt(env1, data2, data1, 512);
crypto_cipher_decrypt(env2, data3, data2, 512);
- test_memeq(data1, data3, 512);
- test_memneq(data1, data2, 512);
+ tt_mem_op(data1,OP_EQ, data3, 512);
+ tt_mem_op(data1,OP_NE, data2, 512);
/* Now encrypt 1 at a time, and get 1 at a time. */
for (j = 512; j < 560; ++j) {
@@ -145,7 +147,7 @@ test_crypto_aes(void *arg)
for (j = 512; j < 560; ++j) {
crypto_cipher_decrypt(env2, data3+j, data2+j, 1);
}
- test_memeq(data1, data3, 560);
+ tt_mem_op(data1,OP_EQ, data3, 560);
/* Now encrypt 3 at a time, and get 5 at a time. */
for (j = 560; j < 1024-5; j += 3) {
crypto_cipher_encrypt(env1, data2+j, data1+j, 3);
@@ -153,7 +155,7 @@ test_crypto_aes(void *arg)
for (j = 560; j < 1024-5; j += 5) {
crypto_cipher_decrypt(env2, data3+j, data2+j, 5);
}
- test_memeq(data1, data3, 1024-5);
+ tt_mem_op(data1,OP_EQ, data3, 1024-5);
/* Now make sure that when we encrypt with different chunk sizes, we get
the same results. */
crypto_cipher_free(env2);
@@ -161,7 +163,7 @@ test_crypto_aes(void *arg)
memset(data3, 0, 1024);
env2 = crypto_cipher_new(crypto_cipher_get_key(env1));
- test_neq_ptr(env2, NULL);
+ tt_ptr_op(env2, OP_NE, NULL);
for (j = 0; j < 1024-16; j += 17) {
crypto_cipher_encrypt(env2, data3+j, data1+j, 17);
}
@@ -170,7 +172,7 @@ test_crypto_aes(void *arg)
printf("%d: %d\t%d\n", j, (int) data2[j], (int) data3[j]);
}
}
- test_memeq(data2, data3, 1024-16);
+ tt_mem_op(data2,OP_EQ, data3, 1024-16);
crypto_cipher_free(env1);
env1 = NULL;
crypto_cipher_free(env2);
@@ -237,7 +239,7 @@ test_crypto_aes(void *arg)
"\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff");
crypto_cipher_crypt_inplace(env1, data2, 64);
- test_assert(tor_mem_is_zero(data2, 64));
+ tt_assert(tor_mem_is_zero(data2, 64));
done:
tor_free(mem_op_hex_tmp);
@@ -252,7 +254,7 @@ test_crypto_aes(void *arg)
/** Run unit tests for our SHA-1 functionality */
static void
-test_crypto_sha(void)
+test_crypto_sha(void *arg)
{
crypto_digest_t *d1 = NULL, *d2 = NULL;
int i;
@@ -263,27 +265,28 @@ test_crypto_sha(void)
char *mem_op_hex_tmp=NULL;
/* Test SHA-1 with a test vector from the specification. */
+ (void)arg;
i = crypto_digest(data, "abc", 3);
test_memeq_hex(data, "A9993E364706816ABA3E25717850C26C9CD0D89D");
- tt_int_op(i, ==, 0);
+ tt_int_op(i, OP_EQ, 0);
/* Test SHA-256 with a test vector from the specification. */
i = crypto_digest256(data, "abc", 3, DIGEST_SHA256);
test_memeq_hex(data, "BA7816BF8F01CFEA414140DE5DAE2223B00361A3"
"96177A9CB410FF61F20015AD");
- tt_int_op(i, ==, 0);
+ tt_int_op(i, OP_EQ, 0);
/* Test HMAC-SHA256 with test cases from wikipedia and RFC 4231 */
/* Case empty (wikipedia) */
crypto_hmac_sha256(digest, "", 0, "", 0);
- test_streq(hex_str(digest, 32),
+ tt_str_op(hex_str(digest, 32),OP_EQ,
"B613679A0814D9EC772F95D778C35FC5FF1697C493715653C6C712144292C5AD");
/* Case quick-brown (wikipedia) */
crypto_hmac_sha256(digest, "key", 3,
"The quick brown fox jumps over the lazy dog", 43);
- test_streq(hex_str(digest, 32),
+ tt_str_op(hex_str(digest, 32),OP_EQ,
"F7BC83F430538424B13298E6AA6FB143EF4D59A14946175997479DBC2D1A3CD8");
/* "Test Case 1" from RFC 4231 */
@@ -344,43 +347,43 @@ test_crypto_sha(void)
/* Incremental digest code. */
d1 = crypto_digest_new();
- test_assert(d1);
+ tt_assert(d1);
crypto_digest_add_bytes(d1, "abcdef", 6);
d2 = crypto_digest_dup(d1);
- test_assert(d2);
+ tt_assert(d2);
crypto_digest_add_bytes(d2, "ghijkl", 6);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest(d_out2, "abcdefghijkl", 12);
- test_memeq(d_out1, d_out2, DIGEST_LEN);
+ tt_mem_op(d_out1,OP_EQ, d_out2, DIGEST_LEN);
crypto_digest_assign(d2, d1);
crypto_digest_add_bytes(d2, "mno", 3);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest(d_out2, "abcdefmno", 9);
- test_memeq(d_out1, d_out2, DIGEST_LEN);
+ tt_mem_op(d_out1,OP_EQ, d_out2, DIGEST_LEN);
crypto_digest_get_digest(d1, d_out1, sizeof(d_out1));
crypto_digest(d_out2, "abcdef", 6);
- test_memeq(d_out1, d_out2, DIGEST_LEN);
+ tt_mem_op(d_out1,OP_EQ, d_out2, DIGEST_LEN);
crypto_digest_free(d1);
crypto_digest_free(d2);
/* Incremental digest code with sha256 */
d1 = crypto_digest256_new(DIGEST_SHA256);
- test_assert(d1);
+ tt_assert(d1);
crypto_digest_add_bytes(d1, "abcdef", 6);
d2 = crypto_digest_dup(d1);
- test_assert(d2);
+ tt_assert(d2);
crypto_digest_add_bytes(d2, "ghijkl", 6);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest256(d_out2, "abcdefghijkl", 12, DIGEST_SHA256);
- test_memeq(d_out1, d_out2, DIGEST_LEN);
+ tt_mem_op(d_out1,OP_EQ, d_out2, DIGEST_LEN);
crypto_digest_assign(d2, d1);
crypto_digest_add_bytes(d2, "mno", 3);
crypto_digest_get_digest(d2, d_out1, sizeof(d_out1));
crypto_digest256(d_out2, "abcdefmno", 9, DIGEST_SHA256);
- test_memeq(d_out1, d_out2, DIGEST_LEN);
+ tt_mem_op(d_out1,OP_EQ, d_out2, DIGEST_LEN);
crypto_digest_get_digest(d1, d_out1, sizeof(d_out1));
crypto_digest256(d_out2, "abcdef", 6, DIGEST_SHA256);
- test_memeq(d_out1, d_out2, DIGEST_LEN);
+ tt_mem_op(d_out1,OP_EQ, d_out2, DIGEST_LEN);
done:
if (d1)
@@ -392,7 +395,7 @@ test_crypto_sha(void)
/** Run unit tests for our public key crypto functions */
static void
-test_crypto_pk(void)
+test_crypto_pk(void *arg)
{
crypto_pk_t *pk1 = NULL, *pk2 = NULL;
char *encoded = NULL;
@@ -401,74 +404,83 @@ test_crypto_pk(void)
int i, len;
/* Public-key ciphers */
+ (void)arg;
pk1 = pk_generate(0);
pk2 = crypto_pk_new();
- test_assert(pk1 && pk2);
- test_assert(! crypto_pk_write_public_key_to_string(pk1, &encoded, &size));
- test_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size));
- test_eq(0, crypto_pk_cmp_keys(pk1, pk2));
+ tt_assert(pk1 && pk2);
+ tt_assert(! crypto_pk_write_public_key_to_string(pk1, &encoded, &size));
+ tt_assert(! crypto_pk_read_public_key_from_string(pk2, encoded, size));
+ tt_int_op(0,OP_EQ, crypto_pk_cmp_keys(pk1, pk2));
/* comparison between keys and NULL */
- tt_int_op(crypto_pk_cmp_keys(NULL, pk1), <, 0);
- tt_int_op(crypto_pk_cmp_keys(NULL, NULL), ==, 0);
- tt_int_op(crypto_pk_cmp_keys(pk1, NULL), >, 0);
+ tt_int_op(crypto_pk_cmp_keys(NULL, pk1), OP_LT, 0);
+ tt_int_op(crypto_pk_cmp_keys(NULL, NULL), OP_EQ, 0);
+ tt_int_op(crypto_pk_cmp_keys(pk1, NULL), OP_GT, 0);
- test_eq(128, crypto_pk_keysize(pk1));
- test_eq(1024, crypto_pk_num_bits(pk1));
- test_eq(128, crypto_pk_keysize(pk2));
- test_eq(1024, crypto_pk_num_bits(pk2));
+ tt_int_op(128,OP_EQ, crypto_pk_keysize(pk1));
+ tt_int_op(1024,OP_EQ, crypto_pk_num_bits(pk1));
+ tt_int_op(128,OP_EQ, crypto_pk_keysize(pk2));
+ tt_int_op(1024,OP_EQ, crypto_pk_num_bits(pk2));
- test_eq(128, crypto_pk_public_encrypt(pk2, data1, sizeof(data1),
+ tt_int_op(128,OP_EQ, crypto_pk_public_encrypt(pk2, data1, sizeof(data1),
"Hello whirled.", 15,
PK_PKCS1_OAEP_PADDING));
- test_eq(128, crypto_pk_public_encrypt(pk1, data2, sizeof(data1),
+ tt_int_op(128,OP_EQ, crypto_pk_public_encrypt(pk1, data2, sizeof(data1),
"Hello whirled.", 15,
PK_PKCS1_OAEP_PADDING));
/* oaep padding should make encryption not match */
- test_memneq(data1, data2, 128);
- test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data1, 128,
+ tt_mem_op(data1,OP_NE, data2, 128);
+ tt_int_op(15,OP_EQ,
+ crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data1, 128,
PK_PKCS1_OAEP_PADDING,1));
- test_streq(data3, "Hello whirled.");
+ tt_str_op(data3,OP_EQ, "Hello whirled.");
memset(data3, 0, 1024);
- test_eq(15, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128,
+ tt_int_op(15,OP_EQ,
+ crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128,
PK_PKCS1_OAEP_PADDING,1));
- test_streq(data3, "Hello whirled.");
+ tt_str_op(data3,OP_EQ, "Hello whirled.");
/* Can't decrypt with public key. */
- test_eq(-1, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data2, 128,
+ tt_int_op(-1,OP_EQ,
+ crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data2, 128,
PK_PKCS1_OAEP_PADDING,1));
/* Try again with bad padding */
memcpy(data2+1, "XYZZY", 5); /* This has fails ~ once-in-2^40 */
- test_eq(-1, crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128,
+ tt_int_op(-1,OP_EQ,
+ crypto_pk_private_decrypt(pk1, data3, sizeof(data3), data2, 128,
PK_PKCS1_OAEP_PADDING,1));
/* File operations: save and load private key */
- test_assert(! crypto_pk_write_private_key_to_filename(pk1,
+ tt_assert(! crypto_pk_write_private_key_to_filename(pk1,
get_fname("pkey1")));
/* failing case for read: can't read. */
- test_assert(crypto_pk_read_private_key_from_filename(pk2,
+ tt_assert(crypto_pk_read_private_key_from_filename(pk2,
get_fname("xyzzy")) < 0);
write_str_to_file(get_fname("xyzzy"), "foobar", 6);
/* Failing case for read: no key. */
- test_assert(crypto_pk_read_private_key_from_filename(pk2,
+ tt_assert(crypto_pk_read_private_key_from_filename(pk2,
get_fname("xyzzy")) < 0);
- test_assert(! crypto_pk_read_private_key_from_filename(pk2,
+ tt_assert(! crypto_pk_read_private_key_from_filename(pk2,
get_fname("pkey1")));
- test_eq(15, crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data1, 128,
+ tt_int_op(15,OP_EQ,
+ crypto_pk_private_decrypt(pk2, data3, sizeof(data3), data1, 128,
PK_PKCS1_OAEP_PADDING,1));
/* Now try signing. */
strlcpy(data1, "Ossifrage", 1024);
- test_eq(128, crypto_pk_private_sign(pk1, data2, sizeof(data2), data1, 10));
- test_eq(10,
+ tt_int_op(128,OP_EQ,
+ crypto_pk_private_sign(pk1, data2, sizeof(data2), data1, 10));
+ tt_int_op(10,OP_EQ,
crypto_pk_public_checksig(pk1, data3, sizeof(data3), data2, 128));
- test_streq(data3, "Ossifrage");
+ tt_str_op(data3,OP_EQ, "Ossifrage");
/* Try signing digests. */
- test_eq(128, crypto_pk_private_sign_digest(pk1, data2, sizeof(data2),
+ tt_int_op(128,OP_EQ, crypto_pk_private_sign_digest(pk1, data2, sizeof(data2),
data1, 10));
- test_eq(20,
+ tt_int_op(20,OP_EQ,
crypto_pk_public_checksig(pk1, data3, sizeof(data3), data2, 128));
- test_eq(0, crypto_pk_public_checksig_digest(pk1, data1, 10, data2, 128));
- test_eq(-1, crypto_pk_public_checksig_digest(pk1, data1, 11, data2, 128));
+ tt_int_op(0,OP_EQ,
+ crypto_pk_public_checksig_digest(pk1, data1, 10, data2, 128));
+ tt_int_op(-1,OP_EQ,
+ crypto_pk_public_checksig_digest(pk1, data1, 11, data2, 128));
/*XXXX test failed signing*/
@@ -476,9 +488,9 @@ test_crypto_pk(void)
crypto_pk_free(pk2);
pk2 = NULL;
i = crypto_pk_asn1_encode(pk1, data1, 1024);
- test_assert(i>0);
+ tt_int_op(i, OP_GT, 0);
pk2 = crypto_pk_asn1_decode(data1, i);
- test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);
+ tt_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);
/* Try with hybrid encryption wrappers. */
crypto_rand(data1, 1024);
@@ -487,19 +499,19 @@ test_crypto_pk(void)
memset(data3,0,1024);
len = crypto_pk_public_hybrid_encrypt(pk1,data2,sizeof(data2),
data1,i,PK_PKCS1_OAEP_PADDING,0);
- test_assert(len>=0);
+ tt_int_op(len, OP_GE, 0);
len = crypto_pk_private_hybrid_decrypt(pk1,data3,sizeof(data3),
data2,len,PK_PKCS1_OAEP_PADDING,1);
- test_eq(len,i);
- test_memeq(data1,data3,i);
+ tt_int_op(len,OP_EQ, i);
+ tt_mem_op(data1,OP_EQ, data3,i);
}
/* Try copy_full */
crypto_pk_free(pk2);
pk2 = crypto_pk_copy_full(pk1);
- test_assert(pk2 != NULL);
- test_neq_ptr(pk1, pk2);
- test_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);
+ tt_assert(pk2 != NULL);
+ tt_ptr_op(pk1, OP_NE, pk2);
+ tt_assert(crypto_pk_cmp_keys(pk1,pk2) == 0);
done:
if (pk1)
@@ -525,33 +537,33 @@ test_crypto_pk_fingerprints(void *arg)
pk = pk_generate(1);
tt_assert(pk);
n = crypto_pk_asn1_encode(pk, encoded, sizeof(encoded));
- tt_int_op(n, >, 0);
- tt_int_op(n, >, 128);
- tt_int_op(n, <, 256);
+ tt_int_op(n, OP_GT, 0);
+ tt_int_op(n, OP_GT, 128);
+ tt_int_op(n, OP_LT, 256);
/* Is digest as expected? */
crypto_digest(d, encoded, n);
- tt_int_op(0, ==, crypto_pk_get_digest(pk, d2));
- test_memeq(d, d2, DIGEST_LEN);
+ tt_int_op(0, OP_EQ, crypto_pk_get_digest(pk, d2));
+ tt_mem_op(d,OP_EQ, d2, DIGEST_LEN);
/* Is fingerprint right? */
- tt_int_op(0, ==, crypto_pk_get_fingerprint(pk, fingerprint, 0));
- tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2);
+ tt_int_op(0, OP_EQ, crypto_pk_get_fingerprint(pk, fingerprint, 0));
+ tt_int_op(strlen(fingerprint), OP_EQ, DIGEST_LEN * 2);
test_memeq_hex(d, fingerprint);
/* Are spaces right? */
- tt_int_op(0, ==, crypto_pk_get_fingerprint(pk, fingerprint, 1));
+ tt_int_op(0, OP_EQ, crypto_pk_get_fingerprint(pk, fingerprint, 1));
for (i = 4; i < strlen(fingerprint); i += 5) {
- tt_int_op(fingerprint[i], ==, ' ');
+ tt_int_op(fingerprint[i], OP_EQ, ' ');
}
tor_strstrip(fingerprint, " ");
- tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2);
+ tt_int_op(strlen(fingerprint), OP_EQ, DIGEST_LEN * 2);
test_memeq_hex(d, fingerprint);
/* Now hash again and check crypto_pk_get_hashed_fingerprint. */
crypto_digest(d2, d, sizeof(d));
- tt_int_op(0, ==, crypto_pk_get_hashed_fingerprint(pk, fingerprint));
- tt_int_op(strlen(fingerprint), ==, DIGEST_LEN * 2);
+ tt_int_op(0, OP_EQ, crypto_pk_get_hashed_fingerprint(pk, fingerprint));
+ tt_int_op(strlen(fingerprint), OP_EQ, DIGEST_LEN * 2);
test_memeq_hex(d2, fingerprint);
done:
@@ -561,28 +573,29 @@ test_crypto_pk_fingerprints(void *arg)
/** Sanity check for crypto pk digests */
static void
-test_crypto_digests(void)
+test_crypto_digests(void *arg)
{
crypto_pk_t *k = NULL;
ssize_t r;
digests_t pkey_digests;
char digest[DIGEST_LEN];
+ (void)arg;
k = crypto_pk_new();
- test_assert(k);
+ tt_assert(k);
r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_3, -1);
- test_assert(!r);
+ tt_assert(!r);
r = crypto_pk_get_digest(k, digest);
- test_assert(r == 0);
- test_memeq(hex_str(digest, DIGEST_LEN),
+ tt_assert(r == 0);
+ tt_mem_op(hex_str(digest, DIGEST_LEN),OP_EQ,
AUTHORITY_SIGNKEY_A_DIGEST, HEX_DIGEST_LEN);
r = crypto_pk_get_all_digests(k, &pkey_digests);
- test_memeq(hex_str(pkey_digests.d[DIGEST_SHA1], DIGEST_LEN),
+ tt_mem_op(hex_str(pkey_digests.d[DIGEST_SHA1], DIGEST_LEN),OP_EQ,
AUTHORITY_SIGNKEY_A_DIGEST, HEX_DIGEST_LEN);
- test_memeq(hex_str(pkey_digests.d[DIGEST_SHA256], DIGEST256_LEN),
+ tt_mem_op(hex_str(pkey_digests.d[DIGEST_SHA256], DIGEST256_LEN),OP_EQ,
AUTHORITY_SIGNKEY_A_DIGEST256, HEX_DIGEST256_LEN);
done:
crypto_pk_free(k);
@@ -591,58 +604,59 @@ test_crypto_digests(void)
/** Run unit tests for misc crypto formatting functionality (base64, base32,
* fingerprints, etc) */
static void
-test_crypto_formats(void)
+test_crypto_formats(void *arg)
{
char *data1 = NULL, *data2 = NULL, *data3 = NULL;
int i, j, idx;
+ (void)arg;
data1 = tor_malloc(1024);
data2 = tor_malloc(1024);
data3 = tor_malloc(1024);
- test_assert(data1 && data2 && data3);
+ tt_assert(data1 && data2 && data3);
/* Base64 tests */
memset(data1, 6, 1024);
for (idx = 0; idx < 10; ++idx) {
i = base64_encode(data2, 1024, data1, idx);
- test_assert(i >= 0);
+ tt_int_op(i, OP_GE, 0);
j = base64_decode(data3, 1024, data2, i);
- test_eq(j,idx);
- test_memeq(data3, data1, idx);
+ tt_int_op(j,OP_EQ, idx);
+ tt_mem_op(data3,OP_EQ, data1, idx);
}
strlcpy(data1, "Test string that contains 35 chars.", 1024);
strlcat(data1, " 2nd string that contains 35 chars.", 1024);
i = base64_encode(data2, 1024, data1, 71);
- test_assert(i >= 0);
+ tt_int_op(i, OP_GE, 0);
j = base64_decode(data3, 1024, data2, i);
- test_eq(j, 71);
- test_streq(data3, data1);
- test_assert(data2[i] == '\0');
+ tt_int_op(j,OP_EQ, 71);
+ tt_str_op(data3,OP_EQ, data1);
+ tt_int_op(data2[i], OP_EQ, '\0');
crypto_rand(data1, DIGEST_LEN);
memset(data2, 100, 1024);
digest_to_base64(data2, data1);
- test_eq(BASE64_DIGEST_LEN, strlen(data2));
- test_eq(100, data2[BASE64_DIGEST_LEN+2]);
+ tt_int_op(BASE64_DIGEST_LEN,OP_EQ, strlen(data2));
+ tt_int_op(100,OP_EQ, data2[BASE64_DIGEST_LEN+2]);
memset(data3, 99, 1024);
- test_eq(digest_from_base64(data3, data2), 0);
- test_memeq(data1, data3, DIGEST_LEN);
- test_eq(99, data3[DIGEST_LEN+1]);
+ tt_int_op(digest_from_base64(data3, data2),OP_EQ, 0);
+ tt_mem_op(data1,OP_EQ, data3, DIGEST_LEN);
+ tt_int_op(99,OP_EQ, data3[DIGEST_LEN+1]);
- test_assert(digest_from_base64(data3, "###") < 0);
+ tt_assert(digest_from_base64(data3, "###") < 0);
/* Encoding SHA256 */
crypto_rand(data2, DIGEST256_LEN);
memset(data2, 100, 1024);
digest256_to_base64(data2, data1);
- test_eq(BASE64_DIGEST256_LEN, strlen(data2));
- test_eq(100, data2[BASE64_DIGEST256_LEN+2]);
+ tt_int_op(BASE64_DIGEST256_LEN,OP_EQ, strlen(data2));
+ tt_int_op(100,OP_EQ, data2[BASE64_DIGEST256_LEN+2]);
memset(data3, 99, 1024);
- test_eq(digest256_from_base64(data3, data2), 0);
- test_memeq(data1, data3, DIGEST256_LEN);
- test_eq(99, data3[DIGEST256_LEN+1]);
+ tt_int_op(digest256_from_base64(data3, data2),OP_EQ, 0);
+ tt_mem_op(data1,OP_EQ, data3, DIGEST256_LEN);
+ tt_int_op(99,OP_EQ, data3[DIGEST256_LEN+1]);
/* Base32 tests */
strlcpy(data1, "5chrs", 1024);
@@ -651,27 +665,27 @@ test_crypto_formats(void)
* By 5s: [00110 10101 10001 10110 10000 11100 10011 10011]
*/
base32_encode(data2, 9, data1, 5);
- test_streq(data2, "gvrwq4tt");
+ tt_str_op(data2,OP_EQ, "gvrwq4tt");
strlcpy(data1, "\xFF\xF5\x6D\x44\xAE\x0D\x5C\xC9\x62\xC4", 1024);
base32_encode(data2, 30, data1, 10);
- test_streq(data2, "772w2rfobvomsywe");
+ tt_str_op(data2,OP_EQ, "772w2rfobvomsywe");
/* Base16 tests */
strlcpy(data1, "6chrs\xff", 1024);
base16_encode(data2, 13, data1, 6);
- test_streq(data2, "3663687273FF");
+ tt_str_op(data2,OP_EQ, "3663687273FF");
strlcpy(data1, "f0d678affc000100", 1024);
i = base16_decode(data2, 8, data1, 16);
- test_eq(i,0);
- test_memeq(data2, "\xf0\xd6\x78\xaf\xfc\x00\x01\x00",8);
+ tt_int_op(i,OP_EQ, 0);
+ tt_mem_op(data2,OP_EQ, "\xf0\xd6\x78\xaf\xfc\x00\x01\x00",8);
/* now try some failing base16 decodes */
- test_eq(-1, base16_decode(data2, 8, data1, 15)); /* odd input len */
- test_eq(-1, base16_decode(data2, 7, data1, 16)); /* dest too short */
+ tt_int_op(-1,OP_EQ, base16_decode(data2, 8, data1, 15)); /* odd input len */
+ tt_int_op(-1,OP_EQ, base16_decode(data2, 7, data1, 16)); /* dest too short */
strlcpy(data1, "f0dz!8affc000100", 1024);
- test_eq(-1, base16_decode(data2, 8, data1, 16));
+ tt_int_op(-1,OP_EQ, base16_decode(data2, 8, data1, 16));
tor_free(data1);
tor_free(data2);
@@ -680,10 +694,11 @@ test_crypto_formats(void)
/* Add spaces to fingerprint */
{
data1 = tor_strdup("ABCD1234ABCD56780000ABCD1234ABCD56780000");
- test_eq(strlen(data1), 40);
+ tt_int_op(strlen(data1),OP_EQ, 40);
data2 = tor_malloc(FINGERPRINT_LEN+1);
crypto_add_spaces_to_fp(data2, FINGERPRINT_LEN+1, data1);
- test_streq(data2, "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000");
+ tt_str_op(data2, OP_EQ,
+ "ABCD 1234 ABCD 5678 0000 ABCD 1234 ABCD 5678 0000");
tor_free(data1);
tor_free(data2);
}
@@ -694,39 +709,6 @@ test_crypto_formats(void)
tor_free(data3);
}
-/** Run unit tests for our secret-to-key passphrase hashing functionality. */
-static void
-test_crypto_s2k(void)
-{
- char buf[29];
- char buf2[29];
- char *buf3 = NULL;
- int i;
-
- memset(buf, 0, sizeof(buf));
- memset(buf2, 0, sizeof(buf2));
- buf3 = tor_malloc(65536);
- memset(buf3, 0, 65536);
-
- secret_to_key(buf+9, 20, "", 0, buf);
- crypto_digest(buf2+9, buf3, 1024);
- test_memeq(buf, buf2, 29);
-
- memcpy(buf,"vrbacrda",8);
- memcpy(buf2,"vrbacrda",8);
- buf[8] = 96;
- buf2[8] = 96;
- secret_to_key(buf+9, 20, "12345678", 8, buf);
- for (i = 0; i < 65536; i += 16) {
- memcpy(buf3+i, "vrbacrda12345678", 16);
- }
- crypto_digest(buf2+9, buf3, 65536);
- test_memeq(buf, buf2, 29);
-
- done:
- tor_free(buf3);
-}
-
/** Test AES-CTR encryption and decryption with IV. */
static void
test_crypto_aes_iv(void *arg)
@@ -757,79 +739,79 @@ test_crypto_aes_iv(void *arg)
encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 4095,
plain, 4095);
- test_eq(encrypted_size, 16 + 4095);
+ tt_int_op(encrypted_size,OP_EQ, 16 + 4095);
tt_assert(encrypted_size > 0); /* This is obviously true, since 4111 is
* greater than 0, but its truth is not
* obvious to all analysis tools. */
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
encrypted1, encrypted_size);
- test_eq(decrypted_size, 4095);
+ tt_int_op(decrypted_size,OP_EQ, 4095);
tt_assert(decrypted_size > 0);
- test_memeq(plain, decrypted1, 4095);
+ tt_mem_op(plain,OP_EQ, decrypted1, 4095);
/* Encrypt a second time (with a new random initialization vector). */
encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted2, 16 + 4095,
plain, 4095);
- test_eq(encrypted_size, 16 + 4095);
+ tt_int_op(encrypted_size,OP_EQ, 16 + 4095);
tt_assert(encrypted_size > 0);
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted2, 4095,
encrypted2, encrypted_size);
- test_eq(decrypted_size, 4095);
+ tt_int_op(decrypted_size,OP_EQ, 4095);
tt_assert(decrypted_size > 0);
- test_memeq(plain, decrypted2, 4095);
- test_memneq(encrypted1, encrypted2, encrypted_size);
+ tt_mem_op(plain,OP_EQ, decrypted2, 4095);
+ tt_mem_op(encrypted1,OP_NE, encrypted2, encrypted_size);
/* Decrypt with the wrong key. */
decrypted_size = crypto_cipher_decrypt_with_iv(key2, decrypted2, 4095,
encrypted1, encrypted_size);
- test_eq(decrypted_size, 4095);
- test_memneq(plain, decrypted2, decrypted_size);
+ tt_int_op(decrypted_size,OP_EQ, 4095);
+ tt_mem_op(plain,OP_NE, decrypted2, decrypted_size);
/* Alter the initialization vector. */
encrypted1[0] += 42;
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 4095,
encrypted1, encrypted_size);
- test_eq(decrypted_size, 4095);
- test_memneq(plain, decrypted2, 4095);
+ tt_int_op(decrypted_size,OP_EQ, 4095);
+ tt_mem_op(plain,OP_NE, decrypted2, 4095);
/* Special length case: 1. */
encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 1,
plain_1, 1);
- test_eq(encrypted_size, 16 + 1);
+ tt_int_op(encrypted_size,OP_EQ, 16 + 1);
tt_assert(encrypted_size > 0);
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 1,
encrypted1, encrypted_size);
- test_eq(decrypted_size, 1);
+ tt_int_op(decrypted_size,OP_EQ, 1);
tt_assert(decrypted_size > 0);
- test_memeq(plain_1, decrypted1, 1);
+ tt_mem_op(plain_1,OP_EQ, decrypted1, 1);
/* Special length case: 15. */
encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 15,
plain_15, 15);
- test_eq(encrypted_size, 16 + 15);
+ tt_int_op(encrypted_size,OP_EQ, 16 + 15);
tt_assert(encrypted_size > 0);
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 15,
encrypted1, encrypted_size);
- test_eq(decrypted_size, 15);
+ tt_int_op(decrypted_size,OP_EQ, 15);
tt_assert(decrypted_size > 0);
- test_memeq(plain_15, decrypted1, 15);
+ tt_mem_op(plain_15,OP_EQ, decrypted1, 15);
/* Special length case: 16. */
encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 16,
plain_16, 16);
- test_eq(encrypted_size, 16 + 16);
+ tt_int_op(encrypted_size,OP_EQ, 16 + 16);
tt_assert(encrypted_size > 0);
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 16,
encrypted1, encrypted_size);
- test_eq(decrypted_size, 16);
+ tt_int_op(decrypted_size,OP_EQ, 16);
tt_assert(decrypted_size > 0);
- test_memeq(plain_16, decrypted1, 16);
+ tt_mem_op(plain_16,OP_EQ, decrypted1, 16);
/* Special length case: 17. */
encrypted_size = crypto_cipher_encrypt_with_iv(key1, encrypted1, 16 + 17,
plain_17, 17);
- test_eq(encrypted_size, 16 + 17);
+ tt_int_op(encrypted_size,OP_EQ, 16 + 17);
tt_assert(encrypted_size > 0);
decrypted_size = crypto_cipher_decrypt_with_iv(key1, decrypted1, 17,
encrypted1, encrypted_size);
- test_eq(decrypted_size, 17);
+ tt_int_op(decrypted_size,OP_EQ, 17);
tt_assert(decrypted_size > 0);
- test_memeq(plain_17, decrypted1, 17);
+ tt_mem_op(plain_17,OP_EQ, decrypted1, 17);
done:
/* Free memory. */
@@ -842,34 +824,35 @@ test_crypto_aes_iv(void *arg)
/** Test base32 decoding. */
static void
-test_crypto_base32_decode(void)
+test_crypto_base32_decode(void *arg)
{
char plain[60], encoded[96 + 1], decoded[60];
int res;
+ (void)arg;
crypto_rand(plain, 60);
/* Encode and decode a random string. */
base32_encode(encoded, 96 + 1, plain, 60);
res = base32_decode(decoded, 60, encoded, 96);
- test_eq(res, 0);
- test_memeq(plain, decoded, 60);
+ tt_int_op(res,OP_EQ, 0);
+ tt_mem_op(plain,OP_EQ, decoded, 60);
/* Encode, uppercase, and decode a random string. */
base32_encode(encoded, 96 + 1, plain, 60);
tor_strupper(encoded);
res = base32_decode(decoded, 60, encoded, 96);
- test_eq(res, 0);
- test_memeq(plain, decoded, 60);
+ tt_int_op(res,OP_EQ, 0);
+ tt_mem_op(plain,OP_EQ, decoded, 60);
/* Change encoded string and decode. */
if (encoded[0] == 'A' || encoded[0] == 'a')
encoded[0] = 'B';
else
encoded[0] = 'A';
res = base32_decode(decoded, 60, encoded, 96);
- test_eq(res, 0);
- test_memneq(plain, decoded, 60);
+ tt_int_op(res,OP_EQ, 0);
+ tt_mem_op(plain,OP_NE, decoded, 60);
/* Bad encodings. */
encoded[0] = '!';
res = base32_decode(decoded, 60, encoded, 96);
- test_assert(res < 0);
+ tt_int_op(0, OP_GT, res);
done:
;
@@ -892,7 +875,7 @@ test_crypto_kdf_TAP(void *arg)
* your own. */
memset(key_material, 0, sizeof(key_material));
EXPAND("");
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
test_memeq_hex(key_material,
"5ba93c9db0cff93f52b521d7420e43f6eda2784fbf8b4530d8"
"d246dd74ac53a13471bba17941dff7c4ea21bb365bbeeaf5f2"
@@ -900,7 +883,7 @@ test_crypto_kdf_TAP(void *arg)
"f07b01e13da42c6cf1de3abfdea9b95f34687cbbe92b9a7383");
EXPAND("Tor");
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
test_memeq_hex(key_material,
"776c6214fc647aaa5f683c737ee66ec44f03d0372e1cce6922"
"7950f236ddf1e329a7ce7c227903303f525a8c6662426e8034"
@@ -908,7 +891,7 @@ test_crypto_kdf_TAP(void *arg)
"3f45dfda1a80bdc8b80de01b23e3e0ffae099b3e4ccf28dc28");
EXPAND("AN ALARMING ITEM TO FIND ON A MONTHLY AUTO-DEBIT NOTICE");
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
test_memeq_hex(key_material,
"a340b5d126086c3ab29c2af4179196dbf95e1c72431419d331"
"4844bf8f6afb6098db952b95581fb6c33625709d6f4400b8e7"
@@ -944,7 +927,7 @@ test_crypto_hkdf_sha256(void *arg)
/* Test vectors generated with ntor_ref.py */
memset(key_material, 0, sizeof(key_material));
EXPAND("");
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
test_memeq_hex(key_material,
"d3490ed48b12a48f9547861583573fe3f19aafe3f81dc7fc75"
"eeed96d741b3290f941576c1f9f0b2d463d1ec7ab2c6bf71cd"
@@ -952,7 +935,7 @@ test_crypto_hkdf_sha256(void *arg)
"dcf6abe0d20c77cf363e8ffe358927817a3d3e73712cee28d8");
EXPAND("Tor");
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
test_memeq_hex(key_material,
"5521492a85139a8d9107a2d5c0d9c91610d0f95989975ebee6"
"c02a4f8d622a6cfdf9b7c7edd3832e2760ded1eac309b76f8d"
@@ -960,7 +943,7 @@ test_crypto_hkdf_sha256(void *arg)
"961be9fdb9f93197ea8e5977180801926d3321fa21513e59ac");
EXPAND("AN ALARMING ITEM TO FIND ON YOUR CREDIT-RATING STATEMENT");
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
test_memeq_hex(key_material,
"a2aa9b50da7e481d30463adb8f233ff06e9571a0ca6ab6df0f"
"b206fa34e5bc78d063fc291501beec53b36e5a0e434561200c"
@@ -972,7 +955,6 @@ test_crypto_hkdf_sha256(void *arg)
#undef EXPAND
}
-#ifdef CURVE25519_ENABLED
static void
test_crypto_curve25519_impl(void *arg)
{
@@ -1024,7 +1006,7 @@ test_crypto_curve25519_impl(void *arg)
e2k[31] |= (byte & 0x80);
}
curve25519_impl(e1e2k,e1,e2k);
- test_memeq(e1e2k, e2e1k, 32);
+ tt_mem_op(e1e2k,OP_EQ, e2e1k, 32);
if (loop == loop_max-1) {
break;
}
@@ -1056,11 +1038,11 @@ test_crypto_curve25519_wrappers(void *arg)
curve25519_secret_key_generate(&seckey2, 1);
curve25519_public_key_generate(&pubkey1, &seckey1);
curve25519_public_key_generate(&pubkey2, &seckey2);
- test_assert(curve25519_public_key_is_ok(&pubkey1));
- test_assert(curve25519_public_key_is_ok(&pubkey2));
+ tt_assert(curve25519_public_key_is_ok(&pubkey1));
+ tt_assert(curve25519_public_key_is_ok(&pubkey2));
curve25519_handshake(output1, &seckey1, &pubkey2);
curve25519_handshake(output2, &seckey2, &pubkey1);
- test_memeq(output1, output2, sizeof(output1));
+ tt_mem_op(output1,OP_EQ, output2, sizeof(output1));
done:
;
@@ -1077,26 +1059,26 @@ test_crypto_curve25519_encode(void *arg)
curve25519_secret_key_generate(&seckey, 0);
curve25519_public_key_generate(&key1, &seckey);
- tt_int_op(0, ==, curve25519_public_to_base64(buf, &key1));
- tt_int_op(CURVE25519_BASE64_PADDED_LEN, ==, strlen(buf));
+ tt_int_op(0, OP_EQ, curve25519_public_to_base64(buf, &key1));
+ tt_int_op(CURVE25519_BASE64_PADDED_LEN, OP_EQ, strlen(buf));
- tt_int_op(0, ==, curve25519_public_from_base64(&key2, buf));
- test_memeq(key1.public_key, key2.public_key, CURVE25519_PUBKEY_LEN);
+ tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key2, buf));
+ tt_mem_op(key1.public_key,OP_EQ, key2.public_key, CURVE25519_PUBKEY_LEN);
buf[CURVE25519_BASE64_PADDED_LEN - 1] = '\0';
- tt_int_op(CURVE25519_BASE64_PADDED_LEN-1, ==, strlen(buf));
- tt_int_op(0, ==, curve25519_public_from_base64(&key3, buf));
- test_memeq(key1.public_key, key3.public_key, CURVE25519_PUBKEY_LEN);
+ tt_int_op(CURVE25519_BASE64_PADDED_LEN-1, OP_EQ, strlen(buf));
+ tt_int_op(0, OP_EQ, curve25519_public_from_base64(&key3, buf));
+ tt_mem_op(key1.public_key,OP_EQ, key3.public_key, CURVE25519_PUBKEY_LEN);
/* Now try bogus parses. */
strlcpy(buf, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$=", sizeof(buf));
- tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf));
+ tt_int_op(-1, OP_EQ, curve25519_public_from_base64(&key3, buf));
strlcpy(buf, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", sizeof(buf));
- tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf));
+ tt_int_op(-1, OP_EQ, curve25519_public_from_base64(&key3, buf));
strlcpy(buf, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", sizeof(buf));
- tt_int_op(-1, ==, curve25519_public_from_base64(&key3, buf));
+ tt_int_op(-1, OP_EQ, curve25519_public_from_base64(&key3, buf));
done:
;
@@ -1115,45 +1097,49 @@ test_crypto_curve25519_persist(void *arg)
(void)arg;
- tt_int_op(0,==,curve25519_keypair_generate(&keypair, 0));
+ tt_int_op(0,OP_EQ,curve25519_keypair_generate(&keypair, 0));
- tt_int_op(0,==,curve25519_keypair_write_to_file(&keypair, fname, "testing"));
- tt_int_op(0,==,curve25519_keypair_read_from_file(&keypair2, &tag, fname));
- tt_str_op(tag,==,"testing");
+ tt_int_op(0,OP_EQ,
+ curve25519_keypair_write_to_file(&keypair, fname, "testing"));
+ tt_int_op(0,OP_EQ,curve25519_keypair_read_from_file(&keypair2, &tag, fname));
+ tt_str_op(tag,OP_EQ,"testing");
tor_free(tag);
- test_memeq(keypair.pubkey.public_key,
+ tt_mem_op(keypair.pubkey.public_key,OP_EQ,
keypair2.pubkey.public_key,
CURVE25519_PUBKEY_LEN);
- test_memeq(keypair.seckey.secret_key,
+ tt_mem_op(keypair.seckey.secret_key,OP_EQ,
keypair2.seckey.secret_key,
CURVE25519_SECKEY_LEN);
content = read_file_to_str(fname, RFTS_BIN, &st);
tt_assert(content);
taglen = strlen("== c25519v1: testing ==");
- tt_u64_op((uint64_t)st.st_size, ==,
+ tt_u64_op((uint64_t)st.st_size, OP_EQ,
32+CURVE25519_PUBKEY_LEN+CURVE25519_SECKEY_LEN);
tt_assert(fast_memeq(content, "== c25519v1: testing ==", taglen));
tt_assert(tor_mem_is_zero(content+taglen, 32-taglen));
cp = content + 32;
- test_memeq(keypair.seckey.secret_key,
+ tt_mem_op(keypair.seckey.secret_key,OP_EQ,
cp,
CURVE25519_SECKEY_LEN);
cp += CURVE25519_SECKEY_LEN;
- test_memeq(keypair.pubkey.public_key,
+ tt_mem_op(keypair.pubkey.public_key,OP_EQ,
cp,
CURVE25519_SECKEY_LEN);
tor_free(fname);
fname = tor_strdup(get_fname("bogus_keypair"));
- tt_int_op(-1, ==, curve25519_keypair_read_from_file(&keypair2, &tag, fname));
+ tt_int_op(-1, OP_EQ,
+ curve25519_keypair_read_from_file(&keypair2, &tag, fname));
tor_free(tag);
content[69] ^= 0xff;
- tt_int_op(0, ==, write_bytes_to_file(fname, content, (size_t)st.st_size, 1));
- tt_int_op(-1, ==, curve25519_keypair_read_from_file(&keypair2, &tag, fname));
+ tt_int_op(0, OP_EQ,
+ write_bytes_to_file(fname, content, (size_t)st.st_size, 1));
+ tt_int_op(-1, OP_EQ,
+ curve25519_keypair_read_from_file(&keypair2, &tag, fname));
done:
tor_free(fname);
@@ -1161,7 +1147,361 @@ test_crypto_curve25519_persist(void *arg)
tor_free(tag);
}
-#endif
+static void
+test_crypto_ed25519_simple(void *arg)
+{
+ ed25519_keypair_t kp1, kp2;
+ ed25519_public_key_t pub1, pub2;
+ ed25519_secret_key_t sec1, sec2;
+ ed25519_signature_t sig1, sig2;
+ const uint8_t msg[] =
+ "GNU will be able to run Unix programs, "
+ "but will not be identical to Unix.";
+ const uint8_t msg2[] =
+ "Microsoft Windows extends the features of the DOS operating system, "
+ "yet is compatible with most existing applications that run under DOS.";
+ size_t msg_len = strlen((const char*)msg);
+ size_t msg2_len = strlen((const char*)msg2);
+
+ (void)arg;
+
+ tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sec1, 0));
+ tt_int_op(0, OP_EQ, ed25519_secret_key_generate(&sec2, 1));
+
+ tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub1, &sec1));
+ tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec1));
+
+ tt_mem_op(pub1.pubkey, OP_EQ, pub2.pubkey, sizeof(pub1.pubkey));
+
+ memcpy(&kp1.pubkey, &pub1, sizeof(pub1));
+ memcpy(&kp1.seckey, &sec1, sizeof(sec1));
+ tt_int_op(0, OP_EQ, ed25519_sign(&sig1, msg, msg_len, &kp1));
+ tt_int_op(0, OP_EQ, ed25519_sign(&sig2, msg, msg_len, &kp1));
+
+ /* Ed25519 signatures are deterministic */
+ tt_mem_op(sig1.sig, OP_EQ, sig2.sig, sizeof(sig1.sig));
+
+ /* Basic signature is valid. */
+ tt_int_op(0, OP_EQ, ed25519_checksig(&sig1, msg, msg_len, &pub1));
+
+ /* Altered signature doesn't work. */
+ sig1.sig[0] ^= 3;
+ tt_int_op(-1, OP_EQ, ed25519_checksig(&sig1, msg, msg_len, &pub1));
+
+ /* Wrong public key doesn't work. */
+ tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pub2, &sec2));
+ tt_int_op(-1, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub2));
+
+ /* Wrong message doesn't work. */
+ tt_int_op(0, OP_EQ, ed25519_checksig(&sig2, msg, msg_len, &pub1));
+ tt_int_op(-1, OP_EQ, ed25519_checksig(&sig2, msg, msg_len-1, &pub1));
+ tt_int_op(-1, OP_EQ, ed25519_checksig(&sig2, msg2, msg2_len, &pub1));
+
+ /* Batch signature checking works with some bad. */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&kp2, 0));
+ tt_int_op(0, OP_EQ, ed25519_sign(&sig1, msg, msg_len, &kp2));
+ {
+ ed25519_checkable_t ch[] = {
+ { &pub1, sig2, msg, msg_len }, /*ok*/
+ { &pub1, sig2, msg, msg_len-1 }, /*bad*/
+ { &kp2.pubkey, sig2, msg2, msg2_len }, /*bad*/
+ { &kp2.pubkey, sig1, msg, msg_len }, /*ok*/
+ };
+ int okay[4];
+ tt_int_op(-2, OP_EQ, ed25519_checksig_batch(okay, ch, 4));
+ tt_int_op(okay[0], OP_EQ, 1);
+ tt_int_op(okay[1], OP_EQ, 0);
+ tt_int_op(okay[2], OP_EQ, 0);
+ tt_int_op(okay[3], OP_EQ, 1);
+ tt_int_op(-2, OP_EQ, ed25519_checksig_batch(NULL, ch, 4));
+ }
+
+ /* Batch signature checking works with all good. */
+ {
+ ed25519_checkable_t ch[] = {
+ { &pub1, sig2, msg, msg_len }, /*ok*/
+ { &kp2.pubkey, sig1, msg, msg_len }, /*ok*/
+ };
+ int okay[2];
+ tt_int_op(0, OP_EQ, ed25519_checksig_batch(okay, ch, 2));
+ tt_int_op(okay[0], OP_EQ, 1);
+ tt_int_op(okay[1], OP_EQ, 1);
+ tt_int_op(0, OP_EQ, ed25519_checksig_batch(NULL, ch, 2));
+ }
+
+ done:
+ ;
+}
+
+static void
+test_crypto_ed25519_test_vectors(void *arg)
+{
+ char *mem_op_hex_tmp=NULL;
+ int i;
+ struct {
+ const char *sk;
+ const char *pk;
+ const char *sig;
+ const char *msg;
+ } items[] = {
+ /* These test vectors were generated with the "ref" implementation of
+ * ed25519 from SUPERCOP-20130419 */
+ { "4c6574277320686f706520746865726520617265206e6f206275677320696e20",
+ "f3e0e493b30f56e501aeb868fc912fe0c8b76621efca47a78f6d75875193dd87",
+ "b5d7fd6fd3adf643647ce1fe87a2931dedd1a4e38e6c662bedd35cdd80bfac51"
+ "1b2c7d1ee6bd929ac213014e1a8dc5373854c7b25dbe15ec96bf6c94196fae06",
+ "506c6561736520657863757365206d7920667269656e642e2048652069736e2774"
+ "204e554c2d7465726d696e617465642e"
+ },
+
+ { "74686520696d706c656d656e746174696f6e20776869636820617265206e6f74",
+ "407f0025a1e1351a4cb68e92f5c0ebaf66e7aaf93a4006a4d1a66e3ede1cfeac",
+ "02884fde1c3c5944d0ecf2d133726fc820c303aae695adceabf3a1e01e95bf28"
+ "da88c0966f5265e9c6f8edc77b3b96b5c91baec3ca993ccd21a3f64203600601",
+ "506c6561736520657863757365206d7920667269656e642e2048652069736e2774"
+ "204e554c2d7465726d696e617465642e"
+ },
+ { "6578706f73656420627920456e676c697368207465787420617320696e707574",
+ "61681cb5fbd69f9bc5a462a21a7ab319011237b940bc781cdc47fcbe327e7706",
+ "6a127d0414de7510125d4bc214994ffb9b8857a46330832d05d1355e882344ad"
+ "f4137e3ca1f13eb9cc75c887ef2309b98c57528b4acd9f6376c6898889603209",
+ "506c6561736520657863757365206d7920667269656e642e2048652069736e2774"
+ "204e554c2d7465726d696e617465642e"
+ },
+
+ /* These come from "sign.input" in ed25519's page */
+ { "5b5a619f8ce1c66d7ce26e5a2ae7b0c04febcd346d286c929e19d0d5973bfef9",
+ "6fe83693d011d111131c4f3fbaaa40a9d3d76b30012ff73bb0e39ec27ab18257",
+ "0f9ad9793033a2fa06614b277d37381e6d94f65ac2a5a94558d09ed6ce922258"
+ "c1a567952e863ac94297aec3c0d0c8ddf71084e504860bb6ba27449b55adc40e",
+ "5a8d9d0a22357e6655f9c785"
+ },
+ { "940c89fe40a81dafbdb2416d14ae469119869744410c3303bfaa0241dac57800",
+ "a2eb8c0501e30bae0cf842d2bde8dec7386f6b7fc3981b8c57c9792bb94cf2dd",
+ "d8bb64aad8c9955a115a793addd24f7f2b077648714f49c4694ec995b330d09d"
+ "640df310f447fd7b6cb5c14f9fe9f490bcf8cfadbfd2169c8ac20d3b8af49a0c",
+ "b87d3813e03f58cf19fd0b6395"
+ },
+ { "9acad959d216212d789a119252ebfe0c96512a23c73bd9f3b202292d6916a738",
+ "cf3af898467a5b7a52d33d53bc037e2642a8da996903fc252217e9c033e2f291",
+ "6ee3fe81e23c60eb2312b2006b3b25e6838e02106623f844c44edb8dafd66ab0"
+ "671087fd195df5b8f58a1d6e52af42908053d55c7321010092748795ef94cf06",
+ "55c7fa434f5ed8cdec2b7aeac173",
+ },
+ { "d5aeee41eeb0e9d1bf8337f939587ebe296161e6bf5209f591ec939e1440c300",
+ "fd2a565723163e29f53c9de3d5e8fbe36a7ab66e1439ec4eae9c0a604af291a5",
+ "f68d04847e5b249737899c014d31c805c5007a62c0a10d50bb1538c5f3550395"
+ "1fbc1e08682f2cc0c92efe8f4985dec61dcbd54d4b94a22547d24451271c8b00",
+ "0a688e79be24f866286d4646b5d81c"
+ },
+
+ { NULL, NULL, NULL, NULL}
+ };
+
+ (void)arg;
+
+ for (i = 0; items[i].pk; ++i) {
+ ed25519_keypair_t kp;
+ ed25519_signature_t sig;
+ uint8_t sk_seed[32];
+ uint8_t *msg;
+ size_t msg_len;
+ base16_decode((char*)sk_seed, sizeof(sk_seed),
+ items[i].sk, 64);
+ ed25519_secret_key_from_seed(&kp.seckey, sk_seed);
+ tt_int_op(0, OP_EQ, ed25519_public_key_generate(&kp.pubkey, &kp.seckey));
+ test_memeq_hex(kp.pubkey.pubkey, items[i].pk);
+
+ msg_len = strlen(items[i].msg) / 2;
+ msg = tor_malloc(msg_len);
+ base16_decode((char*)msg, msg_len, items[i].msg, strlen(items[i].msg));
+
+ tt_int_op(0, OP_EQ, ed25519_sign(&sig, msg, msg_len, &kp));
+ test_memeq_hex(sig.sig, items[i].sig);
+
+ tor_free(msg);
+ }
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_crypto_ed25519_encode(void *arg)
+{
+ char buf[ED25519_BASE64_LEN+1];
+ ed25519_keypair_t kp;
+ ed25519_public_key_t pk;
+ char *mem_op_hex_tmp = NULL;
+ (void) arg;
+
+ /* Test roundtrip. */
+ tt_int_op(0, OP_EQ, ed25519_keypair_generate(&kp, 0));
+ tt_int_op(0, OP_EQ, ed25519_public_to_base64(buf, &kp.pubkey));
+ tt_int_op(ED25519_BASE64_LEN, OP_EQ, strlen(buf));
+ tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk, buf));
+ tt_mem_op(kp.pubkey.pubkey, OP_EQ, pk.pubkey, ED25519_PUBKEY_LEN);
+
+ /* Test known value. */
+ tt_int_op(0, OP_EQ, ed25519_public_from_base64(&pk,
+ "lVIuIctLjbGZGU5wKMNXxXlSE3cW4kaqkqm04u6pxvM"));
+ test_memeq_hex(pk.pubkey,
+ "95522e21cb4b8db199194e7028c357c57952137716e246aa92a9b4e2eea9c6f3");
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_crypto_ed25519_convert(void *arg)
+{
+ const uint8_t msg[] =
+ "The eyes are not here / There are no eyes here.";
+ const int N = 30;
+ int i;
+ (void)arg;
+
+ for (i = 0; i < N; ++i) {
+ curve25519_keypair_t curve25519_keypair;
+ ed25519_keypair_t ed25519_keypair;
+ ed25519_public_key_t ed25519_pubkey;
+
+ int bit=0;
+ ed25519_signature_t sig;
+
+ tt_int_op(0,OP_EQ,curve25519_keypair_generate(&curve25519_keypair, i&1));
+ tt_int_op(0,OP_EQ,ed25519_keypair_from_curve25519_keypair(
+ &ed25519_keypair, &bit, &curve25519_keypair));
+ tt_int_op(0,OP_EQ,ed25519_public_key_from_curve25519_public_key(
+ &ed25519_pubkey, &curve25519_keypair.pubkey, bit));
+ tt_mem_op(ed25519_pubkey.pubkey, OP_EQ, ed25519_keypair.pubkey.pubkey, 32);
+
+ tt_int_op(0,OP_EQ,ed25519_sign(&sig, msg, sizeof(msg), &ed25519_keypair));
+ tt_int_op(0,OP_EQ,ed25519_checksig(&sig, msg, sizeof(msg),
+ &ed25519_pubkey));
+
+ tt_int_op(-1,OP_EQ,ed25519_checksig(&sig, msg, sizeof(msg)-1,
+ &ed25519_pubkey));
+ sig.sig[0] ^= 15;
+ tt_int_op(-1,OP_EQ,ed25519_checksig(&sig, msg, sizeof(msg),
+ &ed25519_pubkey));
+ }
+
+ done:
+ ;
+}
+
+static void
+test_crypto_ed25519_blinding(void *arg)
+{
+ const uint8_t msg[] =
+ "Eyes I dare not meet in dreams / In death's dream kingdom";
+
+ const int N = 30;
+ int i;
+ (void)arg;
+
+ for (i = 0; i < N; ++i) {
+ uint8_t blinding[32];
+ ed25519_keypair_t ed25519_keypair;
+ ed25519_keypair_t ed25519_keypair_blinded;
+ ed25519_public_key_t ed25519_pubkey_blinded;
+
+ ed25519_signature_t sig;
+
+ crypto_rand((char*) blinding, sizeof(blinding));
+
+ tt_int_op(0,OP_EQ,ed25519_keypair_generate(&ed25519_keypair, 0));
+ tt_int_op(0,OP_EQ,ed25519_keypair_blind(&ed25519_keypair_blinded,
+ &ed25519_keypair, blinding));
+
+ tt_int_op(0,OP_EQ,ed25519_public_blind(&ed25519_pubkey_blinded,
+ &ed25519_keypair.pubkey, blinding));
+
+ tt_mem_op(ed25519_pubkey_blinded.pubkey, OP_EQ,
+ ed25519_keypair_blinded.pubkey.pubkey, 32);
+
+ tt_int_op(0,OP_EQ,ed25519_sign(&sig, msg, sizeof(msg),
+ &ed25519_keypair_blinded));
+
+ tt_int_op(0,OP_EQ,ed25519_checksig(&sig, msg, sizeof(msg),
+ &ed25519_pubkey_blinded));
+
+ tt_int_op(-1,OP_EQ,ed25519_checksig(&sig, msg, sizeof(msg)-1,
+ &ed25519_pubkey_blinded));
+ sig.sig[0] ^= 15;
+ tt_int_op(-1,OP_EQ,ed25519_checksig(&sig, msg, sizeof(msg),
+ &ed25519_pubkey_blinded));
+ }
+
+ done:
+ ;
+}
+
+static void
+test_crypto_ed25519_testvectors(void *arg)
+{
+ unsigned i;
+ char *mem_op_hex_tmp = NULL;
+ (void)arg;
+
+ for (i = 0; i < ARRAY_LENGTH(ED25519_SECRET_KEYS); ++i) {
+ uint8_t sk[32];
+ ed25519_secret_key_t esk;
+ ed25519_public_key_t pk, blind_pk, pkfromcurve;
+ ed25519_keypair_t keypair, blind_keypair;
+ curve25519_keypair_t curvekp;
+ uint8_t blinding_param[32];
+ ed25519_signature_t sig;
+ int sign;
+
+#define DECODE(p,s) base16_decode((char*)(p),sizeof(p),(s),strlen(s))
+#define EQ(a,h) test_memeq_hex((const char*)(a), (h))
+
+ tt_int_op(0, OP_EQ, DECODE(sk, ED25519_SECRET_KEYS[i]));
+ tt_int_op(0, OP_EQ, DECODE(blinding_param, ED25519_BLINDING_PARAMS[i]));
+
+ tt_int_op(0, OP_EQ, ed25519_secret_key_from_seed(&esk, sk));
+ EQ(esk.seckey, ED25519_EXPANDED_SECRET_KEYS[i]);
+
+ tt_int_op(0, OP_EQ, ed25519_public_key_generate(&pk, &esk));
+ EQ(pk.pubkey, ED25519_PUBLIC_KEYS[i]);
+
+ memcpy(&curvekp.seckey.secret_key, esk.seckey, 32);
+ curve25519_public_key_generate(&curvekp.pubkey, &curvekp.seckey);
+
+ tt_int_op(0, OP_EQ,
+ ed25519_keypair_from_curve25519_keypair(&keypair, &sign, &curvekp));
+ tt_int_op(0, OP_EQ, ed25519_public_key_from_curve25519_public_key(
+ &pkfromcurve, &curvekp.pubkey, sign));
+ tt_mem_op(keypair.pubkey.pubkey, OP_EQ, pkfromcurve.pubkey, 32);
+ EQ(curvekp.pubkey.public_key, ED25519_CURVE25519_PUBLIC_KEYS[i]);
+
+ /* Self-signing */
+ memcpy(&keypair.seckey, &esk, sizeof(esk));
+ memcpy(&keypair.pubkey, &pk, sizeof(pk));
+
+ tt_int_op(0, OP_EQ, ed25519_sign(&sig, pk.pubkey, 32, &keypair));
+
+ EQ(sig.sig, ED25519_SELF_SIGNATURES[i]);
+
+ /* Blinding */
+ tt_int_op(0, OP_EQ,
+ ed25519_keypair_blind(&blind_keypair, &keypair, blinding_param));
+ tt_int_op(0, OP_EQ,
+ ed25519_public_blind(&blind_pk, &pk, blinding_param));
+
+ EQ(blind_keypair.seckey.seckey, ED25519_BLINDED_SECRET_KEYS[i]);
+ EQ(blind_pk.pubkey, ED25519_BLINDED_PUBLIC_KEYS[i]);
+
+ tt_mem_op(blind_pk.pubkey, OP_EQ, blind_keypair.pubkey.pubkey, 32);
+
+#undef DECODE
+#undef EQ
+ }
+ done:
+ tor_free(mem_op_hex_tmp);
+}
static void
test_crypto_siphash(void *arg)
@@ -1251,7 +1591,7 @@ test_crypto_siphash(void *arg)
for (i = 0; i < 64; ++i) {
uint64_t r = siphash24(input, i, &K);
for (j = 0; j < 8; ++j) {
- tt_int_op( (r >> (j*8)) & 0xff, ==, VECTORS[i][j]);
+ tt_int_op( (r >> (j*8)) & 0xff, OP_EQ, VECTORS[i][j]);
}
}
@@ -1259,48 +1599,37 @@ test_crypto_siphash(void *arg)
;
}
-static void *
-pass_data_setup_fn(const struct testcase_t *testcase)
-{
- return testcase->setup_data;
-}
-static int
-pass_data_cleanup_fn(const struct testcase_t *testcase, void *ptr)
-{
- (void)ptr;
- (void)testcase;
- return 1;
-}
-static const struct testcase_setup_t pass_data = {
- pass_data_setup_fn, pass_data_cleanup_fn
-};
-
#define CRYPTO_LEGACY(name) \
- { #name, legacy_test_helper, 0, &legacy_setup, test_crypto_ ## name }
+ { #name, test_crypto_ ## name , 0, NULL, NULL }
struct testcase_t crypto_tests[] = {
CRYPTO_LEGACY(formats),
CRYPTO_LEGACY(rng),
- { "aes_AES", test_crypto_aes, TT_FORK, &pass_data, (void*)"aes" },
- { "aes_EVP", test_crypto_aes, TT_FORK, &pass_data, (void*)"evp" },
+ { "aes_AES", test_crypto_aes, TT_FORK, &passthrough_setup, (void*)"aes" },
+ { "aes_EVP", test_crypto_aes, TT_FORK, &passthrough_setup, (void*)"evp" },
CRYPTO_LEGACY(sha),
CRYPTO_LEGACY(pk),
{ "pk_fingerprints", test_crypto_pk_fingerprints, TT_FORK, NULL, NULL },
CRYPTO_LEGACY(digests),
CRYPTO_LEGACY(dh),
- CRYPTO_LEGACY(s2k),
- { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"aes" },
- { "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &pass_data, (void*)"evp" },
+ { "aes_iv_AES", test_crypto_aes_iv, TT_FORK, &passthrough_setup,
+ (void*)"aes" },
+ { "aes_iv_EVP", test_crypto_aes_iv, TT_FORK, &passthrough_setup,
+ (void*)"evp" },
CRYPTO_LEGACY(base32_decode),
{ "kdf_TAP", test_crypto_kdf_TAP, 0, NULL, NULL },
{ "hkdf_sha256", test_crypto_hkdf_sha256, 0, NULL, NULL },
-#ifdef CURVE25519_ENABLED
{ "curve25519_impl", test_crypto_curve25519_impl, 0, NULL, NULL },
{ "curve25519_impl_hibit", test_crypto_curve25519_impl, 0, NULL, (void*)"y"},
{ "curve25519_wrappers", test_crypto_curve25519_wrappers, 0, NULL, NULL },
{ "curve25519_encode", test_crypto_curve25519_encode, 0, NULL, NULL },
{ "curve25519_persist", test_crypto_curve25519_persist, 0, NULL, NULL },
-#endif
+ { "ed25519_simple", test_crypto_ed25519_simple, 0, NULL, NULL },
+ { "ed25519_test_vectors", test_crypto_ed25519_test_vectors, 0, NULL, NULL },
+ { "ed25519_encode", test_crypto_ed25519_encode, 0, NULL, NULL },
+ { "ed25519_convert", test_crypto_ed25519_convert, 0, NULL, NULL },
+ { "ed25519_blinding", test_crypto_ed25519_blinding, 0, NULL, NULL },
+ { "ed25519_testvectors", test_crypto_ed25519_testvectors, 0, NULL, NULL },
{ "siphash", test_crypto_siphash, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c
new file mode 100644
index 0000000000..a0f6cdc116
--- /dev/null
+++ b/src/test/test_crypto_slow.c
@@ -0,0 +1,409 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#define CRYPTO_S2K_PRIVATE
+#include "or.h"
+#include "test.h"
+#include "crypto_s2k.h"
+#include "crypto_pwbox.h"
+
+/** Run unit tests for our secret-to-key passphrase hashing functionality. */
+static void
+test_crypto_s2k_rfc2440(void *arg)
+{
+ char buf[29];
+ char buf2[29];
+ char *buf3 = NULL;
+ int i;
+
+ (void)arg;
+ memset(buf, 0, sizeof(buf));
+ memset(buf2, 0, sizeof(buf2));
+ buf3 = tor_malloc(65536);
+ memset(buf3, 0, 65536);
+
+ secret_to_key_rfc2440(buf+9, 20, "", 0, buf);
+ crypto_digest(buf2+9, buf3, 1024);
+ tt_mem_op(buf,OP_EQ, buf2, 29);
+
+ memcpy(buf,"vrbacrda",8);
+ memcpy(buf2,"vrbacrda",8);
+ buf[8] = 96;
+ buf2[8] = 96;
+ secret_to_key_rfc2440(buf+9, 20, "12345678", 8, buf);
+ for (i = 0; i < 65536; i += 16) {
+ memcpy(buf3+i, "vrbacrda12345678", 16);
+ }
+ crypto_digest(buf2+9, buf3, 65536);
+ tt_mem_op(buf,OP_EQ, buf2, 29);
+
+ done:
+ tor_free(buf3);
+}
+
+static void
+run_s2k_tests(const unsigned flags, const unsigned type,
+ int speclen, const int keylen, int legacy)
+{
+ uint8_t buf[S2K_MAXLEN], buf2[S2K_MAXLEN], buf3[S2K_MAXLEN];
+ int r;
+ size_t sz;
+ const char pw1[] = "You can't come in here unless you say swordfish!";
+ const char pw2[] = "Now, I give you one more guess.";
+
+ r = secret_to_key_new(buf, sizeof(buf), &sz,
+ pw1, strlen(pw1), flags);
+ tt_int_op(r, OP_EQ, S2K_OKAY);
+ tt_int_op(buf[0], OP_EQ, type);
+
+ tt_int_op(sz, OP_EQ, keylen + speclen);
+
+ if (legacy) {
+ memmove(buf, buf+1, sz-1);
+ --sz;
+ --speclen;
+ }
+
+ tt_int_op(S2K_OKAY, OP_EQ,
+ secret_to_key_check(buf, sz, pw1, strlen(pw1)));
+
+ tt_int_op(S2K_BAD_SECRET, OP_EQ,
+ secret_to_key_check(buf, sz, pw2, strlen(pw2)));
+
+ /* Move key to buf2, and clear it. */
+ memset(buf3, 0, sizeof(buf3));
+ memcpy(buf2, buf+speclen, keylen);
+ memset(buf+speclen, 0, sz - speclen);
+
+ /* Derivekey should produce the same results. */
+ tt_int_op(S2K_OKAY, OP_EQ,
+ secret_to_key_derivekey(buf3, keylen, buf, speclen, pw1, strlen(pw1)));
+
+ tt_mem_op(buf2, OP_EQ, buf3, keylen);
+
+ /* Derivekey with a longer output should fill the output. */
+ memset(buf2, 0, sizeof(buf2));
+ tt_int_op(S2K_OKAY, OP_EQ,
+ secret_to_key_derivekey(buf2, sizeof(buf2), buf, speclen,
+ pw1, strlen(pw1)));
+
+ tt_mem_op(buf2, OP_NE, buf3, sizeof(buf2));
+
+ memset(buf3, 0, sizeof(buf3));
+ tt_int_op(S2K_OKAY, OP_EQ,
+ secret_to_key_derivekey(buf3, sizeof(buf3), buf, speclen,
+ pw1, strlen(pw1)));
+ tt_mem_op(buf2, OP_EQ, buf3, sizeof(buf3));
+ tt_assert(!tor_mem_is_zero((char*)buf2+keylen, sizeof(buf2)-keylen));
+
+ done:
+ ;
+}
+
+static void
+test_crypto_s2k_general(void *arg)
+{
+ const char *which = arg;
+
+ if (!strcmp(which, "scrypt")) {
+ run_s2k_tests(0, 2, 19, 32, 0);
+ } else if (!strcmp(which, "scrypt-low")) {
+ run_s2k_tests(S2K_FLAG_LOW_MEM, 2, 19, 32, 0);
+ } else if (!strcmp(which, "pbkdf2")) {
+ run_s2k_tests(S2K_FLAG_USE_PBKDF2, 1, 18, 20, 0);
+ } else if (!strcmp(which, "rfc2440")) {
+ run_s2k_tests(S2K_FLAG_NO_SCRYPT, 0, 10, 20, 0);
+ } else if (!strcmp(which, "rfc2440-legacy")) {
+ run_s2k_tests(S2K_FLAG_NO_SCRYPT, 0, 10, 20, 1);
+ } else {
+ tt_fail();
+ }
+}
+
+static void
+test_crypto_s2k_errors(void *arg)
+{
+ uint8_t buf[S2K_MAXLEN], buf2[S2K_MAXLEN];
+ size_t sz;
+
+ (void)arg;
+
+ /* Bogus specifiers: simple */
+ tt_int_op(S2K_BAD_LEN, OP_EQ,
+ secret_to_key_derivekey(buf, sizeof(buf),
+ (const uint8_t*)"", 0, "ABC", 3));
+ tt_int_op(S2K_BAD_ALGORITHM, OP_EQ,
+ secret_to_key_derivekey(buf, sizeof(buf),
+ (const uint8_t*)"\x10", 1, "ABC", 3));
+ tt_int_op(S2K_BAD_LEN, OP_EQ,
+ secret_to_key_derivekey(buf, sizeof(buf),
+ (const uint8_t*)"\x01\x02", 2, "ABC", 3));
+
+ tt_int_op(S2K_BAD_LEN, OP_EQ,
+ secret_to_key_check((const uint8_t*)"", 0, "ABC", 3));
+ tt_int_op(S2K_BAD_ALGORITHM, OP_EQ,
+ secret_to_key_check((const uint8_t*)"\x10", 1, "ABC", 3));
+ tt_int_op(S2K_BAD_LEN, OP_EQ,
+ secret_to_key_check((const uint8_t*)"\x01\x02", 2, "ABC", 3));
+
+ /* too long gets "BAD_LEN" too */
+ memset(buf, 0, sizeof(buf));
+ buf[0] = 2;
+ tt_int_op(S2K_BAD_LEN, OP_EQ,
+ secret_to_key_derivekey(buf2, sizeof(buf2),
+ buf, sizeof(buf), "ABC", 3));
+
+ /* Truncated output */
+#ifdef HAVE_LIBSCRYPT_H
+ tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 50, &sz,
+ "ABC", 3, 0));
+ tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 50, &sz,
+ "ABC", 3, S2K_FLAG_LOW_MEM));
+#endif
+ tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 37, &sz,
+ "ABC", 3, S2K_FLAG_USE_PBKDF2));
+ tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_new(buf, 29, &sz,
+ "ABC", 3, S2K_FLAG_NO_SCRYPT));
+
+#ifdef HAVE_LIBSCRYPT_H
+ tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 18, 0));
+ tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 18,
+ S2K_FLAG_LOW_MEM));
+#endif
+ tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 17,
+ S2K_FLAG_USE_PBKDF2));
+ tt_int_op(S2K_TRUNCATED, OP_EQ, secret_to_key_make_specifier(buf, 9,
+ S2K_FLAG_NO_SCRYPT));
+
+ /* Now try using type-specific bogus specifiers. */
+
+ /* It's a bad pbkdf2 buffer if it has an iteration count that would overflow
+ * int32_t. */
+ memset(buf, 0, sizeof(buf));
+ buf[0] = 1; /* pbkdf2 */
+ buf[17] = 100; /* 1<<100 is much bigger than INT32_MAX */
+ tt_int_op(S2K_BAD_PARAMS, OP_EQ,
+ secret_to_key_derivekey(buf2, sizeof(buf2),
+ buf, 18, "ABC", 3));
+
+#ifdef HAVE_LIBSCRYPT_H
+ /* It's a bad scrypt buffer if N would overflow uint64 */
+ memset(buf, 0, sizeof(buf));
+ buf[0] = 2; /* scrypt */
+ buf[17] = 100; /* 1<<100 is much bigger than UINT64_MAX */
+ tt_int_op(S2K_BAD_PARAMS, OP_EQ,
+ secret_to_key_derivekey(buf2, sizeof(buf2),
+ buf, 19, "ABC", 3));
+#endif
+
+ done:
+ ;
+}
+
+static void
+test_crypto_scrypt_vectors(void *arg)
+{
+ char *mem_op_hex_tmp = NULL;
+ uint8_t spec[64], out[64];
+
+ (void)arg;
+#ifndef HAVE_LIBSCRYPT_H
+ if (1)
+ tt_skip();
+#endif
+
+ /* Test vectors from
+ http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-00 section 11.
+
+ Note that the names of 'r' and 'N' are switched in that section. Or
+ possibly in libscrypt.
+ */
+
+ base16_decode((char*)spec, sizeof(spec),
+ "0400", 4);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(64, OP_EQ,
+ secret_to_key_compute_key(out, 64, spec, 2, "", 0, 2));
+ test_memeq_hex(out,
+ "77d6576238657b203b19ca42c18a0497"
+ "f16b4844e3074ae8dfdffa3fede21442"
+ "fcd0069ded0948f8326a753a0fc81f17"
+ "e8d3e0fb2e0d3628cf35e20c38d18906");
+
+ base16_decode((char*)spec, sizeof(spec),
+ "4e61436c" "0A34", 12);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(64, OP_EQ,
+ secret_to_key_compute_key(out, 64, spec, 6, "password", 8, 2));
+ test_memeq_hex(out,
+ "fdbabe1c9d3472007856e7190d01e9fe"
+ "7c6ad7cbc8237830e77376634b373162"
+ "2eaf30d92e22a3886ff109279d9830da"
+ "c727afb94a83ee6d8360cbdfa2cc0640");
+
+ base16_decode((char*)spec, sizeof(spec),
+ "536f6469756d43686c6f72696465" "0e30", 32);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(64, OP_EQ,
+ secret_to_key_compute_key(out, 64, spec, 16,
+ "pleaseletmein", 13, 2));
+ test_memeq_hex(out,
+ "7023bdcb3afd7348461c06cd81fd38eb"
+ "fda8fbba904f8e3ea9b543f6545da1f2"
+ "d5432955613f0fcf62d49705242a9af9"
+ "e61e85dc0d651e40dfcf017b45575887");
+
+ base16_decode((char*)spec, sizeof(spec),
+ "536f6469756d43686c6f72696465" "1430", 32);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(64, OP_EQ,
+ secret_to_key_compute_key(out, 64, spec, 16,
+ "pleaseletmein", 13, 2));
+ test_memeq_hex(out,
+ "2101cb9b6a511aaeaddbbe09cf70f881"
+ "ec568d574a2ffd4dabe5ee9820adaa47"
+ "8e56fd8f4ba5d09ffa1c6d927c40f4c3"
+ "37304049e8a952fbcbf45c6fa77a41a4");
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_crypto_pbkdf2_vectors(void *arg)
+{
+ char *mem_op_hex_tmp = NULL;
+ uint8_t spec[64], out[64];
+ (void)arg;
+
+ /* Test vectors from RFC6070, section 2 */
+ base16_decode((char*)spec, sizeof(spec),
+ "73616c74" "00" , 10);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(20, OP_EQ,
+ secret_to_key_compute_key(out, 20, spec, 5, "password", 8, 1));
+ test_memeq_hex(out, "0c60c80f961f0e71f3a9b524af6012062fe037a6");
+
+ base16_decode((char*)spec, sizeof(spec),
+ "73616c74" "01" , 10);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(20, OP_EQ,
+ secret_to_key_compute_key(out, 20, spec, 5, "password", 8, 1));
+ test_memeq_hex(out, "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957");
+
+ base16_decode((char*)spec, sizeof(spec),
+ "73616c74" "0C" , 10);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(20, OP_EQ,
+ secret_to_key_compute_key(out, 20, spec, 5, "password", 8, 1));
+ test_memeq_hex(out, "4b007901b765489abead49d926f721d065a429c1");
+
+ base16_decode((char*)spec, sizeof(spec),
+ "73616c74" "18" , 10);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(20, OP_EQ,
+ secret_to_key_compute_key(out, 20, spec, 5, "password", 8, 1));
+ test_memeq_hex(out, "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984");
+
+ base16_decode((char*)spec, sizeof(spec),
+ "73616c7453414c5473616c7453414c5473616c745"
+ "3414c5473616c7453414c5473616c74" "0C" , 74);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(25, OP_EQ,
+ secret_to_key_compute_key(out, 25, spec, 37,
+ "passwordPASSWORDpassword", 24, 1));
+ test_memeq_hex(out, "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038");
+
+ base16_decode((char*)spec, sizeof(spec),
+ "7361006c74" "0c" , 12);
+ memset(out, 0x00, sizeof(out));
+ tt_int_op(16, OP_EQ,
+ secret_to_key_compute_key(out, 16, spec, 6, "pass\0word", 9, 1));
+ test_memeq_hex(out, "56fa6aa75548099dcc37d7f03425e0c3");
+
+ done:
+ tor_free(mem_op_hex_tmp);
+}
+
+static void
+test_crypto_pwbox(void *arg)
+{
+ uint8_t *boxed=NULL, *decoded=NULL;
+ size_t len, dlen;
+ unsigned i;
+ const char msg[] = "This bunny reminds you that you still have a "
+ "salamander in your sylladex. She is holding the bunny Dave got you. "
+ "It’s sort of uncanny how similar they are, aside from the knitted "
+ "enhancements. Seriously, what are the odds?? So weird.";
+ const char pw[] = "I'm a night owl and a wise bird too";
+
+ const unsigned flags[] = { 0,
+ S2K_FLAG_NO_SCRYPT,
+ S2K_FLAG_LOW_MEM,
+ S2K_FLAG_NO_SCRYPT|S2K_FLAG_LOW_MEM,
+ S2K_FLAG_USE_PBKDF2 };
+ (void)arg;
+
+ for (i = 0; i < ARRAY_LENGTH(flags); ++i) {
+ tt_int_op(0, OP_EQ, crypto_pwbox(&boxed, &len,
+ (const uint8_t*)msg, strlen(msg),
+ pw, strlen(pw), flags[i]));
+ tt_assert(boxed);
+ tt_assert(len > 128+32);
+
+ tt_int_op(0, OP_EQ, crypto_unpwbox(&decoded, &dlen, boxed, len,
+ pw, strlen(pw)));
+
+ tt_assert(decoded);
+ tt_uint_op(dlen, OP_EQ, strlen(msg));
+ tt_mem_op(decoded, OP_EQ, msg, dlen);
+
+ tor_free(decoded);
+
+ tt_int_op(UNPWBOX_BAD_SECRET, OP_EQ, crypto_unpwbox(&decoded, &dlen,
+ boxed, len,
+ pw, strlen(pw)-1));
+ boxed[len-1] ^= 1;
+ tt_int_op(UNPWBOX_BAD_SECRET, OP_EQ, crypto_unpwbox(&decoded, &dlen,
+ boxed, len,
+ pw, strlen(pw)));
+ boxed[0] = 255;
+ tt_int_op(UNPWBOX_CORRUPTED, OP_EQ, crypto_unpwbox(&decoded, &dlen,
+ boxed, len,
+ pw, strlen(pw)));
+
+ tor_free(boxed);
+ }
+
+ done:
+ tor_free(boxed);
+ tor_free(decoded);
+}
+
+#define CRYPTO_LEGACY(name) \
+ { #name, test_crypto_ ## name , 0, NULL, NULL }
+
+struct testcase_t slow_crypto_tests[] = {
+ CRYPTO_LEGACY(s2k_rfc2440),
+#ifdef HAVE_LIBSCRYPT_H
+ { "s2k_scrypt", test_crypto_s2k_general, 0, &passthrough_setup,
+ (void*)"scrypt" },
+ { "s2k_scrypt_low", test_crypto_s2k_general, 0, &passthrough_setup,
+ (void*)"scrypt-low" },
+#endif
+ { "s2k_pbkdf2", test_crypto_s2k_general, 0, &passthrough_setup,
+ (void*)"pbkdf2" },
+ { "s2k_rfc2440_general", test_crypto_s2k_general, 0, &passthrough_setup,
+ (void*)"rfc2440" },
+ { "s2k_rfc2440_legacy", test_crypto_s2k_general, 0, &passthrough_setup,
+ (void*)"rfc2440-legacy" },
+ { "s2k_errors", test_crypto_s2k_errors, 0, NULL, NULL },
+ { "scrypt_vectors", test_crypto_scrypt_vectors, 0, NULL, NULL },
+ { "pbkdf2_vectors", test_crypto_pbkdf2_vectors, 0, NULL, NULL },
+ { "pwbox", test_crypto_pwbox, 0, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_data.c b/src/test/test_data.c
index 0c51c98f1e..6afba65757 100644
--- a/src/test/test_data.c
+++ b/src/test/test_data.c
@@ -1,6 +1,6 @@
/* Copyright 2001-2004 Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Our unit test expect that the AUTHORITY_CERT_* public keys will sort
diff --git a/src/test/test_descriptors.inc b/src/test/test_descriptors.inc
new file mode 100644
index 0000000000..ecbccbd43a
--- /dev/null
+++ b/src/test/test_descriptors.inc
@@ -0,0 +1,305 @@
+const char TEST_DESCRIPTORS[] =
+"@uploaded-at 2014-06-08 19:20:11\n"
+"@source \"127.0.0.1\"\n"
+"router test000a 127.0.0.1 5000 0 7000\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint C7E7 CCB8 179F 8CC3 7F5C 8A04 2B3A 180B 934B 14BA\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 67A152A4C7686FB07664F872620635F194D76D95\n"
+"caches-extra-info\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAOuBUIEBARMkkka/TGyaQNgUEDLP0KG7sy6KNQTNOlZHUresPr/vlVjo\n"
+"HPpLMfu9M2z18c51YX/muWwY9x4MyQooD56wI4+AqXQcJRwQfQlPn3Ay82uZViA9\n"
+"DpBajRieLlKKkl145KjArpD7F5BVsqccvjErgFYXvhhjSrx7BVLnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAN6NLnSxWQnFXxqZi5D3b0BMgV6y9NJLGjYQVP+eWtPZWgqyv4zeYsqv\n"
+"O9y6c5lvxyUxmNHfoAbe/s8f2Vf3/YaC17asAVSln4ktrr3e9iY74a9RMWHv1Gzk\n"
+"3042nMcqj3PEhRN0PoLkcOZNjjmNbaqki6qy9bWWZDNTdo+uI44dAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"contact auth0@test.test\n"
+"ntor-onion-key pK4bs08ERYN591jj7ca17Rn9Q02TIEfhnjR6hSq+fhU=\n"
+"reject *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"rx88DuM3Y7tODlHNDDEVzKpwh3csaG1or+T4l2Xs1oq3iHHyPEtB6QTLYrC60trG\n"
+"aAPsj3DEowGfjga1b248g2dtic8Ab+0exfjMm1RHXfDam5TXXZU3A0wMyoHjqHuf\n"
+"eChGPgFNUvEc+5YtD27qEDcUjcinYztTs7/dzxBT4PE=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:11\n"
+"@source \"127.0.0.1\"\n"
+"router test001a 127.0.0.1 5001 0 7001\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint 35DA 711C FC62 F88B C243 DE32 DC0B C28A 3F62 2610\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 9E12278D6CF7608071FE98CE9DCEE48FA264518A\n"
+"caches-extra-info\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAPbyUrorqoXMW4oezqd307ZGxgobqvQs2nb3TdQyWrwsHtJmS3utdrJS\n"
+"xJUZPNHOQ2hrDWW1VvevYqRTGeXGZr9TDZ3+t/gVUttqYRhuzzgEKVAZSsTo5ctO\n"
+"QNHnzJ6Xx/w/trhWqPTeJ7R0TCyAbWW7aE3KaKdwvZilRZp/oRUnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALwOJ7XZHBnjJEuwF3Os6eashNbTH9YnH8TBZBdKgu3iFJYqDslcMIPX\n"
+"gWCJ9apPHyh1+/8OLRWeEYlwoZzgGi0rjm/+BNeOOmJbjfyjk97DuB9/2O5zr1BM\n"
+"CvOHqQSzMD+vz1ebvfM039a2mO8lXruUFPZQaFVxk8371XP2khqhAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"contact auth1@test.test\n"
+"ntor-onion-key t5bI1ksTdigOksMKRHUDwx/34ajEvDN1IpArOxIEWgk=\n"
+"reject *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"KtMW7A/pzu+np6aKJSy6d7drIb4yjz8SPCo+oQNxj2IqNHJir2O2nWu69xy+K0c1\n"
+"RL05KkcDaYzr5hC80FD1H+sTpGYD28SPkQkzPw+0pReSDl93pVXh0rU6Cdcm75FC\n"
+"t0UZzDt4TsMuFB0ZYpM3phKcQPpiDG6aR0LskL/YUvY=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:11\n"
+"@source \"127.0.0.1\"\n"
+"router test004r 127.0.0.1 5004 0 7004\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:10\n"
+"fingerprint CC6A 48BD 52BD 9A2C 6670 5863 AC31 AE17 6E63 8B02\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest B5CC249CEF394B5AFCA0C77FA7D5605615FA487C\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAMze36Hupy7HACcF3TMv5mJuZbx3d3cS0WYLl6vTeChBgpS5CEXq6zIu\n"
+"d31YmtUcxH6fOjDOudhbnXuoh1nH4CP+LocVHAdlGG1giAm7u8yZudVvVJiIqFgQ\n"
+"wVDcWx8LbGCi5P9J/ZPKAIVsSyS7xkOqHjz3VMo/uYLbQCFAwfkdAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAM/qGP365x6bH+ug7rKVy7V5lC9Ff2Jfk0wlTFIzzwn+DMSG6xDvulKe\n"
+"wcIzgGNdQu7qlKlQUif3GPMr0KSS32cRsmoRQJcsm9+lGUK871NyZ8AyrHT+LhyF\n"
+"cs718P0iN5yKF2FikNr727kEANCzvC1l9eP4qF5GGzsNtglbJ7bTAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key a9Pavqnx7DFhMWUO0d17qF9Py8+iie4FnxTHaTgfIXY=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"HVW7kjBgEt+Qdvcrq+NQE1F9B8uV9D38KA2Bp6cYHLWCxL6N4GS8JQqbOEtnqaj7\n"
+"Vxrv7uy1Fzb15Zr+1sUVMxNv+LLRfr+JzfETMNYVkYDrNgr1cAAVEQzFWbIziond\n"
+"xMFp64yjEW9/I+82lb5GBZEiKdEd4QqWMmQosoYMTM8=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test002a 127.0.0.1 5002 0 7002\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint 29C7 BBB6 C437 32D5 BDF1 5671 F5C5 F1FB 6E36 4B47\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 9BB181EA86E0130680C3CC04AD7DE4C341ADC2C7\n"
+"caches-extra-info\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALNH19oF8Ajf+djlH/g7L+enFBf5Wwjmf3bPwNKWZ9G+B+Lg8SpfhZiw\n"
+"rUqi7h21f45BV/dN05dK6leWD8rj1T9kuM9TKBOEZxIWeq7zbXihyu4XPxP4FNTS\n"
+"+0G7BhdP4biALENmeyLhUCZaw5Ic/jFkHT4gV9S0iVZiEDwC9twXAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALeyQGMQBHgTxpO/i30uHjflTm9MNi3ZBNcOKpvBXWYgY42qTqOZ7Uam\n"
+"c5pmZhTLrQ1W8XlGDw8Cl8ktZ0ylodLZyUNajBtJvSFWTb8iwdZsshW6Ahb8TyfI\n"
+"Y7MwTlQ/7xw4mj1NEaui6bwGgEZUs18RTqhDrUc2Mcj1Yf61Rq+7AgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"contact auth2@test.test\n"
+"ntor-onion-key ukR41RjtiZ69KO0SrFTvL0LoZK/ZTT01FQWmCXTCUlE=\n"
+"reject *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"IY2s/RY4tdahrgfGG+vW7lOvpfofoxxSo7guGpSKGxVApiroCQtumoYifnnJ88G2\n"
+"K4IbxwEO8pgO8fnz1mibblUWw2vdDNjCifc1wtXJUE+ONA0UcLRlfQ94GbL8h2PG\n"
+"72z6i1+NN0QahXMk7MUbzI7bOXTJOiO8e2Zjk9vRnxI=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test006r 127.0.0.1 5006 0 7006\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint 829B 3FAA A42B 605A EB0B F380 8F32 8ED1 73E7 0D25\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 7ECB757002EB9B5838B13AE6F2357A5E585131B8\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALsNBChcLVndlS4HNXL3hxBJVgXctATz6yXcJt3bkDB5cjv7Q9fqN3Ue\n"
+"j3SI1OUBx4YrLcSLD/hELHVilLrrfbaraAFfAsydlRLjTVcMRx5FFlDd0E7TAadc\n"
+"71CkTipNnjwqz1mTRKkEFeepnh/JaFDidY9ER1rMBA5JRyBvqrD9AgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAPgipA8yLj1kqrMlAH7cK7IQEdmqmfNHGXdkYQ+TKtfLh0zeEIvvh9yh\n"
+"k+vKHS+HVoHo3tecB9QjJyDyyJTiETXCupSOY+ebG648JADAvv8v1WiE+KBXtjpl\n"
+"qgDTrDj5CwGuY6cvQdej5yg1UAVlMMZSg3thL3tCYtQbOq66lAlnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key q02F3AQsCX7+zXNpfTqBF8O8lusPhRJpQVxOnBvbOwc=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"L1fdgoN/eXgdzIIXO63W4yGoC9lRozMU+T0Fimhd/XFV8qxeUT83Vgf63vxLUHIb\n"
+"D4a80Wj7Pm4y5a766qLGXxlz2FYjCdkp070UpgZneB+VifUlFd/bNAjsiYTstBKM\n"
+"EI2L0mhl9d/7KK8vgtadHdX1z1u7QjyF6ccnzhfqeiY=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test003r 127.0.0.1 5003 0 7003\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint 71FD 3A35 F705 8020 D595 B711 D52A 9A0A 99BB B467\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest 3796BE0A95B699595445DFD3453CA2074E75BCE8\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAL44ctIioIfCYFzMTYNfK5qFAPGGUpsAFmS8pThQEY/tJU14+frJDBrC\n"
+"BkLvBs05Bw7xOUb0f2geiYGowBA6028smiq5HzTO7Kaga8vfV7AnANPX+n9cfHCr\n"
+"/2cMnKkT/GZzpdk0WbUw5Kc/G1ATIPFQHA8gZAi1fsSIDDn3GRV5AgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBALlPo5AI1mVTi+194yOSf40caoFlxSTfXt8KjGVa1dO/bpX7L3noOjYg\n"
+"goU4Aqim7BHmBWQDE/tZNTrchFoLQFHi9N4pv/0ND3sY904pzqGpe3FeTuU8P9Jg\n"
+"q2w3MeO3GwG8CJf4FOdSkgi8UKkJhOld4g4kViQbrFLXfdFvnT/zAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key qluYCRrsesOTkavCLnNK6H1ToywyDquCyYeP0h/qol4=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"d09K7rW/OpVzoUpfZXJuJW7a+P4pROCOZTgvDUIy/Nv+EAjcYqv95PlJ8cAMqnn3\n"
+"1oQibRmmQwn0OmG5cB8NaZiueaVIRheGzHEM8rndpHn5oFXdFvV7KKjScvfuBbTk\n"
+"RYME8XyawRaqsEZnwirDDlZuiZOjdQs8bbGsko3grJE=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test005r 127.0.0.1 5005 0 7005\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint EB6E 42ED E6BF 5EE0 19F5 EFC1 53AD 094C 1327 7B76\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest C031EE4E1AE826C1E3C4E21D81C961869E63F5D2\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAMd9Fm4KTSjFDzEABPZ1fwBCC2DNgee6nAmlde8FRbCVfcIHRiJyv9YG\n"
+"h530yUJal3hBfiWwy/SBA4LDz1flNCEwJm81s3waj4T9c676dAOLPcnOcJM5SbaQ\n"
+"hYPDrIZLEZHAk+IoM+avKYYocwCJXwx6WTtsedF0wJBZ9mQAJERJAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAKT7ldhV43S1CgoER/pU0Rigf0NzcSy25DQJrMRQnNmXnL03Dwuv/Iu7\n"
+"dCjgg64odnvSkXHFhkbjGcg8aXikvfbMyZTbsD8NrrP6FS6pfgPgZD9W2TK7QdHI\n"
+"QXwx1IYaaJK4nDUNfJhjrclydEdxmHbO1nLG1aS0ypn/G0EBpOSnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key umFmyRPA0dIsi0CFYCbGIPe2+OUkyslTkKKDEohjQQg=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"JiXEbqPgDPWEb9DzCYINRXfmvMIc/IRtvshS8Vmmn7DW67TrTLKCEAnisGo92gMA\n"
+"bhxGb9G5Mxq/8YqGoqdI2Vp6tfKlz/9AmjHzFAo01y42gafXIdr1oUS2RimA8jfF\n"
+"hwfQkbG0FYEsJrH3EUa8sMhcjsEaohK/kgklMR7OgQY=\n"
+"-----END SIGNATURE-----\n"
+"@uploaded-at 2014-06-08 19:20:12\n"
+"@source \"127.0.0.1\"\n"
+"router test007r 127.0.0.1 5007 0 7007\n"
+"platform Tor 0.2.5.3-alpha-dev on Linux\n"
+"protocols Link 1 2 Circuit 1\n"
+"published 2014-06-08 19:20:11\n"
+"fingerprint DABD 2AAF 8C9F 3B71 7839 9C08 DCD8 CD9D 341D 0002\n"
+"uptime 0\n"
+"bandwidth 1073741824 1073741824 0\n"
+"extra-info-digest F80104A0DFFB4EB429325D41D1F71E5BF8C6C726\n"
+"onion-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAL42fYAriR/JeB/9NpVq5Y5EEHca+ugIpaSdRfbopWDtFjXLEk2jmO5A\n"
+"KoAGIkTKDr7e9101x63H+0Nh/7w3uYs/WqTXEH8/1sHwe+0PY2HL0S6qhlOo6X54\n"
+"EfK0nDDBAWFOpyiAMHRk8JVikKb56+FVIhCJgi1RIbLIiUQK2/kxAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"signing-key\n"
+"-----BEGIN RSA PUBLIC KEY-----\n"
+"MIGJAoGBAKQj2U5hmB68V6NQBqD8DfIkJjovvM8t6nGfYpkT8ORsROnmgI5mjM38\n"
+"cmh5GIjY9RgoOWolLmsWQ4SXtS0FvrPft1M61UMTSHzlrEeuod5KenV7vGlX2TxT\n"
+"0DoA5TL9yY7CmxCk8CNRCtN/g7WocgIiP4KCIiEZ4VE6LIb6sxUnAgMBAAE=\n"
+"-----END RSA PUBLIC KEY-----\n"
+"hidden-service-dir\n"
+"ntor-onion-key 1UBS8rTlL39u9YxRJWhz+GTG1dS15VRi4au1i5qZOyI=\n"
+"reject *:25\n"
+"reject *:119\n"
+"reject *:135-139\n"
+"reject *:445\n"
+"reject *:563\n"
+"reject *:1214\n"
+"reject *:4661-4666\n"
+"reject *:6346-6429\n"
+"reject *:6699\n"
+"reject *:6881-6999\n"
+"accept *:*\n"
+"router-signature\n"
+"-----BEGIN SIGNATURE-----\n"
+"m7xHh+XPdLN+qcMLz1dBAEAmcdCFrtdseMHCc0FyAP2kXdayxqe3o2IOOHN++bTH\n"
+"Y5iHsZembsIJJ+D/d0YEKWKh42TUWCXBu0Gbfc4OcNuR6PFlTWO2wk7rDT3HOiFr\n"
+"pe3wJqZYkLxlBDamROAlMMRe71iag89H/4EulC18opw=\n"
+"-----END SIGNATURE-----\n";
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index c03b63be27..a949f5de73 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -25,55 +25,56 @@
#include "test.h"
static void
-test_dir_nicknames(void)
+test_dir_nicknames(void *arg)
{
- test_assert( is_legal_nickname("a"));
- test_assert(!is_legal_nickname(""));
- test_assert(!is_legal_nickname("abcdefghijklmnopqrst")); /* 20 chars */
- test_assert(!is_legal_nickname("hyphen-")); /* bad char */
- test_assert( is_legal_nickname("abcdefghijklmnopqrs")); /* 19 chars */
- test_assert(!is_legal_nickname("$AAAAAAAA01234AAAAAAAAAAAAAAAAAAAAAAAAAAA"));
+ (void)arg;
+ tt_assert( is_legal_nickname("a"));
+ tt_assert(!is_legal_nickname(""));
+ tt_assert(!is_legal_nickname("abcdefghijklmnopqrst")); /* 20 chars */
+ tt_assert(!is_legal_nickname("hyphen-")); /* bad char */
+ tt_assert( is_legal_nickname("abcdefghijklmnopqrs")); /* 19 chars */
+ tt_assert(!is_legal_nickname("$AAAAAAAA01234AAAAAAAAAAAAAAAAAAAAAAAAAAA"));
/* valid */
- test_assert( is_legal_nickname_or_hexdigest(
+ tt_assert( is_legal_nickname_or_hexdigest(
"$AAAAAAAA01234AAAAAAAAAAAAAAAAAAAAAAAAAAA"));
- test_assert( is_legal_nickname_or_hexdigest(
+ tt_assert( is_legal_nickname_or_hexdigest(
"$AAAAAAAA01234AAAAAAAAAAAAAAAAAAAAAAAAAAA=fred"));
- test_assert( is_legal_nickname_or_hexdigest(
+ tt_assert( is_legal_nickname_or_hexdigest(
"$AAAAAAAA01234AAAAAAAAAAAAAAAAAAAAAAAAAAA~fred"));
/* too short */
- test_assert(!is_legal_nickname_or_hexdigest(
+ tt_assert(!is_legal_nickname_or_hexdigest(
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
/* illegal char */
- test_assert(!is_legal_nickname_or_hexdigest(
+ tt_assert(!is_legal_nickname_or_hexdigest(
"$AAAAAAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
/* hex part too long */
- test_assert(!is_legal_nickname_or_hexdigest(
+ tt_assert(!is_legal_nickname_or_hexdigest(
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"));
- test_assert(!is_legal_nickname_or_hexdigest(
+ tt_assert(!is_legal_nickname_or_hexdigest(
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=fred"));
/* Bad nickname */
- test_assert(!is_legal_nickname_or_hexdigest(
+ tt_assert(!is_legal_nickname_or_hexdigest(
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="));
- test_assert(!is_legal_nickname_or_hexdigest(
+ tt_assert(!is_legal_nickname_or_hexdigest(
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~"));
- test_assert(!is_legal_nickname_or_hexdigest(
+ tt_assert(!is_legal_nickname_or_hexdigest(
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~hyphen-"));
- test_assert(!is_legal_nickname_or_hexdigest(
+ tt_assert(!is_legal_nickname_or_hexdigest(
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~"
"abcdefghijklmnoppqrst"));
/* Bad extra char. */
- test_assert(!is_legal_nickname_or_hexdigest(
+ tt_assert(!is_legal_nickname_or_hexdigest(
"$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!"));
- test_assert(is_legal_nickname_or_hexdigest("xyzzy"));
- test_assert(is_legal_nickname_or_hexdigest("abcdefghijklmnopqrs"));
- test_assert(!is_legal_nickname_or_hexdigest("abcdefghijklmnopqrst"));
+ tt_assert(is_legal_nickname_or_hexdigest("xyzzy"));
+ tt_assert(is_legal_nickname_or_hexdigest("abcdefghijklmnopqrs"));
+ tt_assert(!is_legal_nickname_or_hexdigest("abcdefghijklmnopqrst"));
done:
;
}
/** Run unit tests for router descriptor generation logic. */
static void
-test_dir_formats(void)
+test_dir_formats(void *arg)
{
char *buf = NULL;
char buf2[8192];
@@ -89,10 +90,11 @@ test_dir_formats(void)
or_options_t *options = get_options_mutable();
const addr_policy_t *p;
+ (void)arg;
pk1 = pk_generate(0);
pk2 = pk_generate(1);
- test_assert(pk1 && pk2);
+ tt_assert(pk1 && pk2);
hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
@@ -140,9 +142,9 @@ test_dir_formats(void)
smartlist_add(r2->exit_policy, ex2);
r2->nickname = tor_strdup("Fred");
- test_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str,
+ tt_assert(!crypto_pk_write_public_key_to_string(pk1, &pk1_str,
&pk1_str_len));
- test_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str,
+ tt_assert(!crypto_pk_write_public_key_to_string(pk2 , &pk2_str,
&pk2_str_len));
/* XXXX025 router_dump_to_string should really take this from ri.*/
@@ -150,7 +152,7 @@ test_dir_formats(void)
"<magri@elsewhere.example.com>");
buf = router_dump_router_to_string(r1, pk2);
tor_free(options->ContactInfo);
- test_assert(buf);
+ tt_assert(buf);
strlcpy(buf2, "router Magri 192.168.0.1 9000 0 9003\n"
"or-address [1:2:3:4::]:9999\n"
@@ -160,7 +162,7 @@ test_dir_formats(void)
"protocols Link 1 2 Circuit 1\n"
"published 1970-01-01 00:00:00\n"
"fingerprint ", sizeof(buf2));
- test_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1));
+ tt_assert(!crypto_pk_get_fingerprint(pk2, fingerprint, 1));
strlcat(buf2, fingerprint, sizeof(buf2));
strlcat(buf2, "\nuptime 0\n"
/* XXX the "0" above is hard-coded, but even if we made it reflect
@@ -178,23 +180,23 @@ test_dir_formats(void)
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
* twice */
- test_streq(buf, buf2);
+ tt_str_op(buf,OP_EQ, buf2);
tor_free(buf);
buf = router_dump_router_to_string(r1, pk2);
- test_assert(buf);
+ tt_assert(buf);
cp = buf;
- rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL);
- test_assert(rp1);
- test_eq(rp1->addr, r1->addr);
- test_eq(rp1->or_port, r1->or_port);
+ rp1 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
+ tt_assert(rp1);
+ tt_int_op(rp1->addr,OP_EQ, r1->addr);
+ tt_int_op(rp1->or_port,OP_EQ, r1->or_port);
//test_eq(rp1->dir_port, r1->dir_port);
- test_eq(rp1->bandwidthrate, r1->bandwidthrate);
- test_eq(rp1->bandwidthburst, r1->bandwidthburst);
- test_eq(rp1->bandwidthcapacity, r1->bandwidthcapacity);
- test_assert(crypto_pk_cmp_keys(rp1->onion_pkey, pk1) == 0);
- test_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0);
- //test_assert(rp1->exit_policy == NULL);
+ tt_int_op(rp1->bandwidthrate,OP_EQ, r1->bandwidthrate);
+ tt_int_op(rp1->bandwidthburst,OP_EQ, r1->bandwidthburst);
+ tt_int_op(rp1->bandwidthcapacity,OP_EQ, r1->bandwidthcapacity);
+ tt_assert(crypto_pk_cmp_keys(rp1->onion_pkey, pk1) == 0);
+ tt_assert(crypto_pk_cmp_keys(rp1->identity_pkey, pk2) == 0);
+ //tt_assert(rp1->exit_policy == NULL);
tor_free(buf);
strlcpy(buf2,
@@ -205,7 +207,7 @@ test_dir_formats(void)
"protocols Link 1 2 Circuit 1\n"
"published 1970-01-01 00:00:05\n"
"fingerprint ", sizeof(buf2));
- test_assert(!crypto_pk_get_fingerprint(pk1, fingerprint, 1));
+ tt_assert(!crypto_pk_get_fingerprint(pk1, fingerprint, 1));
strlcat(buf2, fingerprint, sizeof(buf2));
strlcat(buf2, "\nuptime 0\n"
"bandwidth 3000 3000 3000\n", sizeof(buf2));
@@ -214,61 +216,57 @@ test_dir_formats(void)
strlcat(buf2, "signing-key\n", sizeof(buf2));
strlcat(buf2, pk1_str, sizeof(buf2));
strlcat(buf2, "hidden-service-dir\n", sizeof(buf2));
-#ifdef CURVE25519_ENABLED
strlcat(buf2, "ntor-onion-key "
"skyinAnvardNostarsNomoonNowindormistsorsnow=\n", sizeof(buf2));
-#endif
strlcat(buf2, "accept *:80\nreject 18.0.0.0/8:24\n", sizeof(buf2));
strlcat(buf2, "router-signature\n", sizeof(buf2));
buf = router_dump_router_to_string(r2, pk1);
buf[strlen(buf2)] = '\0'; /* Don't compare the sig; it's never the same
* twice */
- test_streq(buf, buf2);
+ tt_str_op(buf,OP_EQ, buf2);
tor_free(buf);
buf = router_dump_router_to_string(r2, pk1);
cp = buf;
- rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL);
- test_assert(rp2);
- test_eq(rp2->addr, r2->addr);
- test_eq(rp2->or_port, r2->or_port);
- test_eq(rp2->dir_port, r2->dir_port);
- test_eq(rp2->bandwidthrate, r2->bandwidthrate);
- test_eq(rp2->bandwidthburst, r2->bandwidthburst);
- test_eq(rp2->bandwidthcapacity, r2->bandwidthcapacity);
-#ifdef CURVE25519_ENABLED
- test_memeq(rp2->onion_curve25519_pkey->public_key,
+ rp2 = router_parse_entry_from_string((const char*)cp,NULL,1,0,NULL,NULL);
+ tt_assert(rp2);
+ tt_int_op(rp2->addr,OP_EQ, r2->addr);
+ tt_int_op(rp2->or_port,OP_EQ, r2->or_port);
+ tt_int_op(rp2->dir_port,OP_EQ, r2->dir_port);
+ tt_int_op(rp2->bandwidthrate,OP_EQ, r2->bandwidthrate);
+ tt_int_op(rp2->bandwidthburst,OP_EQ, r2->bandwidthburst);
+ tt_int_op(rp2->bandwidthcapacity,OP_EQ, r2->bandwidthcapacity);
+ tt_mem_op(rp2->onion_curve25519_pkey->public_key,OP_EQ,
r2->onion_curve25519_pkey->public_key,
CURVE25519_PUBKEY_LEN);
-#endif
- test_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0);
- test_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0);
+ tt_assert(crypto_pk_cmp_keys(rp2->onion_pkey, pk2) == 0);
+ tt_assert(crypto_pk_cmp_keys(rp2->identity_pkey, pk1) == 0);
- test_eq(smartlist_len(rp2->exit_policy), 2);
+ tt_int_op(smartlist_len(rp2->exit_policy),OP_EQ, 2);
p = smartlist_get(rp2->exit_policy, 0);
- test_eq(p->policy_type, ADDR_POLICY_ACCEPT);
- test_assert(tor_addr_is_null(&p->addr));
- test_eq(p->maskbits, 0);
- test_eq(p->prt_min, 80);
- test_eq(p->prt_max, 80);
+ tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_ACCEPT);
+ tt_assert(tor_addr_is_null(&p->addr));
+ tt_int_op(p->maskbits,OP_EQ, 0);
+ tt_int_op(p->prt_min,OP_EQ, 80);
+ tt_int_op(p->prt_max,OP_EQ, 80);
p = smartlist_get(rp2->exit_policy, 1);
- test_eq(p->policy_type, ADDR_POLICY_REJECT);
- test_assert(tor_addr_eq(&p->addr, &ex2->addr));
- test_eq(p->maskbits, 8);
- test_eq(p->prt_min, 24);
- test_eq(p->prt_max, 24);
+ tt_int_op(p->policy_type,OP_EQ, ADDR_POLICY_REJECT);
+ tt_assert(tor_addr_eq(&p->addr, &ex2->addr));
+ tt_int_op(p->maskbits,OP_EQ, 8);
+ tt_int_op(p->prt_min,OP_EQ, 24);
+ tt_int_op(p->prt_max,OP_EQ, 24);
#if 0
/* Okay, now for the directories. */
{
fingerprint_list = smartlist_new();
crypto_pk_get_fingerprint(pk2, buf, 1);
- add_fingerprint_to_dir("Magri", buf, fingerprint_list);
+ add_fingerprint_to_dir(buf, fingerprint_list, 0);
crypto_pk_get_fingerprint(pk1, buf, 1);
- add_fingerprint_to_dir("Fred", buf, fingerprint_list);
+ add_fingerprint_to_dir(buf, fingerprint_list, 0);
}
#endif
@@ -292,56 +290,603 @@ test_dir_formats(void)
tor_free(dir2); /* And more !*/
}
+#include "failing_routerdescs.inc"
+
+static void
+test_dir_routerparse_bad(void *arg)
+{
+ (void) arg;
+
+ int again;
+ routerinfo_t *ri = NULL;
+
+#define CHECK_OK(s) \
+ do { \
+ routerinfo_free(ri); \
+ ri = router_parse_entry_from_string((s), NULL, 0, 0, NULL, NULL); \
+ tt_assert(ri); \
+ } while (0)
+#define CHECK_FAIL(s, againval) \
+ do { \
+ routerinfo_free(ri); \
+ again = 999; \
+ ri = router_parse_entry_from_string((s), NULL, 0, 0, NULL, &again); \
+ tt_assert(ri == NULL); \
+ tt_int_op(again, OP_EQ, (againval)); \
+ } while (0)
+
+ CHECK_OK(EX_RI_MINIMAL);
+ CHECK_OK(EX_RI_MAXIMAL);
+
+ /* good annotations prepended */
+ routerinfo_free(ri);
+ ri = router_parse_entry_from_string(EX_RI_MINIMAL, NULL, 0, 0,
+ "@purpose bridge\n", NULL);
+ tt_assert(ri != NULL);
+ tt_assert(ri->purpose == ROUTER_PURPOSE_BRIDGE);
+ routerinfo_free(ri);
+
+ /* bad annotations prepended. */
+ ri = router_parse_entry_from_string(EX_RI_MINIMAL,
+ NULL, 0, 0, "@purpose\n", NULL);
+ tt_assert(ri == NULL);
+
+ /* bad annotations on router. */
+ ri = router_parse_entry_from_string("@purpose\nrouter x\n", NULL, 0, 1,
+ NULL, NULL);
+ tt_assert(ri == NULL);
+
+ /* unwanted annotations on router. */
+ ri = router_parse_entry_from_string("@purpose foo\nrouter x\n", NULL, 0, 0,
+ NULL, NULL);
+ tt_assert(ri == NULL);
+
+ /* No signature. */
+ ri = router_parse_entry_from_string("router x\n", NULL, 0, 0,
+ NULL, NULL);
+ tt_assert(ri == NULL);
+
+ /* Not a router */
+ routerinfo_free(ri);
+ ri = router_parse_entry_from_string("hello\n", NULL, 0, 0, NULL, NULL);
+ tt_assert(ri == NULL);
+
+ CHECK_FAIL(EX_RI_BAD_SIG1, 1);
+ CHECK_FAIL(EX_RI_BAD_SIG2, 1);
+ CHECK_FAIL(EX_RI_BAD_TOKENS, 0);
+ CHECK_FAIL(EX_RI_BAD_PUBLISHED, 0);
+ CHECK_FAIL(EX_RI_NEG_BANDWIDTH, 0);
+ CHECK_FAIL(EX_RI_BAD_BANDWIDTH, 0);
+ CHECK_FAIL(EX_RI_BAD_BANDWIDTH2, 0);
+ CHECK_FAIL(EX_RI_BAD_ONIONKEY1, 0);
+ CHECK_FAIL(EX_RI_BAD_ONIONKEY2, 0);
+ CHECK_FAIL(EX_RI_BAD_PORTS, 0);
+ CHECK_FAIL(EX_RI_BAD_IP, 0);
+ CHECK_FAIL(EX_RI_BAD_DIRPORT, 0);
+ CHECK_FAIL(EX_RI_BAD_NAME2, 0);
+ CHECK_FAIL(EX_RI_BAD_UPTIME, 0);
+
+ CHECK_FAIL(EX_RI_BAD_BANDWIDTH3, 0);
+ CHECK_FAIL(EX_RI_BAD_NTOR_KEY, 0);
+ CHECK_FAIL(EX_RI_BAD_FINGERPRINT, 0);
+ CHECK_FAIL(EX_RI_MISMATCHED_FINGERPRINT, 0);
+ CHECK_FAIL(EX_RI_BAD_HAS_ACCEPT6, 0);
+ CHECK_FAIL(EX_RI_BAD_NO_EXIT_POLICY, 0);
+ CHECK_FAIL(EX_RI_BAD_IPV6_EXIT_POLICY, 0);
+ CHECK_FAIL(EX_RI_BAD_FAMILY, 0);
+ CHECK_FAIL(EX_RI_ZERO_ORPORT, 0);
+
+ /* This is allowed; we just ignore it. */
+ CHECK_OK(EX_RI_BAD_EI_DIGEST);
+
+#undef CHECK_FAIL
+#undef CHECK_OK
+ done:
+ routerinfo_free(ri);
+}
+
+#include "example_extrainfo.inc"
+
+static void
+routerinfo_free_wrapper_(void *arg)
+{
+ routerinfo_free(arg);
+}
+
+static void
+test_dir_extrainfo_parsing(void *arg)
+{
+ (void) arg;
+
+#define CHECK_OK(s) \
+ do { \
+ extrainfo_free(ei); \
+ ei = extrainfo_parse_entry_from_string((s), NULL, 0, map, NULL); \
+ tt_assert(ei); \
+ } while (0)
+#define CHECK_FAIL(s, againval) \
+ do { \
+ extrainfo_free(ei); \
+ again = 999; \
+ ei = extrainfo_parse_entry_from_string((s), NULL, 0, map, &again); \
+ tt_assert(ei == NULL); \
+ tt_int_op(again, OP_EQ, (againval)); \
+ } while (0)
+#define ADD(name) \
+ do { \
+ ri = tor_malloc_zero(sizeof(routerinfo_t)); \
+ crypto_pk_t *pk = ri->identity_pkey = crypto_pk_new(); \
+ tt_assert(! crypto_pk_read_public_key_from_string(pk, \
+ name##_KEY, strlen(name##_KEY))); \
+ tt_int_op(0,OP_EQ,base16_decode(d, 20, name##_FP, strlen(name##_FP))); \
+ digestmap_set((digestmap_t*)map, d, ri); \
+ ri = NULL; \
+ } while (0)
+
+ routerinfo_t *ri = NULL;
+ char d[20];
+ struct digest_ri_map_t *map = NULL;
+ extrainfo_t *ei = NULL;
+ int again;
+
+ CHECK_OK(EX_EI_MINIMAL);
+ tt_assert(ei->pending_sig);
+ CHECK_OK(EX_EI_MAXIMAL);
+ tt_assert(ei->pending_sig);
+
+ map = (struct digest_ri_map_t *)digestmap_new();
+ ADD(EX_EI_MINIMAL);
+ ADD(EX_EI_MAXIMAL);
+ ADD(EX_EI_BAD_FP);
+ ADD(EX_EI_BAD_NICKNAME);
+ ADD(EX_EI_BAD_TOKENS);
+ ADD(EX_EI_BAD_START);
+ ADD(EX_EI_BAD_PUBLISHED);
+
+ CHECK_OK(EX_EI_MINIMAL);
+ tt_assert(!ei->pending_sig);
+ CHECK_OK(EX_EI_MAXIMAL);
+ tt_assert(!ei->pending_sig);
+
+ CHECK_FAIL(EX_EI_BAD_SIG1,1);
+ CHECK_FAIL(EX_EI_BAD_SIG2,1);
+ CHECK_FAIL(EX_EI_BAD_SIG3,1);
+ CHECK_FAIL(EX_EI_BAD_FP,0);
+ CHECK_FAIL(EX_EI_BAD_NICKNAME,0);
+ CHECK_FAIL(EX_EI_BAD_TOKENS,0);
+ CHECK_FAIL(EX_EI_BAD_START,0);
+ CHECK_FAIL(EX_EI_BAD_PUBLISHED,0);
+
+#undef CHECK_OK
+#undef CHECK_FAIL
+
+ done:
+ extrainfo_free(ei);
+ routerinfo_free(ri);
+ digestmap_free((digestmap_t*)map, routerinfo_free_wrapper_);
+}
+
+static void
+test_dir_parse_router_list(void *arg)
+{
+ (void) arg;
+ smartlist_t *invalid = smartlist_new();
+ smartlist_t *dest = smartlist_new();
+ smartlist_t *chunks = smartlist_new();
+ int dest_has_ri = 1;
+ char *list = NULL;
+ const char *cp;
+ digestmap_t *map = NULL;
+ char *mem_op_hex_tmp = NULL;
+ routerinfo_t *ri = NULL;
+ char d[DIGEST_LEN];
+
+ smartlist_add(chunks, tor_strdup(EX_RI_MINIMAL)); // ri 0
+ smartlist_add(chunks, tor_strdup(EX_RI_BAD_PORTS)); // bad ri 0
+ smartlist_add(chunks, tor_strdup(EX_EI_MAXIMAL)); // ei 0
+ smartlist_add(chunks, tor_strdup(EX_EI_BAD_SIG2)); // bad ei --
+ smartlist_add(chunks, tor_strdup(EX_EI_BAD_NICKNAME));// bad ei 0
+ smartlist_add(chunks, tor_strdup(EX_RI_BAD_SIG1)); // bad ri --
+ smartlist_add(chunks, tor_strdup(EX_EI_BAD_PUBLISHED)); // bad ei 1
+ smartlist_add(chunks, tor_strdup(EX_RI_MAXIMAL)); // ri 1
+ smartlist_add(chunks, tor_strdup(EX_RI_BAD_FAMILY)); // bad ri 1
+ smartlist_add(chunks, tor_strdup(EX_EI_MINIMAL)); // ei 1
+
+ list = smartlist_join_strings(chunks, "", 0, NULL);
+
+ /* First, parse the routers. */
+ cp = list;
+ tt_int_op(0,OP_EQ,
+ router_parse_list_from_string(&cp, NULL, dest, SAVED_NOWHERE,
+ 0, 0, NULL, invalid));
+ tt_int_op(2, OP_EQ, smartlist_len(dest));
+ tt_ptr_op(cp, OP_EQ, list + strlen(list));
+
+ routerinfo_t *r = smartlist_get(dest, 0);
+ tt_mem_op(r->cache_info.signed_descriptor_body, OP_EQ,
+ EX_RI_MINIMAL, strlen(EX_RI_MINIMAL));
+ r = smartlist_get(dest, 1);
+ tt_mem_op(r->cache_info.signed_descriptor_body, OP_EQ,
+ EX_RI_MAXIMAL, strlen(EX_RI_MAXIMAL));
+
+ tt_int_op(2, OP_EQ, smartlist_len(invalid));
+ test_memeq_hex(smartlist_get(invalid, 0),
+ "ab9eeaa95e7d45740185b4e519c76ead756277a9");
+ test_memeq_hex(smartlist_get(invalid, 1),
+ "9a651ee03b64325959e8f1b46f2b689b30750b4c");
+
+ /* Now tidy up */
+ SMARTLIST_FOREACH(dest, routerinfo_t *, ri, routerinfo_free(ri));
+ SMARTLIST_FOREACH(invalid, uint8_t *, d, tor_free(d));
+ smartlist_clear(dest);
+ smartlist_clear(invalid);
+
+ /* And check extrainfos. */
+ dest_has_ri = 0;
+ map = (digestmap_t*)router_get_routerlist()->identity_map;
+ ADD(EX_EI_MINIMAL);
+ ADD(EX_EI_MAXIMAL);
+ ADD(EX_EI_BAD_NICKNAME);
+ ADD(EX_EI_BAD_PUBLISHED);
+ cp = list;
+ tt_int_op(0,OP_EQ,
+ router_parse_list_from_string(&cp, NULL, dest, SAVED_NOWHERE,
+ 1, 0, NULL, invalid));
+ tt_int_op(2, OP_EQ, smartlist_len(dest));
+ extrainfo_t *e = smartlist_get(dest, 0);
+ tt_mem_op(e->cache_info.signed_descriptor_body, OP_EQ,
+ EX_EI_MAXIMAL, strlen(EX_EI_MAXIMAL));
+ e = smartlist_get(dest, 1);
+ tt_mem_op(e->cache_info.signed_descriptor_body, OP_EQ,
+ EX_EI_MINIMAL, strlen(EX_EI_MINIMAL));
+
+ tt_int_op(2, OP_EQ, smartlist_len(invalid));
+ test_memeq_hex(smartlist_get(invalid, 0),
+ "d5df4aa62ee9ffc9543d41150c9864908e0390af");
+ test_memeq_hex(smartlist_get(invalid, 1),
+ "f61efd2a7f4531f3687a9043e0de90a862ec64ba");
+
+ done:
+ tor_free(list);
+ if (dest_has_ri)
+ SMARTLIST_FOREACH(dest, routerinfo_t *, rt, routerinfo_free(rt));
+ else
+ SMARTLIST_FOREACH(dest, extrainfo_t *, ei, extrainfo_free(ei));
+ smartlist_free(dest);
+ SMARTLIST_FOREACH(invalid, uint8_t *, d, tor_free(d));
+ smartlist_free(invalid);
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+ routerinfo_free(ri);
+ if (map) {
+ digestmap_free((digestmap_t*)map, routerinfo_free_wrapper_);
+ router_get_routerlist()->identity_map =
+ (struct digest_ri_map_t*)digestmap_new();
+ }
+ tor_free(mem_op_hex_tmp);
+
+#undef ADD
+}
+
+static download_status_t dls_minimal;
+static download_status_t dls_maximal;
+static download_status_t dls_bad_fingerprint;
+static download_status_t dls_bad_sig2;
+static download_status_t dls_bad_ports;
+static download_status_t dls_bad_tokens;
+
+static int mock_router_get_dl_status_unrecognized = 0;
+static int mock_router_get_dl_status_calls = 0;
+
+static download_status_t *
+mock_router_get_dl_status(const char *d)
+{
+ ++mock_router_get_dl_status_calls;
+ char hex[HEX_DIGEST_LEN+1];
+ base16_encode(hex, sizeof(hex), d, DIGEST_LEN);
+ if (!strcmp(hex, "3E31D19A69EB719C00B02EC60D13356E3F7A3452")) {
+ return &dls_minimal;
+ } else if (!strcmp(hex, "581D8A368A0FA854ECDBFAB841D88B3F1B004038")) {
+ return &dls_maximal;
+ } else if (!strcmp(hex, "2578AE227C6116CDE29B3F0E95709B9872DEE5F1")) {
+ return &dls_bad_fingerprint;
+ } else if (!strcmp(hex, "16D387D3A58F7DB3CF46638F8D0B90C45C7D769C")) {
+ return &dls_bad_sig2;
+ } else if (!strcmp(hex, "AB9EEAA95E7D45740185B4E519C76EAD756277A9")) {
+ return &dls_bad_ports;
+ } else if (!strcmp(hex, "A0CC2CEFAD59DBF19F468BFEE60E0868C804B422")) {
+ return &dls_bad_tokens;
+ } else {
+ ++mock_router_get_dl_status_unrecognized;
+ return NULL;
+ }
+}
+
static void
-test_dir_versions(void)
+test_dir_load_routers(void *arg)
+{
+ (void) arg;
+ smartlist_t *chunks = smartlist_new();
+ smartlist_t *wanted = smartlist_new();
+ char buf[DIGEST_LEN];
+ char *mem_op_hex_tmp = NULL;
+ char *list = NULL;
+
+#define ADD(str) \
+ do { \
+ tt_int_op(0,OP_EQ,router_get_router_hash(str, strlen(str), buf)); \
+ smartlist_add(wanted, tor_strdup(hex_str(buf, DIGEST_LEN))); \
+ } while (0)
+
+ MOCK(router_get_dl_status_by_descriptor_digest, mock_router_get_dl_status);
+
+ update_approx_time(1412510400);
+
+ smartlist_add(chunks, tor_strdup(EX_RI_MINIMAL));
+ smartlist_add(chunks, tor_strdup(EX_RI_BAD_FINGERPRINT));
+ smartlist_add(chunks, tor_strdup(EX_RI_BAD_SIG2));
+ smartlist_add(chunks, tor_strdup(EX_RI_MAXIMAL));
+ smartlist_add(chunks, tor_strdup(EX_RI_BAD_PORTS));
+ smartlist_add(chunks, tor_strdup(EX_RI_BAD_TOKENS));
+
+ /* not ADDing MINIMIAL */
+ ADD(EX_RI_MAXIMAL);
+ ADD(EX_RI_BAD_FINGERPRINT);
+ ADD(EX_RI_BAD_SIG2);
+ /* Not ADDing BAD_PORTS */
+ ADD(EX_RI_BAD_TOKENS);
+
+ list = smartlist_join_strings(chunks, "", 0, NULL);
+ tt_int_op(1, OP_EQ,
+ router_load_routers_from_string(list, NULL, SAVED_IN_JOURNAL,
+ wanted, 1, NULL));
+
+ /* The "maximal" router was added. */
+ /* "minimal" was not. */
+ tt_int_op(smartlist_len(router_get_routerlist()->routers),OP_EQ,1);
+ routerinfo_t *r = smartlist_get(router_get_routerlist()->routers, 0);
+ test_memeq_hex(r->cache_info.signed_descriptor_digest,
+ "581D8A368A0FA854ECDBFAB841D88B3F1B004038");
+ tt_int_op(dls_minimal.n_download_failures, OP_EQ, 0);
+ tt_int_op(dls_maximal.n_download_failures, OP_EQ, 0);
+
+ /* "Bad fingerprint" and "Bad tokens" should have gotten marked
+ * non-retriable. */
+ tt_want_int_op(mock_router_get_dl_status_calls, OP_EQ, 2);
+ tt_want_int_op(mock_router_get_dl_status_unrecognized, OP_EQ, 0);
+ tt_int_op(dls_bad_fingerprint.n_download_failures, OP_EQ, 255);
+ tt_int_op(dls_bad_tokens.n_download_failures, OP_EQ, 255);
+
+ /* bad_sig2 and bad ports" are retriable -- one since only the signature
+ * was bad, and one because we didn't ask for it. */
+ tt_int_op(dls_bad_sig2.n_download_failures, OP_EQ, 0);
+ tt_int_op(dls_bad_ports.n_download_failures, OP_EQ, 0);
+
+ /* Wanted still contains "BAD_SIG2" */
+ tt_int_op(smartlist_len(wanted), OP_EQ, 1);
+ tt_str_op(smartlist_get(wanted, 0), OP_EQ,
+ "E0A3753CEFD54128EAB239F294954121DB23D2EF");
+
+#undef ADD
+
+ done:
+ tor_free(mem_op_hex_tmp);
+ UNMOCK(router_get_dl_status_by_descriptor_digest);
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+ SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp));
+ smartlist_free(wanted);
+ tor_free(list);
+}
+
+static int mock_get_by_ei_dd_calls = 0;
+static int mock_get_by_ei_dd_unrecognized = 0;
+
+static signed_descriptor_t sd_ei_minimal;
+static signed_descriptor_t sd_ei_bad_nickname;
+static signed_descriptor_t sd_ei_maximal;
+static signed_descriptor_t sd_ei_bad_tokens;
+static signed_descriptor_t sd_ei_bad_sig2;
+
+static signed_descriptor_t *
+mock_get_by_ei_desc_digest(const char *d)
+{
+
+ ++mock_get_by_ei_dd_calls;
+ char hex[HEX_DIGEST_LEN+1];
+ base16_encode(hex, sizeof(hex), d, DIGEST_LEN);
+
+ if (!strcmp(hex, "11E0EDF526950739F7769810FCACAB8C882FAEEE")) {
+ return &sd_ei_minimal;
+ } else if (!strcmp(hex, "47803B02A0E70E9E8BDA226CB1D74DE354D67DFF")) {
+ return &sd_ei_maximal;
+ } else if (!strcmp(hex, "D5DF4AA62EE9FFC9543D41150C9864908E0390AF")) {
+ return &sd_ei_bad_nickname;
+ } else if (!strcmp(hex, "16D387D3A58F7DB3CF46638F8D0B90C45C7D769C")) {
+ return &sd_ei_bad_sig2;
+ } else if (!strcmp(hex, "9D90F8C42955BBC57D54FB05E54A3F083AF42E8B")) {
+ return &sd_ei_bad_tokens;
+ } else {
+ ++mock_get_by_ei_dd_unrecognized;
+ return NULL;
+ }
+}
+
+static smartlist_t *mock_ei_insert_list = NULL;
+static was_router_added_t
+mock_ei_insert(routerlist_t *rl, extrainfo_t *ei, int warn_if_incompatible)
+{
+ (void) rl;
+ (void) warn_if_incompatible;
+ smartlist_add(mock_ei_insert_list, ei);
+ return ROUTER_ADDED_SUCCESSFULLY;
+}
+
+static void
+test_dir_load_extrainfo(void *arg)
+{
+ (void) arg;
+ smartlist_t *chunks = smartlist_new();
+ smartlist_t *wanted = smartlist_new();
+ char buf[DIGEST_LEN];
+ char *mem_op_hex_tmp = NULL;
+ char *list = NULL;
+
+#define ADD(str) \
+ do { \
+ tt_int_op(0,OP_EQ,router_get_extrainfo_hash(str, strlen(str), buf)); \
+ smartlist_add(wanted, tor_strdup(hex_str(buf, DIGEST_LEN))); \
+ } while (0)
+
+ mock_ei_insert_list = smartlist_new();
+ MOCK(router_get_by_extrainfo_digest, mock_get_by_ei_desc_digest);
+ MOCK(extrainfo_insert, mock_ei_insert);
+
+ smartlist_add(chunks, tor_strdup(EX_EI_MINIMAL));
+ smartlist_add(chunks, tor_strdup(EX_EI_BAD_NICKNAME));
+ smartlist_add(chunks, tor_strdup(EX_EI_MAXIMAL));
+ smartlist_add(chunks, tor_strdup(EX_EI_BAD_PUBLISHED));
+ smartlist_add(chunks, tor_strdup(EX_EI_BAD_TOKENS));
+
+ /* not ADDing MINIMIAL */
+ ADD(EX_EI_MAXIMAL);
+ ADD(EX_EI_BAD_NICKNAME);
+ /* Not ADDing BAD_PUBLISHED */
+ ADD(EX_EI_BAD_TOKENS);
+ ADD(EX_EI_BAD_SIG2);
+
+ list = smartlist_join_strings(chunks, "", 0, NULL);
+ router_load_extrainfo_from_string(list, NULL, SAVED_IN_JOURNAL, wanted, 1);
+
+ /* The "maximal" router was added. */
+ /* "minimal" was also added, even though we didn't ask for it, since
+ * that's what we do with extrainfos. */
+ tt_int_op(smartlist_len(mock_ei_insert_list),OP_EQ,2);
+
+ extrainfo_t *e = smartlist_get(mock_ei_insert_list, 0);
+ test_memeq_hex(e->cache_info.signed_descriptor_digest,
+ "11E0EDF526950739F7769810FCACAB8C882FAEEE");
+
+ e = smartlist_get(mock_ei_insert_list, 1);
+ test_memeq_hex(e->cache_info.signed_descriptor_digest,
+ "47803B02A0E70E9E8BDA226CB1D74DE354D67DFF");
+ tt_int_op(dls_minimal.n_download_failures, OP_EQ, 0);
+ tt_int_op(dls_maximal.n_download_failures, OP_EQ, 0);
+
+ /* "Bad nickname" and "Bad tokens" should have gotten marked
+ * non-retriable. */
+ tt_want_int_op(mock_get_by_ei_dd_calls, OP_EQ, 2);
+ tt_want_int_op(mock_get_by_ei_dd_unrecognized, OP_EQ, 0);
+ tt_int_op(sd_ei_bad_nickname.ei_dl_status.n_download_failures, OP_EQ, 255);
+ tt_int_op(sd_ei_bad_tokens.ei_dl_status.n_download_failures, OP_EQ, 255);
+
+ /* bad_ports is retriable -- because we didn't ask for it. */
+ tt_int_op(dls_bad_ports.n_download_failures, OP_EQ, 0);
+
+ /* Wanted still contains "BAD_SIG2" */
+ tt_int_op(smartlist_len(wanted), OP_EQ, 1);
+ tt_str_op(smartlist_get(wanted, 0), OP_EQ,
+ "16D387D3A58F7DB3CF46638F8D0B90C45C7D769C");
+
+#undef ADD
+
+ done:
+ tor_free(mem_op_hex_tmp);
+ UNMOCK(router_get_by_extrainfo_digest);
+ SMARTLIST_FOREACH(chunks, char *, cp, tor_free(cp));
+ smartlist_free(chunks);
+ SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp));
+ smartlist_free(wanted);
+ tor_free(list);
+}
+
+static void
+test_dir_versions(void *arg)
{
tor_version_t ver1;
/* Try out version parsing functionality */
- test_eq(0, tor_version_parse("0.3.4pre2-cvs", &ver1));
- test_eq(0, ver1.major);
- test_eq(3, ver1.minor);
- test_eq(4, ver1.micro);
- test_eq(VER_PRE, ver1.status);
- test_eq(2, ver1.patchlevel);
- test_eq(0, tor_version_parse("0.3.4rc1", &ver1));
- test_eq(0, ver1.major);
- test_eq(3, ver1.minor);
- test_eq(4, ver1.micro);
- test_eq(VER_RC, ver1.status);
- test_eq(1, ver1.patchlevel);
- test_eq(0, tor_version_parse("1.3.4", &ver1));
- test_eq(1, ver1.major);
- test_eq(3, ver1.minor);
- test_eq(4, ver1.micro);
- test_eq(VER_RELEASE, ver1.status);
- test_eq(0, ver1.patchlevel);
- test_eq(0, tor_version_parse("1.3.4.999", &ver1));
- test_eq(1, ver1.major);
- test_eq(3, ver1.minor);
- test_eq(4, ver1.micro);
- test_eq(VER_RELEASE, ver1.status);
- test_eq(999, ver1.patchlevel);
- test_eq(0, tor_version_parse("0.1.2.4-alpha", &ver1));
- test_eq(0, ver1.major);
- test_eq(1, ver1.minor);
- test_eq(2, ver1.micro);
- test_eq(4, ver1.patchlevel);
- test_eq(VER_RELEASE, ver1.status);
- test_streq("alpha", ver1.status_tag);
- test_eq(0, tor_version_parse("0.1.2.4", &ver1));
- test_eq(0, ver1.major);
- test_eq(1, ver1.minor);
- test_eq(2, ver1.micro);
- test_eq(4, ver1.patchlevel);
- test_eq(VER_RELEASE, ver1.status);
- test_streq("", ver1.status_tag);
+ (void)arg;
+ tt_int_op(0,OP_EQ, tor_version_parse("0.3.4pre2-cvs", &ver1));
+ tt_int_op(0,OP_EQ, ver1.major);
+ tt_int_op(3,OP_EQ, ver1.minor);
+ tt_int_op(4,OP_EQ, ver1.micro);
+ tt_int_op(VER_PRE,OP_EQ, ver1.status);
+ tt_int_op(2,OP_EQ, ver1.patchlevel);
+ tt_int_op(0,OP_EQ, tor_version_parse("0.3.4rc1", &ver1));
+ tt_int_op(0,OP_EQ, ver1.major);
+ tt_int_op(3,OP_EQ, ver1.minor);
+ tt_int_op(4,OP_EQ, ver1.micro);
+ tt_int_op(VER_RC,OP_EQ, ver1.status);
+ tt_int_op(1,OP_EQ, ver1.patchlevel);
+ tt_int_op(0,OP_EQ, tor_version_parse("1.3.4", &ver1));
+ tt_int_op(1,OP_EQ, ver1.major);
+ tt_int_op(3,OP_EQ, ver1.minor);
+ tt_int_op(4,OP_EQ, ver1.micro);
+ tt_int_op(VER_RELEASE,OP_EQ, ver1.status);
+ tt_int_op(0,OP_EQ, ver1.patchlevel);
+ tt_int_op(0,OP_EQ, tor_version_parse("1.3.4.999", &ver1));
+ tt_int_op(1,OP_EQ, ver1.major);
+ tt_int_op(3,OP_EQ, ver1.minor);
+ tt_int_op(4,OP_EQ, ver1.micro);
+ tt_int_op(VER_RELEASE,OP_EQ, ver1.status);
+ tt_int_op(999,OP_EQ, ver1.patchlevel);
+ tt_int_op(0,OP_EQ, tor_version_parse("0.1.2.4-alpha", &ver1));
+ tt_int_op(0,OP_EQ, ver1.major);
+ tt_int_op(1,OP_EQ, ver1.minor);
+ tt_int_op(2,OP_EQ, ver1.micro);
+ tt_int_op(4,OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE,OP_EQ, ver1.status);
+ tt_str_op("alpha",OP_EQ, ver1.status_tag);
+ tt_int_op(0,OP_EQ, tor_version_parse("0.1.2.4", &ver1));
+ tt_int_op(0,OP_EQ, ver1.major);
+ tt_int_op(1,OP_EQ, ver1.minor);
+ tt_int_op(2,OP_EQ, ver1.micro);
+ tt_int_op(4,OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE,OP_EQ, ver1.status);
+ tt_str_op("",OP_EQ, ver1.status_tag);
+
+ tt_int_op(0, OP_EQ, tor_version_parse("10.1", &ver1));
+ tt_int_op(10, OP_EQ, ver1.major);
+ tt_int_op(1, OP_EQ, ver1.minor);
+ tt_int_op(0, OP_EQ, ver1.micro);
+ tt_int_op(0, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("", OP_EQ, ver1.status_tag);
+ tt_int_op(0, OP_EQ, tor_version_parse("5.99.999", &ver1));
+ tt_int_op(5, OP_EQ, ver1.major);
+ tt_int_op(99, OP_EQ, ver1.minor);
+ tt_int_op(999, OP_EQ, ver1.micro);
+ tt_int_op(0, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("", OP_EQ, ver1.status_tag);
+ tt_int_op(0, OP_EQ, tor_version_parse("10.1-alpha", &ver1));
+ tt_int_op(10, OP_EQ, ver1.major);
+ tt_int_op(1, OP_EQ, ver1.minor);
+ tt_int_op(0, OP_EQ, ver1.micro);
+ tt_int_op(0, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("alpha", OP_EQ, ver1.status_tag);
+ tt_int_op(0, OP_EQ, tor_version_parse("2.1.700-alpha", &ver1));
+ tt_int_op(2, OP_EQ, ver1.major);
+ tt_int_op(1, OP_EQ, ver1.minor);
+ tt_int_op(700, OP_EQ, ver1.micro);
+ tt_int_op(0, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("alpha", OP_EQ, ver1.status_tag);
+ tt_int_op(0, OP_EQ, tor_version_parse("1.6.8-alpha-dev", &ver1));
+ tt_int_op(1, OP_EQ, ver1.major);
+ tt_int_op(6, OP_EQ, ver1.minor);
+ tt_int_op(8, OP_EQ, ver1.micro);
+ tt_int_op(0, OP_EQ, ver1.patchlevel);
+ tt_int_op(VER_RELEASE, OP_EQ, ver1.status);
+ tt_str_op("alpha-dev", OP_EQ, ver1.status_tag);
#define tt_versionstatus_op(vs1, op, vs2) \
tt_assert_test_type(vs1,vs2,#vs1" "#op" "#vs2,version_status_t, \
(val1_ op val2_),"%d",TT_EXIT_TEST_FUNCTION)
#define test_v_i_o(val, ver, lst) \
- tt_versionstatus_op(val, ==, tor_version_is_obsolete(ver, lst))
+ tt_versionstatus_op(val, OP_EQ, tor_version_is_obsolete(ver, lst))
/* make sure tor_version_is_obsolete() works */
test_v_i_o(VS_OLD, "0.0.1", "Tor 0.0.2");
@@ -368,53 +913,55 @@ test_dir_versions(void)
/* On list, not newer than any on same series. */
test_v_i_o(VS_UNRECOMMENDED,
"0.1.0.1", "Tor 0.1.0.2,Tor 0.0.9.5,Tor 0.1.1.0");
- test_eq(0, tor_version_as_new_as("Tor 0.0.5", "0.0.9pre1-cvs"));
- test_eq(1, tor_version_as_new_as(
+ tt_int_op(0,OP_EQ, tor_version_as_new_as("Tor 0.0.5", "0.0.9pre1-cvs"));
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
"Tor 0.0.8 on Darwin 64-121-192-100.c3-0."
"sfpo-ubr1.sfrn-sfpo.ca.cable.rcn.com Power Macintosh",
"0.0.8rc2"));
- test_eq(0, tor_version_as_new_as(
+ tt_int_op(0,OP_EQ, tor_version_as_new_as(
"Tor 0.0.8 on Darwin 64-121-192-100.c3-0."
"sfpo-ubr1.sfrn-sfpo.ca.cable.rcn.com Power Macintosh", "0.0.8.2"));
/* Now try svn revisions. */
- test_eq(1, tor_version_as_new_as("Tor 0.2.1.0-dev (r100)",
+ tt_int_op(1,OP_EQ, tor_version_as_new_as("Tor 0.2.1.0-dev (r100)",
"Tor 0.2.1.0-dev (r99)"));
- test_eq(1, tor_version_as_new_as("Tor 0.2.1.0-dev (r100) on Banana Jr",
+ tt_int_op(1,OP_EQ, tor_version_as_new_as(
+ "Tor 0.2.1.0-dev (r100) on Banana Jr",
"Tor 0.2.1.0-dev (r99) on Hal 9000"));
- test_eq(1, tor_version_as_new_as("Tor 0.2.1.0-dev (r100)",
+ tt_int_op(1,OP_EQ, tor_version_as_new_as("Tor 0.2.1.0-dev (r100)",
"Tor 0.2.1.0-dev on Colossus"));
- test_eq(0, tor_version_as_new_as("Tor 0.2.1.0-dev (r99)",
+ tt_int_op(0,OP_EQ, tor_version_as_new_as("Tor 0.2.1.0-dev (r99)",
"Tor 0.2.1.0-dev (r100)"));
- test_eq(0, tor_version_as_new_as("Tor 0.2.1.0-dev (r99) on MCP",
+ tt_int_op(0,OP_EQ, tor_version_as_new_as("Tor 0.2.1.0-dev (r99) on MCP",
"Tor 0.2.1.0-dev (r100) on AM"));
- test_eq(0, tor_version_as_new_as("Tor 0.2.1.0-dev",
+ tt_int_op(0,OP_EQ, tor_version_as_new_as("Tor 0.2.1.0-dev",
"Tor 0.2.1.0-dev (r99)"));
- test_eq(1, tor_version_as_new_as("Tor 0.2.1.1",
+ tt_int_op(1,OP_EQ, tor_version_as_new_as("Tor 0.2.1.1",
"Tor 0.2.1.0-dev (r99)"));
/* Now try git revisions */
- test_eq(0, tor_version_parse("0.5.6.7 (git-ff00ff)", &ver1));
- test_eq(0, ver1.major);
- test_eq(5, ver1.minor);
- test_eq(6, ver1.micro);
- test_eq(7, ver1.patchlevel);
- test_eq(3, ver1.git_tag_len);
- test_memeq(ver1.git_tag, "\xff\x00\xff", 3);
- test_eq(-1, tor_version_parse("0.5.6.7 (git-ff00xx)", &ver1));
- test_eq(-1, tor_version_parse("0.5.6.7 (git-ff00fff)", &ver1));
- test_eq(0, tor_version_parse("0.5.6.7 (git ff00fff)", &ver1));
+ tt_int_op(0,OP_EQ, tor_version_parse("0.5.6.7 (git-ff00ff)", &ver1));
+ tt_int_op(0,OP_EQ, ver1.major);
+ tt_int_op(5,OP_EQ, ver1.minor);
+ tt_int_op(6,OP_EQ, ver1.micro);
+ tt_int_op(7,OP_EQ, ver1.patchlevel);
+ tt_int_op(3,OP_EQ, ver1.git_tag_len);
+ tt_mem_op(ver1.git_tag,OP_EQ, "\xff\x00\xff", 3);
+ tt_int_op(-1,OP_EQ, tor_version_parse("0.5.6.7 (git-ff00xx)", &ver1));
+ tt_int_op(-1,OP_EQ, tor_version_parse("0.5.6.7 (git-ff00fff)", &ver1));
+ tt_int_op(0,OP_EQ, tor_version_parse("0.5.6.7 (git ff00fff)", &ver1));
done:
;
}
/** Run unit tests for directory fp_pair functions. */
static void
-test_dir_fp_pairs(void)
+test_dir_fp_pairs(void *arg)
{
smartlist_t *sl = smartlist_new();
fp_pair_t *pair;
+ (void)arg;
dir_split_resource_into_fingerprint_pairs(
/* Two pairs, out of order, with one duplicate. */
"73656372657420646174612E0000000000FFFFFF-"
@@ -424,13 +971,14 @@ test_dir_fp_pairs(void)
"48657861646563696d616c2069736e277420736f-"
"676f6f6420666f7220686964696e6720796f7572.z", sl);
- test_eq(smartlist_len(sl), 2);
+ tt_int_op(smartlist_len(sl),OP_EQ, 2);
pair = smartlist_get(sl, 0);
- test_memeq(pair->first, "Hexadecimal isn't so", DIGEST_LEN);
- test_memeq(pair->second, "good for hiding your", DIGEST_LEN);
+ tt_mem_op(pair->first,OP_EQ, "Hexadecimal isn't so", DIGEST_LEN);
+ tt_mem_op(pair->second,OP_EQ, "good for hiding your", DIGEST_LEN);
pair = smartlist_get(sl, 1);
- test_memeq(pair->first, "secret data.\0\0\0\0\0\xff\xff\xff", DIGEST_LEN);
- test_memeq(pair->second, "Use AES-256 instead.", DIGEST_LEN);
+ tt_mem_op(pair->first,OP_EQ, "secret data.\0\0\0\0\0\xff\xff\xff",
+ DIGEST_LEN);
+ tt_mem_op(pair->second,OP_EQ, "Use AES-256 instead.", DIGEST_LEN);
done:
SMARTLIST_FOREACH(sl, fp_pair_t *, pair, tor_free(pair));
@@ -461,56 +1009,56 @@ test_dir_split_fps(void *testdata)
/* no flags set */
dir_split_resource_into_fingerprints("A+C+B", sl, NULL, 0);
- tt_int_op(smartlist_len(sl), ==, 3);
- tt_str_op(smartlist_get(sl, 0), ==, "A");
- tt_str_op(smartlist_get(sl, 1), ==, "C");
- tt_str_op(smartlist_get(sl, 2), ==, "B");
+ tt_int_op(smartlist_len(sl), OP_EQ, 3);
+ tt_str_op(smartlist_get(sl, 0), OP_EQ, "A");
+ tt_str_op(smartlist_get(sl, 1), OP_EQ, "C");
+ tt_str_op(smartlist_get(sl, 2), OP_EQ, "B");
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* uniq strings. */
dir_split_resource_into_fingerprints("A+C+B+A+B+B", sl, NULL, DSR_SORT_UNIQ);
- tt_int_op(smartlist_len(sl), ==, 3);
- tt_str_op(smartlist_get(sl, 0), ==, "A");
- tt_str_op(smartlist_get(sl, 1), ==, "B");
- tt_str_op(smartlist_get(sl, 2), ==, "C");
+ tt_int_op(smartlist_len(sl), OP_EQ, 3);
+ tt_str_op(smartlist_get(sl, 0), OP_EQ, "A");
+ tt_str_op(smartlist_get(sl, 1), OP_EQ, "B");
+ tt_str_op(smartlist_get(sl, 2), OP_EQ, "C");
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* Decode hex. */
dir_split_resource_into_fingerprints(HEX1"+"HEX2, sl, NULL, DSR_HEX);
- tt_int_op(smartlist_len(sl), ==, 2);
- test_mem_op_hex(smartlist_get(sl, 0), ==, HEX1);
- test_mem_op_hex(smartlist_get(sl, 1), ==, HEX2);
+ tt_int_op(smartlist_len(sl), OP_EQ, 2);
+ test_mem_op_hex(smartlist_get(sl, 0), OP_EQ, HEX1);
+ test_mem_op_hex(smartlist_get(sl, 1), OP_EQ, HEX2);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* decode hex and drop weirdness. */
dir_split_resource_into_fingerprints(HEX1"+bogus+"HEX2"+"HEX256_1,
sl, NULL, DSR_HEX);
- tt_int_op(smartlist_len(sl), ==, 2);
- test_mem_op_hex(smartlist_get(sl, 0), ==, HEX1);
- test_mem_op_hex(smartlist_get(sl, 1), ==, HEX2);
+ tt_int_op(smartlist_len(sl), OP_EQ, 2);
+ test_mem_op_hex(smartlist_get(sl, 0), OP_EQ, HEX1);
+ test_mem_op_hex(smartlist_get(sl, 1), OP_EQ, HEX2);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* Decode long hex */
dir_split_resource_into_fingerprints(HEX256_1"+"HEX256_2"+"HEX2"+"HEX256_3,
sl, NULL, DSR_HEX|DSR_DIGEST256);
- tt_int_op(smartlist_len(sl), ==, 3);
- test_mem_op_hex(smartlist_get(sl, 0), ==, HEX256_1);
- test_mem_op_hex(smartlist_get(sl, 1), ==, HEX256_2);
- test_mem_op_hex(smartlist_get(sl, 2), ==, HEX256_3);
+ tt_int_op(smartlist_len(sl), OP_EQ, 3);
+ test_mem_op_hex(smartlist_get(sl, 0), OP_EQ, HEX256_1);
+ test_mem_op_hex(smartlist_get(sl, 1), OP_EQ, HEX256_2);
+ test_mem_op_hex(smartlist_get(sl, 2), OP_EQ, HEX256_3);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* Decode hex and sort. */
dir_split_resource_into_fingerprints(HEX1"+"HEX2"+"HEX3"+"HEX2,
sl, NULL, DSR_HEX|DSR_SORT_UNIQ);
- tt_int_op(smartlist_len(sl), ==, 3);
- test_mem_op_hex(smartlist_get(sl, 0), ==, HEX3);
- test_mem_op_hex(smartlist_get(sl, 1), ==, HEX2);
- test_mem_op_hex(smartlist_get(sl, 2), ==, HEX1);
+ tt_int_op(smartlist_len(sl), OP_EQ, 3);
+ test_mem_op_hex(smartlist_get(sl, 0), OP_EQ, HEX3);
+ test_mem_op_hex(smartlist_get(sl, 1), OP_EQ, HEX2);
+ test_mem_op_hex(smartlist_get(sl, 2), OP_EQ, HEX1);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
@@ -519,34 +1067,34 @@ test_dir_split_fps(void *testdata)
"+"HEX256_1,
sl, NULL,
DSR_HEX|DSR_DIGEST256|DSR_SORT_UNIQ);
- tt_int_op(smartlist_len(sl), ==, 3);
- test_mem_op_hex(smartlist_get(sl, 0), ==, HEX256_3);
- test_mem_op_hex(smartlist_get(sl, 1), ==, HEX256_2);
- test_mem_op_hex(smartlist_get(sl, 2), ==, HEX256_1);
+ tt_int_op(smartlist_len(sl), OP_EQ, 3);
+ test_mem_op_hex(smartlist_get(sl, 0), OP_EQ, HEX256_3);
+ test_mem_op_hex(smartlist_get(sl, 1), OP_EQ, HEX256_2);
+ test_mem_op_hex(smartlist_get(sl, 2), OP_EQ, HEX256_1);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* Decode base64 */
dir_split_resource_into_fingerprints(B64_1"-"B64_2, sl, NULL, DSR_BASE64);
- tt_int_op(smartlist_len(sl), ==, 2);
- test_mem_op_hex(smartlist_get(sl, 0), ==, HEX1);
- test_mem_op_hex(smartlist_get(sl, 1), ==, HEX2);
+ tt_int_op(smartlist_len(sl), OP_EQ, 2);
+ test_mem_op_hex(smartlist_get(sl, 0), OP_EQ, HEX1);
+ test_mem_op_hex(smartlist_get(sl, 1), OP_EQ, HEX2);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
/* Decode long base64 */
dir_split_resource_into_fingerprints(B64_256_1"-"B64_256_2,
sl, NULL, DSR_BASE64|DSR_DIGEST256);
- tt_int_op(smartlist_len(sl), ==, 2);
- test_mem_op_hex(smartlist_get(sl, 0), ==, HEX256_1);
- test_mem_op_hex(smartlist_get(sl, 1), ==, HEX256_2);
+ tt_int_op(smartlist_len(sl), OP_EQ, 2);
+ test_mem_op_hex(smartlist_get(sl, 0), OP_EQ, HEX256_1);
+ test_mem_op_hex(smartlist_get(sl, 1), OP_EQ, HEX256_2);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
dir_split_resource_into_fingerprints(B64_256_1,
sl, NULL, DSR_BASE64|DSR_DIGEST256);
- tt_int_op(smartlist_len(sl), ==, 1);
- test_mem_op_hex(smartlist_get(sl, 0), ==, HEX256_1);
+ tt_int_op(smartlist_len(sl), OP_EQ, 1);
+ test_mem_op_hex(smartlist_get(sl, 0), OP_EQ, HEX256_1);
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
smartlist_clear(sl);
@@ -557,7 +1105,7 @@ test_dir_split_fps(void *testdata)
}
static void
-test_dir_measured_bw_kb(void)
+test_dir_measured_bw_kb(void *arg)
{
measured_bw_line_t mbwl;
int i;
@@ -605,16 +1153,17 @@ test_dir_measured_bw_kb(void)
"end"
};
+ (void)arg;
for (i = 0; strcmp(lines_fail[i], "end"); i++) {
//fprintf(stderr, "Testing: %s\n", lines_fail[i]);
- test_assert(measured_bw_line_parse(&mbwl, lines_fail[i]) == -1);
+ tt_assert(measured_bw_line_parse(&mbwl, lines_fail[i]) == -1);
}
for (i = 0; strcmp(lines_pass[i], "end"); i++) {
//fprintf(stderr, "Testing: %s %d\n", lines_pass[i], TOR_ISSPACE('\n'));
- test_assert(measured_bw_line_parse(&mbwl, lines_pass[i]) == 0);
- test_assert(mbwl.bw_kb == 1024);
- test_assert(strcmp(mbwl.node_hex,
+ tt_assert(measured_bw_line_parse(&mbwl, lines_pass[i]) == 0);
+ tt_assert(mbwl.bw_kb == 1024);
+ tt_assert(strcmp(mbwl.node_hex,
"557365204145532d32353620696e73746561642e") == 0);
}
@@ -626,7 +1175,7 @@ test_dir_measured_bw_kb(void)
/** Do the measured bandwidth cache unit test */
static void
-test_dir_measured_bw_kb_cache(void)
+test_dir_measured_bw_kb_cache(void *arg)
{
/* Initial fake time_t for testing */
time_t curr = MBWC_INIT_TIME;
@@ -637,8 +1186,9 @@ test_dir_measured_bw_kb_cache(void)
time_t as_of;
/* First, clear the cache and assert that it's empty */
+ (void)arg;
dirserv_clear_measured_bw_cache();
- test_eq(dirserv_get_measured_bw_cache_size(), 0);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 0);
/*
* Set up test mbwls; none of the dirserv_cache_*() functions care about
* the node_hex field.
@@ -651,56 +1201,56 @@ test_dir_measured_bw_kb_cache(void)
mbwl[2].bw_kb = 80;
/* Try caching something */
dirserv_cache_measured_bw(&(mbwl[0]), curr);
- test_eq(dirserv_get_measured_bw_cache_size(), 1);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 1);
/* Okay, let's see if we can retrieve it */
- test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, &as_of));
- test_eq(bw, 20);
- test_eq(as_of, MBWC_INIT_TIME);
+ tt_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, &as_of));
+ tt_int_op(bw,OP_EQ, 20);
+ tt_int_op(as_of,OP_EQ, MBWC_INIT_TIME);
/* Try retrieving it without some outputs */
- test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL, NULL));
- test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, NULL));
- test_eq(bw, 20);
- test_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL,&as_of));
- test_eq(as_of, MBWC_INIT_TIME);
+ tt_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL, NULL));
+ tt_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,&bw, NULL));
+ tt_int_op(bw,OP_EQ, 20);
+ tt_assert(dirserv_query_measured_bw_cache_kb(mbwl[0].node_id,NULL,&as_of));
+ tt_int_op(as_of,OP_EQ, MBWC_INIT_TIME);
/* Now expire it */
curr += MAX_MEASUREMENT_AGE + 1;
dirserv_expire_measured_bw_cache(curr);
/* Check that the cache is empty */
- test_eq(dirserv_get_measured_bw_cache_size(), 0);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 0);
/* Check that we can't retrieve it */
- test_assert(!dirserv_query_measured_bw_cache_kb(mbwl[0].node_id, NULL,NULL));
+ tt_assert(!dirserv_query_measured_bw_cache_kb(mbwl[0].node_id, NULL,NULL));
/* Try caching a few things now */
dirserv_cache_measured_bw(&(mbwl[0]), curr);
- test_eq(dirserv_get_measured_bw_cache_size(), 1);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 1);
curr += MAX_MEASUREMENT_AGE / 4;
dirserv_cache_measured_bw(&(mbwl[1]), curr);
- test_eq(dirserv_get_measured_bw_cache_size(), 2);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 2);
curr += MAX_MEASUREMENT_AGE / 4;
dirserv_cache_measured_bw(&(mbwl[2]), curr);
- test_eq(dirserv_get_measured_bw_cache_size(), 3);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 3);
curr += MAX_MEASUREMENT_AGE / 4 + 1;
/* Do an expire that's too soon to get any of them */
dirserv_expire_measured_bw_cache(curr);
- test_eq(dirserv_get_measured_bw_cache_size(), 3);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 3);
/* Push the oldest one off the cliff */
curr += MAX_MEASUREMENT_AGE / 4;
dirserv_expire_measured_bw_cache(curr);
- test_eq(dirserv_get_measured_bw_cache_size(), 2);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 2);
/* And another... */
curr += MAX_MEASUREMENT_AGE / 4;
dirserv_expire_measured_bw_cache(curr);
- test_eq(dirserv_get_measured_bw_cache_size(), 1);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 1);
/* This should empty it out again */
curr += MAX_MEASUREMENT_AGE / 4;
dirserv_expire_measured_bw_cache(curr);
- test_eq(dirserv_get_measured_bw_cache_size(), 0);
+ tt_int_op(dirserv_get_measured_bw_cache_size(),OP_EQ, 0);
done:
return;
}
static void
-test_dir_param_voting(void)
+test_dir_param_voting(void *arg)
{
networkstatus_t vote1, vote2, vote3, vote4;
smartlist_t *votes = smartlist_new();
@@ -709,6 +1259,7 @@ test_dir_param_voting(void)
/* dirvote_compute_params only looks at the net_params field of the votes,
so that's all we need to set.
*/
+ (void)arg;
memset(&vote1, 0, sizeof(vote1));
memset(&vote2, 0, sizeof(vote2));
memset(&vote3, 0, sizeof(vote3));
@@ -725,87 +1276,71 @@ test_dir_param_voting(void)
"abcd=20 c=60 cw=500 x-yz=-9 zzzzz=101", NULL, 0, 0);
smartlist_split_string(vote4.net_params,
"ab=900 abcd=200 c=1 cw=51 x-yz=100", NULL, 0, 0);
- test_eq(100, networkstatus_get_param(&vote4, "x-yz", 50, 0, 300));
- test_eq(222, networkstatus_get_param(&vote4, "foobar", 222, 0, 300));
- test_eq(80, networkstatus_get_param(&vote4, "ab", 12, 0, 80));
- test_eq(-8, networkstatus_get_param(&vote4, "ab", -12, -100, -8));
- test_eq(0, networkstatus_get_param(&vote4, "foobar", 0, -100, 8));
+ tt_int_op(100,OP_EQ, networkstatus_get_param(&vote4, "x-yz", 50, 0, 300));
+ tt_int_op(222,OP_EQ, networkstatus_get_param(&vote4, "foobar", 222, 0, 300));
+ tt_int_op(80,OP_EQ, networkstatus_get_param(&vote4, "ab", 12, 0, 80));
+ tt_int_op(-8,OP_EQ, networkstatus_get_param(&vote4, "ab", -12, -100, -8));
+ tt_int_op(0,OP_EQ, networkstatus_get_param(&vote4, "foobar", 0, -100, 8));
smartlist_add(votes, &vote1);
/* Do the first tests without adding all the other votes, for
* networks without many dirauths. */
- res = dirvote_compute_params(votes, 11, 6);
- test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-99");
- tor_free(res);
-
res = dirvote_compute_params(votes, 12, 2);
- test_streq(res, "");
+ tt_str_op(res,OP_EQ, "");
tor_free(res);
res = dirvote_compute_params(votes, 12, 1);
- test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-99");
+ tt_str_op(res,OP_EQ, "ab=90 abcd=20 cw=50 x-yz=-99");
tor_free(res);
smartlist_add(votes, &vote2);
- res = dirvote_compute_params(votes, 11, 2);
- test_streq(res, "ab=27 abcd=20 cw=5 x-yz=-99");
- tor_free(res);
-
res = dirvote_compute_params(votes, 12, 2);
- test_streq(res, "ab=27 cw=5 x-yz=-99");
+ tt_str_op(res,OP_EQ, "ab=27 cw=5 x-yz=-99");
tor_free(res);
res = dirvote_compute_params(votes, 12, 3);
- test_streq(res, "ab=27 cw=5 x-yz=-99");
+ tt_str_op(res,OP_EQ, "ab=27 cw=5 x-yz=-99");
tor_free(res);
res = dirvote_compute_params(votes, 12, 6);
- test_streq(res, "");
+ tt_str_op(res,OP_EQ, "");
tor_free(res);
smartlist_add(votes, &vote3);
- res = dirvote_compute_params(votes, 11, 3);
- test_streq(res, "ab=27 abcd=20 c=60 cw=50 x-yz=-9 zzzzz=101");
- tor_free(res);
-
res = dirvote_compute_params(votes, 12, 3);
- test_streq(res, "ab=27 abcd=20 cw=50 x-yz=-9");
+ tt_str_op(res,OP_EQ, "ab=27 abcd=20 cw=50 x-yz=-9");
tor_free(res);
res = dirvote_compute_params(votes, 12, 5);
- test_streq(res, "cw=50 x-yz=-9");
+ tt_str_op(res,OP_EQ, "cw=50 x-yz=-9");
tor_free(res);
res = dirvote_compute_params(votes, 12, 9);
- test_streq(res, "cw=50 x-yz=-9");
+ tt_str_op(res,OP_EQ, "cw=50 x-yz=-9");
tor_free(res);
smartlist_add(votes, &vote4);
- res = dirvote_compute_params(votes, 11, 4);
- test_streq(res, "ab=90 abcd=20 c=1 cw=50 x-yz=-9 zzzzz=101");
- tor_free(res);
-
res = dirvote_compute_params(votes, 12, 4);
- test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tt_str_op(res,OP_EQ, "ab=90 abcd=20 cw=50 x-yz=-9");
tor_free(res);
res = dirvote_compute_params(votes, 12, 5);
- test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tt_str_op(res,OP_EQ, "ab=90 abcd=20 cw=50 x-yz=-9");
tor_free(res);
/* Test that the special-cased "at least three dirauths voted for
* this param" logic works as expected. */
res = dirvote_compute_params(votes, 12, 6);
- test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tt_str_op(res,OP_EQ, "ab=90 abcd=20 cw=50 x-yz=-9");
tor_free(res);
res = dirvote_compute_params(votes, 12, 10);
- test_streq(res, "ab=90 abcd=20 cw=50 x-yz=-9");
+ tt_str_op(res,OP_EQ, "ab=90 abcd=20 cw=50 x-yz=-9");
tor_free(res);
done:
@@ -837,14 +1372,14 @@ static void
test_same_voter(networkstatus_voter_info_t *v1,
networkstatus_voter_info_t *v2)
{
- test_streq(v1->nickname, v2->nickname);
- test_memeq(v1->identity_digest, v2->identity_digest, DIGEST_LEN);
- test_streq(v1->address, v2->address);
- test_eq(v1->addr, v2->addr);
- test_eq(v1->dir_port, v2->dir_port);
- test_eq(v1->or_port, v2->or_port);
- test_streq(v1->contact, v2->contact);
- test_memeq(v1->vote_digest, v2->vote_digest, DIGEST_LEN);
+ tt_str_op(v1->nickname,OP_EQ, v2->nickname);
+ tt_mem_op(v1->identity_digest,OP_EQ, v2->identity_digest, DIGEST_LEN);
+ tt_str_op(v1->address,OP_EQ, v2->address);
+ tt_int_op(v1->addr,OP_EQ, v2->addr);
+ tt_int_op(v1->dir_port,OP_EQ, v2->dir_port);
+ tt_int_op(v1->or_port,OP_EQ, v2->or_port);
+ tt_str_op(v1->contact,OP_EQ, v2->contact);
+ tt_mem_op(v1->vote_digest,OP_EQ, v2->vote_digest, DIGEST_LEN);
done:
;
}
@@ -981,7 +1516,7 @@ gen_routerstatus_for_v3ns(int idx, time_t now)
break;
default:
/* Shouldn't happen */
- test_assert(0);
+ tt_assert(0);
}
if (vrs) {
vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
@@ -1002,14 +1537,14 @@ vote_tweaks_for_v3ns(networkstatus_t *v, int voter, time_t now)
vote_routerstatus_t *vrs;
const char *msg = NULL;
- test_assert(v);
+ tt_assert(v);
(void)now;
if (voter == 1) {
measured_bw_line_t mbw;
memset(mbw.node_id, 33, sizeof(mbw.node_id));
mbw.bw_kb = 1024;
- test_assert(measured_bw_line_apply(&mbw,
+ tt_assert(measured_bw_line_apply(&mbw,
v->routerstatus_list) == 1);
} else if (voter == 2 || voter == 3) {
/* Monkey around with the list a bit */
@@ -1025,7 +1560,7 @@ vote_tweaks_for_v3ns(networkstatus_t *v, int voter, time_t now)
vote_routerstatus_free(vrs);
vrs = smartlist_get(v->routerstatus_list, 0);
memset(vrs->status.descriptor_digest, (int)'Z', DIGEST_LEN);
- test_assert(router_add_to_routerlist(
+ tt_assert(router_add_to_routerlist(
generate_ri_from_rs(vrs), &msg,0,0) >= 0);
}
}
@@ -1043,9 +1578,9 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
routerstatus_t *rs;
tor_addr_t addr_ipv6;
- test_assert(vrs);
+ tt_assert(vrs);
rs = &(vrs->status);
- test_assert(rs);
+ tt_assert(rs);
/* Split out by digests to test */
if (tor_memeq(rs->identity_digest,
@@ -1054,48 +1589,48 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
DIGEST_LEN) &&
(voter == 1)) {
/* Check the first routerstatus. */
- test_streq(vrs->version, "0.1.2.14");
- test_eq(rs->published_on, now-1500);
- test_streq(rs->nickname, "router2");
- test_memeq(rs->identity_digest,
+ tt_str_op(vrs->version,OP_EQ, "0.1.2.14");
+ tt_int_op(rs->published_on,OP_EQ, now-1500);
+ tt_str_op(rs->nickname,OP_EQ, "router2");
+ tt_mem_op(rs->identity_digest,OP_EQ,
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
"\x3\x3\x3\x3",
DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- test_eq(rs->addr, 0x99008801);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 8000);
+ tt_mem_op(rs->descriptor_digest,OP_EQ, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ tt_int_op(rs->addr,OP_EQ, 0x99008801);
+ tt_int_op(rs->or_port,OP_EQ, 443);
+ tt_int_op(rs->dir_port,OP_EQ, 8000);
/* no flags except "running" (16) and "v2dir" (64) */
- tt_u64_op(vrs->flags, ==, U64_LITERAL(80));
+ tt_u64_op(vrs->flags, OP_EQ, U64_LITERAL(80));
} else if (tor_memeq(rs->identity_digest,
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
"\x5\x5\x5\x5",
DIGEST_LEN) &&
(voter == 1 || voter == 2)) {
- test_memeq(rs->identity_digest,
+ tt_mem_op(rs->identity_digest,OP_EQ,
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
"\x5\x5\x5\x5",
DIGEST_LEN);
if (voter == 1) {
/* Check the second routerstatus. */
- test_streq(vrs->version, "0.2.0.5");
- test_eq(rs->published_on, now-1000);
- test_streq(rs->nickname, "router1");
+ tt_str_op(vrs->version,OP_EQ, "0.2.0.5");
+ tt_int_op(rs->published_on,OP_EQ, now-1000);
+ tt_str_op(rs->nickname,OP_EQ, "router1");
}
- test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- test_eq(rs->addr, 0x99009901);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 0);
+ tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ tt_int_op(rs->addr,OP_EQ, 0x99009901);
+ tt_int_op(rs->or_port,OP_EQ, 443);
+ tt_int_op(rs->dir_port,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
- test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
- test_eq(rs->ipv6_orport, 4711);
+ tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
if (voter == 1) {
/* all except "authority" (1) and "v2dir" (64) */
- tt_u64_op(vrs->flags, ==, U64_LITERAL(190));
+ tt_u64_op(vrs->flags, OP_EQ, U64_LITERAL(190));
} else {
/* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) - v2dir(256) */
- tt_u64_op(vrs->flags, ==, U64_LITERAL(718));
+ tt_u64_op(vrs->flags, OP_EQ, U64_LITERAL(718));
}
} else if (tor_memeq(rs->identity_digest,
"\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
@@ -1103,14 +1638,14 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now)
DIGEST_LEN) &&
(voter == 1 || voter == 2)) {
/* Check the measured bandwidth bits */
- test_assert(vrs->has_measured_bw &&
+ tt_assert(vrs->has_measured_bw &&
vrs->measured_bw_kb == 1024);
} else {
/*
* Didn't expect this, but the old unit test only checked some of them,
* so don't assert.
*/
- /* test_assert(0); */
+ /* tt_assert(0); */
}
done:
@@ -1125,9 +1660,9 @@ test_consensus_for_v3ns(networkstatus_t *con, time_t now)
{
(void)now;
- test_assert(con);
- test_assert(!con->cert);
- test_eq(2, smartlist_len(con->routerstatus_list));
+ tt_assert(con);
+ tt_assert(!con->cert);
+ tt_int_op(2,OP_EQ, smartlist_len(con->routerstatus_list));
/* There should be two listed routers: one with identity 3, one with
* identity 5. */
@@ -1143,7 +1678,7 @@ test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
{
tor_addr_t addr_ipv6;
- test_assert(rs);
+ tt_assert(rs);
/* There should be two listed routers: one with identity 3, one with
* identity 5. */
@@ -1152,49 +1687,49 @@ test_routerstatus_for_v3ns(routerstatus_t *rs, time_t now)
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
"\x3\x3",
DIGEST_LEN)) {
- test_memeq(rs->identity_digest,
+ tt_mem_op(rs->identity_digest,OP_EQ,
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- test_assert(!rs->is_authority);
- test_assert(!rs->is_exit);
- test_assert(!rs->is_fast);
- test_assert(!rs->is_possible_guard);
- test_assert(!rs->is_stable);
+ tt_mem_op(rs->descriptor_digest,OP_EQ, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ tt_assert(!rs->is_authority);
+ tt_assert(!rs->is_exit);
+ tt_assert(!rs->is_fast);
+ tt_assert(!rs->is_possible_guard);
+ tt_assert(!rs->is_stable);
/* (If it wasn't running it wouldn't be here) */
- test_assert(rs->is_flagged_running);
- test_assert(!rs->is_valid);
- test_assert(!rs->is_named);
+ tt_assert(rs->is_flagged_running);
+ tt_assert(!rs->is_valid);
+ tt_assert(!rs->is_named);
/* XXXX check version */
} else if (tor_memeq(rs->identity_digest,
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
"\x5\x5\x5\x5",
DIGEST_LEN)) {
/* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */
- test_memeq(rs->identity_digest,
+ tt_mem_op(rs->identity_digest,OP_EQ,
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
DIGEST_LEN);
- test_streq(rs->nickname, "router1");
- test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- test_eq(rs->published_on, now-1000);
- test_eq(rs->addr, 0x99009901);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 0);
+ tt_str_op(rs->nickname,OP_EQ, "router1");
+ tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ tt_int_op(rs->published_on,OP_EQ, now-1000);
+ tt_int_op(rs->addr,OP_EQ, 0x99009901);
+ tt_int_op(rs->or_port,OP_EQ, 443);
+ tt_int_op(rs->dir_port,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
- test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
- test_eq(rs->ipv6_orport, 4711);
- test_assert(!rs->is_authority);
- test_assert(rs->is_exit);
- test_assert(rs->is_fast);
- test_assert(rs->is_possible_guard);
- test_assert(rs->is_stable);
- test_assert(rs->is_flagged_running);
- test_assert(rs->is_valid);
- test_assert(!rs->is_named);
+ tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
+ tt_assert(!rs->is_authority);
+ tt_assert(rs->is_exit);
+ tt_assert(rs->is_fast);
+ tt_assert(rs->is_possible_guard);
+ tt_assert(rs->is_stable);
+ tt_assert(rs->is_flagged_running);
+ tt_assert(rs->is_valid);
+ tt_assert(!rs->is_named);
/* XXXX check version */
} else {
/* Weren't expecting this... */
- test_assert(0);
+ tt_assert(0);
}
done:
@@ -1242,31 +1777,31 @@ test_a_networkstatus(
networkstatus_t *con2=NULL, *con_md2=NULL, *con3=NULL, *con_md3=NULL;
ns_detached_signatures_t *dsig1=NULL, *dsig2=NULL;
- test_assert(vrs_gen);
- test_assert(rs_test);
- test_assert(vrs_test);
+ tt_assert(vrs_gen);
+ tt_assert(rs_test);
+ tt_assert(vrs_test);
/* Parse certificates and keys. */
cert1 = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
- test_assert(cert1);
+ tt_assert(cert1);
cert2 = authority_cert_parse_from_string(AUTHORITY_CERT_2, NULL);
- test_assert(cert2);
+ tt_assert(cert2);
cert3 = authority_cert_parse_from_string(AUTHORITY_CERT_3, NULL);
- test_assert(cert3);
+ tt_assert(cert3);
sign_skey_1 = crypto_pk_new();
sign_skey_2 = crypto_pk_new();
sign_skey_3 = crypto_pk_new();
sign_skey_leg1 = pk_generate(4);
- test_assert(!crypto_pk_read_private_key_from_string(sign_skey_1,
+ tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_1,
AUTHORITY_SIGNKEY_1, -1));
- test_assert(!crypto_pk_read_private_key_from_string(sign_skey_2,
+ tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_2,
AUTHORITY_SIGNKEY_2, -1));
- test_assert(!crypto_pk_read_private_key_from_string(sign_skey_3,
+ tt_assert(!crypto_pk_read_private_key_from_string(sign_skey_3,
AUTHORITY_SIGNKEY_3, -1));
- test_assert(!crypto_pk_cmp_keys(sign_skey_1, cert1->signing_key));
- test_assert(!crypto_pk_cmp_keys(sign_skey_2, cert2->signing_key));
+ tt_assert(!crypto_pk_cmp_keys(sign_skey_1, cert1->signing_key));
+ tt_assert(!crypto_pk_cmp_keys(sign_skey_2, cert2->signing_key));
/*
* Set up a vote; generate it; try to parse it.
@@ -1308,7 +1843,7 @@ test_a_networkstatus(
vrs = vrs_gen(idx, now);
if (vrs) {
smartlist_add(vote->routerstatus_list, vrs);
- test_assert(router_add_to_routerlist(generate_ri_from_rs(vrs),
+ tt_assert(router_add_to_routerlist(generate_ri_from_rs(vrs),
&msg,0,0)>=0);
++idx;
}
@@ -1317,41 +1852,41 @@ test_a_networkstatus(
/* dump the vote and try to parse it. */
v1_text = format_networkstatus_vote(sign_skey_1, vote);
- test_assert(v1_text);
+ tt_assert(v1_text);
v1 = networkstatus_parse_vote_from_string(v1_text, NULL, NS_TYPE_VOTE);
- test_assert(v1);
+ tt_assert(v1);
/* Make sure the parsed thing was right. */
- test_eq(v1->type, NS_TYPE_VOTE);
- test_eq(v1->published, vote->published);
- test_eq(v1->valid_after, vote->valid_after);
- test_eq(v1->fresh_until, vote->fresh_until);
- test_eq(v1->valid_until, vote->valid_until);
- test_eq(v1->vote_seconds, vote->vote_seconds);
- test_eq(v1->dist_seconds, vote->dist_seconds);
- test_streq(v1->client_versions, vote->client_versions);
- test_streq(v1->server_versions, vote->server_versions);
- test_assert(v1->voters && smartlist_len(v1->voters));
+ tt_int_op(v1->type,OP_EQ, NS_TYPE_VOTE);
+ tt_int_op(v1->published,OP_EQ, vote->published);
+ tt_int_op(v1->valid_after,OP_EQ, vote->valid_after);
+ tt_int_op(v1->fresh_until,OP_EQ, vote->fresh_until);
+ tt_int_op(v1->valid_until,OP_EQ, vote->valid_until);
+ tt_int_op(v1->vote_seconds,OP_EQ, vote->vote_seconds);
+ tt_int_op(v1->dist_seconds,OP_EQ, vote->dist_seconds);
+ tt_str_op(v1->client_versions,OP_EQ, vote->client_versions);
+ tt_str_op(v1->server_versions,OP_EQ, vote->server_versions);
+ tt_assert(v1->voters && smartlist_len(v1->voters));
voter = smartlist_get(v1->voters, 0);
- test_streq(voter->nickname, "Voter1");
- test_streq(voter->address, "1.2.3.4");
- test_eq(voter->addr, 0x01020304);
- test_eq(voter->dir_port, 80);
- test_eq(voter->or_port, 9000);
- test_streq(voter->contact, "voter@example.com");
- test_assert(v1->cert);
- test_assert(!crypto_pk_cmp_keys(sign_skey_1, v1->cert->signing_key));
+ tt_str_op(voter->nickname,OP_EQ, "Voter1");
+ tt_str_op(voter->address,OP_EQ, "1.2.3.4");
+ tt_int_op(voter->addr,OP_EQ, 0x01020304);
+ tt_int_op(voter->dir_port,OP_EQ, 80);
+ tt_int_op(voter->or_port,OP_EQ, 9000);
+ tt_str_op(voter->contact,OP_EQ, "voter@example.com");
+ tt_assert(v1->cert);
+ tt_assert(!crypto_pk_cmp_keys(sign_skey_1, v1->cert->signing_key));
cp = smartlist_join_strings(v1->known_flags, ":", 0, NULL);
- test_streq(cp, "Authority:Exit:Fast:Guard:Running:Stable:V2Dir:Valid");
+ tt_str_op(cp,OP_EQ, "Authority:Exit:Fast:Guard:Running:Stable:V2Dir:Valid");
tor_free(cp);
- test_eq(smartlist_len(v1->routerstatus_list), n_vrs);
+ tt_int_op(smartlist_len(v1->routerstatus_list),OP_EQ, n_vrs);
if (vote_tweaks) params_tweaked += vote_tweaks(v1, 1, now);
/* Check the routerstatuses. */
for (idx = 0; idx < n_vrs; ++idx) {
vrs = smartlist_get(v1->routerstatus_list, idx);
- test_assert(vrs);
+ tt_assert(vrs);
vrs_test(vrs, 1, now);
}
@@ -1381,15 +1916,15 @@ test_a_networkstatus(
/* generate and parse v2. */
v2_text = format_networkstatus_vote(sign_skey_2, vote);
- test_assert(v2_text);
+ tt_assert(v2_text);
v2 = networkstatus_parse_vote_from_string(v2_text, NULL, NS_TYPE_VOTE);
- test_assert(v2);
+ tt_assert(v2);
if (vote_tweaks) params_tweaked += vote_tweaks(v2, 2, now);
/* Check that flags come out right.*/
cp = smartlist_join_strings(v2->known_flags, ":", 0, NULL);
- test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:"
+ tt_str_op(cp,OP_EQ, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:"
"Running:Stable:V2Dir:Valid");
tor_free(cp);
@@ -1397,7 +1932,7 @@ test_a_networkstatus(
n_vrs = smartlist_len(v2->routerstatus_list);
for (idx = 0; idx < n_vrs; ++idx) {
vrs = smartlist_get(v2->routerstatus_list, idx);
- test_assert(vrs);
+ tt_assert(vrs);
vrs_test(vrs, 2, now);
}
@@ -1425,10 +1960,10 @@ test_a_networkstatus(
memset(voter->legacy_id_digest, (int)'A', DIGEST_LEN);
v3_text = format_networkstatus_vote(sign_skey_3, vote);
- test_assert(v3_text);
+ tt_assert(v3_text);
v3 = networkstatus_parse_vote_from_string(v3_text, NULL, NS_TYPE_VOTE);
- test_assert(v3);
+ tt_assert(v3);
if (vote_tweaks) params_tweaked += vote_tweaks(v3, 3, now);
@@ -1442,10 +1977,10 @@ test_a_networkstatus(
"AAAAAAAAAAAAAAAAAAAA",
sign_skey_leg1,
FLAV_NS);
- test_assert(consensus_text);
+ tt_assert(consensus_text);
con = networkstatus_parse_vote_from_string(consensus_text, NULL,
NS_TYPE_CONSENSUS);
- test_assert(con);
+ tt_assert(con);
//log_notice(LD_GENERAL, "<<%s>>\n<<%s>>\n<<%s>>\n",
// v1_text, v2_text, v3_text);
consensus_text_md = networkstatus_compute_consensus(votes, 3,
@@ -1454,38 +1989,38 @@ test_a_networkstatus(
"AAAAAAAAAAAAAAAAAAAA",
sign_skey_leg1,
FLAV_MICRODESC);
- test_assert(consensus_text_md);
+ tt_assert(consensus_text_md);
con_md = networkstatus_parse_vote_from_string(consensus_text_md, NULL,
NS_TYPE_CONSENSUS);
- test_assert(con_md);
- test_eq(con_md->flavor, FLAV_MICRODESC);
+ tt_assert(con_md);
+ tt_int_op(con_md->flavor,OP_EQ, FLAV_MICRODESC);
/* Check consensus contents. */
- test_assert(con->type == NS_TYPE_CONSENSUS);
- test_eq(con->published, 0); /* this field only appears in votes. */
- test_eq(con->valid_after, now+1000);
- test_eq(con->fresh_until, now+2003); /* median */
- test_eq(con->valid_until, now+3000);
- test_eq(con->vote_seconds, 100);
- test_eq(con->dist_seconds, 250); /* median */
- test_streq(con->client_versions, "0.1.2.14");
- test_streq(con->server_versions, "0.1.2.15,0.1.2.16");
+ tt_assert(con->type == NS_TYPE_CONSENSUS);
+ tt_int_op(con->published,OP_EQ, 0); /* this field only appears in votes. */
+ tt_int_op(con->valid_after,OP_EQ, now+1000);
+ tt_int_op(con->fresh_until,OP_EQ, now+2003); /* median */
+ tt_int_op(con->valid_until,OP_EQ, now+3000);
+ tt_int_op(con->vote_seconds,OP_EQ, 100);
+ tt_int_op(con->dist_seconds,OP_EQ, 250); /* median */
+ tt_str_op(con->client_versions,OP_EQ, "0.1.2.14");
+ tt_str_op(con->server_versions,OP_EQ, "0.1.2.15,0.1.2.16");
cp = smartlist_join_strings(v2->known_flags, ":", 0, NULL);
- test_streq(cp, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:"
+ tt_str_op(cp,OP_EQ, "Authority:Exit:Fast:Guard:MadeOfCheese:MadeOfTin:"
"Running:Stable:V2Dir:Valid");
tor_free(cp);
if (!params_tweaked) {
/* Skip this one if vote_tweaks() messed with the param lists */
cp = smartlist_join_strings(con->net_params, ":", 0, NULL);
- test_streq(cp, "circuitwindow=80:foo=660");
+ tt_str_op(cp,OP_EQ, "circuitwindow=80:foo=660");
tor_free(cp);
}
- test_eq(4, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/
+ tt_int_op(4,OP_EQ, smartlist_len(con->voters)); /*3 voters, 1 legacy key.*/
/* The voter id digests should be in this order. */
- test_assert(memcmp(cert2->cache_info.identity_digest,
+ tt_assert(memcmp(cert2->cache_info.identity_digest,
cert1->cache_info.identity_digest,DIGEST_LEN)<0);
- test_assert(memcmp(cert1->cache_info.identity_digest,
+ tt_assert(memcmp(cert1->cache_info.identity_digest,
cert3->cache_info.identity_digest,DIGEST_LEN)<0);
test_same_voter(smartlist_get(con->voters, 1),
smartlist_get(v2->voters, 0));
@@ -1500,26 +2035,26 @@ test_a_networkstatus(
n_rs = smartlist_len(con->routerstatus_list);
for (idx = 0; idx < n_rs; ++idx) {
rs = smartlist_get(con->routerstatus_list, idx);
- test_assert(rs);
+ tt_assert(rs);
rs_test(rs, now);
}
/* Check signatures. the first voter is a pseudo-entry with a legacy key.
* The second one hasn't signed. The fourth one has signed: validate it. */
voter = smartlist_get(con->voters, 1);
- test_eq(smartlist_len(voter->sigs), 0);
+ tt_int_op(smartlist_len(voter->sigs),OP_EQ, 0);
voter = smartlist_get(con->voters, 3);
- test_eq(smartlist_len(voter->sigs), 1);
+ tt_int_op(smartlist_len(voter->sigs),OP_EQ, 1);
sig = smartlist_get(voter->sigs, 0);
- test_assert(sig->signature);
- test_assert(!sig->good_signature);
- test_assert(!sig->bad_signature);
+ tt_assert(sig->signature);
+ tt_assert(!sig->good_signature);
+ tt_assert(!sig->bad_signature);
- test_assert(!networkstatus_check_document_signature(con, sig, cert3));
- test_assert(sig->signature);
- test_assert(sig->good_signature);
- test_assert(!sig->bad_signature);
+ tt_assert(!networkstatus_check_document_signature(con, sig, cert3));
+ tt_assert(sig->signature);
+ tt_assert(sig->good_signature);
+ tt_assert(!sig->bad_signature);
{
const char *msg=NULL;
@@ -1542,10 +2077,10 @@ test_a_networkstatus(
cert1->identity_key,
sign_skey_1, NULL,NULL,
FLAV_MICRODESC);
- test_assert(consensus_text2);
- test_assert(consensus_text3);
- test_assert(consensus_text_md2);
- test_assert(consensus_text_md3);
+ tt_assert(consensus_text2);
+ tt_assert(consensus_text3);
+ tt_assert(consensus_text_md2);
+ tt_assert(consensus_text_md3);
con2 = networkstatus_parse_vote_from_string(consensus_text2, NULL,
NS_TYPE_CONSENSUS);
con3 = networkstatus_parse_vote_from_string(consensus_text3, NULL,
@@ -1554,17 +2089,17 @@ test_a_networkstatus(
NS_TYPE_CONSENSUS);
con_md3 = networkstatus_parse_vote_from_string(consensus_text_md3, NULL,
NS_TYPE_CONSENSUS);
- test_assert(con2);
- test_assert(con3);
- test_assert(con_md2);
- test_assert(con_md3);
+ tt_assert(con2);
+ tt_assert(con3);
+ tt_assert(con_md2);
+ tt_assert(con_md3);
/* All three should have the same digest. */
- test_memeq(&con->digests, &con2->digests, sizeof(digests_t));
- test_memeq(&con->digests, &con3->digests, sizeof(digests_t));
+ tt_mem_op(&con->digests,OP_EQ, &con2->digests, sizeof(digests_t));
+ tt_mem_op(&con->digests,OP_EQ, &con3->digests, sizeof(digests_t));
- test_memeq(&con_md->digests, &con_md2->digests, sizeof(digests_t));
- test_memeq(&con_md->digests, &con_md3->digests, sizeof(digests_t));
+ tt_mem_op(&con_md->digests,OP_EQ, &con_md2->digests, sizeof(digests_t));
+ tt_mem_op(&con_md->digests,OP_EQ, &con_md3->digests, sizeof(digests_t));
/* Extract a detached signature from con3. */
detached_text1 = get_detached_sigs(con3, con_md3);
@@ -1574,50 +2109,51 @@ test_a_networkstatus(
tt_assert(dsig1);
/* Are parsed values as expected? */
- test_eq(dsig1->valid_after, con3->valid_after);
- test_eq(dsig1->fresh_until, con3->fresh_until);
- test_eq(dsig1->valid_until, con3->valid_until);
+ tt_int_op(dsig1->valid_after,OP_EQ, con3->valid_after);
+ tt_int_op(dsig1->fresh_until,OP_EQ, con3->fresh_until);
+ tt_int_op(dsig1->valid_until,OP_EQ, con3->valid_until);
{
digests_t *dsig_digests = strmap_get(dsig1->digests, "ns");
- test_assert(dsig_digests);
- test_memeq(dsig_digests->d[DIGEST_SHA1], con3->digests.d[DIGEST_SHA1],
- DIGEST_LEN);
+ tt_assert(dsig_digests);
+ tt_mem_op(dsig_digests->d[DIGEST_SHA1], OP_EQ,
+ con3->digests.d[DIGEST_SHA1], DIGEST_LEN);
dsig_digests = strmap_get(dsig1->digests, "microdesc");
- test_assert(dsig_digests);
- test_memeq(dsig_digests->d[DIGEST_SHA256],
+ tt_assert(dsig_digests);
+ tt_mem_op(dsig_digests->d[DIGEST_SHA256],OP_EQ,
con_md3->digests.d[DIGEST_SHA256],
DIGEST256_LEN);
}
{
smartlist_t *dsig_signatures = strmap_get(dsig1->signatures, "ns");
- test_assert(dsig_signatures);
- test_eq(1, smartlist_len(dsig_signatures));
+ tt_assert(dsig_signatures);
+ tt_int_op(1,OP_EQ, smartlist_len(dsig_signatures));
sig = smartlist_get(dsig_signatures, 0);
- test_memeq(sig->identity_digest, cert1->cache_info.identity_digest,
+ tt_mem_op(sig->identity_digest,OP_EQ, cert1->cache_info.identity_digest,
DIGEST_LEN);
- test_eq(sig->alg, DIGEST_SHA1);
+ tt_int_op(sig->alg,OP_EQ, DIGEST_SHA1);
dsig_signatures = strmap_get(dsig1->signatures, "microdesc");
- test_assert(dsig_signatures);
- test_eq(1, smartlist_len(dsig_signatures));
+ tt_assert(dsig_signatures);
+ tt_int_op(1,OP_EQ, smartlist_len(dsig_signatures));
sig = smartlist_get(dsig_signatures, 0);
- test_memeq(sig->identity_digest, cert1->cache_info.identity_digest,
+ tt_mem_op(sig->identity_digest,OP_EQ, cert1->cache_info.identity_digest,
DIGEST_LEN);
- test_eq(sig->alg, DIGEST_SHA256);
+ tt_int_op(sig->alg,OP_EQ, DIGEST_SHA256);
}
/* Try adding it to con2. */
detached_text2 = get_detached_sigs(con2,con_md2);
- test_eq(1, networkstatus_add_detached_signatures(con2, dsig1, "test",
- LOG_INFO, &msg));
+ tt_int_op(1,OP_EQ, networkstatus_add_detached_signatures(con2, dsig1,
+ "test", LOG_INFO, &msg));
tor_free(detached_text2);
- test_eq(1, networkstatus_add_detached_signatures(con_md2, dsig1, "test",
+ tt_int_op(1,OP_EQ,
+ networkstatus_add_detached_signatures(con_md2, dsig1, "test",
LOG_INFO, &msg));
tor_free(detached_text2);
detached_text2 = get_detached_sigs(con2,con_md2);
//printf("\n<%s>\n", detached_text2);
dsig2 = networkstatus_parse_detached_signatures(detached_text2, NULL);
- test_assert(dsig2);
+ tt_assert(dsig2);
/*
printf("\n");
SMARTLIST_FOREACH(dsig2->signatures, networkstatus_voter_info_t *, vi, {
@@ -1626,28 +2162,28 @@ test_a_networkstatus(
printf("%s\n", hd);
});
*/
- test_eq(2,
+ tt_int_op(2,OP_EQ,
smartlist_len((smartlist_t*)strmap_get(dsig2->signatures, "ns")));
- test_eq(2,
+ tt_int_op(2,OP_EQ,
smartlist_len((smartlist_t*)strmap_get(dsig2->signatures,
"microdesc")));
/* Try adding to con2 twice; verify that nothing changes. */
- test_eq(0, networkstatus_add_detached_signatures(con2, dsig1, "test",
- LOG_INFO, &msg));
+ tt_int_op(0,OP_EQ, networkstatus_add_detached_signatures(con2, dsig1,
+ "test", LOG_INFO, &msg));
/* Add to con. */
- test_eq(2, networkstatus_add_detached_signatures(con, dsig2, "test",
- LOG_INFO, &msg));
+ tt_int_op(2,OP_EQ, networkstatus_add_detached_signatures(con, dsig2,
+ "test", LOG_INFO, &msg));
/* Check signatures */
voter = smartlist_get(con->voters, 1);
sig = smartlist_get(voter->sigs, 0);
- test_assert(sig);
- test_assert(!networkstatus_check_document_signature(con, sig, cert2));
+ tt_assert(sig);
+ tt_assert(!networkstatus_check_document_signature(con, sig, cert2));
voter = smartlist_get(con->voters, 2);
sig = smartlist_get(voter->sigs, 0);
- test_assert(sig);
- test_assert(!networkstatus_check_document_signature(con, sig, cert1));
+ tt_assert(sig);
+ tt_assert(!networkstatus_check_document_signature(con, sig, cert1));
}
done:
@@ -1709,8 +2245,9 @@ test_a_networkstatus(
/** Run unit tests for generating and parsing V3 consensus networkstatus
* documents. */
static void
-test_dir_v3_networkstatus(void)
+test_dir_v3_networkstatus(void *arg)
{
+ (void)arg;
test_a_networkstatus(gen_routerstatus_for_v3ns,
vote_tweaks_for_v3ns,
test_vrs_for_v3ns,
@@ -1740,7 +2277,7 @@ test_dir_scale_bw(void *testdata)
scale_array_elements_to_u64(vals, 8, &total);
- tt_int_op((int)total, ==, 48);
+ tt_int_op((int)total, OP_EQ, 48);
total = 0;
for (i=0; i<8; ++i) {
total += vals[i].u64;
@@ -1749,10 +2286,37 @@ test_dir_scale_bw(void *testdata)
tt_assert(total <= (U64_LITERAL(1)<<62));
for (i=0; i<8; ++i) {
+ /* vals[2].u64 is the scaled value of 1.0 */
double ratio = ((double)vals[i].u64) / vals[2].u64;
- tt_double_op(fabs(ratio - v[i]), <, .00001);
+ tt_double_op(fabs(ratio - v[i]), OP_LT, .00001);
}
+ /* test handling of no entries */
+ total = 1;
+ scale_array_elements_to_u64(vals, 0, &total);
+ tt_assert(total == 0);
+
+ /* make sure we don't read the array when we have no entries
+ * may require compiler flags to catch NULL dereferences */
+ total = 1;
+ scale_array_elements_to_u64(NULL, 0, &total);
+ tt_assert(total == 0);
+
+ scale_array_elements_to_u64(NULL, 0, NULL);
+
+ /* test handling of zero totals */
+ total = 1;
+ vals[0].dbl = 0.0;
+ scale_array_elements_to_u64(vals, 1, &total);
+ tt_assert(total == 0);
+ tt_assert(vals[0].u64 == 0);
+
+ vals[0].dbl = 0.0;
+ vals[1].dbl = 0.0;
+ scale_array_elements_to_u64(vals, 2, NULL);
+ tt_assert(vals[0].u64 == 0);
+ tt_assert(vals[1].u64 == 0);
+
done:
;
}
@@ -1775,11 +2339,11 @@ test_dir_random_weighted(void *testdata)
inp[i].u64 = vals[i];
total += vals[i];
}
- tt_u64_op(total, ==, 45);
+ tt_u64_op(total, OP_EQ, 45);
for (i=0; i<n; ++i) {
choice = choose_array_element_by_weight(inp, 10);
- tt_int_op(choice, >=, 0);
- tt_int_op(choice, <, 10);
+ tt_int_op(choice, OP_GE, 0);
+ tt_int_op(choice, OP_LT, 10);
histogram[choice]++;
}
@@ -1792,7 +2356,7 @@ test_dir_random_weighted(void *testdata)
if (expected)
frac_diff = (histogram[i] - expected) / ((double)expected);
else
- tt_int_op(histogram[i], ==, 0);
+ tt_int_op(histogram[i], OP_EQ, 0);
sq = frac_diff * frac_diff;
if (sq > max_sq_error)
@@ -1800,12 +2364,12 @@ test_dir_random_weighted(void *testdata)
}
/* It should almost always be much much less than this. If you want to
* figure out the odds, please feel free. */
- tt_double_op(max_sq_error, <, .05);
+ tt_double_op(max_sq_error, OP_LT, .05);
/* Now try a singleton; do we choose it? */
for (i = 0; i < 100; ++i) {
choice = choose_array_element_by_weight(inp, 1);
- tt_int_op(choice, ==, 0);
+ tt_int_op(choice, OP_EQ, 0);
}
/* Now try an array of zeros. We should choose randomly. */
@@ -1814,8 +2378,8 @@ test_dir_random_weighted(void *testdata)
inp[i].u64 = 0;
for (i = 0; i < n; ++i) {
choice = choose_array_element_by_weight(inp, 5);
- tt_int_op(choice, >=, 0);
- tt_int_op(choice, <, 5);
+ tt_int_op(choice, OP_GE, 0);
+ tt_int_op(choice, OP_LT, 5);
histogram[choice]++;
}
/* Now see if we chose things about frequently enough. */
@@ -1831,7 +2395,7 @@ test_dir_random_weighted(void *testdata)
}
/* It should almost always be much much less than this. If you want to
* figure out the odds, please feel free. */
- tt_double_op(max_sq_error, <, .05);
+ tt_double_op(max_sq_error, OP_LT, .05);
done:
;
}
@@ -1958,7 +2522,7 @@ gen_routerstatus_for_umbw(int idx, time_t now)
break;
default:
/* Shouldn't happen */
- test_assert(0);
+ tt_assert(0);
}
if (vrs) {
vrs->microdesc = tor_malloc_zero(sizeof(vote_microdesc_hash_t));
@@ -1980,11 +2544,11 @@ vote_tweaks_for_umbw(networkstatus_t *v, int voter, time_t now)
char *maxbw_param = NULL;
int rv = 0;
- test_assert(v);
+ tt_assert(v);
(void)voter;
(void)now;
- test_assert(v->supported_methods);
+ tt_assert(v->supported_methods);
SMARTLIST_FOREACH(v->supported_methods, char *, c, tor_free(c));
smartlist_clear(v->supported_methods);
/* Method 17 is MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB */
@@ -1994,7 +2558,7 @@ vote_tweaks_for_umbw(networkstatus_t *v, int voter, time_t now)
/* If we're using a non-default clip bandwidth, add it to net_params */
if (alternate_clip_bw > 0) {
tor_asprintf(&maxbw_param, "maxunmeasuredbw=%u", alternate_clip_bw);
- test_assert(maxbw_param);
+ tt_assert(maxbw_param);
if (maxbw_param) {
smartlist_add(v->net_params, maxbw_param);
rv = 1;
@@ -2017,9 +2581,9 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB;
(void)voter;
- test_assert(vrs);
+ tt_assert(vrs);
rs = &(vrs->status);
- test_assert(rs);
+ tt_assert(rs);
/* Split out by digests to test */
if (tor_memeq(rs->identity_digest,
@@ -2030,21 +2594,21 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
* Check the first routerstatus - measured bandwidth below the clip
* cutoff.
*/
- test_streq(vrs->version, "0.1.2.14");
- test_eq(rs->published_on, now-1500);
- test_streq(rs->nickname, "router2");
- test_memeq(rs->identity_digest,
+ tt_str_op(vrs->version,OP_EQ, "0.1.2.14");
+ tt_int_op(rs->published_on,OP_EQ, now-1500);
+ tt_str_op(rs->nickname,OP_EQ, "router2");
+ tt_mem_op(rs->identity_digest,OP_EQ,
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- test_eq(rs->addr, 0x99008801);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 8000);
- test_assert(rs->has_bandwidth);
- test_assert(vrs->has_measured_bw);
- test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
- test_eq(vrs->measured_bw_kb, max_unmeasured_bw_kb / 2);
+ tt_mem_op(rs->descriptor_digest,OP_EQ, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ tt_int_op(rs->addr,OP_EQ, 0x99008801);
+ tt_int_op(rs->or_port,OP_EQ, 443);
+ tt_int_op(rs->dir_port,OP_EQ, 8000);
+ tt_assert(rs->has_bandwidth);
+ tt_assert(vrs->has_measured_bw);
+ tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb / 2);
+ tt_int_op(vrs->measured_bw_kb,OP_EQ, max_unmeasured_bw_kb / 2);
} else if (tor_memeq(rs->identity_digest,
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
@@ -2054,24 +2618,24 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
* Check the second routerstatus - measured bandwidth above the clip
* cutoff.
*/
- test_streq(vrs->version, "0.2.0.5");
- test_eq(rs->published_on, now-1000);
- test_streq(rs->nickname, "router1");
- test_memeq(rs->identity_digest,
+ tt_str_op(vrs->version,OP_EQ, "0.2.0.5");
+ tt_int_op(rs->published_on,OP_EQ, now-1000);
+ tt_str_op(rs->nickname,OP_EQ, "router1");
+ tt_mem_op(rs->identity_digest,OP_EQ,
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- test_eq(rs->addr, 0x99009901);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 0);
+ tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ tt_int_op(rs->addr,OP_EQ, 0x99009901);
+ tt_int_op(rs->or_port,OP_EQ, 443);
+ tt_int_op(rs->dir_port,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
- test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
- test_eq(rs->ipv6_orport, 4711);
- test_assert(rs->has_bandwidth);
- test_assert(vrs->has_measured_bw);
- test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2);
- test_eq(vrs->measured_bw_kb, max_unmeasured_bw_kb * 2);
+ tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
+ tt_assert(rs->has_bandwidth);
+ tt_assert(vrs->has_measured_bw);
+ tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb * 2);
+ tt_int_op(vrs->measured_bw_kb,OP_EQ, max_unmeasured_bw_kb * 2);
} else if (tor_memeq(rs->identity_digest,
"\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
"\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33",
@@ -2081,10 +2645,10 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
* cutoff; this one should be clipped later on in the consensus, but
* appears unclipped in the vote.
*/
- test_assert(rs->has_bandwidth);
- test_assert(!(vrs->has_measured_bw));
- test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2);
- test_eq(vrs->measured_bw_kb, 0);
+ tt_assert(rs->has_bandwidth);
+ tt_assert(!(vrs->has_measured_bw));
+ tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb * 2);
+ tt_int_op(vrs->measured_bw_kb,OP_EQ, 0);
} else if (tor_memeq(rs->identity_digest,
"\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34"
"\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34",
@@ -2093,12 +2657,12 @@ test_vrs_for_umbw(vote_routerstatus_t *vrs, int voter, time_t now)
* Check the fourth routerstatus - unmeasured bandwidth below the clip
* cutoff; this one should not be clipped.
*/
- test_assert(rs->has_bandwidth);
- test_assert(!(vrs->has_measured_bw));
- test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
- test_eq(vrs->measured_bw_kb, 0);
+ tt_assert(rs->has_bandwidth);
+ tt_assert(!(vrs->has_measured_bw));
+ tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb / 2);
+ tt_int_op(vrs->measured_bw_kb,OP_EQ, 0);
} else {
- test_assert(0);
+ tt_assert(0);
}
done:
@@ -2113,11 +2677,11 @@ test_consensus_for_umbw(networkstatus_t *con, time_t now)
{
(void)now;
- test_assert(con);
- test_assert(!con->cert);
- // test_assert(con->consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB);
- test_assert(con->consensus_method >= 16);
- test_eq(4, smartlist_len(con->routerstatus_list));
+ tt_assert(con);
+ tt_assert(!con->cert);
+ // tt_assert(con->consensus_method >= MIN_METHOD_TO_CLIP_UNMEASURED_BW_KB);
+ tt_assert(con->consensus_method >= 16);
+ tt_int_op(4,OP_EQ, smartlist_len(con->routerstatus_list));
/* There should be four listed routers; all voters saw the same in this */
done:
@@ -2134,61 +2698,61 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
uint32_t max_unmeasured_bw_kb = (alternate_clip_bw > 0) ?
alternate_clip_bw : DEFAULT_MAX_UNMEASURED_BW_KB;
- test_assert(rs);
+ tt_assert(rs);
/* There should be four listed routers, as constructed above */
if (tor_memeq(rs->identity_digest,
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
DIGEST_LEN)) {
- test_memeq(rs->identity_digest,
+ tt_mem_op(rs->identity_digest,OP_EQ,
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3"
"\x3\x3\x3\x3\x3\x3\x3\x3\x3\x3",
DIGEST_LEN);
- test_memeq(rs->descriptor_digest, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
- test_assert(!rs->is_authority);
- test_assert(!rs->is_exit);
- test_assert(!rs->is_fast);
- test_assert(!rs->is_possible_guard);
- test_assert(!rs->is_stable);
+ tt_mem_op(rs->descriptor_digest,OP_EQ, "NNNNNNNNNNNNNNNNNNNN", DIGEST_LEN);
+ tt_assert(!rs->is_authority);
+ tt_assert(!rs->is_exit);
+ tt_assert(!rs->is_fast);
+ tt_assert(!rs->is_possible_guard);
+ tt_assert(!rs->is_stable);
/* (If it wasn't running it wouldn't be here) */
- test_assert(rs->is_flagged_running);
- test_assert(!rs->is_valid);
- test_assert(!rs->is_named);
+ tt_assert(rs->is_flagged_running);
+ tt_assert(!rs->is_valid);
+ tt_assert(!rs->is_named);
/* This one should have measured bandwidth below the clip cutoff */
- test_assert(rs->has_bandwidth);
- test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
- test_assert(!(rs->bw_is_unmeasured));
+ tt_assert(rs->has_bandwidth);
+ tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb / 2);
+ tt_assert(!(rs->bw_is_unmeasured));
} else if (tor_memeq(rs->identity_digest,
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
DIGEST_LEN)) {
/* This one showed up in 3 digests. Twice with ID 'M', once with 'Z'. */
- test_memeq(rs->identity_digest,
+ tt_mem_op(rs->identity_digest,OP_EQ,
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5"
"\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5",
DIGEST_LEN);
- test_streq(rs->nickname, "router1");
- test_memeq(rs->descriptor_digest, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
- test_eq(rs->published_on, now-1000);
- test_eq(rs->addr, 0x99009901);
- test_eq(rs->or_port, 443);
- test_eq(rs->dir_port, 0);
+ tt_str_op(rs->nickname,OP_EQ, "router1");
+ tt_mem_op(rs->descriptor_digest,OP_EQ, "MMMMMMMMMMMMMMMMMMMM", DIGEST_LEN);
+ tt_int_op(rs->published_on,OP_EQ, now-1000);
+ tt_int_op(rs->addr,OP_EQ, 0x99009901);
+ tt_int_op(rs->or_port,OP_EQ, 443);
+ tt_int_op(rs->dir_port,OP_EQ, 0);
tor_addr_parse(&addr_ipv6, "[1:2:3::4]");
- test_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
- test_eq(rs->ipv6_orport, 4711);
- test_assert(!rs->is_authority);
- test_assert(rs->is_exit);
- test_assert(rs->is_fast);
- test_assert(rs->is_possible_guard);
- test_assert(rs->is_stable);
- test_assert(rs->is_flagged_running);
- test_assert(rs->is_valid);
- test_assert(!rs->is_named);
+ tt_assert(tor_addr_eq(&rs->ipv6_addr, &addr_ipv6));
+ tt_int_op(rs->ipv6_orport,OP_EQ, 4711);
+ tt_assert(!rs->is_authority);
+ tt_assert(rs->is_exit);
+ tt_assert(rs->is_fast);
+ tt_assert(rs->is_possible_guard);
+ tt_assert(rs->is_stable);
+ tt_assert(rs->is_flagged_running);
+ tt_assert(rs->is_valid);
+ tt_assert(!rs->is_named);
/* This one should have measured bandwidth above the clip cutoff */
- test_assert(rs->has_bandwidth);
- test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb * 2);
- test_assert(!(rs->bw_is_unmeasured));
+ tt_assert(rs->has_bandwidth);
+ tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb * 2);
+ tt_assert(!(rs->bw_is_unmeasured));
} else if (tor_memeq(rs->identity_digest,
"\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33"
"\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33",
@@ -2197,9 +2761,9 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
* This one should have unmeasured bandwidth above the clip cutoff,
* and so should be clipped
*/
- test_assert(rs->has_bandwidth);
- test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb);
- test_assert(rs->bw_is_unmeasured);
+ tt_assert(rs->has_bandwidth);
+ tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb);
+ tt_assert(rs->bw_is_unmeasured);
} else if (tor_memeq(rs->identity_digest,
"\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34"
"\x34\x34\x34\x34\x34\x34\x34\x34\x34\x34",
@@ -2208,12 +2772,12 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
* This one should have unmeasured bandwidth below the clip cutoff,
* and so should not be clipped
*/
- test_assert(rs->has_bandwidth);
- test_eq(rs->bandwidth_kb, max_unmeasured_bw_kb / 2);
- test_assert(rs->bw_is_unmeasured);
+ tt_assert(rs->has_bandwidth);
+ tt_int_op(rs->bandwidth_kb,OP_EQ, max_unmeasured_bw_kb / 2);
+ tt_assert(rs->bw_is_unmeasured);
} else {
/* Weren't expecting this... */
- test_assert(0);
+ tt_assert(0);
}
done:
@@ -2227,9 +2791,10 @@ test_routerstatus_for_umbw(routerstatus_t *rs, time_t now)
*/
static void
-test_dir_clip_unmeasured_bw_kb(void)
+test_dir_clip_unmeasured_bw_kb(void *arg)
{
/* Run the test with the default clip bandwidth */
+ (void)arg;
alternate_clip_bw = 0;
test_a_networkstatus(gen_routerstatus_for_umbw,
vote_tweaks_for_umbw,
@@ -2244,7 +2809,7 @@ test_dir_clip_unmeasured_bw_kb(void)
*/
static void
-test_dir_clip_unmeasured_bw_kb_alt(void)
+test_dir_clip_unmeasured_bw_kb_alt(void *arg)
{
/*
* Try a different one; this value is chosen so that the below-the-cutoff
@@ -2252,6 +2817,7 @@ test_dir_clip_unmeasured_bw_kb_alt(void)
* DEFAULT_MAX_UNMEASURED_BW_KB and if the consensus incorrectly uses that
* cutoff it will fail the test.
*/
+ (void)arg;
alternate_clip_bw = 3 * DEFAULT_MAX_UNMEASURED_BW_KB;
test_a_networkstatus(gen_routerstatus_for_umbw,
vote_tweaks_for_umbw,
@@ -2283,7 +2849,7 @@ test_dir_fmt_control_ns(void *arg)
s = networkstatus_getinfo_helper_single(&rs);
tt_assert(s);
- tt_str_op(s, ==,
+ tt_str_op(s, OP_EQ,
"r TetsuoMilk U3RhdGVseSwgcGx1bXAgQnVjayA "
"TXVsbGlnYW4gY2FtZSB1cCBmcm8 2013-04-02 17:53:18 "
"32.48.64.80 9001 9002\n"
@@ -2302,68 +2868,239 @@ test_dir_http_handling(void *args)
/* Parse http url tests: */
/* Good headers */
- test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1\r\n"
+ tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1\r\n"
"Host: example.com\r\n"
"User-Agent: Mozilla/5.0 (Windows;"
" U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
- &url), 0);
- test_streq(url, "/tor/a/b/c.txt");
+ &url),OP_EQ, 0);
+ tt_str_op(url,OP_EQ, "/tor/a/b/c.txt");
tor_free(url);
- test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.0\r\n", &url), 0);
- test_streq(url, "/tor/a/b/c.txt");
+ tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.0\r\n", &url),OP_EQ, 0);
+ tt_str_op(url,OP_EQ, "/tor/a/b/c.txt");
tor_free(url);
- test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.600\r\n", &url), 0);
- test_streq(url, "/tor/a/b/c.txt");
+ tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.600\r\n", &url),
+ OP_EQ, 0);
+ tt_str_op(url,OP_EQ, "/tor/a/b/c.txt");
tor_free(url);
/* Should prepend '/tor/' to url if required */
- test_eq(parse_http_url("GET /a/b/c.txt HTTP/1.1\r\n"
+ tt_int_op(parse_http_url("GET /a/b/c.txt HTTP/1.1\r\n"
"Host: example.com\r\n"
"User-Agent: Mozilla/5.0 (Windows;"
" U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
- &url), 0);
- test_streq(url, "/tor/a/b/c.txt");
+ &url),OP_EQ, 0);
+ tt_str_op(url,OP_EQ, "/tor/a/b/c.txt");
tor_free(url);
/* Bad headers -- no HTTP/1.x*/
- test_eq(parse_http_url("GET /a/b/c.txt\r\n"
+ tt_int_op(parse_http_url("GET /a/b/c.txt\r\n"
"Host: example.com\r\n"
"User-Agent: Mozilla/5.0 (Windows;"
" U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
- &url), -1);
+ &url),OP_EQ, -1);
tt_assert(!url);
/* Bad headers */
- test_eq(parse_http_url("GET /a/b/c.txt\r\n"
+ tt_int_op(parse_http_url("GET /a/b/c.txt\r\n"
"Host: example.com\r\n"
"User-Agent: Mozilla/5.0 (Windows;"
" U; Windows NT 6.1; en-US; rv:1.9.1.5)\r\n",
- &url), -1);
+ &url),OP_EQ, -1);
tt_assert(!url);
- test_eq(parse_http_url("GET /tor/a/b/c.txt", &url), -1);
+ tt_int_op(parse_http_url("GET /tor/a/b/c.txt", &url),OP_EQ, -1);
tt_assert(!url);
- test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1", &url), -1);
+ tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1", &url),OP_EQ, -1);
tt_assert(!url);
- test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1x\r\n", &url), -1);
+ tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.1x\r\n", &url),
+ OP_EQ, -1);
tt_assert(!url);
- test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.", &url), -1);
+ tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.", &url),OP_EQ, -1);
tt_assert(!url);
- test_eq(parse_http_url("GET /tor/a/b/c.txt HTTP/1.\r", &url), -1);
+ tt_int_op(parse_http_url("GET /tor/a/b/c.txt HTTP/1.\r", &url),OP_EQ, -1);
tt_assert(!url);
done:
tor_free(url);
}
+static void
+test_dir_purpose_needs_anonymity(void *arg)
+{
+ (void)arg;
+ tt_int_op(1, ==, purpose_needs_anonymity(0, ROUTER_PURPOSE_BRIDGE));
+ tt_int_op(1, ==, purpose_needs_anonymity(0, ROUTER_PURPOSE_GENERAL));
+ tt_int_op(0, ==, purpose_needs_anonymity(DIR_PURPOSE_FETCH_MICRODESC,
+ ROUTER_PURPOSE_GENERAL));
+ done: ;
+}
+
+static void
+test_dir_fetch_type(void *arg)
+{
+ (void)arg;
+ tt_assert(dir_fetch_type(DIR_PURPOSE_FETCH_MICRODESC, ROUTER_PURPOSE_GENERAL,
+ NULL) == MICRODESC_DIRINFO);
+ tt_assert(dir_fetch_type(DIR_PURPOSE_FETCH_SERVERDESC, ROUTER_PURPOSE_BRIDGE,
+ NULL) == BRIDGE_DIRINFO);
+ tt_assert(dir_fetch_type(DIR_PURPOSE_FETCH_CONSENSUS, ROUTER_PURPOSE_GENERAL,
+ "microdesc") == (V3_DIRINFO | MICRODESC_DIRINFO));
+ done: ;
+}
+
+static void
+test_dir_packages(void *arg)
+{
+ smartlist_t *votes = smartlist_new();
+ char *res = NULL;
+ (void)arg;
+
+#define BAD(s) \
+ tt_int_op(0, ==, validate_recommended_package_line(s));
+#define GOOD(s) \
+ tt_int_op(1, ==, validate_recommended_package_line(s));
+ GOOD("tor 0.2.6.3-alpha "
+ "http://torproject.example.com/dist/tor-0.2.6.3-alpha.tar.gz "
+ "sha256=sssdlkfjdsklfjdskfljasdklfj");
+ GOOD("tor 0.2.6.3-alpha "
+ "http://torproject.example.com/dist/tor-0.2.6.3-alpha.tar.gz "
+ "sha256=sssdlkfjdsklfjdskfljasdklfj blake2b=fred");
+ BAD("tor 0.2.6.3-alpha "
+ "http://torproject.example.com/dist/tor-0.2.6.3-alpha.tar.gz "
+ "sha256=sssdlkfjdsklfjdskfljasdklfj=");
+ BAD("tor 0.2.6.3-alpha "
+ "http://torproject.example.com/dist/tor-0.2.6.3-alpha.tar.gz "
+ "sha256=sssdlkfjdsklfjdskfljasdklfj blake2b");
+ BAD("tor 0.2.6.3-alpha "
+ "http://torproject.example.com/dist/tor-0.2.6.3-alpha.tar.gz ");
+ BAD("tor 0.2.6.3-alpha "
+ "http://torproject.example.com/dist/tor-0.2.6.3-alpha.tar.gz");
+ BAD("tor 0.2.6.3-alpha ");
+ BAD("tor 0.2.6.3-alpha");
+ BAD("tor ");
+ BAD("tor");
+ BAD("");
+ BAD("=foobar sha256="
+ "3c179f46ca77069a6a0bac70212a9b3b838b2f66129cb52d568837fc79d8fcc7");
+ BAD("= = sha256="
+ "3c179f46ca77069a6a0bac70212a9b3b838b2f66129cb52d568837fc79d8fcc7");
+
+ BAD("sha512= sha256="
+ "3c179f46ca77069a6a0bac70212a9b3b838b2f66129cb52d568837fc79d8fcc7");
+
+ smartlist_add(votes, tor_malloc_zero(sizeof(networkstatus_t)));
+ smartlist_add(votes, tor_malloc_zero(sizeof(networkstatus_t)));
+ smartlist_add(votes, tor_malloc_zero(sizeof(networkstatus_t)));
+ smartlist_add(votes, tor_malloc_zero(sizeof(networkstatus_t)));
+ smartlist_add(votes, tor_malloc_zero(sizeof(networkstatus_t)));
+ smartlist_add(votes, tor_malloc_zero(sizeof(networkstatus_t)));
+ SMARTLIST_FOREACH(votes, networkstatus_t *, ns,
+ ns->package_lines = smartlist_new());
+
+#define ADD(i, s) \
+ smartlist_add(((networkstatus_t*)smartlist_get(votes, (i)))->package_lines, \
+ (void*)(s));
+
+ /* Only one vote for this one. */
+ ADD(4, "cisco 99z http://foobar.example.com/ sha256=blahblah");
+
+ /* Only two matching entries for this one, but 3 voters */
+ ADD(1, "mystic 99y http://barfoo.example.com/ sha256=blahblah");
+ ADD(3, "mystic 99y http://foobar.example.com/ sha256=blahblah");
+ ADD(4, "mystic 99y http://foobar.example.com/ sha256=blahblah");
+
+ /* Only two matching entries for this one, but at least 4 voters */
+ ADD(1, "mystic 99p http://barfoo.example.com/ sha256=ggggggg");
+ ADD(3, "mystic 99p http://foobar.example.com/ sha256=blahblah");
+ ADD(4, "mystic 99p http://foobar.example.com/ sha256=blahblah");
+ ADD(5, "mystic 99p http://foobar.example.com/ sha256=ggggggg");
+
+ /* This one has only invalid votes. */
+ ADD(0, "haffenreffer 1.2 http://foobar.example.com/ sha256");
+ ADD(1, "haffenreffer 1.2 http://foobar.example.com/ ");
+ ADD(2, "haffenreffer 1.2 ");
+ ADD(3, "haffenreffer ");
+ ADD(4, "haffenreffer");
+
+ /* Three matching votes for this; it should actually go in! */
+ ADD(2, "element 0.66.1 http://quux.example.com/ sha256=abcdef");
+ ADD(3, "element 0.66.1 http://quux.example.com/ sha256=abcdef");
+ ADD(4, "element 0.66.1 http://quux.example.com/ sha256=abcdef");
+ ADD(1, "element 0.66.1 http://quum.example.com/ sha256=abcdef");
+ ADD(0, "element 0.66.1 http://quux.example.com/ sha256=abcde");
+
+ /* Three votes for A, three votes for B */
+ ADD(0, "clownshoes 22alpha1 http://quumble.example.com/ blake2=foob");
+ ADD(1, "clownshoes 22alpha1 http://quumble.example.com/ blake2=foob");
+ ADD(2, "clownshoes 22alpha1 http://quumble.example.com/ blake2=foob");
+ ADD(3, "clownshoes 22alpha1 http://quumble.example.com/ blake2=fooz");
+ ADD(4, "clownshoes 22alpha1 http://quumble.example.com/ blake2=fooz");
+ ADD(5, "clownshoes 22alpha1 http://quumble.example.com/ blake2=fooz");
+
+ /* Three votes for A, two votes for B */
+ ADD(1, "clownshoes 22alpha3 http://quumble.example.com/ blake2=foob");
+ ADD(2, "clownshoes 22alpha3 http://quumble.example.com/ blake2=foob");
+ ADD(3, "clownshoes 22alpha3 http://quumble.example.com/ blake2=fooz");
+ ADD(4, "clownshoes 22alpha3 http://quumble.example.com/ blake2=fooz");
+ ADD(5, "clownshoes 22alpha3 http://quumble.example.com/ blake2=fooz");
+
+ /* Four votes for A, two for B. */
+ ADD(0, "clownshoes 22alpha4 http://quumble.example.com/ blake2=foob");
+ ADD(1, "clownshoes 22alpha4 http://quumble.example.com/ blake2=foob");
+ ADD(2, "clownshoes 22alpha4 http://quumble.example.cam/ blake2=fooa");
+ ADD(3, "clownshoes 22alpha4 http://quumble.example.cam/ blake2=fooa");
+ ADD(4, "clownshoes 22alpha4 http://quumble.example.cam/ blake2=fooa");
+ ADD(5, "clownshoes 22alpha4 http://quumble.example.cam/ blake2=fooa");
+
+ /* Five votes for A ... all from the same guy. Three for B. */
+ ADD(0, "cbc 99.1.11.1.1 http://example.com/cbc/ cubehash=ahooy sha512=m");
+ ADD(1, "cbc 99.1.11.1.1 http://example.com/cbc/ cubehash=ahooy sha512=m");
+ ADD(3, "cbc 99.1.11.1.1 http://example.com/cbc/ cubehash=ahooy sha512=m");
+ ADD(2, "cbc 99.1.11.1.1 http://example.com/ cubehash=ahooy");
+ ADD(2, "cbc 99.1.11.1.1 http://example.com/ cubehash=ahooy");
+ ADD(2, "cbc 99.1.11.1.1 http://example.com/ cubehash=ahooy");
+ ADD(2, "cbc 99.1.11.1.1 http://example.com/ cubehash=ahooy");
+ ADD(2, "cbc 99.1.11.1.1 http://example.com/ cubehash=ahooy");
+
+ /* As above but new replaces old: no two match. */
+ ADD(0, "cbc 99.1.11.1.2 http://example.com/cbc/ cubehash=ahooy sha512=m");
+ ADD(1, "cbc 99.1.11.1.2 http://example.com/cbc/ cubehash=ahooy sha512=m");
+ ADD(1, "cbc 99.1.11.1.2 http://example.com/cbc/x cubehash=ahooy sha512=m");
+ ADD(2, "cbc 99.1.11.1.2 http://example.com/cbc/ cubehash=ahooy sha512=m");
+ ADD(2, "cbc 99.1.11.1.2 http://example.com/ cubehash=ahooy");
+ ADD(2, "cbc 99.1.11.1.2 http://example.com/ cubehash=ahooy");
+ ADD(2, "cbc 99.1.11.1.2 http://example.com/ cubehash=ahooy");
+ ADD(2, "cbc 99.1.11.1.2 http://example.com/ cubehash=ahooy");
+ ADD(2, "cbc 99.1.11.1.2 http://example.com/ cubehash=ahooy");
+
+ res = compute_consensus_package_lines(votes);
+ tt_assert(res);
+ tt_str_op(res, ==,
+ "package cbc 99.1.11.1.1 http://example.com/cbc/ cubehash=ahooy sha512=m\n"
+ "package clownshoes 22alpha3 http://quumble.example.com/ blake2=fooz\n"
+ "package clownshoes 22alpha4 http://quumble.example.cam/ blake2=fooa\n"
+ "package element 0.66.1 http://quux.example.com/ sha256=abcdef\n"
+ "package mystic 99y http://foobar.example.com/ sha256=blahblah\n"
+ );
+
+#undef ADD
+#undef BAD
+#undef GOOD
+ done:
+ SMARTLIST_FOREACH(votes, networkstatus_t *, ns,
+ { smartlist_free(ns->package_lines); tor_free(ns); });
+ smartlist_free(votes);
+ tor_free(res);
+}
+
#define DIR_LEGACY(name) \
- { #name, legacy_test_helper, TT_FORK, &legacy_setup, test_dir_ ## name }
+ { #name, test_dir_ ## name , TT_FORK, NULL, NULL }
#define DIR(name,flags) \
{ #name, test_dir_##name, (flags), NULL, NULL }
@@ -2371,6 +3108,11 @@ test_dir_http_handling(void *args)
struct testcase_t dir_tests[] = {
DIR_LEGACY(nicknames),
DIR_LEGACY(formats),
+ DIR(routerparse_bad, 0),
+ DIR(extrainfo_parsing, 0),
+ DIR(parse_router_list, TT_FORK),
+ DIR(load_routers, TT_FORK),
+ DIR(load_extrainfo, TT_FORK),
DIR_LEGACY(versions),
DIR_LEGACY(fp_pairs),
DIR(split_fps, 0),
@@ -2384,6 +3126,9 @@ struct testcase_t dir_tests[] = {
DIR_LEGACY(clip_unmeasured_bw_kb_alt),
DIR(fmt_control_ns, 0),
DIR(http_handling, 0),
+ DIR(purpose_needs_anonymity, 0),
+ DIR(fetch_type, 0),
+ DIR(packages, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c
new file mode 100644
index 0000000000..6edc166743
--- /dev/null
+++ b/src/test/test_entryconn.c
@@ -0,0 +1,769 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define CONNECTION_PRIVATE
+#define CONNECTION_EDGE_PRIVATE
+
+#include "or.h"
+#include "test.h"
+
+#include "addressmap.h"
+#include "config.h"
+#include "confparse.h"
+#include "connection.h"
+#include "connection_edge.h"
+
+static void *
+entryconn_rewrite_setup(const struct testcase_t *tc)
+{
+ (void)tc;
+ entry_connection_t *ec = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ addressmap_init();
+ return ec;
+}
+
+static int
+entryconn_rewrite_teardown(const struct testcase_t *tc, void *arg)
+{
+ (void)tc;
+ entry_connection_t *ec = arg;
+ if (ec)
+ connection_free_(ENTRY_TO_CONN(ec));
+ addressmap_free_all();
+ return 1;
+}
+
+static struct testcase_setup_t test_rewrite_setup = {
+ entryconn_rewrite_setup, entryconn_rewrite_teardown
+};
+
+/* Simple rewrite: no changes needed */
+static void
+test_entryconn_rewrite_basic(void *arg)
+{
+ entry_connection_t *ec = arg;
+ rewrite_result_t rr;
+
+ tt_assert(ec->socks_request);
+ strlcpy(ec->socks_request->address, "www.TORproject.org",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.torproject.org");
+ tt_str_op(ec->socks_request->address, OP_EQ, "www.torproject.org");
+ tt_str_op(ec->original_dest_address, OP_EQ, "www.torproject.org");
+
+ done:
+ ;
+}
+
+/* Rewrite but reject because of disallowed .exit */
+static void
+test_entryconn_rewrite_bad_dotexit(void *arg)
+{
+ entry_connection_t *ec = arg;
+ rewrite_result_t rr;
+
+ get_options_mutable()->AllowDotExit = 0;
+ tt_assert(ec->socks_request);
+ strlcpy(ec->socks_request->address, "www.TORproject.org.foo.exit",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.should_close, OP_EQ, 1);
+ tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_TORPROTOCOL);
+
+ done:
+ ;
+}
+
+/* Automap on resolve, connect to automapped address, resolve again and get
+ * same answer. (IPv4) */
+static void
+test_entryconn_rewrite_automap_ipv4(void *arg)
+{
+ entry_connection_t *ec = arg;
+ entry_connection_t *ec2=NULL, *ec3=NULL;
+ rewrite_result_t rr;
+ char *msg = NULL;
+
+ ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+
+ get_options_mutable()->AutomapHostsOnResolve = 1;
+ smartlist_add(get_options_mutable()->AutomapHostsSuffixes, tor_strdup("."));
+ parse_virtual_addr_network("127.202.0.0/16", AF_INET, 0, &msg);
+
+ /* Automap this on resolve. */
+ strlcpy(ec->socks_request->address, "WWW.MIT.EDU",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 1);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu");
+ tt_str_op(ec->original_dest_address, OP_EQ, "www.mit.edu");
+
+ tt_assert(!strcmpstart(ec->socks_request->address,"127.202."));
+
+ /* Connect to it and make sure we get the original address back. */
+ strlcpy(ec2->socks_request->address, ec->socks_request->address,
+ sizeof(ec2->socks_request->address));
+
+ ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec2, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address);
+ tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address);
+ tt_str_op(ec2->socks_request->address, OP_EQ, "www.mit.edu");
+
+ /* Resolve it again, make sure the answer is the same. */
+ strlcpy(ec3->socks_request->address, "www.MIT.EDU",
+ sizeof(ec3->socks_request->address));
+ ec3->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ connection_ap_handshake_rewrite(ec3, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 1);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu");
+ tt_str_op(ec3->original_dest_address, OP_EQ, "www.mit.edu");
+
+ tt_str_op(ec3->socks_request->address, OP_EQ,
+ ec->socks_request->address);
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec2));
+ connection_free_(ENTRY_TO_CONN(ec3));
+}
+
+/* Automap on resolve, connect to automapped address, resolve again and get
+ * same answer. (IPv6) */
+static void
+test_entryconn_rewrite_automap_ipv6(void *arg)
+{
+ (void)arg;
+ entry_connection_t *ec =NULL;
+ entry_connection_t *ec2=NULL, *ec3=NULL;
+ rewrite_result_t rr;
+ char *msg = NULL;
+
+ ec = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+ ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+ ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+
+ get_options_mutable()->AutomapHostsOnResolve = 1;
+ smartlist_add(get_options_mutable()->AutomapHostsSuffixes, tor_strdup("."));
+ parse_virtual_addr_network("FE80::/32", AF_INET6, 0, &msg);
+
+ /* Automap this on resolve. */
+ strlcpy(ec->socks_request->address, "WWW.MIT.EDU",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 1);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu");
+ tt_str_op(ec->original_dest_address, OP_EQ, "www.mit.edu");
+
+ /* Yes, this [ should be here. */
+ tt_assert(!strcmpstart(ec->socks_request->address,"[fe80:"));
+
+ /* Connect to it and make sure we get the original address back. */
+ strlcpy(ec2->socks_request->address, ec->socks_request->address,
+ sizeof(ec2->socks_request->address));
+
+ ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec2, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address);
+ tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address);
+ tt_str_op(ec2->socks_request->address, OP_EQ, "www.mit.edu");
+
+ /* Resolve it again, make sure the answer is the same. */
+ strlcpy(ec3->socks_request->address, "www.MIT.EDU",
+ sizeof(ec3->socks_request->address));
+ ec3->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ connection_ap_handshake_rewrite(ec3, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 1);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.mit.edu");
+ tt_str_op(ec3->original_dest_address, OP_EQ, "www.mit.edu");
+
+ tt_str_op(ec3->socks_request->address, OP_EQ,
+ ec->socks_request->address);
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec));
+ connection_free_(ENTRY_TO_CONN(ec2));
+ connection_free_(ENTRY_TO_CONN(ec3));
+}
+
+#if 0
+/* FFFF not actually supported. */
+/* automap on resolve, reverse lookup. */
+static void
+test_entryconn_rewrite_automap_reverse(void *arg)
+{
+ entry_connection_t *ec = arg;
+ entry_connection_t *ec2=NULL;
+ rewrite_result_t rr;
+ char *msg = NULL;
+
+ ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+
+ get_options_mutable()->AutomapHostsOnResolve = 1;
+ get_options_mutable()->SafeLogging_ = SAFELOG_SCRUB_NONE;
+ smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+ tor_strdup(".bloom"));
+ parse_virtual_addr_network("127.80.0.0/16", AF_INET, 0, &msg);
+
+ /* Automap this on resolve. */
+ strlcpy(ec->socks_request->address, "www.poldy.BLOOM",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 1);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.poldy.bloom");
+ tt_str_op(ec->original_dest_address, OP_EQ, "www.poldy.bloom");
+
+ tt_assert(!strcmpstart(ec->socks_request->address,"127.80."));
+
+ strlcpy(ec2->socks_request->address, ec->socks_request->address,
+ sizeof(ec2->socks_request->address));
+ ec2->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
+ connection_ap_handshake_rewrite(ec2, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 1);
+ tt_int_op(rr.end_reason, OP_EQ,
+ END_STREAM_REASON_DONE|END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec2));
+}
+#endif
+
+/* Rewrite because of cached DNS entry. */
+static void
+test_entryconn_rewrite_cached_dns_ipv4(void *arg)
+{
+ entry_connection_t *ec = arg;
+ rewrite_result_t rr;
+ time_t expires = time(NULL) + 3600;
+ entry_connection_t *ec2=NULL;
+
+ ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+
+ addressmap_register("www.friendly.example.com",
+ tor_strdup("240.240.241.241"),
+ expires,
+ ADDRMAPSRC_DNS,
+ 0, 0);
+
+ strlcpy(ec->socks_request->address, "www.friendly.example.com",
+ sizeof(ec->socks_request->address));
+ strlcpy(ec2->socks_request->address, "www.friendly.example.com",
+ sizeof(ec2->socks_request->address));
+
+ ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+ ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+
+ ec2->entry_cfg.use_cached_ipv4_answers = 1; /* only ec2 gets this flag */
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com");
+ tt_str_op(ec->socks_request->address, OP_EQ, "www.friendly.example.com");
+
+ connection_ap_handshake_rewrite(ec2, &rr);
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, expires);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com");
+ tt_str_op(ec2->socks_request->address, OP_EQ, "240.240.241.241");
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec2));
+}
+
+/* Rewrite because of cached DNS entry. */
+static void
+test_entryconn_rewrite_cached_dns_ipv6(void *arg)
+{
+ entry_connection_t *ec = NULL;
+ rewrite_result_t rr;
+ time_t expires = time(NULL) + 3600;
+ entry_connection_t *ec2=NULL;
+
+ (void)arg;
+
+ ec = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+ ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+
+ addressmap_register("www.friendly.example.com",
+ tor_strdup("[::f00f]"),
+ expires,
+ ADDRMAPSRC_DNS,
+ 0, 0);
+
+ strlcpy(ec->socks_request->address, "www.friendly.example.com",
+ sizeof(ec->socks_request->address));
+ strlcpy(ec2->socks_request->address, "www.friendly.example.com",
+ sizeof(ec2->socks_request->address));
+
+ ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+ ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+
+ ec2->entry_cfg.use_cached_ipv6_answers = 1; /* only ec2 gets this flag */
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com");
+ tt_str_op(ec->socks_request->address, OP_EQ, "www.friendly.example.com");
+
+ connection_ap_handshake_rewrite(ec2, &rr);
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, expires);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "www.friendly.example.com");
+ tt_str_op(ec2->socks_request->address, OP_EQ, "[::f00f]");
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec));
+ connection_free_(ENTRY_TO_CONN(ec2));
+}
+
+/* Fail to connect to unmapped address in virtual range. */
+static void
+test_entryconn_rewrite_unmapped_virtual(void *arg)
+{
+ entry_connection_t *ec = arg;
+ rewrite_result_t rr;
+ entry_connection_t *ec2 = NULL;
+ char *msg = NULL;
+
+ ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET6);
+
+ parse_virtual_addr_network("18.202.0.0/16", AF_INET, 0, &msg);
+ parse_virtual_addr_network("[ABCD::]/16", AF_INET6, 0, &msg);
+
+ strlcpy(ec->socks_request->address, "18.202.5.5",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.should_close, OP_EQ, 1);
+ tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_INTERNAL);
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+
+ strlcpy(ec2->socks_request->address, "[ABCD:9::5314:9543]",
+ sizeof(ec2->socks_request->address));
+ ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec2, &rr);
+
+ tt_int_op(rr.should_close, OP_EQ, 1);
+ tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_INTERNAL);
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec2));
+}
+
+/* Rewrite because of mapaddress option */
+static void
+test_entryconn_rewrite_mapaddress(void *arg)
+{
+ entry_connection_t *ec = arg;
+ rewrite_result_t rr;
+
+ config_line_append(&get_options_mutable()->AddressMap,
+ "MapAddress", "meta metaobjects.example");
+ config_register_addressmaps(get_options());
+
+ strlcpy(ec->socks_request->address, "meta",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(ec->socks_request->address, OP_EQ, "metaobjects.example");
+
+ done:
+ ;
+}
+
+/* Reject reverse lookups of internal address. */
+static void
+test_entryconn_rewrite_reject_internal_reverse(void *arg)
+{
+ entry_connection_t *ec = arg;
+ rewrite_result_t rr;
+
+ strlcpy(ec->socks_request->address, "10.0.0.1",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.should_close, OP_EQ, 1);
+ tt_int_op(rr.end_reason, OP_EQ, END_STREAM_REASON_SOCKSPROTOCOL |
+ END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+
+ done:
+ ;
+}
+
+/* Rewrite into .exit because of virtual address mapping */
+static void
+test_entryconn_rewrite_automap_exit(void *arg)
+{
+ entry_connection_t *ec = arg;
+ entry_connection_t *ec2=NULL;
+ rewrite_result_t rr;
+ char *msg = NULL;
+
+ ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+
+ get_options_mutable()->AutomapHostsOnResolve = 1;
+ get_options_mutable()->AllowDotExit = 1;
+ smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+ tor_strdup(".EXIT"));
+ parse_virtual_addr_network("127.1.0.0/16", AF_INET, 0, &msg);
+
+ /* Automap this on resolve. */
+ strlcpy(ec->socks_request->address, "website.example.exit",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 1);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "website.example.exit");
+ tt_str_op(ec->original_dest_address, OP_EQ, "website.example.exit");
+
+ tt_assert(!strcmpstart(ec->socks_request->address,"127.1."));
+
+ /* Connect to it and make sure we get the original address back. */
+ strlcpy(ec2->socks_request->address, ec->socks_request->address,
+ sizeof(ec2->socks_request->address));
+
+ ec2->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec2, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_AUTOMAP);
+ tt_str_op(rr.orig_address, OP_EQ, ec->socks_request->address);
+ tt_str_op(ec2->original_dest_address, OP_EQ, ec->socks_request->address);
+ tt_str_op(ec2->socks_request->address, OP_EQ, "website.example.exit");
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec2));
+}
+
+/* Rewrite into .exit because of mapaddress */
+static void
+test_entryconn_rewrite_mapaddress_exit(void *arg)
+{
+ entry_connection_t *ec = arg;
+ rewrite_result_t rr;
+
+ config_line_append(&get_options_mutable()->AddressMap,
+ "MapAddress", "*.example.com *.example.com.abc.exit");
+ config_register_addressmaps(get_options());
+
+ /* Automap this on resolve. */
+ strlcpy(ec->socks_request->address, "abc.example.com",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_TORRC);
+ tt_str_op(rr.orig_address, OP_EQ, "abc.example.com");
+ tt_str_op(ec->socks_request->address, OP_EQ, "abc.example.com.abc.exit");
+ done:
+ ;
+}
+
+/* Map foo.onion to longthing.onion, and also automap. */
+static void
+test_entryconn_rewrite_mapaddress_automap_onion(void *arg)
+{
+ entry_connection_t *ec = arg;
+ entry_connection_t *ec2 = NULL;
+ entry_connection_t *ec3 = NULL;
+ entry_connection_t *ec4 = NULL;
+ rewrite_result_t rr;
+ char *msg = NULL;
+
+ ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ ec4 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+
+ get_options_mutable()->AutomapHostsOnResolve = 1;
+ get_options_mutable()->AllowDotExit = 1;
+ smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+ tor_strdup(".onion"));
+ parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg);
+ config_line_append(&get_options_mutable()->AddressMap,
+ "MapAddress", "foo.onion abcdefghijklmnop.onion");
+ config_register_addressmaps(get_options());
+
+ /* Connect to foo.onion. */
+ strlcpy(ec->socks_request->address, "foo.onion",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "foo.onion");
+ tt_str_op(ec->socks_request->address, OP_EQ, "abcdefghijklmnop.onion");
+
+ /* Okay, resolve foo.onion */
+ strlcpy(ec2->socks_request->address, "foo.onion",
+ sizeof(ec2->socks_request->address));
+ ec2->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ connection_ap_handshake_rewrite(ec2, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 1);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "foo.onion");
+ tt_assert(!strcmpstart(ec2->socks_request->address, "192.168."));
+
+ /* Now connect */
+ strlcpy(ec3->socks_request->address, ec2->socks_request->address,
+ sizeof(ec3->socks_request->address));
+ ec3->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec3, &rr);
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_assert(!strcmpstart(ec3->socks_request->address,
+ "abcdefghijklmnop.onion"));
+
+ /* Now resolve abcefghijklmnop.onion. */
+ strlcpy(ec4->socks_request->address, "abcdefghijklmnop.onion",
+ sizeof(ec4->socks_request->address));
+ ec4->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ connection_ap_handshake_rewrite(ec4, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 1);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "abcdefghijklmnop.onion");
+ tt_assert(!strcmpstart(ec4->socks_request->address, "192.168."));
+ /* XXXX doesn't work
+ tt_str_op(ec4->socks_request->address, OP_EQ, ec2->socks_request->address);
+ */
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec2));
+ connection_free_(ENTRY_TO_CONN(ec3));
+ connection_free_(ENTRY_TO_CONN(ec4));
+}
+
+static void
+test_entryconn_rewrite_mapaddress_automap_onion_common(entry_connection_t *ec,
+ int map_to_onion,
+ int map_to_address)
+{
+ entry_connection_t *ec2 = NULL;
+ entry_connection_t *ec3 = NULL;
+ rewrite_result_t rr;
+
+ ec2 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+ ec3 = entry_connection_new(CONN_TYPE_AP, AF_INET);
+
+ /* Connect to irc.example.com */
+ strlcpy(ec->socks_request->address, "irc.example.com",
+ sizeof(ec->socks_request->address));
+ ec->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "irc.example.com");
+ tt_str_op(ec->socks_request->address, OP_EQ,
+ map_to_onion ? "abcdefghijklmnop.onion" : "irc.example.com");
+
+ /* Okay, resolve irc.example.com */
+ strlcpy(ec2->socks_request->address, "irc.example.com",
+ sizeof(ec2->socks_request->address));
+ ec2->socks_request->command = SOCKS_COMMAND_RESOLVE;
+ connection_ap_handshake_rewrite(ec2, &rr);
+
+ tt_int_op(rr.automap, OP_EQ, map_to_onion && map_to_address);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ tt_i64_op(rr.map_expires, OP_EQ, TIME_MAX);
+ tt_int_op(rr.exit_source, OP_EQ, ADDRMAPSRC_NONE);
+ tt_str_op(rr.orig_address, OP_EQ, "irc.example.com");
+ if (map_to_onion && map_to_address)
+ tt_assert(!strcmpstart(ec2->socks_request->address, "192.168."));
+
+ /* Now connect */
+ strlcpy(ec3->socks_request->address, ec2->socks_request->address,
+ sizeof(ec3->socks_request->address));
+ ec3->socks_request->command = SOCKS_COMMAND_CONNECT;
+ connection_ap_handshake_rewrite(ec3, &rr);
+ tt_int_op(rr.automap, OP_EQ, 0);
+ tt_int_op(rr.should_close, OP_EQ, 0);
+ tt_int_op(rr.end_reason, OP_EQ, 0);
+ if (map_to_onion)
+ tt_assert(!strcmpstart(ec3->socks_request->address,
+ "abcdefghijklmnop.onion"));
+
+ done:
+ connection_free_(ENTRY_TO_CONN(ec2));
+ connection_free_(ENTRY_TO_CONN(ec3));
+}
+
+/* This time is the same, but we start with a mapping from a non-onion
+ * address. */
+static void
+test_entryconn_rewrite_mapaddress_automap_onion2(void *arg)
+{
+ char *msg = NULL;
+ get_options_mutable()->AutomapHostsOnResolve = 1;
+ smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+ tor_strdup(".onion"));
+ parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg);
+ config_line_append(&get_options_mutable()->AddressMap,
+ "MapAddress", "irc.example.com abcdefghijklmnop.onion");
+ config_register_addressmaps(get_options());
+
+ test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 1, 1);
+}
+
+/* Same as above, with automapped turned off */
+static void
+test_entryconn_rewrite_mapaddress_automap_onion3(void *arg)
+{
+ config_line_append(&get_options_mutable()->AddressMap,
+ "MapAddress", "irc.example.com abcdefghijklmnop.onion");
+ config_register_addressmaps(get_options());
+
+ test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 1, 0);
+}
+
+/* As above, with no mapping. */
+static void
+test_entryconn_rewrite_mapaddress_automap_onion4(void *arg)
+{
+ char *msg = NULL;
+ get_options_mutable()->AutomapHostsOnResolve = 1;
+ smartlist_add(get_options_mutable()->AutomapHostsSuffixes,
+ tor_strdup(".onion"));
+ parse_virtual_addr_network("192.168.0.0/16", AF_INET, 0, &msg);
+
+ test_entryconn_rewrite_mapaddress_automap_onion_common(arg, 0, 1);
+}
+
+#define REWRITE(name) \
+ { #name, test_entryconn_##name, TT_FORK, &test_rewrite_setup, NULL }
+
+struct testcase_t entryconn_tests[] = {
+ REWRITE(rewrite_basic),
+ REWRITE(rewrite_bad_dotexit),
+ REWRITE(rewrite_automap_ipv4),
+ REWRITE(rewrite_automap_ipv6),
+ // REWRITE(rewrite_automap_reverse),
+ REWRITE(rewrite_cached_dns_ipv4),
+ REWRITE(rewrite_cached_dns_ipv6),
+ REWRITE(rewrite_unmapped_virtual),
+ REWRITE(rewrite_mapaddress),
+ REWRITE(rewrite_reject_internal_reverse),
+ REWRITE(rewrite_automap_exit),
+ REWRITE(rewrite_mapaddress_exit),
+ REWRITE(rewrite_mapaddress_automap_onion),
+ REWRITE(rewrite_mapaddress_automap_onion2),
+ REWRITE(rewrite_mapaddress_automap_onion3),
+ REWRITE(rewrite_mapaddress_automap_onion4),
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
new file mode 100644
index 0000000000..17cb9d9329
--- /dev/null
+++ b/src/test/test_entrynodes.c
@@ -0,0 +1,662 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+
+#define STATEFILE_PRIVATE
+#define ENTRYNODES_PRIVATE
+#define ROUTERLIST_PRIVATE
+
+#include "or.h"
+#include "test.h"
+#include "entrynodes.h"
+#include "routerparse.h"
+#include "nodelist.h"
+#include "util.h"
+#include "routerlist.h"
+#include "routerset.h"
+#include "statefile.h"
+#include "config.h"
+
+#include "test_helpers.h"
+
+/* TODO:
+ * choose_random_entry() test with state set.
+ *
+ * parse_state() tests with more than one guards.
+ *
+ * More tests for set_from_config(): Multiple nodes, use fingerprints,
+ * use country codes.
+ */
+
+/** Dummy Tor state used in unittests. */
+static or_state_t *dummy_state = NULL;
+static or_state_t *
+get_or_state_replacement(void)
+{
+ return dummy_state;
+}
+
+/* Unittest cleanup function: Cleanup the fake network. */
+static int
+fake_network_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ (void) testcase;
+ (void) ptr;
+
+ routerlist_free_all();
+ nodelist_free_all();
+ entry_guards_free_all();
+ or_state_free(dummy_state);
+
+ return 1; /* NOP */
+}
+
+/* Unittest setup function: Setup a fake network. */
+static void *
+fake_network_setup(const struct testcase_t *testcase)
+{
+ (void) testcase;
+
+ /* Setup fake state */
+ dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ MOCK(get_or_state,
+ get_or_state_replacement);
+
+ /* Setup fake routerlist. */
+ helper_setup_fake_routerlist();
+
+ /* Return anything but NULL (it's interpreted as test fail) */
+ return dummy_state;
+}
+
+/** Test choose_random_entry() with none of our routers being guard nodes. */
+static void
+test_choose_random_entry_no_guards(void *arg)
+{
+ const node_t *chosen_entry = NULL;
+
+ (void) arg;
+
+ /* Try to pick an entry even though none of our routers are guards. */
+ chosen_entry = choose_random_entry(NULL);
+
+ /* Unintuitively, we actually pick a random node as our entry,
+ because router_choose_random_node() relaxes its constraints if it
+ can't find a proper entry guard. */
+ tt_assert(chosen_entry);
+
+ done:
+ ;
+}
+
+/** Test choose_random_entry() with only one of our routers being a
+ guard node. */
+static void
+test_choose_random_entry_one_possible_guard(void *arg)
+{
+ const node_t *chosen_entry = NULL;
+ node_t *the_guard = NULL;
+ smartlist_t *our_nodelist = NULL;
+
+ (void) arg;
+
+ /* Set one of the nodes to be a guard. */
+ our_nodelist = nodelist_get_list();
+ the_guard = smartlist_get(our_nodelist, 4); /* chosen by fair dice roll */
+ the_guard->is_possible_guard = 1;
+
+ /* Pick an entry. Make sure we pick the node we marked as guard. */
+ chosen_entry = choose_random_entry(NULL);
+ tt_ptr_op(chosen_entry, OP_EQ, the_guard);
+
+ done:
+ ;
+}
+
+/** Helper to conduct tests for populate_live_entry_guards().
+
+ This test adds some entry guards to our list, and then tests
+ populate_live_entry_guards() to mke sure it filters them correctly.
+
+ <b>num_needed</b> is the number of guard nodes we support. It's
+ configurable to make sure we function properly with 1 or 3 guard
+ nodes configured.
+*/
+static void
+populate_live_entry_guards_test_helper(int num_needed)
+{
+ smartlist_t *our_nodelist = NULL;
+ smartlist_t *live_entry_guards = smartlist_new();
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ or_options_t *options = get_options_mutable();
+ int retval;
+
+ /* Set NumEntryGuards to the provided number. */
+ options->NumEntryGuards = num_needed;
+ tt_int_op(num_needed, OP_EQ, decide_num_guards(options, 0));
+
+ /* The global entry guards smartlist should be empty now. */
+ tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 0);
+
+ /* Walk the nodelist and add all nodes as entry guards. */
+ our_nodelist = nodelist_get_list();
+ tt_int_op(smartlist_len(our_nodelist), OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS);
+
+ SMARTLIST_FOREACH_BEGIN(our_nodelist, const node_t *, node) {
+ const node_t *node_tmp;
+ node_tmp = add_an_entry_guard(node, 0, 1, 0, 0);
+ tt_assert(node_tmp);
+ } SMARTLIST_FOREACH_END(node);
+
+ /* Make sure the nodes were added as entry guards. */
+ tt_int_op(smartlist_len(all_entry_guards), OP_EQ,
+ HELPER_NUMBER_OF_DESCRIPTORS);
+
+ /* Ensure that all the possible entry guards are enough to satisfy us. */
+ tt_int_op(smartlist_len(all_entry_guards), OP_GE, num_needed);
+
+ /* Walk the entry guard list for some sanity checking */
+ SMARTLIST_FOREACH_BEGIN(all_entry_guards, const entry_guard_t *, entry) {
+ /* Since we called add_an_entry_guard() with 'for_discovery' being
+ False, all guards should have made_contact enabled. */
+ tt_int_op(entry->made_contact, OP_EQ, 1);
+
+ /* Since we don't have a routerstatus, all of the entry guards are
+ not directory servers. */
+ tt_int_op(entry->is_dir_cache, OP_EQ, 0);
+ } SMARTLIST_FOREACH_END(entry);
+
+ /* First, try to get some fast guards. This should fail. */
+ retval = populate_live_entry_guards(live_entry_guards,
+ all_entry_guards,
+ NULL,
+ NO_DIRINFO, /* Don't care about DIRINFO*/
+ 0, 0,
+ 1); /* We want fast guard! */
+ tt_int_op(retval, OP_EQ, 0);
+ tt_int_op(smartlist_len(live_entry_guards), OP_EQ, 0);
+
+ /* Now try to get some stable guards. This should fail too. */
+ retval = populate_live_entry_guards(live_entry_guards,
+ all_entry_guards,
+ NULL,
+ NO_DIRINFO,
+ 0,
+ 1, /* We want stable guard! */
+ 0);
+ tt_int_op(retval, OP_EQ, 0);
+ tt_int_op(smartlist_len(live_entry_guards), OP_EQ, 0);
+
+ /* Now try to get any guard we can find. This should succeed. */
+ retval = populate_live_entry_guards(live_entry_guards,
+ all_entry_guards,
+ NULL,
+ NO_DIRINFO,
+ 0, 0, 0); /* No restrictions! */
+
+ /* Since we had more than enough guards in 'all_entry_guards', we
+ should have added 'num_needed' of them to live_entry_guards.
+ 'retval' should be 1 since we now have enough live entry guards
+ to pick one. */
+ tt_int_op(retval, OP_EQ, 1);
+ tt_int_op(smartlist_len(live_entry_guards), OP_EQ, num_needed);
+
+ done:
+ smartlist_free(live_entry_guards);
+}
+
+/* Test populate_live_entry_guards() for 1 guard node. */
+static void
+test_populate_live_entry_guards_1guard(void *arg)
+{
+ (void) arg;
+
+ populate_live_entry_guards_test_helper(1);
+}
+
+/* Test populate_live_entry_guards() for 3 guard nodes. */
+static void
+test_populate_live_entry_guards_3guards(void *arg)
+{
+ (void) arg;
+
+ populate_live_entry_guards_test_helper(3);
+}
+
+/** Append some EntryGuard lines to the Tor state at <b>state</b>.
+
+ <b>entry_guard_lines</b> is a smartlist containing 2-tuple
+ smartlists that carry the key and values of the statefile.
+ As an example:
+ entry_guard_lines =
+ (("EntryGuard", "name 67E72FF33D7D41BF11C569646A0A7B4B188340DF DirCache"),
+ ("EntryGuardDownSince", "2014-06-07 16:02:46 2014-06-07 16:02:46"))
+*/
+static void
+state_insert_entry_guard_helper(or_state_t *state,
+ smartlist_t *entry_guard_lines)
+{
+ config_line_t **next, *line;
+
+ next = &state->EntryGuards;
+ *next = NULL;
+
+ /* Loop over all the state lines in the smartlist */
+ SMARTLIST_FOREACH_BEGIN(entry_guard_lines, const smartlist_t *,state_lines) {
+ /* Get key and value for each line */
+ const char *state_key = smartlist_get(state_lines, 0);
+ const char *state_value = smartlist_get(state_lines, 1);
+
+ *next = line = tor_malloc_zero(sizeof(config_line_t));
+ line->key = tor_strdup(state_key);
+ tor_asprintf(&line->value, "%s", state_value);
+ next = &(line->next);
+ } SMARTLIST_FOREACH_END(state_lines);
+}
+
+/** Free memory occupied by <b>entry_guard_lines</b>. */
+static void
+state_lines_free(smartlist_t *entry_guard_lines)
+{
+ SMARTLIST_FOREACH_BEGIN(entry_guard_lines, smartlist_t *, state_lines) {
+ char *state_key = smartlist_get(state_lines, 0);
+ char *state_value = smartlist_get(state_lines, 1);
+
+ tor_free(state_key);
+ tor_free(state_value);
+ smartlist_free(state_lines);
+ } SMARTLIST_FOREACH_END(state_lines);
+
+ smartlist_free(entry_guard_lines);
+}
+
+/* Tests entry_guards_parse_state(). It creates a fake Tor state with
+ a saved entry guard and makes sure that Tor can parse it and
+ creates the right entry node out of it.
+*/
+static void
+test_entry_guards_parse_state_simple(void *arg)
+{
+ or_state_t *state = or_state_new();
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ smartlist_t *entry_state_lines = smartlist_new();
+ char *msg = NULL;
+ int retval;
+
+ /* Details of our fake guard node */
+ const char *nickname = "hagbard";
+ const char *fpr = "B29D536DD1752D542E1FBB3C9CE4449D51298212";
+ const char *tor_version = "0.2.5.3-alpha-dev";
+ const char *added_at = get_yesterday_date_str();
+ const char *unlisted_since = "2014-06-08 16:16:50";
+
+ (void) arg;
+
+ /* The global entry guards smartlist should be empty now. */
+ tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 0);
+
+ { /* Prepare the state entry */
+
+ /* Prepare the smartlist to hold the key/value of each line */
+ smartlist_t *state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuard");
+ smartlist_add_asprintf(state_line, "%s %s %s", nickname, fpr, "DirCache");
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardAddedBy");
+ smartlist_add_asprintf(state_line, "%s %s %s", fpr, tor_version, added_at);
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardUnlistedSince");
+ smartlist_add_asprintf(state_line, "%s", unlisted_since);
+ smartlist_add(entry_state_lines, state_line);
+ }
+
+ /* Inject our lines in the state */
+ state_insert_entry_guard_helper(state, entry_state_lines);
+
+ /* Parse state */
+ retval = entry_guards_parse_state(state, 1, &msg);
+ tt_int_op(retval, OP_GE, 0);
+
+ /* Test that the guard was registered.
+ We need to re-get the entry guard list since its pointer was
+ overwritten in entry_guards_parse_state(). */
+ all_entry_guards = get_entry_guards();
+ tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 1);
+
+ { /* Test the entry guard structure */
+ char hex_digest[1024];
+ char str_time[1024];
+
+ const entry_guard_t *e = smartlist_get(all_entry_guards, 0);
+ tt_str_op(e->nickname, OP_EQ, nickname); /* Verify nickname */
+
+ base16_encode(hex_digest, sizeof(hex_digest),
+ e->identity, DIGEST_LEN);
+ tt_str_op(hex_digest, OP_EQ, fpr); /* Verify fingerprint */
+
+ tt_assert(e->is_dir_cache); /* Verify dirness */
+
+ tt_str_op(e->chosen_by_version, OP_EQ, tor_version); /* Verify version */
+
+ tt_assert(e->made_contact); /* All saved guards have been contacted */
+
+ tt_assert(e->bad_since); /* Verify bad_since timestamp */
+ format_iso_time(str_time, e->bad_since);
+ tt_str_op(str_time, OP_EQ, unlisted_since);
+
+ /* The rest should be unset */
+ tt_assert(!e->unreachable_since);
+ tt_assert(!e->can_retry);
+ tt_assert(!e->path_bias_noticed);
+ tt_assert(!e->path_bias_warned);
+ tt_assert(!e->path_bias_extreme);
+ tt_assert(!e->path_bias_disabled);
+ tt_assert(!e->path_bias_use_noticed);
+ tt_assert(!e->path_bias_use_extreme);
+ tt_assert(!e->last_attempted);
+ }
+
+ done:
+ state_lines_free(entry_state_lines);
+ or_state_free(state);
+ tor_free(msg);
+}
+
+/** Similar to test_entry_guards_parse_state_simple() but aims to test
+ the PathBias-related details of the entry guard. */
+static void
+test_entry_guards_parse_state_pathbias(void *arg)
+{
+ or_state_t *state = or_state_new();
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ char *msg = NULL;
+ int retval;
+ smartlist_t *entry_state_lines = smartlist_new();
+
+ /* Path bias details of the fake guard */
+ const double circ_attempts = 9;
+ const double circ_successes = 8;
+ const double successful_closed = 4;
+ const double collapsed = 2;
+ const double unusable = 0;
+ const double timeouts = 1;
+
+ (void) arg;
+
+ /* The global entry guards smartlist should be empty now. */
+ tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 0);
+
+ { /* Prepare the state entry */
+
+ /* Prepare the smartlist to hold the key/value of each line */
+ smartlist_t *state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuard");
+ smartlist_add_asprintf(state_line,
+ "givethanks B29D536DD1752D542E1FBB3C9CE4449D51298212 NoDirCache");
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardAddedBy");
+ smartlist_add_asprintf(state_line,
+ "B29D536DD1752D542E1FBB3C9CE4449D51298212 0.2.5.3-alpha-dev "
+ "%s", get_yesterday_date_str());
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardUnlistedSince");
+ smartlist_add_asprintf(state_line, "2014-06-08 16:16:50");
+ smartlist_add(entry_state_lines, state_line);
+
+ state_line = smartlist_new();
+ smartlist_add_asprintf(state_line, "EntryGuardPathBias");
+ smartlist_add_asprintf(state_line, "%f %f %f %f %f %f",
+ circ_attempts, circ_successes, successful_closed,
+ collapsed, unusable, timeouts);
+ smartlist_add(entry_state_lines, state_line);
+ }
+
+ /* Inject our lines in the state */
+ state_insert_entry_guard_helper(state, entry_state_lines);
+
+ /* Parse state */
+ retval = entry_guards_parse_state(state, 1, &msg);
+ tt_int_op(retval, OP_GE, 0);
+
+ /* Test that the guard was registered */
+ all_entry_guards = get_entry_guards();
+ tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 1);
+
+ { /* Test the path bias of this guard */
+ const entry_guard_t *e = smartlist_get(all_entry_guards, 0);
+
+ tt_assert(!e->is_dir_cache);
+ tt_assert(!e->can_retry);
+
+ /* XXX tt_double_op doesn't support equality. Cast to int for now. */
+ tt_int_op((int)e->circ_attempts, OP_EQ, (int)circ_attempts);
+ tt_int_op((int)e->circ_successes, OP_EQ, (int)circ_successes);
+ tt_int_op((int)e->successful_circuits_closed, OP_EQ,
+ (int)successful_closed);
+ tt_int_op((int)e->timeouts, OP_EQ, (int)timeouts);
+ tt_int_op((int)e->collapsed_circuits, OP_EQ, (int)collapsed);
+ tt_int_op((int)e->unusable_circuits, OP_EQ, (int)unusable);
+ }
+
+ done:
+ or_state_free(state);
+ state_lines_free(entry_state_lines);
+ tor_free(msg);
+}
+
+/* Simple test of entry_guards_set_from_config() by specifying a
+ particular EntryNode and making sure it gets picked. */
+static void
+test_entry_guards_set_from_config(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ const char *entrynodes_str = "test003r";
+ const node_t *chosen_entry = NULL;
+ int retval;
+
+ (void) arg;
+
+ /* Prase EntryNodes as a routerset. */
+ options->EntryNodes = routerset_new();
+ retval = routerset_parse(options->EntryNodes,
+ entrynodes_str,
+ "test_entrynodes");
+ tt_int_op(retval, OP_GE, 0);
+
+ /* Read nodes from EntryNodes */
+ entry_guards_set_from_config(options);
+
+ /* Test that only one guard was added. */
+ tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 1);
+
+ /* Make sure it was the guard we specified. */
+ chosen_entry = choose_random_entry(NULL);
+ tt_str_op(chosen_entry->ri->nickname, OP_EQ, entrynodes_str);
+
+ done:
+ routerset_free(options->EntryNodes);
+}
+
+static void
+test_entry_is_time_to_retry(void *arg)
+{
+ entry_guard_t *test_guard;
+ time_t now;
+ int retval;
+ (void)arg;
+
+ now = time(NULL);
+
+ test_guard = tor_malloc_zero(sizeof(entry_guard_t));
+
+ test_guard->last_attempted = now - 10;
+ test_guard->unreachable_since = now - 1;
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,1);
+
+ test_guard->unreachable_since = now - (6*60*60 - 1);
+ test_guard->last_attempted = now - (60*60 + 1);
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,1);
+
+ test_guard->last_attempted = now - (60*60 - 1);
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,0);
+
+ test_guard->unreachable_since = now - (6*60*60 + 1);
+ test_guard->last_attempted = now - (4*60*60 + 1);
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,1);
+
+ test_guard->unreachable_since = now - (3*24*60*60 - 1);
+ test_guard->last_attempted = now - (4*60*60 + 1);
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,1);
+
+ test_guard->unreachable_since = now - (3*24*60*60 + 1);
+ test_guard->last_attempted = now - (18*60*60 + 1);
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,1);
+
+ test_guard->unreachable_since = now - (7*24*60*60 - 1);
+ test_guard->last_attempted = now - (18*60*60 + 1);
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,1);
+
+ test_guard->last_attempted = now - (18*60*60 - 1);
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,0);
+
+ test_guard->unreachable_since = now - (7*24*60*60 + 1);
+ test_guard->last_attempted = now - (36*60*60 + 1);
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,1);
+
+ test_guard->unreachable_since = now - (7*24*60*60 + 1);
+ test_guard->last_attempted = now - (36*60*60 + 1);
+
+ retval = entry_is_time_to_retry(test_guard,now);
+ tt_int_op(retval,OP_EQ,1);
+
+ done:
+ tor_free(test_guard);
+}
+
+/** XXX Do some tests that entry_is_live() */
+static void
+test_entry_is_live(void *arg)
+{
+ smartlist_t *our_nodelist = NULL;
+ const smartlist_t *all_entry_guards = get_entry_guards();
+ const node_t *test_node = NULL;
+ const entry_guard_t *test_entry = NULL;
+ const char *msg;
+ int which_node;
+
+ (void) arg;
+
+ /* The global entry guards smartlist should be empty now. */
+ tt_int_op(smartlist_len(all_entry_guards), OP_EQ, 0);
+
+ /* Walk the nodelist and add all nodes as entry guards. */
+ our_nodelist = nodelist_get_list();
+ tt_int_op(smartlist_len(our_nodelist), OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS);
+
+ SMARTLIST_FOREACH_BEGIN(our_nodelist, const node_t *, node) {
+ const node_t *node_tmp;
+ node_tmp = add_an_entry_guard(node, 0, 1, 0, 0);
+ tt_assert(node_tmp);
+
+ tt_int_op(node->is_stable, OP_EQ, 0);
+ tt_int_op(node->is_fast, OP_EQ, 0);
+ } SMARTLIST_FOREACH_END(node);
+
+ /* Make sure the nodes were added as entry guards. */
+ tt_int_op(smartlist_len(all_entry_guards), OP_EQ,
+ HELPER_NUMBER_OF_DESCRIPTORS);
+
+ /* Now get a random test entry that we will use for this unit test. */
+ which_node = 3; /* (chosen by fair dice roll) */
+ test_entry = smartlist_get(all_entry_guards, which_node);
+
+ /* Let's do some entry_is_live() tests! */
+
+ /* Require the node to be stable, but it's not. Should fail.
+ Also enable 'assume_reachable' because why not. */
+ test_node = entry_is_live(test_entry,
+ ENTRY_NEED_UPTIME | ENTRY_ASSUME_REACHABLE,
+ &msg);
+ tt_assert(!test_node);
+
+ /* Require the node to be fast, but it's not. Should fail. */
+ test_node = entry_is_live(test_entry,
+ ENTRY_NEED_CAPACITY | ENTRY_ASSUME_REACHABLE,
+ &msg);
+ tt_assert(!test_node);
+
+ /* Don't impose any restrictions on the node. Should succeed. */
+ test_node = entry_is_live(test_entry, 0, &msg);
+ tt_assert(test_node);
+ tt_ptr_op(test_node, OP_EQ, node_get_by_id(test_entry->identity));
+
+ /* Require descriptor for this node. It has one so it should succeed. */
+ test_node = entry_is_live(test_entry, ENTRY_NEED_DESCRIPTOR, &msg);
+ tt_assert(test_node);
+ tt_ptr_op(test_node, OP_EQ, node_get_by_id(test_entry->identity));
+
+ done:
+ ; /* XXX */
+}
+
+static const struct testcase_setup_t fake_network = {
+ fake_network_setup, fake_network_cleanup
+};
+
+struct testcase_t entrynodes_tests[] = {
+ { "entry_is_time_to_retry", test_entry_is_time_to_retry,
+ TT_FORK, NULL, NULL },
+ { "choose_random_entry_no_guards", test_choose_random_entry_no_guards,
+ TT_FORK, &fake_network, NULL },
+ { "choose_random_entry_one_possibleguard",
+ test_choose_random_entry_one_possible_guard,
+ TT_FORK, &fake_network, NULL },
+ { "populate_live_entry_guards_1guard",
+ test_populate_live_entry_guards_1guard,
+ TT_FORK, &fake_network, NULL },
+ { "populate_live_entry_guards_3guards",
+ test_populate_live_entry_guards_3guards,
+ TT_FORK, &fake_network, NULL },
+ { "entry_guards_parse_state_simple",
+ test_entry_guards_parse_state_simple,
+ TT_FORK, &fake_network, NULL },
+ { "entry_guards_parse_state_pathbias",
+ test_entry_guards_parse_state_pathbias,
+ TT_FORK, &fake_network, NULL },
+ { "entry_guards_set_from_config",
+ test_entry_guards_set_from_config,
+ TT_FORK, &fake_network, NULL },
+ { "entry_is_live",
+ test_entry_is_live,
+ TT_FORK, &fake_network, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c
index 93c8f77d5b..2e5a32eef3 100644
--- a/src/test/test_extorport.c
+++ b/src/test/test_extorport.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONNECTION_PRIVATE
@@ -24,35 +24,37 @@ test_ext_or_id_map(void *arg)
(void)arg;
/* pre-initialization */
- tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
+ tt_ptr_op(NULL, OP_EQ,
+ connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
c1 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
c2 = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
c3 = or_connection_new(CONN_TYPE_OR, AF_INET);
- tt_ptr_op(c1->ext_or_conn_id, !=, NULL);
- tt_ptr_op(c2->ext_or_conn_id, !=, NULL);
- tt_ptr_op(c3->ext_or_conn_id, ==, NULL);
+ tt_ptr_op(c1->ext_or_conn_id, OP_NE, NULL);
+ tt_ptr_op(c2->ext_or_conn_id, OP_NE, NULL);
+ tt_ptr_op(c3->ext_or_conn_id, OP_EQ, NULL);
- tt_ptr_op(c1, ==, connection_or_get_by_ext_or_id(c1->ext_or_conn_id));
- tt_ptr_op(c2, ==, connection_or_get_by_ext_or_id(c2->ext_or_conn_id));
- tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
+ tt_ptr_op(c1, OP_EQ, connection_or_get_by_ext_or_id(c1->ext_or_conn_id));
+ tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(c2->ext_or_conn_id));
+ tt_ptr_op(NULL, OP_EQ,
+ connection_or_get_by_ext_or_id("xxxxxxxxxxxxxxxxxxxx"));
idp = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
/* Give c2 a new ID. */
connection_or_set_ext_or_identifier(c2);
- test_mem_op(idp, !=, c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
+ tt_mem_op(idp, OP_NE, c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
idp2 = tor_memdup(c2->ext_or_conn_id, EXT_OR_CONN_ID_LEN);
tt_assert(!tor_digest_is_zero(idp2));
- tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id(idp));
- tt_ptr_op(c2, ==, connection_or_get_by_ext_or_id(idp2));
+ tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp));
+ tt_ptr_op(c2, OP_EQ, connection_or_get_by_ext_or_id(idp2));
/* Now remove it. */
connection_or_remove_from_ext_or_id_map(c2);
- tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id(idp));
- tt_ptr_op(NULL, ==, connection_or_get_by_ext_or_id(idp2));
+ tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp));
+ tt_ptr_op(NULL, OP_EQ, connection_or_get_by_ext_or_id(idp2));
done:
if (c1)
@@ -112,33 +114,33 @@ test_ext_or_write_command(void *arg)
/* Length too long */
tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 100, "X", 100000),
- <, 0);
+ OP_LT, 0);
/* Empty command */
tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99, NULL, 0),
- ==, 0);
+ OP_EQ, 0);
cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
- tt_int_op(sz, ==, 4);
- test_mem_op(cp, ==, "\x00\x99\x00\x00", 4);
+ tt_int_op(sz, OP_EQ, 4);
+ tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x00", 4);
tor_free(cp);
/* Medium command. */
tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0x99,
- "Wai\0Hello", 9), ==, 0);
+ "Wai\0Hello", 9), OP_EQ, 0);
cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
- tt_int_op(sz, ==, 13);
- test_mem_op(cp, ==, "\x00\x99\x00\x09Wai\x00Hello", 13);
+ tt_int_op(sz, OP_EQ, 13);
+ tt_mem_op(cp, OP_EQ, "\x00\x99\x00\x09Wai\x00Hello", 13);
tor_free(cp);
/* Long command */
buf = tor_malloc(65535);
memset(buf, 'x', 65535);
tt_int_op(connection_write_ext_or_command(TO_CONN(c1), 0xf00d,
- buf, 65535), ==, 0);
+ buf, 65535), OP_EQ, 0);
cp = buf_get_contents(TO_CONN(c1)->outbuf, &sz);
- tt_int_op(sz, ==, 65539);
- test_mem_op(cp, ==, "\xf0\x0d\xff\xff", 4);
- test_mem_op(cp+4, ==, buf, 65535);
+ tt_int_op(sz, OP_EQ, 65539);
+ tt_mem_op(cp, OP_EQ, "\xf0\x0d\xff\xff", 4);
+ tt_mem_op(cp+4, OP_EQ, buf, 65535);
tor_free(cp);
done:
@@ -175,42 +177,42 @@ test_ext_or_init_auth(void *arg)
tor_free(options->DataDirectory);
options->DataDirectory = tor_strdup("foo");
cp = get_ext_or_auth_cookie_file_name();
- tt_str_op(cp, ==, "foo"PATH_SEPARATOR"extended_orport_auth_cookie");
+ tt_str_op(cp, OP_EQ, "foo"PATH_SEPARATOR"extended_orport_auth_cookie");
tor_free(cp);
/* Shouldn't be initialized already, or our tests will be a bit
* meaningless */
ext_or_auth_cookie = tor_malloc_zero(32);
- test_assert(tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
+ tt_assert(tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
/* Now make sure we use a temporary file */
fn = get_fname("ext_cookie_file");
options->ExtORPortCookieAuthFile = tor_strdup(fn);
cp = get_ext_or_auth_cookie_file_name();
- tt_str_op(cp, ==, fn);
+ tt_str_op(cp, OP_EQ, fn);
tor_free(cp);
/* Test the initialization function with a broken
write_bytes_to_file(). See if the problem is handled properly. */
MOCK(write_bytes_to_file, write_bytes_to_file_fail);
- tt_int_op(-1, ==, init_ext_or_cookie_authentication(1));
- tt_int_op(ext_or_auth_cookie_is_set, ==, 0);
+ tt_int_op(-1, OP_EQ, init_ext_or_cookie_authentication(1));
+ tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 0);
UNMOCK(write_bytes_to_file);
/* Now do the actual initialization. */
- tt_int_op(0, ==, init_ext_or_cookie_authentication(1));
- tt_int_op(ext_or_auth_cookie_is_set, ==, 1);
+ tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
+ tt_int_op(ext_or_auth_cookie_is_set, OP_EQ, 1);
cp = read_file_to_str(fn, RFTS_BIN, &st);
- tt_ptr_op(cp, !=, NULL);
- tt_u64_op((uint64_t)st.st_size, ==, 64);
- test_memeq(cp, "! Extended ORPort Auth Cookie !\x0a", 32);
- test_memeq(cp+32, ext_or_auth_cookie, 32);
+ tt_ptr_op(cp, OP_NE, NULL);
+ tt_u64_op((uint64_t)st.st_size, OP_EQ, 64);
+ tt_mem_op(cp,OP_EQ, "! Extended ORPort Auth Cookie !\x0a", 32);
+ tt_mem_op(cp+32,OP_EQ, ext_or_auth_cookie, 32);
memcpy(cookie0, ext_or_auth_cookie, 32);
- test_assert(!tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
+ tt_assert(!tor_mem_is_zero((char*)ext_or_auth_cookie, 32));
/* Operation should be idempotent. */
- tt_int_op(0, ==, init_ext_or_cookie_authentication(1));
- test_memeq(cookie0, ext_or_auth_cookie, 32);
+ tt_int_op(0, OP_EQ, init_ext_or_cookie_authentication(1));
+ tt_mem_op(cookie0,OP_EQ, ext_or_auth_cookie, 32);
done:
tor_free(cp);
@@ -237,8 +239,8 @@ test_ext_or_cookie_auth(void *arg)
(void)arg;
- tt_int_op(strlen(client_hash_input), ==, 46+32+32);
- tt_int_op(strlen(server_hash_input), ==, 46+32+32);
+ tt_int_op(strlen(client_hash_input), OP_EQ, 46+32+32);
+ tt_int_op(strlen(server_hash_input), OP_EQ, 46+32+32);
ext_or_auth_cookie = tor_malloc_zero(32);
memcpy(ext_or_auth_cookie, "s beside you? When I count, ther", 32);
@@ -258,20 +260,20 @@ test_ext_or_cookie_auth(void *arg)
*/
/* Wrong length */
- tt_int_op(-1, ==,
+ tt_int_op(-1, OP_EQ,
handle_client_auth_nonce(client_nonce, 33, &client_hash, &reply,
&reply_len));
- tt_int_op(-1, ==,
+ tt_int_op(-1, OP_EQ,
handle_client_auth_nonce(client_nonce, 31, &client_hash, &reply,
&reply_len));
/* Now let's try this for real! */
- tt_int_op(0, ==,
+ tt_int_op(0, OP_EQ,
handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
&reply_len));
- tt_int_op(reply_len, ==, 64);
- tt_ptr_op(reply, !=, NULL);
- tt_ptr_op(client_hash, !=, NULL);
+ tt_int_op(reply_len, OP_EQ, 64);
+ tt_ptr_op(reply, OP_NE, NULL);
+ tt_ptr_op(client_hash, OP_NE, NULL);
/* Fill in the server nonce into the hash inputs... */
memcpy(server_hash_input+46+32, reply+32, 32);
memcpy(client_hash_input+46+32, reply+32, 32);
@@ -280,15 +282,15 @@ test_ext_or_cookie_auth(void *arg)
46+32+32);
crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
46+32+32);
- test_memeq(hmac1, reply, 32);
- test_memeq(hmac2, client_hash, 32);
+ tt_mem_op(hmac1,OP_EQ, reply, 32);
+ tt_mem_op(hmac2,OP_EQ, client_hash, 32);
/* Now do it again and make sure that the results are *different* */
- tt_int_op(0, ==,
+ tt_int_op(0, OP_EQ,
handle_client_auth_nonce(client_nonce, 32, &client_hash2, &reply2,
&reply_len));
- test_memneq(reply2, reply, reply_len);
- test_memneq(client_hash2, client_hash, 32);
+ tt_mem_op(reply2,OP_NE, reply, reply_len);
+ tt_mem_op(client_hash2,OP_NE, client_hash, 32);
/* But that this one checks out too. */
memcpy(server_hash_input+46+32, reply2+32, 32);
memcpy(client_hash_input+46+32, reply2+32, 32);
@@ -297,8 +299,8 @@ test_ext_or_cookie_auth(void *arg)
46+32+32);
crypto_hmac_sha256(hmac2, (char*)ext_or_auth_cookie, 32, client_hash_input,
46+32+32);
- test_memeq(hmac1, reply2, 32);
- test_memeq(hmac2, client_hash2, 32);
+ tt_mem_op(hmac1,OP_EQ, reply2, 32);
+ tt_mem_op(hmac2,OP_EQ, client_hash2, 32);
done:
tor_free(reply);
@@ -334,12 +336,12 @@ test_ext_or_cookie_auth_testvec(void *arg)
MOCK(crypto_rand, crypto_rand_return_tse_str);
- tt_int_op(0, ==,
+ tt_int_op(0, OP_EQ,
handle_client_auth_nonce(client_nonce, 32, &client_hash, &reply,
&reply_len));
- tt_ptr_op(reply, !=, NULL );
- tt_uint_op(reply_len, ==, 64);
- test_memeq(reply+32, "te road There is always another ", 32);
+ tt_ptr_op(reply, OP_NE, NULL );
+ tt_uint_op(reply_len, OP_EQ, 64);
+ tt_mem_op(reply+32,OP_EQ, "te road There is always another ", 32);
/* HMACSHA256("Gliding wrapt in a brown mantle,"
* "ExtORPort authentication server-to-client hash"
* "But when I look ahead up the write road There is always another ");
@@ -402,11 +404,11 @@ handshake_start(or_connection_t *conn, int receiving)
} while (0)
#define CONTAINS(s,n) \
do { \
- tt_int_op((n), <=, sizeof(b)); \
- tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), ==, (n)); \
+ tt_int_op((n), OP_LE, sizeof(b)); \
+ tt_int_op(buf_datalen(TO_CONN(conn)->outbuf), OP_EQ, (n)); \
if ((n)) { \
fetch_from_buf(b, (n), TO_CONN(conn)->outbuf); \
- test_memeq(b, (s), (n)); \
+ tt_mem_op(b, OP_EQ, (s), (n)); \
} \
} while (0)
@@ -416,14 +418,15 @@ do_ext_or_handshake(or_connection_t *conn)
{
char b[256];
- tt_int_op(0, ==, connection_ext_or_start_auth(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
CONTAINS("\x01\x00", 2);
WRITE("\x01", 1);
WRITE("But when I look ahead up the whi", 32);
MOCK(crypto_rand, crypto_rand_return_tse_str);
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
UNMOCK(crypto_rand);
- tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
+ tt_int_op(TO_CONN(conn)->state, OP_EQ,
+ EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH);
CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
"\x02\x9f\x1a\xde\x76\x10\xd9\x10\x87\x8b\x62\xee\xb7\x40\x38\x21"
"te road There is always another ", 64);
@@ -431,10 +434,10 @@ do_ext_or_handshake(or_connection_t *conn)
WRITE("\xab\x39\x17\x32\xdd\x2e\xd9\x68\xcd\x40\xc0\x87\xd1\xb1\xf2\x5b"
"\x33\xb3\xcd\x77\xff\x79\xbd\x80\xc2\x07\x4b\xbf\x43\x81\x19\xa2",
32);
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("\x01", 1);
tt_assert(! TO_CONN(conn)->marked_for_close);
- tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_OPEN);
+ tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
done: ;
}
@@ -456,14 +459,14 @@ test_ext_or_handshake(void *arg)
init_connection_lists();
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
- tt_int_op(0, ==, connection_ext_or_start_auth(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
/* The server starts by telling us about the one supported authtype. */
CONTAINS("\x01\x00", 2);
/* Say the client hasn't responded yet. */
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
/* Let's say the client replies badly. */
WRITE("\x99", 1);
- tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
@@ -471,23 +474,23 @@ test_ext_or_handshake(void *arg)
/* Okay, try again. */
conn = or_connection_new(CONN_TYPE_EXT_OR, AF_INET);
- tt_int_op(0, ==, connection_ext_or_start_auth(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_start_auth(conn));
CONTAINS("\x01\x00", 2);
/* Let's say the client replies sensibly this time. "Yes, AUTHTYPE_COOKIE
* sounds delicious. Let's have some of that!" */
WRITE("\x01", 1);
/* Let's say that the client also sends part of a nonce. */
WRITE("But when I look ", 16);
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
- tt_int_op(TO_CONN(conn)->state, ==,
+ tt_int_op(TO_CONN(conn)->state, OP_EQ,
EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE);
/* Pump it again. Nothing should happen. */
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
/* send the rest of the nonce. */
WRITE("ahead up the whi", 16);
MOCK(crypto_rand, crypto_rand_return_tse_str);
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
UNMOCK(crypto_rand);
/* We should get the right reply from the server. */
CONTAINS("\xec\x80\xed\x6e\x54\x6d\x3b\x36\xfd\xfc\x22\xfe\x13\x15\x41\x6b"
@@ -496,7 +499,7 @@ test_ext_or_handshake(void *arg)
/* Send the wrong response. */
WRITE("not with a bang but a whimper...", 32);
MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
- tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("\x00", 1);
tt_assert(TO_CONN(conn)->marked_for_close);
/* XXXX Hold-open-until-flushed. */
@@ -515,32 +518,32 @@ test_ext_or_handshake(void *arg)
/* Now let's run through some messages. */
/* First let's send some junk and make sure it's ignored. */
WRITE("\xff\xf0\x00\x03""ABC", 7);
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
/* Now let's send a USERADDR command. */
WRITE("\x00\x01\x00\x0c""1.2.3.4:5678", 16);
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
- tt_int_op(TO_CONN(conn)->port, ==, 5678);
- tt_int_op(tor_addr_to_ipv4h(&TO_CONN(conn)->addr), ==, 0x01020304);
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
+ tt_int_op(TO_CONN(conn)->port, OP_EQ, 5678);
+ tt_int_op(tor_addr_to_ipv4h(&TO_CONN(conn)->addr), OP_EQ, 0x01020304);
/* Now let's send a TRANSPORT command. */
WRITE("\x00\x02\x00\x07""rfc1149", 11);
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
- tt_ptr_op(NULL, !=, conn->ext_or_transport);
- tt_str_op("rfc1149", ==, conn->ext_or_transport);
- tt_int_op(is_reading,==,1);
- tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_OPEN);
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
+ tt_ptr_op(NULL, OP_NE, conn->ext_or_transport);
+ tt_str_op("rfc1149", OP_EQ, conn->ext_or_transport);
+ tt_int_op(is_reading,OP_EQ,1);
+ tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_OPEN);
/* DONE */
WRITE("\x00\x00\x00\x00", 4);
- tt_int_op(0, ==, connection_ext_or_process_inbuf(conn));
- tt_int_op(TO_CONN(conn)->state, ==, EXT_OR_CONN_STATE_FLUSHING);
- tt_int_op(is_reading,==,0);
+ tt_int_op(0, OP_EQ, connection_ext_or_process_inbuf(conn));
+ tt_int_op(TO_CONN(conn)->state, OP_EQ, EXT_OR_CONN_STATE_FLUSHING);
+ tt_int_op(is_reading,OP_EQ,0);
CONTAINS("\x10\x00\x00\x00", 4);
- tt_int_op(handshake_start_called,==,0);
- tt_int_op(0, ==, connection_ext_or_finished_flushing(conn));
- tt_int_op(is_reading,==,1);
- tt_int_op(handshake_start_called,==,1);
- tt_int_op(TO_CONN(conn)->type, ==, CONN_TYPE_OR);
- tt_int_op(TO_CONN(conn)->state, ==, 0);
+ tt_int_op(handshake_start_called,OP_EQ,0);
+ tt_int_op(0, OP_EQ, connection_ext_or_finished_flushing(conn));
+ tt_int_op(is_reading,OP_EQ,1);
+ tt_int_op(handshake_start_called,OP_EQ,1);
+ tt_int_op(TO_CONN(conn)->type, OP_EQ, CONN_TYPE_OR);
+ tt_int_op(TO_CONN(conn)->state, OP_EQ, 0);
close_closeable_connections();
conn = NULL;
@@ -551,7 +554,7 @@ test_ext_or_handshake(void *arg)
/* USERADDR command with an extra NUL byte */
WRITE("\x00\x01\x00\x0d""1.2.3.4:5678\x00", 17);
MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
- tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
@@ -564,7 +567,7 @@ test_ext_or_handshake(void *arg)
/* TRANSPORT command with an extra NUL byte */
WRITE("\x00\x02\x00\x08""rfc1149\x00", 12);
MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
- tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
@@ -578,7 +581,7 @@ test_ext_or_handshake(void *arg)
C-identifier) */
WRITE("\x00\x02\x00\x07""rf*1149", 11);
MOCK(control_event_bootstrap_problem, ignore_bootstrap_problem);
- tt_int_op(-1, ==, connection_ext_or_process_inbuf(conn));
+ tt_int_op(-1, OP_EQ, connection_ext_or_process_inbuf(conn));
CONTAINS("", 0);
tt_assert(TO_CONN(conn)->marked_for_close);
close_closeable_connections();
diff --git a/src/test/test_guardfraction.c b/src/test/test_guardfraction.c
new file mode 100644
index 0000000000..57063c9085
--- /dev/null
+++ b/src/test/test_guardfraction.c
@@ -0,0 +1,418 @@
+/* Copyright (c) 2014, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define DIRSERV_PRIVATE
+#define ROUTERPARSE_PRIVATE
+#define NETWORKSTATUS_PRIVATE
+
+#include "orconfig.h"
+#include "or.h"
+#include "config.h"
+#include "dirserv.h"
+#include "container.h"
+#include "entrynodes.h"
+#include "util.h"
+#include "routerparse.h"
+#include "networkstatus.h"
+
+#include "test.h"
+#include "test_helpers.h"
+
+/** Generate a vote_routerstatus_t for a router with identity digest
+ * <b>digest_in_hex</b>. */
+static vote_routerstatus_t *
+gen_vote_routerstatus_for_tests(const char *digest_in_hex, int is_guard)
+{
+ int retval;
+ vote_routerstatus_t *vrs = NULL;
+ routerstatus_t *rs;
+
+ vrs = tor_malloc_zero(sizeof(vote_routerstatus_t));
+ rs = &vrs->status;
+
+ { /* Useful information for tests */
+ char digest_tmp[DIGEST_LEN];
+
+ /* Guard or not? */
+ rs->is_possible_guard = is_guard;
+
+ /* Fill in the fpr */
+ tt_int_op(strlen(digest_in_hex), ==, HEX_DIGEST_LEN);
+ retval = base16_decode(digest_tmp, sizeof(digest_tmp),
+ digest_in_hex, HEX_DIGEST_LEN);
+ tt_int_op(retval, ==, 0);
+ memcpy(rs->identity_digest, digest_tmp, DIGEST_LEN);
+ }
+
+ { /* Misc info (maybe not used in tests) */
+ vrs->version = tor_strdup("0.1.2.14");
+ strlcpy(rs->nickname, "router2", sizeof(rs->nickname));
+ memset(rs->descriptor_digest, 78, DIGEST_LEN);
+ rs->addr = 0x99008801;
+ rs->or_port = 443;
+ rs->dir_port = 8000;
+ /* all flags but running cleared */
+ rs->is_flagged_running = 1;
+ vrs->has_measured_bw = 1;
+ rs->has_bandwidth = 1;
+ }
+
+ return vrs;
+
+ done:
+ vote_routerstatus_free(vrs);
+
+ return NULL;
+}
+
+/** Make sure our parsers reject corrupted guardfraction files. */
+static void
+test_parse_guardfraction_file_bad(void *arg)
+{
+ int retval;
+ char *guardfraction_bad = NULL;
+ const char *yesterday_date_str = get_yesterday_date_str();
+
+ (void) arg;
+
+ /* Start parsing all those corrupted guardfraction files! */
+
+ /* Guardfraction file version is not a number! */
+ tor_asprintf(&guardfraction_bad,
+ "guardfraction-file-version nan\n"
+ "written-at %s\n"
+ "n-inputs 420 3\n"
+ "guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 100 420\n"
+ "guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n",
+ yesterday_date_str);
+
+ retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
+ tt_int_op(retval, ==, -1);
+ tor_free(guardfraction_bad);
+
+ /* This one does not have a date! Parsing should fail. */
+ tor_asprintf(&guardfraction_bad,
+ "guardfraction-file-version 1\n"
+ "written-at not_date\n"
+ "n-inputs 420 3\n"
+ "guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 100 420\n"
+ "guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n");
+
+ retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
+ tt_int_op(retval, ==, -1);
+ tor_free(guardfraction_bad);
+
+ /* This one has an incomplete n-inputs line, but parsing should
+ still continue. */
+ tor_asprintf(&guardfraction_bad,
+ "guardfraction-file-version 1\n"
+ "written-at %s\n"
+ "n-inputs biggie\n"
+ "guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 100 420\n"
+ "guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n",
+ yesterday_date_str);
+
+ retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
+ tt_int_op(retval, ==, 2);
+ tor_free(guardfraction_bad);
+
+ /* This one does not have a fingerprint in the guard line! */
+ tor_asprintf(&guardfraction_bad,
+ "guardfraction-file-version 1\n"
+ "written-at %s\n"
+ "n-inputs 420 3\n"
+ "guard-seen not_a_fingerprint 100 420\n",
+ yesterday_date_str);
+
+ retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
+ tt_int_op(retval, ==, 0);
+ tor_free(guardfraction_bad);
+
+ /* This one does not even have an integer guardfraction value. */
+ tor_asprintf(&guardfraction_bad,
+ "guardfraction-file-version 1\n"
+ "written-at %s\n"
+ "n-inputs 420 3\n"
+ "guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 NaN 420\n"
+ "guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n",
+ yesterday_date_str);
+
+ retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
+ tt_int_op(retval, ==, 1);
+ tor_free(guardfraction_bad);
+
+ /* This one is not a percentage (not in [0, 100]) */
+ tor_asprintf(&guardfraction_bad,
+ "guardfraction-file-version 1\n"
+ "written-at %s\n"
+ "n-inputs 420 3\n"
+ "guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 666 420\n"
+ "guard-seen 07B5547026DF3E229806E135CFA8552D56AFBABC 5 420\n",
+ yesterday_date_str);
+
+ retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
+ tt_int_op(retval, ==, 1);
+ tor_free(guardfraction_bad);
+
+ /* This one is not a percentage either (not in [0, 100]) */
+ tor_asprintf(&guardfraction_bad,
+ "guardfraction-file-version 1\n"
+ "written-at %s\n"
+ "n-inputs 420 3\n"
+ "guard-seen D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777 -3 420\n",
+ yesterday_date_str);
+
+ retval = dirserv_read_guardfraction_file_from_str(guardfraction_bad, NULL);
+ tt_int_op(retval, ==, 0);
+
+ done:
+ tor_free(guardfraction_bad);
+}
+
+/** Make sure that our test guardfraction file gets parsed properly, and
+ * its information are applied properly to our routerstatuses. */
+static void
+test_parse_guardfraction_file_good(void *arg)
+{
+ int retval;
+ vote_routerstatus_t *vrs_guard = NULL;
+ vote_routerstatus_t *vrs_dummy = NULL;
+ char *guardfraction_good = NULL;
+ const char *yesterday_date_str = get_yesterday_date_str();
+ smartlist_t *routerstatuses = smartlist_new();
+
+ /* Some test values that we need to validate later */
+ const char fpr_guard[] = "D0EDB47BEAD32D26D0A837F7D5357EC3AD3B8777";
+ const char fpr_unlisted[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+ const int guardfraction_value = 42;
+
+ (void) arg;
+
+ {
+ /* Populate the smartlist with some fake routerstatuses, so that
+ after parsing the guardfraction file we can check that their
+ elements got filled properly. */
+
+ /* This one is a guard */
+ vrs_guard = gen_vote_routerstatus_for_tests(fpr_guard, 1);
+ tt_assert(vrs_guard);
+ smartlist_add(routerstatuses, vrs_guard);
+
+ /* This one is a guard but it's not in the guardfraction file */
+ vrs_dummy = gen_vote_routerstatus_for_tests(fpr_unlisted, 1);
+ tt_assert(vrs_dummy);
+ smartlist_add(routerstatuses, vrs_dummy);
+ }
+
+ tor_asprintf(&guardfraction_good,
+ "guardfraction-file-version 1\n"
+ "written-at %s\n"
+ "n-inputs 420 3\n"
+ "guard-seen %s %d 420\n",
+ yesterday_date_str,
+ fpr_guard, guardfraction_value);
+
+ /* Read the guardfraction file */
+ retval = dirserv_read_guardfraction_file_from_str(guardfraction_good,
+ routerstatuses);
+ tt_int_op(retval, ==, 1);
+
+ { /* Test that routerstatus fields got filled properly */
+
+ /* The guardfraction fields of the guard should be filled. */
+ tt_assert(vrs_guard->status.has_guardfraction);
+ tt_int_op(vrs_guard->status.guardfraction_percentage,
+ ==,
+ guardfraction_value);
+
+ /* The guard that was not in the guardfraction file should not have
+ been touched either. */
+ tt_assert(!vrs_dummy->status.has_guardfraction);
+ }
+
+ done:
+ vote_routerstatus_free(vrs_guard);
+ vote_routerstatus_free(vrs_dummy);
+ smartlist_free(routerstatuses);
+ tor_free(guardfraction_good);
+}
+
+/** Make sure that the guardfraction bandwidths get calculated properly. */
+static void
+test_get_guardfraction_bandwidth(void *arg)
+{
+ guardfraction_bandwidth_t gf_bw;
+ const int orig_bw = 1000;
+
+ (void) arg;
+
+ /* A guard with bandwidth 1000 and GuardFraction 0.25, should have
+ bandwidth 250 as a guard and bandwidth 750 as a non-guard. */
+ guard_get_guardfraction_bandwidth(&gf_bw,
+ orig_bw, 25);
+
+ tt_int_op(gf_bw.guard_bw, ==, 250);
+ tt_int_op(gf_bw.non_guard_bw, ==, 750);
+
+ /* Also check the 'guard_bw + non_guard_bw == original_bw'
+ * invariant. */
+ tt_int_op(gf_bw.non_guard_bw + gf_bw.guard_bw, ==, orig_bw);
+
+ done:
+ ;
+}
+
+/** Parse the GuardFraction element of the consensus, and make sure it
+ * gets parsed correctly. */
+static void
+test_parse_guardfraction_consensus(void *arg)
+{
+ int retval;
+ or_options_t *options = get_options_mutable();
+
+ const char *guardfraction_str_good = "GuardFraction=66";
+ routerstatus_t rs_good;
+ routerstatus_t rs_no_guard;
+
+ const char *guardfraction_str_bad1 = "GuardFraction="; /* no value */
+ routerstatus_t rs_bad1;
+
+ const char *guardfraction_str_bad2 = "GuardFraction=166"; /* no percentage */
+ routerstatus_t rs_bad2;
+
+ (void) arg;
+
+ /* GuardFraction use is currently disabled by default. So we need to
+ manually enable it. */
+ options->UseGuardFraction = 1;
+
+ { /* Properly formatted GuardFraction. Check that it gets applied
+ correctly. */
+ memset(&rs_good, 0, sizeof(routerstatus_t));
+ rs_good.is_possible_guard = 1;
+
+ retval = routerstatus_parse_guardfraction(guardfraction_str_good,
+ NULL, NULL,
+ &rs_good);
+ tt_int_op(retval, ==, 0);
+ tt_assert(rs_good.has_guardfraction);
+ tt_int_op(rs_good.guardfraction_percentage, ==, 66);
+ }
+
+ { /* Properly formatted GuardFraction but router is not a
+ guard. GuardFraction should not get applied. */
+ memset(&rs_no_guard, 0, sizeof(routerstatus_t));
+ tt_assert(!rs_no_guard.is_possible_guard);
+
+ retval = routerstatus_parse_guardfraction(guardfraction_str_good,
+ NULL, NULL,
+ &rs_no_guard);
+ tt_int_op(retval, ==, 0);
+ tt_assert(!rs_no_guard.has_guardfraction);
+ }
+
+ { /* Bad GuardFraction. Function should fail and not apply. */
+ memset(&rs_bad1, 0, sizeof(routerstatus_t));
+ rs_bad1.is_possible_guard = 1;
+
+ retval = routerstatus_parse_guardfraction(guardfraction_str_bad1,
+ NULL, NULL,
+ &rs_bad1);
+ tt_int_op(retval, ==, -1);
+ tt_assert(!rs_bad1.has_guardfraction);
+ }
+
+ { /* Bad GuardFraction. Function should fail and not apply. */
+ memset(&rs_bad2, 0, sizeof(routerstatus_t));
+ rs_bad2.is_possible_guard = 1;
+
+ retval = routerstatus_parse_guardfraction(guardfraction_str_bad2,
+ NULL, NULL,
+ &rs_bad2);
+ tt_int_op(retval, ==, -1);
+ tt_assert(!rs_bad2.has_guardfraction);
+ }
+
+ done:
+ ;
+}
+
+/** Make sure that we use GuardFraction information when we should,
+ * according to the torrc option and consensus parameter. */
+static void
+test_should_apply_guardfraction(void *arg)
+{
+ networkstatus_t vote_enabled, vote_disabled, vote_missing;
+ or_options_t *options = get_options_mutable();
+
+ (void) arg;
+
+ { /* Fill the votes for later */
+ /* This one suggests enabled GuardFraction. */
+ memset(&vote_enabled, 0, sizeof(vote_enabled));
+ vote_enabled.net_params = smartlist_new();
+ smartlist_split_string(vote_enabled.net_params,
+ "UseGuardFraction=1", NULL, 0, 0);
+
+ /* This one suggests disabled GuardFraction. */
+ memset(&vote_disabled, 0, sizeof(vote_disabled));
+ vote_disabled.net_params = smartlist_new();
+ smartlist_split_string(vote_disabled.net_params,
+ "UseGuardFraction=0", NULL, 0, 0);
+
+ /* This one doesn't have GuardFraction at all. */
+ memset(&vote_missing, 0, sizeof(vote_missing));
+ vote_missing.net_params = smartlist_new();
+ smartlist_split_string(vote_missing.net_params,
+ "leon=trout", NULL, 0, 0);
+ }
+
+ /* If torrc option is set to yes, we should always use
+ * guardfraction.*/
+ options->UseGuardFraction = 1;
+ tt_int_op(should_apply_guardfraction(&vote_disabled), ==, 1);
+
+ /* If torrc option is set to no, we should never use
+ * guardfraction.*/
+ options->UseGuardFraction = 0;
+ tt_int_op(should_apply_guardfraction(&vote_enabled), ==, 0);
+
+ /* Now let's test torrc option set to auto. */
+ options->UseGuardFraction = -1;
+
+ /* If torrc option is set to auto, and consensus parameter is set to
+ * yes, we should use guardfraction. */
+ tt_int_op(should_apply_guardfraction(&vote_enabled), ==, 1);
+
+ /* If torrc option is set to auto, and consensus parameter is set to
+ * no, we should use guardfraction. */
+ tt_int_op(should_apply_guardfraction(&vote_disabled), ==, 0);
+
+ /* If torrc option is set to auto, and consensus parameter is not
+ * set, we should fallback to "no". */
+ tt_int_op(should_apply_guardfraction(&vote_missing), ==, 0);
+
+ done:
+ SMARTLIST_FOREACH(vote_enabled.net_params, char *, cp, tor_free(cp));
+ SMARTLIST_FOREACH(vote_disabled.net_params, char *, cp, tor_free(cp));
+ SMARTLIST_FOREACH(vote_missing.net_params, char *, cp, tor_free(cp));
+ smartlist_free(vote_enabled.net_params);
+ smartlist_free(vote_disabled.net_params);
+ smartlist_free(vote_missing.net_params);
+}
+
+struct testcase_t guardfraction_tests[] = {
+ { "parse_guardfraction_file_bad", test_parse_guardfraction_file_bad,
+ TT_FORK, NULL, NULL },
+ { "parse_guardfraction_file_good", test_parse_guardfraction_file_good,
+ TT_FORK, NULL, NULL },
+ { "parse_guardfraction_consensus", test_parse_guardfraction_consensus,
+ TT_FORK, NULL, NULL },
+ { "get_guardfraction_bandwidth", test_get_guardfraction_bandwidth,
+ TT_FORK, NULL, NULL },
+ { "should_apply_guardfraction", test_should_apply_guardfraction,
+ TT_FORK, NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
new file mode 100644
index 0000000000..c3ca0c3554
--- /dev/null
+++ b/src/test/test_helpers.c
@@ -0,0 +1,86 @@
+/* Copyright (c) 2014, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_helpers.c
+ * \brief Some helper functions to avoid code duplication in unit tests.
+ */
+
+#define ROUTERLIST_PRIVATE
+#include "orconfig.h"
+#include "or.h"
+
+#include "routerlist.h"
+#include "nodelist.h"
+
+#include "test.h"
+#include "test_helpers.h"
+
+#include "test_descriptors.inc"
+
+/* Return a statically allocated string representing yesterday's date
+ * in ISO format. We use it so that state file items are not found to
+ * be outdated. */
+const char *
+get_yesterday_date_str(void)
+{
+ static char buf[ISO_TIME_LEN+1];
+
+ time_t yesterday = time(NULL) - 24*60*60;
+ format_iso_time(buf, yesterday);
+ return buf;
+}
+
+/* NOP replacement for router_descriptor_is_older_than() */
+static int
+router_descriptor_is_older_than_replacement(const routerinfo_t *router,
+ int seconds)
+{
+ (void) router;
+ (void) seconds;
+ return 0;
+}
+
+/** Parse a file containing router descriptors and load them to our
+ routerlist. This function is used to setup an artificial network
+ so that we can conduct tests on it. */
+void
+helper_setup_fake_routerlist(void)
+{
+ int retval;
+ routerlist_t *our_routerlist = NULL;
+ smartlist_t *our_nodelist = NULL;
+
+ /* Read the file that contains our test descriptors. */
+
+ /* We need to mock this function otherwise the descriptors will not
+ accepted as they are too old. */
+ MOCK(router_descriptor_is_older_than,
+ router_descriptor_is_older_than_replacement);
+
+ /* Load all the test descriptors to the routerlist. */
+ retval = router_load_routers_from_string(TEST_DESCRIPTORS,
+ NULL, SAVED_IN_JOURNAL,
+ NULL, 0, NULL);
+ tt_int_op(retval, ==, HELPER_NUMBER_OF_DESCRIPTORS);
+
+ /* Sanity checking of routerlist and nodelist. */
+ our_routerlist = router_get_routerlist();
+ tt_int_op(smartlist_len(our_routerlist->routers), ==,
+ HELPER_NUMBER_OF_DESCRIPTORS);
+ routerlist_assert_ok(our_routerlist);
+
+ our_nodelist = nodelist_get_list();
+ tt_int_op(smartlist_len(our_nodelist), ==, HELPER_NUMBER_OF_DESCRIPTORS);
+
+ /* Mark all routers as non-guards but up and running! */
+ SMARTLIST_FOREACH_BEGIN(our_nodelist, node_t *, node) {
+ node->is_running = 1;
+ node->is_valid = 1;
+ node->is_possible_guard = 0;
+ } SMARTLIST_FOREACH_END(node);
+
+ done:
+ UNMOCK(router_descriptor_is_older_than);
+}
+
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
new file mode 100644
index 0000000000..369243b459
--- /dev/null
+++ b/src/test/test_helpers.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_TEST_HELPERS_H
+#define TOR_TEST_HELPERS_H
+
+const char *get_yesterday_date_str(void);
+
+/* Number of descriptors contained in test_descriptors.txt. */
+#define HELPER_NUMBER_OF_DESCRIPTORS 8
+
+void helper_setup_fake_routerlist(void);
+
+extern const char TEST_DESCRIPTORS[];
+
+#endif
+
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
index 99ef7dd570..67ef646aab 100644
--- a/src/test/test_hs.c
+++ b/src/test/test_hs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -7,9 +7,15 @@
**/
#define CONTROL_PRIVATE
+#define CIRCUITBUILD_PRIVATE
+
#include "or.h"
#include "test.h"
#include "control.h"
+#include "config.h"
+#include "routerset.h"
+#include "circuitbuild.h"
+#include "test_helpers.h"
/* mock ID digest and longname for node that's in nodelist */
#define HSDIR_EXIST_ID "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \
@@ -84,8 +90,8 @@ test_hs_desc_event(void *arg)
STR_HS_ID);
expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\
STR_HSDIR_EXIST_LONGNAME" "STR_HS_ID"\r\n";
- test_assert(received_msg);
- test_streq(received_msg, expected_msg);
+ tt_assert(received_msg);
+ tt_str_op(received_msg,OP_EQ, expected_msg);
tor_free(received_msg);
/* test received event */
@@ -93,26 +99,28 @@ test_hs_desc_event(void *arg)
control_event_hs_descriptor_received(&rend_query, HSDIR_EXIST_ID);
expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\
STR_HSDIR_EXIST_LONGNAME"\r\n";
- test_assert(received_msg);
- test_streq(received_msg, expected_msg);
+ tt_assert(received_msg);
+ tt_str_op(received_msg,OP_EQ, expected_msg);
tor_free(received_msg);
/* test failed event */
rend_query.auth_type = 2;
- control_event_hs_descriptor_failed(&rend_query, HSDIR_NONE_EXIST_ID);
+ control_event_hs_descriptor_failed(&rend_query, HSDIR_NONE_EXIST_ID,
+ "QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\
- STR_HSDIR_NONE_EXIST_LONGNAME"\r\n";
- test_assert(received_msg);
- test_streq(received_msg, expected_msg);
+ STR_HSDIR_NONE_EXIST_LONGNAME" REASON=QUERY_REJECTED\r\n";
+ tt_assert(received_msg);
+ tt_str_op(received_msg,OP_EQ, expected_msg);
tor_free(received_msg);
/* test invalid auth type */
rend_query.auth_type = 999;
- control_event_hs_descriptor_failed(&rend_query, HSDIR_EXIST_ID);
+ control_event_hs_descriptor_failed(&rend_query, HSDIR_EXIST_ID,
+ "QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\
- STR_HSDIR_EXIST_LONGNAME"\r\n";
- test_assert(received_msg);
- test_streq(received_msg, expected_msg);
+ STR_HSDIR_EXIST_LONGNAME" REASON=QUERY_REJECTED\r\n";
+ tt_assert(received_msg);
+ tt_str_op(received_msg,OP_EQ, expected_msg);
tor_free(received_msg);
done:
@@ -121,9 +129,83 @@ test_hs_desc_event(void *arg)
tor_free(received_msg);
}
+/* Make sure we always pick the right RP, given a well formatted
+ * Tor2webRendezvousPoints value. */
+static void
+test_pick_tor2web_rendezvous_node(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ const node_t *chosen_rp = NULL;
+ router_crn_flags_t flags = CRN_NEED_DESC;
+ int retval, i;
+ const char *tor2web_rendezvous_str = "test003r";
+
+ (void) arg;
+
+ /* Setup fake routerlist. */
+ helper_setup_fake_routerlist();
+
+ /* Parse Tor2webRendezvousPoints as a routerset. */
+ options->Tor2webRendezvousPoints = routerset_new();
+ retval = routerset_parse(options->Tor2webRendezvousPoints,
+ tor2web_rendezvous_str,
+ "test_tor2web_rp");
+ tt_int_op(retval, >=, 0);
+
+ /* Pick rendezvous point. Make sure the correct one is
+ picked. Repeat many times to make sure it works properly. */
+ for (i = 0; i < 50 ; i++) {
+ chosen_rp = pick_tor2web_rendezvous_node(flags, options);
+ tt_assert(chosen_rp);
+ tt_str_op(chosen_rp->ri->nickname, ==, tor2web_rendezvous_str);
+ }
+
+ done:
+ routerset_free(options->Tor2webRendezvousPoints);
+}
+
+/* Make sure we never pick an RP if Tor2webRendezvousPoints doesn't
+ * correspond to an actual node. */
+static void
+test_pick_bad_tor2web_rendezvous_node(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ const node_t *chosen_rp = NULL;
+ router_crn_flags_t flags = CRN_NEED_DESC;
+ int retval, i;
+ const char *tor2web_rendezvous_str = "dummy";
+
+ (void) arg;
+
+ /* Setup fake routerlist. */
+ helper_setup_fake_routerlist();
+
+ /* Parse Tor2webRendezvousPoints as a routerset. */
+ options->Tor2webRendezvousPoints = routerset_new();
+ retval = routerset_parse(options->Tor2webRendezvousPoints,
+ tor2web_rendezvous_str,
+ "test_tor2web_rp");
+ tt_int_op(retval, >=, 0);
+
+ /* Pick rendezvous point. Since Tor2webRendezvousPoints was set to a
+ dummy value, we shouldn't find any eligible RPs. */
+ for (i = 0; i < 50 ; i++) {
+ chosen_rp = pick_tor2web_rendezvous_node(flags, options);
+ tt_assert(!chosen_rp);
+ }
+
+ done:
+ routerset_free(options->Tor2webRendezvousPoints);
+}
+
struct testcase_t hs_tests[] = {
{ "hs_desc_event", test_hs_desc_event, TT_FORK,
NULL, NULL },
+ { "pick_tor2web_rendezvous_node", test_pick_tor2web_rendezvous_node, TT_FORK,
+ NULL, NULL },
+ { "pick_bad_tor2web_rendezvous_node",
+ test_pick_bad_tor2web_rendezvous_node, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c
index 69c1152229..0cab8ef4cc 100644
--- a/src/test/test_introduce.c
+++ b/src/test/test_introduce.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -290,48 +290,48 @@ do_parse_test(uint8_t *plaintext, size_t plaintext_len, int phase)
/* Get a key */
k = crypto_pk_new();
- test_assert(k);
+ tt_assert(k);
r = crypto_pk_read_private_key_from_string(k, AUTHORITY_SIGNKEY_1, -1);
- test_assert(!r);
+ tt_assert(!r);
/* Get digest for future comparison */
r = crypto_pk_get_digest(k, digest);
- test_assert(r >= 0);
+ tt_assert(r >= 0);
/* Make a cell out of it */
r = make_intro_from_plaintext(
plaintext, plaintext_len,
k, (void **)(&cell));
- test_assert(r > 0);
- test_assert(cell);
+ tt_assert(r > 0);
+ tt_assert(cell);
cell_len = r;
/* Do early parsing */
parsed_req = rend_service_begin_parse_intro(cell, cell_len, 2, &err_msg);
- test_assert(parsed_req);
- test_assert(!err_msg);
- test_memeq(parsed_req->pk, digest, DIGEST_LEN);
- test_assert(parsed_req->ciphertext);
- test_assert(parsed_req->ciphertext_len > 0);
+ tt_assert(parsed_req);
+ tt_assert(!err_msg);
+ tt_mem_op(parsed_req->pk,OP_EQ, digest, DIGEST_LEN);
+ tt_assert(parsed_req->ciphertext);
+ tt_assert(parsed_req->ciphertext_len > 0);
if (phase == EARLY_PARSE_ONLY)
goto done;
/* Do decryption */
r = rend_service_decrypt_intro(parsed_req, k, &err_msg);
- test_assert(!r);
- test_assert(!err_msg);
- test_assert(parsed_req->plaintext);
- test_assert(parsed_req->plaintext_len > 0);
+ tt_assert(!r);
+ tt_assert(!err_msg);
+ tt_assert(parsed_req->plaintext);
+ tt_assert(parsed_req->plaintext_len > 0);
if (phase == DECRYPT_ONLY)
goto done;
/* Do late parsing */
r = rend_service_parse_intro_plaintext(parsed_req, &err_msg);
- test_assert(!r);
- test_assert(!err_msg);
- test_assert(parsed_req->parsed);
+ tt_assert(!r);
+ tt_assert(!err_msg);
+ tt_assert(parsed_req->parsed);
done:
tor_free(cell);
@@ -371,14 +371,14 @@ make_intro_from_plaintext(
/* Compute key digest (will be first DIGEST_LEN octets of cell) */
r = crypto_pk_get_digest(key, cell);
- test_assert(r >= 0);
+ tt_assert(r >= 0);
/* Do encryption */
r = crypto_pk_public_hybrid_encrypt(
key, cell + DIGEST_LEN, ciphertext_size,
buf, len,
PK_PKCS1_OAEP_PADDING, 0);
- test_assert(r >= 0);
+ tt_assert(r >= 0);
/* Figure out cell length */
cell_len = DIGEST_LEN + r;
@@ -394,8 +394,9 @@ make_intro_from_plaintext(
*/
static void
-test_introduce_decrypt_v0(void)
+test_introduce_decrypt_v0(void *arg)
{
+ (void)arg;
do_decrypt_test(v0_test_plaintext, sizeof(v0_test_plaintext));
}
@@ -403,8 +404,9 @@ test_introduce_decrypt_v0(void)
*/
static void
-test_introduce_decrypt_v1(void)
+test_introduce_decrypt_v1(void *arg)
{
+ (void)arg;
do_decrypt_test(v1_test_plaintext, sizeof(v1_test_plaintext));
}
@@ -412,8 +414,9 @@ test_introduce_decrypt_v1(void)
*/
static void
-test_introduce_decrypt_v2(void)
+test_introduce_decrypt_v2(void *arg)
{
+ (void)arg;
do_decrypt_test(v2_test_plaintext, sizeof(v2_test_plaintext));
}
@@ -421,8 +424,9 @@ test_introduce_decrypt_v2(void)
*/
static void
-test_introduce_decrypt_v3(void)
+test_introduce_decrypt_v3(void *arg)
{
+ (void)arg;
do_decrypt_test(
v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
do_decrypt_test(
@@ -433,8 +437,9 @@ test_introduce_decrypt_v3(void)
*/
static void
-test_introduce_early_parse_v0(void)
+test_introduce_early_parse_v0(void *arg)
{
+ (void)arg;
do_early_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
}
@@ -442,8 +447,9 @@ test_introduce_early_parse_v0(void)
*/
static void
-test_introduce_early_parse_v1(void)
+test_introduce_early_parse_v1(void *arg)
{
+ (void)arg;
do_early_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
}
@@ -451,8 +457,9 @@ test_introduce_early_parse_v1(void)
*/
static void
-test_introduce_early_parse_v2(void)
+test_introduce_early_parse_v2(void *arg)
{
+ (void)arg;
do_early_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
}
@@ -460,8 +467,9 @@ test_introduce_early_parse_v2(void)
*/
static void
-test_introduce_early_parse_v3(void)
+test_introduce_early_parse_v3(void *arg)
{
+ (void)arg;
do_early_parse_test(
v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
do_early_parse_test(
@@ -472,8 +480,9 @@ test_introduce_early_parse_v3(void)
*/
static void
-test_introduce_late_parse_v0(void)
+test_introduce_late_parse_v0(void *arg)
{
+ (void)arg;
do_late_parse_test(v0_test_plaintext, sizeof(v0_test_plaintext));
}
@@ -481,8 +490,9 @@ test_introduce_late_parse_v0(void)
*/
static void
-test_introduce_late_parse_v1(void)
+test_introduce_late_parse_v1(void *arg)
{
+ (void)arg;
do_late_parse_test(v1_test_plaintext, sizeof(v1_test_plaintext));
}
@@ -490,8 +500,9 @@ test_introduce_late_parse_v1(void)
*/
static void
-test_introduce_late_parse_v2(void)
+test_introduce_late_parse_v2(void *arg)
{
+ (void)arg;
do_late_parse_test(v2_test_plaintext, sizeof(v2_test_plaintext));
}
@@ -499,8 +510,9 @@ test_introduce_late_parse_v2(void)
*/
static void
-test_introduce_late_parse_v3(void)
+test_introduce_late_parse_v3(void *arg)
{
+ (void)arg;
do_late_parse_test(
v3_no_auth_test_plaintext, sizeof(v3_no_auth_test_plaintext));
do_late_parse_test(
@@ -508,7 +520,7 @@ test_introduce_late_parse_v3(void)
}
#define INTRODUCE_LEGACY(name) \
- { #name, legacy_test_helper, 0, &legacy_setup, test_introduce_ ## name }
+ { #name, test_introduce_ ## name , 0, NULL, NULL }
struct testcase_t introduce_tests[] = {
INTRODUCE_LEGACY(early_parse_v0),
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index 7e558f83b1..6205b3bdc5 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -19,11 +19,11 @@ test_get_sigsafe_err_fds(void *arg)
int n;
log_severity_list_t include_bug, no_bug, no_bug2;
(void) arg;
- init_logging();
+ init_logging(1);
n = tor_log_get_sigsafe_err_fds(&fds);
- tt_int_op(n, ==, 1);
- tt_int_op(fds[0], ==, STDERR_FILENO);
+ tt_int_op(n, OP_EQ, 1);
+ tt_int_op(fds[0], OP_EQ, STDERR_FILENO);
set_log_severity_config(LOG_WARN, LOG_ERR, &include_bug);
set_log_severity_config(LOG_WARN, LOG_ERR, &no_bug);
@@ -40,26 +40,26 @@ test_get_sigsafe_err_fds(void *arg)
tor_log_update_sigsafe_err_fds();
n = tor_log_get_sigsafe_err_fds(&fds);
- tt_int_op(n, ==, 2);
- tt_int_op(fds[0], ==, STDERR_FILENO);
- tt_int_op(fds[1], ==, 3);
+ tt_int_op(n, OP_EQ, 2);
+ tt_int_op(fds[0], OP_EQ, STDERR_FILENO);
+ tt_int_op(fds[1], OP_EQ, 3);
/* Allow STDOUT to replace STDERR. */
add_stream_log(&include_bug, "dummy-4", STDOUT_FILENO);
tor_log_update_sigsafe_err_fds();
n = tor_log_get_sigsafe_err_fds(&fds);
- tt_int_op(n, ==, 2);
- tt_int_op(fds[0], ==, 3);
- tt_int_op(fds[1], ==, STDOUT_FILENO);
+ tt_int_op(n, OP_EQ, 2);
+ tt_int_op(fds[0], OP_EQ, 3);
+ tt_int_op(fds[1], OP_EQ, STDOUT_FILENO);
/* But don't allow it to replace explicit STDERR. */
add_stream_log(&include_bug, "dummy-5", STDERR_FILENO);
tor_log_update_sigsafe_err_fds();
n = tor_log_get_sigsafe_err_fds(&fds);
- tt_int_op(n, ==, 3);
- tt_int_op(fds[0], ==, STDERR_FILENO);
- tt_int_op(fds[1], ==, STDOUT_FILENO);
- tt_int_op(fds[2], ==, 3);
+ tt_int_op(n, OP_EQ, 3);
+ tt_int_op(fds[0], OP_EQ, STDERR_FILENO);
+ tt_int_op(fds[1], OP_EQ, STDOUT_FILENO);
+ tt_int_op(fds[2], OP_EQ, 3);
/* Don't overflow the array. */
{
@@ -70,7 +70,7 @@ test_get_sigsafe_err_fds(void *arg)
}
tor_log_update_sigsafe_err_fds();
n = tor_log_get_sigsafe_err_fds(&fds);
- tt_int_op(n, ==, 8);
+ tt_int_op(n, OP_EQ, 8);
done:
;
@@ -87,9 +87,9 @@ test_sigsafe_err(void *arg)
set_log_severity_config(LOG_WARN, LOG_ERR, &include_bug);
- init_logging();
+ init_logging(1);
mark_logs_temp();
- add_file_log(&include_bug, fn);
+ add_file_log(&include_bug, fn, 0);
tor_log_update_sigsafe_err_fds();
close_temp_logs();
@@ -109,7 +109,7 @@ test_sigsafe_err(void *arg)
tt_assert(content != NULL);
tor_split_lines(lines, content, (int)strlen(content));
- tt_int_op(smartlist_len(lines), >=, 5);
+ tt_int_op(smartlist_len(lines), OP_GE, 5);
if (strstr(smartlist_get(lines, 0), "opening new log file"))
smartlist_del_keeporder(lines, 0);
@@ -119,7 +119,7 @@ test_sigsafe_err(void *arg)
tt_assert(!strcmpstart(smartlist_get(lines, 2), "Minimal."));
/* Next line is blank. */
tt_assert(!strcmpstart(smartlist_get(lines, 3), "=============="));
- tt_str_op(smartlist_get(lines, 4), ==,
+ tt_str_op(smartlist_get(lines, 4), OP_EQ,
"Testing any attempt to manually log from a signal.");
done:
diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c
index 78f4823b87..c0376348dd 100644
--- a/src/test/test_microdesc.c
+++ b/src/test/test_microdesc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2013, The Tor Project, Inc. */
+/* Copyright (c) 2010-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -7,11 +7,16 @@
#include "config.h"
#include "dirvote.h"
#include "microdesc.h"
+#include "networkstatus.h"
#include "routerlist.h"
#include "routerparse.h"
#include "test.h"
+#include <openssl/rsa.h>
+#include <openssl/bn.h>
+#include <openssl/pem.h>
+
#ifdef _WIN32
/* For mkdir() */
#include <direct.h>
@@ -70,9 +75,9 @@ test_md_cache(void *data)
tor_free(options->DataDirectory);
options->DataDirectory = tor_strdup(get_fname("md_datadir_test"));
#ifdef _WIN32
- tt_int_op(0, ==, mkdir(options->DataDirectory));
+ tt_int_op(0, OP_EQ, mkdir(options->DataDirectory));
#else
- tt_int_op(0, ==, mkdir(options->DataDirectory, 0700));
+ tt_int_op(0, OP_EQ, mkdir(options->DataDirectory, 0700));
#endif
tt_assert(!strcmpstart(test_md3_noannotation, "onion-key"));
@@ -86,7 +91,7 @@ test_md_cache(void *data)
added = microdescs_add_to_cache(mc, test_md1, NULL, SAVED_NOWHERE, 0,
time1, NULL);
- tt_int_op(1, ==, smartlist_len(added));
+ tt_int_op(1, OP_EQ, smartlist_len(added));
md1 = smartlist_get(added, 0);
smartlist_free(added);
added = NULL;
@@ -95,7 +100,7 @@ test_md_cache(void *data)
added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
time2, wanted);
/* Should fail, since we didn't list test_md2's digest in wanted */
- tt_int_op(0, ==, smartlist_len(added));
+ tt_int_op(0, OP_EQ, smartlist_len(added));
smartlist_free(added);
added = NULL;
@@ -104,75 +109,75 @@ test_md_cache(void *data)
added = microdescs_add_to_cache(mc, test_md2, NULL, SAVED_NOWHERE, 0,
time2, wanted);
/* Now it can work. md2 should have been added */
- tt_int_op(1, ==, smartlist_len(added));
+ tt_int_op(1, OP_EQ, smartlist_len(added));
md2 = smartlist_get(added, 0);
/* And it should have gotten removed from 'wanted' */
- tt_int_op(smartlist_len(wanted), ==, 1);
- test_mem_op(smartlist_get(wanted, 0), ==, d3, DIGEST256_LEN);
+ tt_int_op(smartlist_len(wanted), OP_EQ, 1);
+ tt_mem_op(smartlist_get(wanted, 0), OP_EQ, d3, DIGEST256_LEN);
smartlist_free(added);
added = NULL;
added = microdescs_add_to_cache(mc, test_md3, NULL,
SAVED_NOWHERE, 0, -1, NULL);
/* Must fail, since SAVED_NOWHERE precludes annotations */
- tt_int_op(0, ==, smartlist_len(added));
+ tt_int_op(0, OP_EQ, smartlist_len(added));
smartlist_free(added);
added = NULL;
added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
SAVED_NOWHERE, 0, time3, NULL);
/* Now it can work */
- tt_int_op(1, ==, smartlist_len(added));
+ tt_int_op(1, OP_EQ, smartlist_len(added));
md3 = smartlist_get(added, 0);
smartlist_free(added);
added = NULL;
/* Okay. We added 1...3. Let's poke them to see how they look, and make
* sure they're really in the journal. */
- tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
- tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
- tt_ptr_op(md3, ==, microdesc_cache_lookup_by_digest256(mc, d3));
-
- tt_int_op(md1->last_listed, ==, time1);
- tt_int_op(md2->last_listed, ==, time2);
- tt_int_op(md3->last_listed, ==, time3);
-
- tt_int_op(md1->saved_location, ==, SAVED_IN_JOURNAL);
- tt_int_op(md2->saved_location, ==, SAVED_IN_JOURNAL);
- tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL);
-
- tt_int_op(md1->bodylen, ==, strlen(test_md1));
- tt_int_op(md2->bodylen, ==, strlen(test_md2));
- tt_int_op(md3->bodylen, ==, strlen(test_md3_noannotation));
- test_mem_op(md1->body, ==, test_md1, strlen(test_md1));
- test_mem_op(md2->body, ==, test_md2, strlen(test_md2));
- test_mem_op(md3->body, ==, test_md3_noannotation,
+ tt_ptr_op(md1, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d1));
+ tt_ptr_op(md2, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d2));
+ tt_ptr_op(md3, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d3));
+
+ tt_int_op(md1->last_listed, OP_EQ, time1);
+ tt_int_op(md2->last_listed, OP_EQ, time2);
+ tt_int_op(md3->last_listed, OP_EQ, time3);
+
+ tt_int_op(md1->saved_location, OP_EQ, SAVED_IN_JOURNAL);
+ tt_int_op(md2->saved_location, OP_EQ, SAVED_IN_JOURNAL);
+ tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_JOURNAL);
+
+ tt_int_op(md1->bodylen, OP_EQ, strlen(test_md1));
+ tt_int_op(md2->bodylen, OP_EQ, strlen(test_md2));
+ tt_int_op(md3->bodylen, OP_EQ, strlen(test_md3_noannotation));
+ tt_mem_op(md1->body, OP_EQ, test_md1, strlen(test_md1));
+ tt_mem_op(md2->body, OP_EQ, test_md2, strlen(test_md2));
+ tt_mem_op(md3->body, OP_EQ, test_md3_noannotation,
strlen(test_md3_noannotation));
tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs.new",
options->DataDirectory);
s = read_file_to_str(fn, RFTS_BIN, NULL);
tt_assert(s);
- test_mem_op(md1->body, ==, s + md1->off, md1->bodylen);
- test_mem_op(md2->body, ==, s + md2->off, md2->bodylen);
- test_mem_op(md3->body, ==, s + md3->off, md3->bodylen);
+ tt_mem_op(md1->body, OP_EQ, s + md1->off, md1->bodylen);
+ tt_mem_op(md2->body, OP_EQ, s + md2->off, md2->bodylen);
+ tt_mem_op(md3->body, OP_EQ, s + md3->off, md3->bodylen);
- tt_ptr_op(md1->family, ==, NULL);
- tt_ptr_op(md3->family, !=, NULL);
- tt_int_op(smartlist_len(md3->family), ==, 3);
- tt_str_op(smartlist_get(md3->family, 0), ==, "nodeX");
+ tt_ptr_op(md1->family, OP_EQ, NULL);
+ tt_ptr_op(md3->family, OP_NE, NULL);
+ tt_int_op(smartlist_len(md3->family), OP_EQ, 3);
+ tt_str_op(smartlist_get(md3->family, 0), OP_EQ, "nodeX");
/* Now rebuild the cache! */
- tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
+ tt_int_op(microdesc_cache_rebuild(mc, 1), OP_EQ, 0);
- tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE);
- tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE);
- tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE);
+ tt_int_op(md1->saved_location, OP_EQ, SAVED_IN_CACHE);
+ tt_int_op(md2->saved_location, OP_EQ, SAVED_IN_CACHE);
+ tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_CACHE);
/* The journal should be empty now */
tor_free(s);
s = read_file_to_str(fn, RFTS_BIN, NULL);
- tt_str_op(s, ==, "");
+ tt_str_op(s, OP_EQ, "");
tor_free(s);
tor_free(fn);
@@ -180,9 +185,9 @@ test_md_cache(void *data)
tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
options->DataDirectory);
s = read_file_to_str(fn, RFTS_BIN, NULL);
- test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1));
- test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2));
- test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation));
+ tt_mem_op(md1->body, OP_EQ, s + md1->off, strlen(test_md1));
+ tt_mem_op(md2->body, OP_EQ, s + md2->off, strlen(test_md2));
+ tt_mem_op(md3->body, OP_EQ, s + md3->off, strlen(test_md3_noannotation));
/* Okay, now we are going to forget about the cache entirely, and reload it
* from the disk. */
@@ -191,44 +196,44 @@ test_md_cache(void *data)
md1 = microdesc_cache_lookup_by_digest256(mc, d1);
md2 = microdesc_cache_lookup_by_digest256(mc, d2);
md3 = microdesc_cache_lookup_by_digest256(mc, d3);
- test_assert(md1);
- test_assert(md2);
- test_assert(md3);
- test_mem_op(md1->body, ==, s + md1->off, strlen(test_md1));
- test_mem_op(md2->body, ==, s + md2->off, strlen(test_md2));
- test_mem_op(md3->body, ==, s + md3->off, strlen(test_md3_noannotation));
+ tt_assert(md1);
+ tt_assert(md2);
+ tt_assert(md3);
+ tt_mem_op(md1->body, OP_EQ, s + md1->off, strlen(test_md1));
+ tt_mem_op(md2->body, OP_EQ, s + md2->off, strlen(test_md2));
+ tt_mem_op(md3->body, OP_EQ, s + md3->off, strlen(test_md3_noannotation));
- tt_int_op(md1->last_listed, ==, time1);
- tt_int_op(md2->last_listed, ==, time2);
- tt_int_op(md3->last_listed, ==, time3);
+ tt_int_op(md1->last_listed, OP_EQ, time1);
+ tt_int_op(md2->last_listed, OP_EQ, time2);
+ tt_int_op(md3->last_listed, OP_EQ, time3);
/* Okay, now we are going to clear out everything older than a week old.
* In practice, that means md3 */
microdesc_cache_clean(mc, time(NULL)-7*24*60*60, 1/*force*/);
- tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
- tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
- tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));
+ tt_ptr_op(md1, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d1));
+ tt_ptr_op(md2, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d2));
+ tt_ptr_op(NULL, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d3));
md3 = NULL; /* it's history now! */
/* rebuild again, make sure it stays gone. */
- tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
- tt_ptr_op(md1, ==, microdesc_cache_lookup_by_digest256(mc, d1));
- tt_ptr_op(md2, ==, microdesc_cache_lookup_by_digest256(mc, d2));
- tt_ptr_op(NULL, ==, microdesc_cache_lookup_by_digest256(mc, d3));
+ tt_int_op(microdesc_cache_rebuild(mc, 1), OP_EQ, 0);
+ tt_ptr_op(md1, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d1));
+ tt_ptr_op(md2, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d2));
+ tt_ptr_op(NULL, OP_EQ, microdesc_cache_lookup_by_digest256(mc, d3));
/* Re-add md3, and make sure we can rebuild the cache. */
added = microdescs_add_to_cache(mc, test_md3_noannotation, NULL,
SAVED_NOWHERE, 0, time3, NULL);
- tt_int_op(1, ==, smartlist_len(added));
+ tt_int_op(1, OP_EQ, smartlist_len(added));
md3 = smartlist_get(added, 0);
smartlist_free(added);
added = NULL;
- tt_int_op(md1->saved_location, ==, SAVED_IN_CACHE);
- tt_int_op(md2->saved_location, ==, SAVED_IN_CACHE);
- tt_int_op(md3->saved_location, ==, SAVED_IN_JOURNAL);
+ tt_int_op(md1->saved_location, OP_EQ, SAVED_IN_CACHE);
+ tt_int_op(md2->saved_location, OP_EQ, SAVED_IN_CACHE);
+ tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_JOURNAL);
- tt_int_op(microdesc_cache_rebuild(mc, 1), ==, 0);
- tt_int_op(md3->saved_location, ==, SAVED_IN_CACHE);
+ tt_int_op(microdesc_cache_rebuild(mc, 1), OP_EQ, 0);
+ tt_int_op(md3->saved_location, OP_EQ, SAVED_IN_CACHE);
done:
if (options)
@@ -268,9 +273,9 @@ test_md_cache_broken(void *data)
options->DataDirectory = tor_strdup(get_fname("md_datadir_test2"));
#ifdef _WIN32
- tt_int_op(0, ==, mkdir(options->DataDirectory));
+ tt_int_op(0, OP_EQ, mkdir(options->DataDirectory));
#else
- tt_int_op(0, ==, mkdir(options->DataDirectory, 0700));
+ tt_int_op(0, OP_EQ, mkdir(options->DataDirectory, 0700));
#endif
tor_asprintf(&fn, "%s"PATH_SEPARATOR"cached-microdescs",
@@ -367,10 +372,10 @@ test_md_generate(void *arg)
microdesc_t *md = NULL;
(void)arg;
- ri = router_parse_entry_from_string(test_ri, NULL, 0, 0, NULL);
+ ri = router_parse_entry_from_string(test_ri, NULL, 0, 0, NULL, NULL);
tt_assert(ri);
md = dirvote_create_microdescriptor(ri, 8);
- tt_str_op(md->body, ==, test_md_8);
+ tt_str_op(md->body, OP_EQ, test_md_8);
/* XXXX test family lines. */
/* XXXX test method 14 for A lines. */
@@ -379,22 +384,375 @@ test_md_generate(void *arg)
microdesc_free(md);
md = NULL;
md = dirvote_create_microdescriptor(ri, 16);
- tt_str_op(md->body, ==, test_md_16);
+ tt_str_op(md->body, OP_EQ, test_md_16);
microdesc_free(md);
md = NULL;
md = dirvote_create_microdescriptor(ri, 18);
- tt_str_op(md->body, ==, test_md_18);
+ tt_str_op(md->body, OP_EQ, test_md_18);
done:
microdesc_free(md);
routerinfo_free(ri);
}
+/* Taken at random from my ~/.tor/cached-microdescs file and then
+ * hand-munged */
+static const char MD_PARSE_TEST_DATA[] =
+ /* Good 0 */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANsKd1GRfOuSR1MkcwKqs6SVy4Gi/JXplt/bHDkIGm6Q96TeJ5uyVgUL\n"
+ "DBr/ij6+JqgVFeriuiMzHKREytzjdaTuKsKBFFpLwb+Ppcjr5nMIH/AR6/aHO8hW\n"
+ "T3B9lx5T6Kl7CqZ4yqXxYRHzn50EPTIZuz0y9se4J4gi9mLmL+pHAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "p accept 20-23,43,53,79-81,88,110,143,194,220,443,464,531,543-544\n"
+ "id rsa1024 GEo59/iR1GWSIWZDzXTd5QxtqnU\n"
+ /* Bad 0: I've messed with the onion-key in the second one. */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMr4o/pflVwscx11vC1AKEADlKEqnhpvCIjAEzNEenMhvGQHRlA0EXLC\n"
+ "7G7O5bhnCwEHqK8Pvg8cuX/fD8v08TF1EVPhwPa0UI6ab8KnPP2F!!!!!!b92DG7EQIk3q\n"
+ "d68Uxp7E9/t3v1WWZjzDqvEe0par6ul+DKW6HMlTGebFo5Q4e8R1AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key 761Dmm27via7lXygNHM3l+oJLrYU2Nye0Uz4pkpipyY=\n"
+ "p accept 53\n"
+ "id rsa1024 3Y4fwXhtgkdGDZ5ef5mtb6TJRQQ\n"
+ /* Good 1 */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANsMSjVi3EX8ZHfm/dvPF6KdVR66k1tVul7Jp+dDbDajBYNhgKRzVCxy\n"
+ "Yac1CBuQjOqK89tKap9PQBnhF087eDrfaZDqYTLwB2W2sBJncVej15WEPXPRBifo\n"
+ "iFZ8337kgczkaY+IOfSuhtbOUyDOoDpRJheIKBNq0ZiTqtLbbadVAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key ncfiHJjSgdDEW/gc6q6/7idac7j+x7ejQrRm6i75pGA=\n"
+ "p accept 443,6660-6669,6697,7000-7001\n"
+ "id rsa1024 XXuLzw3mfBELEq3veXoNhdehwD4\n"
+ /* Good 2 */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANQfBlrHrh9F/CAOytrNFgi0ikWMW/HZxuoszF9X+AQ+MudR8bcxxOGl\n"
+ "1RFwb74s8E3uuzrCkNFvSw9Ar1L02F2DOX0gLsxEGuYC4Ave9NUteGqSqDyEJQUJ\n"
+ "KlfxCPn2qC9nvNT7wR/Dg2WRvAEKnJmkpb57N3+WSAOPLjKOFEz3AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AppBt6CSeb1kKid/36ototmFA24ddfW5JpjWPLuoJgs=\n"
+ "id rsa1024 6y60AEI9a1PUUlRPO0YQT9WzrjI\n"
+ /* Bad 1: Here I've messed with the ntor key */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAPjy2HacU3jDNO5nTOFGSwNa0qKCNn4yhtrDVcAJ5alIQeBWZZGJLZ0q\n"
+ "Cqylw1vYqxu8E09g+QXXFbAgBv1U9TICaATxrIJhIJzc8TJPhqJemp1kq0DvHLDx\n"
+ "mxwlkNnCD/P5NS+JYB3EjOlU9EnSKUWNU61+Co344m2JqhEau40vAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key 4i2Fp9JHTUr1uQs0pxD5j5spl4/RG56S2P0gQxU=\n"
+ "id rsa1024 nMRmNEGysA0NmlALVaUmI7D5jLU\n"
+ /* Good 3: I've added a weird token in this one. This shouldn't prevent
+ * it parsing */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKmosxudyNA/yJNz3S890VqV/ebylzoD11Sc0b/d5tyNNaNZjcYy5vRD\n"
+ "kwyxFRMbP2TLZQ1zRfNwY7IDnYjU2SbW0pxuM6M8WRtsmx/YOE3kHMVAFJNrTUqU\n"
+ "6D1zB3IiRDS5q5+NoRxwqo+hYUck60O3WTwEoqb+l3lvXeu7z9rFAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "flux-capacitor 1.21 GW\n"
+ "ntor-onion-key MWBoEkl+RlBiGX44XKIvTSqbznTNZStOmUYtcYRQQyY=\n"
+ "id rsa1024 R+A5O9qRvRac4FT3C4L2QnFyxsc\n"
+ /* Good 4: Here I've made the 'id rsa' token odd. It should still parse
+ * just fine. */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAOh+WMkdNe/Pkjb8UjQyfLOlFgpuVFrxAIGnJsmWWx0yBE97DQxGyh2n\n"
+ "h8G5OJZHRarJQyCIf7vpZQAi0oP0OkGGaCaDQsM+D8TnqhnU++RWGnMqY/cXxPrL\n"
+ "MEq+n6aGiLmzkO7ah8yorZpoREk4GqLUIN89/tHHGOhJL3c4CPGjAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
+ "id rsa1234 jlqAKFD2E7uMKv+8TmKSeo7NBho\n"
+ /* Good 5: Extra id type. */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAMdgPPc5uaw4y/q+SUTN/I8Y+Gvdx9kKgWV4dmDGJ0mxsVZmo1v6+v3F\n"
+ "12M2f9m99G3WB8F8now29C+9XyEv8MBHj1lHRdUFHSQes3YTFvDNlgj+FjLqO5TJ\n"
+ "adOOmfu4DCUUtUEDyQKbNVL4EkMTXY73omTVsjcH3xxFjTx5wixhAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key AAVnWZcnDbxasdZwKqb4fL6O9sZV+XsRNHTpNd1YMz8=\n"
+ "id rsa1024 72EfBL11QuwX2vU8y+p9ExGfGEg\n"
+ "id expolding hedgehog 0+A5O9qRvRac4FT3C4L2QnFyxsc\n"
+ /* Good 6: I've given this a bogus policy. It should parse. */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALNuufwhPMF8BooxYMNvhYJMPqUB8hQDt8wGmPKphJcD1sVD1i4gAZM2\n"
+ "HIo+zUBlljDrRWL5NzVzd1yxUJAiQxvXS5dRRFY3B70M7wTVpXw53xe0/BM5t1AX\n"
+ "n0MFk7Jl6XIKMlzRalZvmMvE/odtyWXkP4Nd1MyZ1QcIwrQ2iwyrAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "p condone 1-10\n"
+ "ntor-onion-key 2/nMJ+L4dd/2GpMyTYjz3zC59MvQy4MIzJZhdzKHekg=\n"
+ "id rsa1024 FHyh10glEMA6MCmBb5R9Y+X/MhQ\n"
+ /* Good 7: I've given this one another sort of odd policy. Should parse. */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAKcd3FmQ8iAADghyvX8eca0ePqtJ2w1IDdUdTlf5Y/8+OMdp//sD01yC\n"
+ "YmiX45LK5ge1O3AzcakYCO6fb3pyIqvXdvm24OjyYZELQ40cmKSLjdhcSf4Fr/N9\n"
+ "uR/CkknR9cEePu1wZ5WBIGmGdXI6s7t3LB+e7XFyBYAx6wMGlnX7AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "p accept frogs-mice\n"
+ "ntor-onion-key AMxvhaQ1Qg7jBJFoyHuPRgETvLbFmJ194hExV24FuAI=\n"
+ "family $D8CFEA0D996F5D1473D2063C041B7910DB23981E\n"
+ "id rsa1024 d0VVZC/cHh1P3y4MMbfKlQHFycc\n"
+ /* Good 8: This one has the ntor-onion-key without terminating =. That's
+ * allowed. */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAL438YfjrJE2SPqkkXeQwICygu8KNO54Juj6sjqk5hgsiazIWMOBgbaX\n"
+ "LIRqPNGaiSq01xSqwjwCBCfwZYT/nSdDBqj1h9aoR8rnjxZjyQ+m3rWpdDqeCDMx\n"
+ "I3NgZ5w4bNX4poRb42lrV6NmQiFdjzpqszVbv5Lpn2CSKu32CwKVAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key UKL6Dnj2KwYsFlkCvOkXVatxvOPB4MaxqwPQQgZMTwI\n"
+ "id rsa1024 FPIXc6k++JnKCtSKWUxaR6oXEKs\n"
+ /* Good 9: Another totally normal one.*/
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBANNGIKRd8PFNXkJ2JPV1ohDMFNbJwKbwybeieaQFjtU9KWedHCbr+QD4\n"
+ "B6zNY5ysguNjHNnlq2f6D09+uhnfDBON8tAz0mPQH/6JqnOXm+EiUn+8bN0E8Nke\n"
+ "/i3GEgDeaxJJMNQcpsJvmmSmKFOlYy9Fy7ejAjTGqtAnqOte7BnTAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key gUsq3e5iYgsQQvyxINtLzBpHxmIt5rtuFlEbKfI4gFk=\n"
+ "id rsa1024 jv+LdatDzsMfEW6pLBeL/5uzwCc\n"
+ /* Bad 2: RSA key has bad exponent of 3. */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGHAoGBAMMTWtvPxYnUNJ5Y7B+XENcpxzPoGstrdiUszCBS+/42xvluLJ+JDSdR\n"
+ "qJaMD6ax8vKAeLS5C6O17MNdG2VldlPRbtgl41MXsOoUqEJ+nY9e3WG9Snjp47xC\n"
+ "zmWIfeduXSavIsb3a43/MLIz/9qO0TkgAAiuQr79JlwKhLdzCqTLAgED\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key NkRB4wTUFogiVp5jYmjGORe2ffb/y5Kk8Itw8jdzMjA=\n"
+ "p reject 25,119,135-139,445,563,1214,4661-4666,6346-6429,6699,6881-6999\n"
+ "id rsa1024 fKvYjP7TAjCC1FzYee5bYAwYkoDg\n"
+ /* Bad 3: Bogus annotation */
+ "@last-listed with strange aeons\n"
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBALcRBFNCZtpd2TFJysU77/fJMFzKisRQEBOtDGtTZ2Bg4aEGosssa0Id\n"
+ "YtUagRLYle08QVGvGB+EHBI5qf6Ah2yPH7k5QiN2a3Sq+nyh85dXKPazBGBBbM+C\n"
+ "DOfDauV02CAnADNMLJEf1voY3oBVvYyIsmHxn5i1R19ZYIiR8NX5AgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "ntor-onion-key m4xcFXMWMjCvZDXq8FT3XmS0EHYseGOeu+fV+6FYDlk=\n"
+ "p accept 20-23,43,53,79-81,88,110,143,194,220,389,443,464,531,543-544\n"
+ "id rsa1024 SSbfNE9vmaiwRKH+eqNAkiKQhds\n"
+ /* Good 10: Normal, with added ipv6 address and added other address */
+ "onion-key\n"
+ "-----BEGIN RSA PUBLIC KEY-----\n"
+ "MIGJAoGBAM7uUtq5F6h63QNYIvC+4NcWaD0DjtnrOORZMkdpJhinXUOwce3cD5Dj\n"
+ "sgdN1wJpWpTQMXJ2DssfSgmOVXETP7qJuZyRprxalQhaEATMDNJA/66Ml1jSO9mZ\n"
+ "+8Xb7m/4q778lNtkSbsvMaYD2Dq6k2QQ3kMhr9z8oUtX0XA23+pfAgMBAAE=\n"
+ "-----END RSA PUBLIC KEY-----\n"
+ "a [::1:2:3:4]:9090\n"
+ "a 18.0.0.1:9999\n"
+ "ntor-onion-key k2yFqTU2vzMCQDEiE/j9UcEHxKrXMLpB3IL0or09sik=\n"
+ "id rsa1024 2A8wYpHxnkKJ92orocvIQBzeHlE\n"
+ "p6 allow 80\n"
+ ;
+
+/** More tests for parsing different kinds of microdescriptors, and getting
+ * invalid digests trackd from them. */
+static void
+test_md_parse(void *arg)
+{
+ (void) arg;
+ char *mem_op_hex_tmp = NULL;
+ smartlist_t *invalid = smartlist_new();
+
+ smartlist_t *mds = microdescs_parse_from_string(MD_PARSE_TEST_DATA,
+ NULL, 1, SAVED_NOWHERE,
+ invalid);
+ tt_int_op(smartlist_len(mds), OP_EQ, 11);
+ tt_int_op(smartlist_len(invalid), OP_EQ, 4);
+
+ test_memeq_hex(smartlist_get(invalid,0),
+ "5d76bf1c6614e885614a1e0ad074e1ab"
+ "4ea14655ebeefb1736a71b5ed8a15a51");
+ test_memeq_hex(smartlist_get(invalid,1),
+ "2fde0ee3343669c2444cd9d53cbd39c6"
+ "a7d1fc0513513e840ca7f6e68864b36c");
+ test_memeq_hex(smartlist_get(invalid,2),
+ "20d1576c5ab11bbcff0dedb1db4a3cfc"
+ "c8bc8dd839d8cbfef92d00a1a7d7b294");
+ test_memeq_hex(smartlist_get(invalid,3),
+ "074770f394c73dbde7b44412e9692add"
+ "691a478d4727f9804b77646c95420a96");
+
+ /* Spot-check the valid ones. */
+ const microdesc_t *md = smartlist_get(mds, 5);
+ test_memeq_hex(md->digest,
+ "54bb6d733ddeb375d2456c79ae103961"
+ "da0cae29620375ac4cf13d54da4d92b3");
+ tt_int_op(md->last_listed, OP_EQ, 0);
+ tt_int_op(md->saved_location, OP_EQ, SAVED_NOWHERE);
+ tt_int_op(md->no_save, OP_EQ, 0);
+ tt_uint_op(md->held_in_map, OP_EQ, 0);
+ tt_uint_op(md->held_by_nodes, OP_EQ, 0);
+ tt_assert(md->onion_curve25519_pkey);
+
+ md = smartlist_get(mds, 6);
+ test_memeq_hex(md->digest,
+ "53f740bd222ab37f19f604b1d3759aa6"
+ "5eff1fbce9ac254bd0fa50d4af9b1bae");
+ tt_assert(! md->exit_policy);
+
+ md = smartlist_get(mds, 8);
+ test_memeq_hex(md->digest,
+ "a0a155562d8093d8fd0feb7b93b7226e"
+ "17f056c2142aab7a4ea8c5867a0376d5");
+ tt_assert(md->onion_curve25519_pkey);
+
+ md = smartlist_get(mds, 10);
+ test_memeq_hex(md->digest,
+ "409ebd87d23925a2732bd467a92813c9"
+ "21ca378fcb9ca193d354c51550b6d5e9");
+ tt_assert(tor_addr_family(&md->ipv6_addr) == AF_INET6);
+ tt_int_op(md->ipv6_orport, OP_EQ, 9090);
+
+ done:
+ SMARTLIST_FOREACH(mds, microdesc_t *, md, microdesc_free(md));
+ smartlist_free(mds);
+ SMARTLIST_FOREACH(invalid, char *, cp, tor_free(cp));
+ smartlist_free(invalid);
+ tor_free(mem_op_hex_tmp);
+}
+
+static int mock_rgsbd_called = 0;
+static routerstatus_t *mock_rgsbd_val_a = NULL;
+static routerstatus_t *mock_rgsbd_val_b = NULL;
+static routerstatus_t *
+mock_router_get_status_by_digest(networkstatus_t *c, const char *d)
+{
+ (void) c;
+ ++mock_rgsbd_called;
+
+ if (fast_memeq(d, "\x5d\x76", 2)) {
+ memcpy(mock_rgsbd_val_a->descriptor_digest, d, 32);
+ return mock_rgsbd_val_a;
+ } else if (fast_memeq(d, "\x20\xd1", 2)) {
+ memcpy(mock_rgsbd_val_b->descriptor_digest, d, 32);
+ return mock_rgsbd_val_b;
+ } else {
+ return NULL;
+ }
+}
+
+static networkstatus_t *mock_ns_val = NULL;
+static networkstatus_t *
+mock_ns_get_by_flavor(consensus_flavor_t f)
+{
+ (void)f;
+ return mock_ns_val;
+}
+
+static void
+test_md_reject_cache(void *arg)
+{
+ (void) arg;
+ microdesc_cache_t *mc = NULL ;
+ smartlist_t *added = NULL, *wanted = smartlist_new();
+ or_options_t *options = get_options_mutable();
+ char buf[DIGEST256_LEN];
+
+ tor_free(options->DataDirectory);
+ options->DataDirectory = tor_strdup(get_fname("md_datadir_test_rej"));
+ mock_rgsbd_val_a = tor_malloc_zero(sizeof(routerstatus_t));
+ mock_rgsbd_val_b = tor_malloc_zero(sizeof(routerstatus_t));
+ mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t));
+
+ mock_ns_val->valid_after = time(NULL) - 86400;
+ mock_ns_val->valid_until = time(NULL) + 86400;
+ mock_ns_val->flavor = FLAV_MICRODESC;
+
+#ifdef _WIN32
+ tt_int_op(0, OP_EQ, mkdir(options->DataDirectory));
+#else
+ tt_int_op(0, OP_EQ, mkdir(options->DataDirectory, 0700));
+#endif
+
+ MOCK(router_get_mutable_consensus_status_by_descriptor_digest,
+ mock_router_get_status_by_digest);
+ MOCK(networkstatus_get_latest_consensus_by_flavor, mock_ns_get_by_flavor);
+
+ mc = get_microdesc_cache();
+#define ADD(hex) \
+ do { \
+ tt_int_op(0,OP_EQ,base16_decode(buf,sizeof(buf),hex,strlen(hex))); \
+ smartlist_add(wanted, tor_memdup(buf, DIGEST256_LEN)); \
+ } while (0)
+
+ /* invalid,0 */
+ ADD("5d76bf1c6614e885614a1e0ad074e1ab4ea14655ebeefb1736a71b5ed8a15a51");
+ /* invalid,2 */
+ ADD("20d1576c5ab11bbcff0dedb1db4a3cfcc8bc8dd839d8cbfef92d00a1a7d7b294");
+ /* valid, 6 */
+ ADD("53f740bd222ab37f19f604b1d3759aa65eff1fbce9ac254bd0fa50d4af9b1bae");
+ /* valid, 8 */
+ ADD("a0a155562d8093d8fd0feb7b93b7226e17f056c2142aab7a4ea8c5867a0376d5");
+
+ added = microdescs_add_to_cache(mc, MD_PARSE_TEST_DATA, NULL,
+ SAVED_NOWHERE, 0, time(NULL), wanted);
+
+ tt_int_op(smartlist_len(added), OP_EQ, 2);
+ tt_int_op(mock_rgsbd_called, OP_EQ, 2);
+ tt_int_op(mock_rgsbd_val_a->dl_status.n_download_failures, OP_EQ, 255);
+ tt_int_op(mock_rgsbd_val_b->dl_status.n_download_failures, OP_EQ, 255);
+
+ done:
+ UNMOCK(networkstatus_get_latest_consensus_by_flavor);
+ UNMOCK(router_get_mutable_consensus_status_by_descriptor_digest);
+ tor_free(options->DataDirectory);
+ microdesc_free_all();
+ smartlist_free(added);
+ SMARTLIST_FOREACH(wanted, char *, cp, tor_free(cp));
+ smartlist_free(wanted);
+ tor_free(mock_rgsbd_val_a);
+ tor_free(mock_rgsbd_val_b);
+ tor_free(mock_ns_val);
+}
+
+static void
+test_md_corrupt_desc(void *arg)
+{
+ char *cp = NULL;
+ smartlist_t *sl = NULL;
+ (void) arg;
+
+ sl = microdescs_add_to_cache(get_microdesc_cache(),
+ "@last-listed 2015-06-22 10:00:00\n"
+ "onion-k\n",
+ NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
+ tt_int_op(smartlist_len(sl), ==, 0);
+ smartlist_free(sl);
+
+ sl = microdescs_add_to_cache(get_microdesc_cache(),
+ "@last-listed 2015-06-22 10:00:00\n"
+ "wiggly\n",
+ NULL, SAVED_IN_JOURNAL, 0, time(NULL), NULL);
+ tt_int_op(smartlist_len(sl), ==, 0);
+ smartlist_free(sl);
+
+ tor_asprintf(&cp, "%s\n%s", test_md1, "@foobar\nonion-wobble\n");
+
+ sl = microdescs_add_to_cache(get_microdesc_cache(),
+ cp, cp+strlen(cp),
+ SAVED_IN_JOURNAL, 0, time(NULL), NULL);
+ tt_int_op(smartlist_len(sl), ==, 0);
+ smartlist_free(sl);
+
+ done:
+ tor_free(cp);
+}
+
struct testcase_t microdesc_tests[] = {
{ "cache", test_md_cache, TT_FORK, NULL, NULL },
{ "broken_cache", test_md_cache_broken, TT_FORK, NULL, NULL },
{ "generate", test_md_generate, 0, NULL, NULL },
+ { "parse", test_md_parse, 0, NULL, NULL },
+ { "reject_cache", test_md_reject_cache, TT_FORK, NULL, NULL },
+ { "corrupt_desc", test_md_corrupt_desc, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
index 600e6a89d4..a8693ec9b5 100644
--- a/src/test/test_nodelist.c
+++ b/src/test/test_nodelist.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -10,7 +10,7 @@
#include "nodelist.h"
#include "test.h"
-/** Tese the case when node_get_by_id() returns NULL,
+/** Test the case when node_get_by_id() returns NULL,
* node_get_verbose_nickname_by_id should return the base 16 encoding
* of the id.
*/
@@ -23,9 +23,9 @@ test_nodelist_node_get_verbose_nickname_by_id_null_node(void *arg)
(void) arg;
/* make sure node_get_by_id returns NULL */
- test_assert(!node_get_by_id(ID));
+ tt_assert(!node_get_by_id(ID));
node_get_verbose_nickname_by_id(ID, vname);
- test_streq(vname, "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+ tt_str_op(vname,OP_EQ, "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
done:
return;
}
@@ -54,7 +54,7 @@ test_nodelist_node_get_verbose_nickname_not_named(void *arg)
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
DIGEST_LEN);
node_get_verbose_nickname(&mock_node, vname);
- test_streq(vname, "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR");
+ tt_str_op(vname,OP_EQ, "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA~TestOR");
done:
return;
diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c
index f2b7a72ad5..bfbf13a476 100644
--- a/src/test/test_ntor_cl.c
+++ b/src/test/test_ntor_cl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -13,10 +13,6 @@
#include "crypto_curve25519.h"
#include "onion_ntor.h"
-#ifndef CURVE25519_ENABLED
-#error "This isn't going to work without curve25519."
-#endif
-
#define N_ARGS(n) STMT_BEGIN { \
if (argc < (n)) { \
fprintf(stderr, "%s needs %d arguments.\n",argv[1],n); \
@@ -130,7 +126,7 @@ client2(int argc, char **argv)
keys = tor_malloc(keybytes);
hexkeys = tor_malloc(keybytes*2+1);
- if (onion_skin_ntor_client_handshake(&state, msg, keys, keybytes)<0) {
+ if (onion_skin_ntor_client_handshake(&state, msg, keys, keybytes, NULL)<0) {
fprintf(stderr, "handshake failed");
result = 2;
goto done;
diff --git a/src/test/test_oom.c b/src/test/test_oom.c
index 2726056b80..41cfcdbd81 100644
--- a/src/test/test_oom.c
+++ b/src/test/test_oom.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Tor Project, Inc. */
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for OOM handling logic */
@@ -13,9 +13,6 @@
#include "compat_libevent.h"
#include "connection.h"
#include "config.h"
-#ifdef ENABLE_MEMPOOLS
-#include "mempool.h"
-#endif
#include "relay.h"
#include "test.h"
@@ -143,17 +140,13 @@ test_oom_circbuf(void *arg)
MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_);
-#ifdef ENABLE_MEMPOOLS
- init_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
-
/* Far too low for real life. */
options->MaxMemInQueues = 256*packed_cell_mem_cost();
options->CellStatistics = 0;
- tt_int_op(cell_queues_check_size(), ==, 0); /* We don't start out OOM. */
- tt_int_op(cell_queues_get_total_allocation(), ==, 0);
- tt_int_op(buf_get_total_allocation(), ==, 0);
+ tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We don't start out OOM. */
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ, 0);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
/* Now we're going to fake up some circuits and get them added to the global
circuit list. */
@@ -164,22 +157,17 @@ test_oom_circbuf(void *arg)
tor_gettimeofday_cache_set(&tv);
c2 = dummy_or_circuit_new(20, 20);
-#ifdef ENABLE_MEMPOOLS
- tt_int_op(packed_cell_mem_cost(), ==,
- sizeof(packed_cell_t) + MP_POOL_ITEM_OVERHEAD);
-#else
- tt_int_op(packed_cell_mem_cost(), ==,
+ tt_int_op(packed_cell_mem_cost(), OP_EQ,
sizeof(packed_cell_t));
-#endif /* ENABLE_MEMPOOLS */
- tt_int_op(cell_queues_get_total_allocation(), ==,
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
packed_cell_mem_cost() * 70);
- tt_int_op(cell_queues_check_size(), ==, 0); /* We are still not OOM */
+ tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We are still not OOM */
tv.tv_usec = 20*1000;
tor_gettimeofday_cache_set(&tv);
c3 = dummy_or_circuit_new(100, 85);
- tt_int_op(cell_queues_check_size(), ==, 0); /* We are still not OOM */
- tt_int_op(cell_queues_get_total_allocation(), ==,
+ tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We are still not OOM */
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
packed_cell_mem_cost() * 255);
tv.tv_usec = 30*1000;
@@ -187,17 +175,17 @@ test_oom_circbuf(void *arg)
/* Adding this cell will trigger our OOM handler. */
c4 = dummy_or_circuit_new(2, 0);
- tt_int_op(cell_queues_get_total_allocation(), ==,
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
packed_cell_mem_cost() * 257);
- tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */
+ tt_int_op(cell_queues_check_size(), OP_EQ, 1); /* We are now OOM */
tt_assert(c1->marked_for_close);
tt_assert(! c2->marked_for_close);
tt_assert(! c3->marked_for_close);
tt_assert(! c4->marked_for_close);
- tt_int_op(cell_queues_get_total_allocation(), ==,
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
packed_cell_mem_cost() * (257 - 30));
circuit_free(c1);
@@ -208,14 +196,14 @@ test_oom_circbuf(void *arg)
tv.tv_usec = 40*1000; /* go back to the future */
tor_gettimeofday_cache_set(&tv);
- tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */
+ tt_int_op(cell_queues_check_size(), OP_EQ, 1); /* We are now OOM */
tt_assert(c1->marked_for_close);
tt_assert(! c2->marked_for_close);
tt_assert(! c3->marked_for_close);
tt_assert(! c4->marked_for_close);
- tt_int_op(cell_queues_get_total_allocation(), ==,
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
packed_cell_mem_cost() * (257 - 30));
done:
@@ -242,17 +230,13 @@ test_oom_streambuf(void *arg)
MOCK(circuit_mark_for_close_, circuit_mark_for_close_dummy_);
-#ifdef ENABLE_MEMPOOLS
- init_cell_pool();
-#endif /* ENABLE_MEMPOOLS */
-
/* Far too low for real life. */
options->MaxMemInQueues = 81*packed_cell_mem_cost() + 4096 * 34;
options->CellStatistics = 0;
- tt_int_op(cell_queues_check_size(), ==, 0); /* We don't start out OOM. */
- tt_int_op(cell_queues_get_total_allocation(), ==, 0);
- tt_int_op(buf_get_total_allocation(), ==, 0);
+ tt_int_op(cell_queues_check_size(), OP_EQ, 0); /* We don't start out OOM. */
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ, 0);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 0);
/* Start all circuits with a bit of data queued in cells */
tv.tv_usec = 500*1000; /* go halfway into the second. */
@@ -267,7 +251,7 @@ test_oom_streambuf(void *arg)
tv.tv_usec = 530*1000;
tor_gettimeofday_cache_set(&tv);
c4 = dummy_or_circuit_new(0,0);
- tt_int_op(cell_queues_get_total_allocation(), ==,
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
packed_cell_mem_cost() * 80);
tv.tv_usec = 600*1000;
@@ -303,24 +287,24 @@ test_oom_streambuf(void *arg)
tv.tv_usec = 0;
tvms = (uint32_t) tv_to_msec(&tv);
- tt_int_op(circuit_max_queued_cell_age(c1, tvms), ==, 500);
- tt_int_op(circuit_max_queued_cell_age(c2, tvms), ==, 490);
- tt_int_op(circuit_max_queued_cell_age(c3, tvms), ==, 480);
- tt_int_op(circuit_max_queued_cell_age(c4, tvms), ==, 0);
+ tt_int_op(circuit_max_queued_cell_age(c1, tvms), OP_EQ, 500);
+ tt_int_op(circuit_max_queued_cell_age(c2, tvms), OP_EQ, 490);
+ tt_int_op(circuit_max_queued_cell_age(c3, tvms), OP_EQ, 480);
+ tt_int_op(circuit_max_queued_cell_age(c4, tvms), OP_EQ, 0);
- tt_int_op(circuit_max_queued_data_age(c1, tvms), ==, 390);
- tt_int_op(circuit_max_queued_data_age(c2, tvms), ==, 380);
- tt_int_op(circuit_max_queued_data_age(c3, tvms), ==, 0);
- tt_int_op(circuit_max_queued_data_age(c4, tvms), ==, 370);
+ tt_int_op(circuit_max_queued_data_age(c1, tvms), OP_EQ, 390);
+ tt_int_op(circuit_max_queued_data_age(c2, tvms), OP_EQ, 380);
+ tt_int_op(circuit_max_queued_data_age(c3, tvms), OP_EQ, 0);
+ tt_int_op(circuit_max_queued_data_age(c4, tvms), OP_EQ, 370);
- tt_int_op(circuit_max_queued_item_age(c1, tvms), ==, 500);
- tt_int_op(circuit_max_queued_item_age(c2, tvms), ==, 490);
- tt_int_op(circuit_max_queued_item_age(c3, tvms), ==, 480);
- tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 370);
+ tt_int_op(circuit_max_queued_item_age(c1, tvms), OP_EQ, 500);
+ tt_int_op(circuit_max_queued_item_age(c2, tvms), OP_EQ, 490);
+ tt_int_op(circuit_max_queued_item_age(c3, tvms), OP_EQ, 480);
+ tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 370);
- tt_int_op(cell_queues_get_total_allocation(), ==,
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
packed_cell_mem_cost() * 80);
- tt_int_op(buf_get_total_allocation(), ==, 4096*16*2);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*16*2);
/* Now give c4 a very old buffer of modest size */
{
@@ -332,21 +316,21 @@ test_oom_streambuf(void *arg)
tt_assert(ec);
smartlist_add(edgeconns, ec);
}
- tt_int_op(buf_get_total_allocation(), ==, 4096*17*2);
- tt_int_op(circuit_max_queued_item_age(c4, tvms), ==, 1000);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2);
+ tt_int_op(circuit_max_queued_item_age(c4, tvms), OP_EQ, 1000);
- tt_int_op(cell_queues_check_size(), ==, 0);
+ tt_int_op(cell_queues_check_size(), OP_EQ, 0);
/* And run over the limit. */
tv.tv_usec = 800*1000;
tor_gettimeofday_cache_set(&tv);
c5 = dummy_or_circuit_new(0,5);
- tt_int_op(cell_queues_get_total_allocation(), ==,
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
packed_cell_mem_cost() * 85);
- tt_int_op(buf_get_total_allocation(), ==, 4096*17*2);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*17*2);
- tt_int_op(cell_queues_check_size(), ==, 1); /* We are now OOM */
+ tt_int_op(cell_queues_check_size(), OP_EQ, 1); /* We are now OOM */
/* C4 should have died. */
tt_assert(! c1->marked_for_close);
@@ -355,9 +339,9 @@ test_oom_streambuf(void *arg)
tt_assert(c4->marked_for_close);
tt_assert(! c5->marked_for_close);
- tt_int_op(cell_queues_get_total_allocation(), ==,
+ tt_int_op(cell_queues_get_total_allocation(), OP_EQ,
packed_cell_mem_cost() * 85);
- tt_int_op(buf_get_total_allocation(), ==, 4096*8*2);
+ tt_int_op(buf_get_total_allocation(), OP_EQ, 4096*8*2);
done:
circuit_free(c1);
diff --git a/src/test/test_options.c b/src/test/test_options.c
index 737f658e2c..a8ebadb14b 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define CONFIG_PRIVATE
@@ -87,10 +87,10 @@ test_options_validate_impl(const char *configuration,
clear_log_messages();
r = config_get_lines(configuration, &cl, 1);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
r = config_assign(&options_format, opt, cl, 0, 0, &msg);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
r = options_validate(NULL, opt, dflt, 0, &msg);
if (expect_errmsg && !msg) {
@@ -103,7 +103,7 @@ test_options_validate_impl(const char *configuration,
TT_DIE(("Expected no error message from <%s> but got <%s>.",
configuration, msg));
}
- tt_int_op((r == 0), ==, (msg == NULL));
+ tt_int_op((r == 0), OP_EQ, (msg == NULL));
if (expect_log) {
int found = 0;
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 4cdcd034bb..33f90c7da5 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -22,7 +22,7 @@ test_short_policy_parse(const char *input,
short_policy = parse_short_policy(input);
tt_assert(short_policy);
out = write_short_policy(short_policy);
- tt_str_op(out, ==, expected);
+ tt_str_op(out, OP_EQ, expected);
done:
tor_free(out);
@@ -47,17 +47,20 @@ test_policy_summary_helper(const char *policy_str,
line.value = (char *)policy_str;
line.next = NULL;
- r = policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1);
- test_eq(r, 0);
+ r = policies_parse_exit_policy(&line, &policy,
+ EXIT_POLICY_IPV6_ENABLED |
+ EXIT_POLICY_ADD_DEFAULT ,0);
+ tt_int_op(r,OP_EQ, 0);
+
summary = policy_summarize(policy, AF_INET);
- test_assert(summary != NULL);
- test_streq(summary, expected_summary);
+ tt_assert(summary != NULL);
+ tt_str_op(summary,OP_EQ, expected_summary);
short_policy = parse_short_policy(summary);
tt_assert(short_policy);
summary_after = write_short_policy(short_policy);
- test_streq(summary, summary_after);
+ tt_str_op(summary,OP_EQ, summary_after);
done:
tor_free(summary_after);
@@ -86,104 +89,108 @@ test_policies_general(void *arg)
policy = smartlist_new();
p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1);
- test_assert(p != NULL);
- test_eq(ADDR_POLICY_REJECT, p->policy_type);
+ tt_assert(p != NULL);
+ tt_int_op(ADDR_POLICY_REJECT,OP_EQ, p->policy_type);
tor_addr_from_ipv4h(&tar, 0xc0a80000u);
- test_eq(0, tor_addr_compare(&p->addr, &tar, CMP_EXACT));
- test_eq(16, p->maskbits);
- test_eq(1, p->prt_min);
- test_eq(65535, p->prt_max);
+ tt_int_op(0,OP_EQ, tor_addr_compare(&p->addr, &tar, CMP_EXACT));
+ tt_int_op(16,OP_EQ, p->maskbits);
+ tt_int_op(1,OP_EQ, p->prt_min);
+ tt_int_op(65535,OP_EQ, p->prt_max);
smartlist_add(policy, p);
tor_addr_from_ipv4h(&tar, 0x01020304u);
- test_assert(ADDR_POLICY_ACCEPTED ==
+ tt_assert(ADDR_POLICY_ACCEPTED ==
compare_tor_addr_to_addr_policy(&tar, 2, policy));
tor_addr_make_unspec(&tar);
- test_assert(ADDR_POLICY_PROBABLY_ACCEPTED ==
+ tt_assert(ADDR_POLICY_PROBABLY_ACCEPTED ==
compare_tor_addr_to_addr_policy(&tar, 2, policy));
tor_addr_from_ipv4h(&tar, 0xc0a80102);
- test_assert(ADDR_POLICY_REJECTED ==
+ tt_assert(ADDR_POLICY_REJECTED ==
compare_tor_addr_to_addr_policy(&tar, 2, policy));
- test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, 0, 1));
- test_assert(policy2);
+ tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy2,
+ EXIT_POLICY_IPV6_ENABLED |
+ EXIT_POLICY_REJECT_PRIVATE |
+ EXIT_POLICY_ADD_DEFAULT, 0));
+
+ tt_assert(policy2);
policy3 = smartlist_new();
p = router_parse_addr_policy_item_from_string("reject *:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy3, p);
p = router_parse_addr_policy_item_from_string("accept *:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy3, p);
policy4 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept *:443",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy4, p);
p = router_parse_addr_policy_item_from_string("accept *:443",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy4, p);
policy5 = smartlist_new();
p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject *:1-65534",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("reject *:65535",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
p = router_parse_addr_policy_item_from_string("accept *:1-65535",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
policy6 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy6, p);
policy7 = smartlist_new();
p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1);
- test_assert(p != NULL);
+ tt_assert(p != NULL);
smartlist_add(policy7, p);
- test_assert(!exit_policy_is_general_exit(policy));
- test_assert(exit_policy_is_general_exit(policy2));
- test_assert(!exit_policy_is_general_exit(NULL));
- test_assert(!exit_policy_is_general_exit(policy3));
- test_assert(!exit_policy_is_general_exit(policy4));
- test_assert(!exit_policy_is_general_exit(policy5));
- test_assert(!exit_policy_is_general_exit(policy6));
- test_assert(!exit_policy_is_general_exit(policy7));
+ tt_assert(!exit_policy_is_general_exit(policy));
+ tt_assert(exit_policy_is_general_exit(policy2));
+ tt_assert(!exit_policy_is_general_exit(NULL));
+ tt_assert(!exit_policy_is_general_exit(policy3));
+ tt_assert(!exit_policy_is_general_exit(policy4));
+ tt_assert(!exit_policy_is_general_exit(policy5));
+ tt_assert(!exit_policy_is_general_exit(policy6));
+ tt_assert(!exit_policy_is_general_exit(policy7));
- test_assert(cmp_addr_policies(policy, policy2));
- test_assert(cmp_addr_policies(policy, NULL));
- test_assert(!cmp_addr_policies(policy2, policy2));
- test_assert(!cmp_addr_policies(NULL, NULL));
+ tt_assert(cmp_addr_policies(policy, policy2));
+ tt_assert(cmp_addr_policies(policy, NULL));
+ tt_assert(!cmp_addr_policies(policy2, policy2));
+ tt_assert(!cmp_addr_policies(NULL, NULL));
- test_assert(!policy_is_reject_star(policy2, AF_INET));
- test_assert(policy_is_reject_star(policy, AF_INET));
- test_assert(policy_is_reject_star(NULL, AF_INET));
+ tt_assert(!policy_is_reject_star(policy2, AF_INET));
+ tt_assert(policy_is_reject_star(policy, AF_INET));
+ tt_assert(policy_is_reject_star(NULL, AF_INET));
addr_policy_list_free(policy);
policy = NULL;
@@ -193,11 +200,14 @@ test_policies_general(void *arg)
line.key = (char*)"foo";
line.value = (char*)"accept *:80,reject private:*,reject *:*";
line.next = NULL;
- test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1));
- test_assert(policy);
+ tt_int_op(0, OP_EQ, policies_parse_exit_policy(&line,&policy,
+ EXIT_POLICY_IPV6_ENABLED |
+ EXIT_POLICY_ADD_DEFAULT,0));
+ tt_assert(policy);
+
//test_streq(policy->string, "accept *:80");
//test_streq(policy->next->string, "reject *:*");
- test_eq(smartlist_len(policy), 4);
+ tt_int_op(smartlist_len(policy),OP_EQ, 4);
/* test policy summaries */
/* check if we properly ignore private IP addresses */
@@ -271,7 +281,7 @@ test_policies_general(void *arg)
/* Try parsing various broken short policies */
#define TT_BAD_SHORT_POLICY(s) \
do { \
- tt_ptr_op(NULL, ==, (short_parsed = parse_short_policy((s)))); \
+ tt_ptr_op(NULL, OP_EQ, (short_parsed = parse_short_policy((s)))); \
} while (0)
TT_BAD_SHORT_POLICY("accept 200-199");
TT_BAD_SHORT_POLICY("");
@@ -301,7 +311,7 @@ test_policies_general(void *arg)
smartlist_free(chunks);
short_parsed = parse_short_policy(policy);/* shouldn't be accepted */
tor_free(policy);
- tt_ptr_op(NULL, ==, short_parsed);
+ tt_ptr_op(NULL, OP_EQ, short_parsed);
}
/* truncation ports */
@@ -359,7 +369,7 @@ test_dump_exit_policy_to_string(void *arg)
ri->exit_policy = NULL; // expecting "reject *:*"
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("reject *:*",ep);
+ tt_str_op("reject *:*",OP_EQ, ep);
tor_free(ep);
@@ -372,7 +382,7 @@ test_dump_exit_policy_to_string(void *arg)
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*",ep);
+ tt_str_op("accept *:*",OP_EQ, ep);
tor_free(ep);
@@ -382,7 +392,7 @@ test_dump_exit_policy_to_string(void *arg)
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*\nreject *:25",ep);
+ tt_str_op("accept *:*\nreject *:25",OP_EQ, ep);
tor_free(ep);
@@ -393,7 +403,7 @@ test_dump_exit_policy_to_string(void *arg)
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*",ep);
+ tt_str_op("accept *:*\nreject *:25\nreject 8.8.8.8:*",OP_EQ, ep);
tor_free(ep);
policy_entry =
@@ -403,8 +413,8 @@ test_dump_exit_policy_to_string(void *arg)
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
- "reject6 [fc00::]/7:*",ep);
+ tt_str_op("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
+ "reject6 [fc00::]/7:*",OP_EQ, ep);
tor_free(ep);
policy_entry =
@@ -414,8 +424,8 @@ test_dump_exit_policy_to_string(void *arg)
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
- "reject6 [fc00::]/7:*\naccept6 [c000::]/3:*",ep);
+ tt_str_op("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
+ "reject6 [fc00::]/7:*\naccept6 [c000::]/3:*",OP_EQ, ep);
done:
diff --git a/src/test/test_pt.c b/src/test/test_pt.c
index f71627df1e..996ef8666b 100644
--- a/src/test/test_pt.c
+++ b/src/test/test_pt.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -27,75 +27,76 @@ reset_mp(managed_proxy_t *mp)
}
static void
-test_pt_parsing(void)
+test_pt_parsing(void *arg)
{
char line[200];
transport_t *transport = NULL;
tor_addr_t test_addr;
- managed_proxy_t *mp = tor_malloc(sizeof(managed_proxy_t));
+ managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t));
+ (void)arg;
mp->conf_state = PT_PROTO_INFANT;
mp->transports = smartlist_new();
/* incomplete cmethod */
strlcpy(line,"CMETHOD trebuchet",sizeof(line));
- test_assert(parse_cmethod_line(line, mp) < 0);
+ tt_assert(parse_cmethod_line(line, mp) < 0);
reset_mp(mp);
/* wrong proxy type */
strlcpy(line,"CMETHOD trebuchet dog 127.0.0.1:1999",sizeof(line));
- test_assert(parse_cmethod_line(line, mp) < 0);
+ tt_assert(parse_cmethod_line(line, mp) < 0);
reset_mp(mp);
/* wrong addrport */
strlcpy(line,"CMETHOD trebuchet socks4 abcd",sizeof(line));
- test_assert(parse_cmethod_line(line, mp) < 0);
+ tt_assert(parse_cmethod_line(line, mp) < 0);
reset_mp(mp);
/* correct line */
strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line));
- test_assert(parse_cmethod_line(line, mp) == 0);
- test_assert(smartlist_len(mp->transports) == 1);
+ tt_assert(parse_cmethod_line(line, mp) == 0);
+ tt_assert(smartlist_len(mp->transports) == 1);
transport = smartlist_get(mp->transports, 0);
/* test registered address of transport */
tor_addr_parse(&test_addr, "127.0.0.1");
- test_assert(tor_addr_eq(&test_addr, &transport->addr));
+ tt_assert(tor_addr_eq(&test_addr, &transport->addr));
/* test registered port of transport */
- test_assert(transport->port == 1999);
+ tt_assert(transport->port == 1999);
/* test registered SOCKS version of transport */
- test_assert(transport->socks_version == PROXY_SOCKS5);
+ tt_assert(transport->socks_version == PROXY_SOCKS5);
/* test registered name of transport */
- test_streq(transport->name, "trebuchet");
+ tt_str_op(transport->name,OP_EQ, "trebuchet");
reset_mp(mp);
/* incomplete smethod */
strlcpy(line,"SMETHOD trebuchet",sizeof(line));
- test_assert(parse_smethod_line(line, mp) < 0);
+ tt_assert(parse_smethod_line(line, mp) < 0);
reset_mp(mp);
/* wrong addr type */
strlcpy(line,"SMETHOD trebuchet abcd",sizeof(line));
- test_assert(parse_smethod_line(line, mp) < 0);
+ tt_assert(parse_smethod_line(line, mp) < 0);
reset_mp(mp);
/* cowwect */
strlcpy(line,"SMETHOD trebuchy 127.0.0.2:2999",sizeof(line));
- test_assert(parse_smethod_line(line, mp) == 0);
- test_assert(smartlist_len(mp->transports) == 1);
+ tt_assert(parse_smethod_line(line, mp) == 0);
+ tt_assert(smartlist_len(mp->transports) == 1);
transport = smartlist_get(mp->transports, 0);
/* test registered address of transport */
tor_addr_parse(&test_addr, "127.0.0.2");
- test_assert(tor_addr_eq(&test_addr, &transport->addr));
+ tt_assert(tor_addr_eq(&test_addr, &transport->addr));
/* test registered port of transport */
- test_assert(transport->port == 2999);
+ tt_assert(transport->port == 2999);
/* test registered name of transport */
- test_streq(transport->name, "trebuchy");
+ tt_str_op(transport->name,OP_EQ, "trebuchy");
reset_mp(mp);
@@ -103,30 +104,30 @@ test_pt_parsing(void)
strlcpy(line,"SMETHOD trebuchet 127.0.0.1:9999 "
"ARGS:counterweight=3,sling=snappy",
sizeof(line));
- test_assert(parse_smethod_line(line, mp) == 0);
- tt_int_op(1, ==, smartlist_len(mp->transports));
+ tt_assert(parse_smethod_line(line, mp) == 0);
+ tt_int_op(1, OP_EQ, smartlist_len(mp->transports));
{
const transport_t *transport = smartlist_get(mp->transports, 0);
tt_assert(transport);
- tt_str_op(transport->name, ==, "trebuchet");
- tt_int_op(transport->port, ==, 9999);
- tt_str_op(fmt_addr(&transport->addr), ==, "127.0.0.1");
- tt_str_op(transport->extra_info_args, ==,
+ tt_str_op(transport->name, OP_EQ, "trebuchet");
+ tt_int_op(transport->port, OP_EQ, 9999);
+ tt_str_op(fmt_addr(&transport->addr), OP_EQ, "127.0.0.1");
+ tt_str_op(transport->extra_info_args, OP_EQ,
"counterweight=3,sling=snappy");
}
reset_mp(mp);
/* unsupported version */
strlcpy(line,"VERSION 666",sizeof(line));
- test_assert(parse_version(line, mp) < 0);
+ tt_assert(parse_version(line, mp) < 0);
/* incomplete VERSION */
strlcpy(line,"VERSION ",sizeof(line));
- test_assert(parse_version(line, mp) < 0);
+ tt_assert(parse_version(line, mp) < 0);
/* correct VERSION */
strlcpy(line,"VERSION 1",sizeof(line));
- test_assert(parse_version(line, mp) == 0);
+ tt_assert(parse_version(line, mp) == 0);
done:
reset_mp(mp);
@@ -150,9 +151,9 @@ test_pt_get_transport_options(void *arg)
execve_args[1] = NULL;
mp = managed_proxy_create(transport_list, execve_args, 1);
- tt_ptr_op(mp, !=, NULL);
+ tt_ptr_op(mp, OP_NE, NULL);
opt_str = get_transport_options_for_server_proxy(mp);
- tt_ptr_op(opt_str, ==, NULL);
+ tt_ptr_op(opt_str, OP_EQ, NULL);
smartlist_add(mp->transports_to_launch, tor_strdup("gruyere"));
smartlist_add(mp->transports_to_launch, tor_strdup("roquefort"));
@@ -175,7 +176,7 @@ test_pt_get_transport_options(void *arg)
options->ServerTransportOptions = cl;
opt_str = get_transport_options_for_server_proxy(mp);
- tt_str_op(opt_str, ==,
+ tt_str_op(opt_str, OP_EQ,
"gruyere:melty=10;gruyere:hardness=se\\;ven;"
"stnectaire:melty=4;stnectaire:hardness=three");
@@ -187,46 +188,47 @@ test_pt_get_transport_options(void *arg)
}
static void
-test_pt_protocol(void)
+test_pt_protocol(void *arg)
{
char line[200];
managed_proxy_t *mp = tor_malloc_zero(sizeof(managed_proxy_t));
+ (void)arg;
mp->conf_state = PT_PROTO_LAUNCHED;
mp->transports = smartlist_new();
- mp->argv = tor_malloc_zero(sizeof(char*)*2);
+ mp->argv = tor_calloc(2, sizeof(char *));
mp->argv[0] = tor_strdup("<testcase>");
/* various wrong protocol runs: */
strlcpy(line,"VERSION 1",sizeof(line));
handle_proxy_line(line, mp);
- test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
strlcpy(line,"VERSION 1",sizeof(line));
handle_proxy_line(line, mp);
- test_assert(mp->conf_state == PT_PROTO_BROKEN);
+ tt_assert(mp->conf_state == PT_PROTO_BROKEN);
reset_mp(mp);
strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line));
handle_proxy_line(line, mp);
- test_assert(mp->conf_state == PT_PROTO_BROKEN);
+ tt_assert(mp->conf_state == PT_PROTO_BROKEN);
reset_mp(mp);
/* correct protocol run: */
strlcpy(line,"VERSION 1",sizeof(line));
handle_proxy_line(line, mp);
- test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
strlcpy(line,"CMETHOD trebuchet socks5 127.0.0.1:1999",sizeof(line));
handle_proxy_line(line, mp);
- test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
strlcpy(line,"CMETHODS DONE",sizeof(line));
handle_proxy_line(line, mp);
- test_assert(mp->conf_state == PT_PROTO_CONFIGURED);
+ tt_assert(mp->conf_state == PT_PROTO_CONFIGURED);
done:
reset_mp(mp);
@@ -260,17 +262,17 @@ test_pt_get_extrainfo_string(void *arg)
mp2 = managed_proxy_create(t2, argv2, 1);
r = parse_smethod_line("SMETHOD hagbard 127.0.0.1:5555", mp1);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
r = parse_smethod_line("SMETHOD celine 127.0.0.1:1723 ARGS:card=no-enemy",
mp2);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
/* Force these proxies to look "completed" or they won't generate output. */
mp1->conf_state = mp2->conf_state = PT_PROTO_COMPLETED;
s = pt_get_extra_info_descriptor_string();
tt_assert(s);
- tt_str_op(s, ==,
+ tt_str_op(s, OP_EQ,
"transport hagbard 127.0.0.1:5555\n"
"transport celine 127.0.0.1:1723 card=no-enemy\n");
@@ -363,7 +365,7 @@ test_pt_configure_proxy(void *arg)
control_testing_set_global_event_mask(EVENT_TRANSPORT_LAUNCHED);
- mp = tor_malloc(sizeof(managed_proxy_t));
+ mp = tor_malloc_zero(sizeof(managed_proxy_t));
mp->conf_state = PT_PROTO_ACCEPTING_METHODS;
mp->transports = smartlist_new();
mp->transports_to_launch = smartlist_new();
@@ -378,33 +380,33 @@ test_pt_configure_proxy(void *arg)
for (i = 0 ; i < 5 ; i++) {
retval = configure_proxy(mp);
/* retval should be zero because proxy hasn't finished configuring yet */
- test_assert(retval == 0);
+ tt_int_op(retval, OP_EQ, 0);
/* check the number of registered transports */
- test_assert(smartlist_len(mp->transports) == i+1);
+ tt_assert(smartlist_len(mp->transports) == i+1);
/* check that the mp is still waiting for transports */
- test_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
+ tt_assert(mp->conf_state == PT_PROTO_ACCEPTING_METHODS);
}
/* this last configure_proxy() should finalize the proxy configuration. */
retval = configure_proxy(mp);
/* retval should be 1 since the proxy finished configuring */
- test_assert(retval == 1);
+ tt_int_op(retval, OP_EQ, 1);
/* check the mp state */
- test_assert(mp->conf_state == PT_PROTO_COMPLETED);
+ tt_assert(mp->conf_state == PT_PROTO_COMPLETED);
- tt_int_op(controlevent_n, ==, 5);
- tt_int_op(controlevent_event, ==, EVENT_TRANSPORT_LAUNCHED);
- tt_int_op(smartlist_len(controlevent_msgs), ==, 5);
+ tt_int_op(controlevent_n, OP_EQ, 5);
+ tt_int_op(controlevent_event, OP_EQ, EVENT_TRANSPORT_LAUNCHED);
+ tt_int_op(smartlist_len(controlevent_msgs), OP_EQ, 5);
smartlist_sort_strings(controlevent_msgs);
- tt_str_op(smartlist_get(controlevent_msgs, 0), ==,
+ tt_str_op(smartlist_get(controlevent_msgs, 0), OP_EQ,
"650 TRANSPORT_LAUNCHED server mock1 127.0.0.1 5551\r\n");
- tt_str_op(smartlist_get(controlevent_msgs, 1), ==,
+ tt_str_op(smartlist_get(controlevent_msgs, 1), OP_EQ,
"650 TRANSPORT_LAUNCHED server mock2 127.0.0.1 5552\r\n");
- tt_str_op(smartlist_get(controlevent_msgs, 2), ==,
+ tt_str_op(smartlist_get(controlevent_msgs, 2), OP_EQ,
"650 TRANSPORT_LAUNCHED server mock3 127.0.0.1 5553\r\n");
- tt_str_op(smartlist_get(controlevent_msgs, 3), ==,
+ tt_str_op(smartlist_get(controlevent_msgs, 3), OP_EQ,
"650 TRANSPORT_LAUNCHED server mock4 127.0.0.1 5554\r\n");
- tt_str_op(smartlist_get(controlevent_msgs, 4), ==,
+ tt_str_op(smartlist_get(controlevent_msgs, 4), OP_EQ,
"650 TRANSPORT_LAUNCHED server mock5 127.0.0.1 5555\r\n");
{ /* check that the transport info were saved properly in the tor state */
@@ -416,13 +418,13 @@ test_pt_configure_proxy(void *arg)
/* Get the bindaddr for "mock1" and check it against the bindaddr
that the mocked tor_get_lines_from_handle() generated. */
transport_in_state = get_transport_in_state_by_name("mock1");
- test_assert(transport_in_state);
+ tt_assert(transport_in_state);
smartlist_split_string(transport_info_sl, transport_in_state->value,
NULL, 0, 0);
name_of_transport = smartlist_get(transport_info_sl, 0);
bindaddr = smartlist_get(transport_info_sl, 1);
- tt_str_op(name_of_transport, ==, "mock1");
- tt_str_op(bindaddr, ==, "127.0.0.1:5551");
+ tt_str_op(name_of_transport, OP_EQ, "mock1");
+ tt_str_op(bindaddr, OP_EQ, "127.0.0.1:5551");
SMARTLIST_FOREACH(transport_info_sl, char *, cp, tor_free(cp));
smartlist_free(transport_info_sl);
@@ -450,8 +452,86 @@ test_pt_configure_proxy(void *arg)
tor_free(mp);
}
+/* Test the get_pt_proxy_uri() function. */
+static void
+test_get_pt_proxy_uri(void *arg)
+{
+ or_options_t *options = get_options_mutable();
+ char *uri = NULL;
+ int ret;
+ (void) arg;
+
+ /* Test with no proxy. */
+ uri = get_pt_proxy_uri();
+ tt_assert(uri == NULL);
+
+ /* Test with a SOCKS4 proxy. */
+ options->Socks4Proxy = tor_strdup("192.0.2.1:1080");
+ ret = tor_addr_port_lookup(options->Socks4Proxy,
+ &options->Socks4ProxyAddr,
+ &options->Socks4ProxyPort);
+ tt_int_op(ret, OP_EQ, 0);
+ uri = get_pt_proxy_uri();
+ tt_str_op(uri, OP_EQ, "socks4a://192.0.2.1:1080");
+ tor_free(uri);
+ tor_free(options->Socks4Proxy);
+
+ /* Test with a SOCKS5 proxy, no username/password. */
+ options->Socks5Proxy = tor_strdup("192.0.2.1:1080");
+ ret = tor_addr_port_lookup(options->Socks5Proxy,
+ &options->Socks5ProxyAddr,
+ &options->Socks5ProxyPort);
+ tt_int_op(ret, OP_EQ, 0);
+ uri = get_pt_proxy_uri();
+ tt_str_op(uri, OP_EQ, "socks5://192.0.2.1:1080");
+ tor_free(uri);
+
+ /* Test with a SOCKS5 proxy, with username/password. */
+ options->Socks5ProxyUsername = tor_strdup("hwest");
+ options->Socks5ProxyPassword = tor_strdup("r34n1m470r");
+ uri = get_pt_proxy_uri();
+ tt_str_op(uri, OP_EQ, "socks5://hwest:r34n1m470r@192.0.2.1:1080");
+ tor_free(uri);
+ tor_free(options->Socks5Proxy);
+ tor_free(options->Socks5ProxyUsername);
+ tor_free(options->Socks5ProxyPassword);
+
+ /* Test with a HTTPS proxy, no authenticator. */
+ options->HTTPSProxy = tor_strdup("192.0.2.1:80");
+ ret = tor_addr_port_lookup(options->HTTPSProxy,
+ &options->HTTPSProxyAddr,
+ &options->HTTPSProxyPort);
+ tt_int_op(ret, OP_EQ, 0);
+ uri = get_pt_proxy_uri();
+ tt_str_op(uri, OP_EQ, "http://192.0.2.1:80");
+ tor_free(uri);
+
+ /* Test with a HTTPS proxy, with authenticator. */
+ options->HTTPSProxyAuthenticator = tor_strdup("hwest:r34n1m470r");
+ uri = get_pt_proxy_uri();
+ tt_str_op(uri, OP_EQ, "http://hwest:r34n1m470r@192.0.2.1:80");
+ tor_free(uri);
+ tor_free(options->HTTPSProxy);
+ tor_free(options->HTTPSProxyAuthenticator);
+
+ /* Token nod to the fact that IPv6 exists. */
+ options->Socks4Proxy = tor_strdup("[2001:db8::1]:1080");
+ ret = tor_addr_port_lookup(options->Socks4Proxy,
+ &options->Socks4ProxyAddr,
+ &options->Socks4ProxyPort);
+ tt_int_op(ret, OP_EQ, 0);
+ uri = get_pt_proxy_uri();
+ tt_str_op(uri, OP_EQ, "socks4a://[2001:db8::1]:1080");
+ tor_free(uri);
+ tor_free(options->Socks4Proxy);
+
+ done:
+ if (uri)
+ tor_free(uri);
+}
+
#define PT_LEGACY(name) \
- { #name, legacy_test_helper, 0, &legacy_setup, test_pt_ ## name }
+ { #name, test_pt_ ## name , 0, NULL, NULL }
struct testcase_t pt_tests[] = {
PT_LEGACY(parsing),
@@ -462,6 +542,8 @@ struct testcase_t pt_tests[] = {
NULL, NULL },
{ "configure_proxy",test_pt_configure_proxy, TT_FORK,
NULL, NULL },
+ { "get_pt_proxy_uri", test_get_pt_proxy_uri, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_relay.c b/src/test/test_relay.c
new file mode 100644
index 0000000000..6081956d46
--- /dev/null
+++ b/src/test/test_relay.c
@@ -0,0 +1,126 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#define CIRCUITBUILD_PRIVATE
+#include "circuitbuild.h"
+#define RELAY_PRIVATE
+#include "relay.h"
+/* For init/free stuff */
+#include "scheduler.h"
+
+/* Test suite stuff */
+#include "test.h"
+#include "fakechans.h"
+
+static or_circuit_t * new_fake_orcirc(channel_t *nchan, channel_t *pchan);
+
+static void test_relay_append_cell_to_circuit_queue(void *arg);
+
+static or_circuit_t *
+new_fake_orcirc(channel_t *nchan, channel_t *pchan)
+{
+ or_circuit_t *orcirc = NULL;
+ circuit_t *circ = NULL;
+
+ orcirc = tor_malloc_zero(sizeof(*orcirc));
+ circ = &(orcirc->base_);
+ circ->magic = OR_CIRCUIT_MAGIC;
+
+ circ->n_chan = nchan;
+ circ->n_circ_id = get_unique_circ_id_by_chan(nchan);
+ circ->n_mux = NULL; /* ?? */
+ cell_queue_init(&(circ->n_chan_cells));
+ circ->n_hop = NULL;
+ circ->streams_blocked_on_n_chan = 0;
+ circ->streams_blocked_on_p_chan = 0;
+ circ->n_delete_pending = 0;
+ circ->p_delete_pending = 0;
+ circ->received_destroy = 0;
+ circ->state = CIRCUIT_STATE_OPEN;
+ circ->purpose = CIRCUIT_PURPOSE_OR;
+ circ->package_window = CIRCWINDOW_START_MAX;
+ circ->deliver_window = CIRCWINDOW_START_MAX;
+ circ->n_chan_create_cell = NULL;
+
+ orcirc->p_chan = pchan;
+ orcirc->p_circ_id = get_unique_circ_id_by_chan(pchan);
+ cell_queue_init(&(orcirc->p_chan_cells));
+
+ return orcirc;
+}
+
+static void
+test_relay_append_cell_to_circuit_queue(void *arg)
+{
+ channel_t *nchan = NULL, *pchan = NULL;
+ or_circuit_t *orcirc = NULL;
+ cell_t *cell = NULL;
+ int old_count, new_count;
+
+ (void)arg;
+
+ /* Make fake channels to be nchan and pchan for the circuit */
+ nchan = new_fake_channel();
+ tt_assert(nchan);
+
+ pchan = new_fake_channel();
+ tt_assert(pchan);
+
+ /* We'll need chans with working cmuxes */
+ nchan->cmux = circuitmux_alloc();
+ pchan->cmux = circuitmux_alloc();
+
+ /* Make a fake orcirc */
+ orcirc = new_fake_orcirc(nchan, pchan);
+ tt_assert(orcirc);
+
+ /* Make a cell */
+ cell = tor_malloc_zero(sizeof(cell_t));
+ make_fake_cell(cell);
+
+ MOCK(scheduler_channel_has_waiting_cells,
+ scheduler_channel_has_waiting_cells_mock);
+
+ /* Append it */
+ old_count = get_mock_scheduler_has_waiting_cells_count();
+ append_cell_to_circuit_queue(TO_CIRCUIT(orcirc), nchan, cell,
+ CELL_DIRECTION_OUT, 0);
+ new_count = get_mock_scheduler_has_waiting_cells_count();
+ tt_int_op(new_count, ==, old_count + 1);
+
+ /* Now try the reverse direction */
+ old_count = get_mock_scheduler_has_waiting_cells_count();
+ append_cell_to_circuit_queue(TO_CIRCUIT(orcirc), pchan, cell,
+ CELL_DIRECTION_IN, 0);
+ new_count = get_mock_scheduler_has_waiting_cells_count();
+ tt_int_op(new_count, ==, old_count + 1);
+
+ UNMOCK(scheduler_channel_has_waiting_cells);
+
+ /* Get rid of the fake channels */
+ MOCK(scheduler_release_channel, scheduler_release_channel_mock);
+ channel_mark_for_close(nchan);
+ channel_mark_for_close(pchan);
+ UNMOCK(scheduler_release_channel);
+
+ /* Shut down channels */
+ channel_free_all();
+
+ done:
+ tor_free(cell);
+ cell_queue_clear(&orcirc->base_.n_chan_cells);
+ cell_queue_clear(&orcirc->p_chan_cells);
+ tor_free(orcirc);
+ free_fake_channel(nchan);
+ free_fake_channel(pchan);
+
+ return;
+}
+
+struct testcase_t relay_tests[] = {
+ { "append_cell_to_circuit_queue", test_relay_append_cell_to_circuit_queue,
+ TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c
index 9aff6ab49e..0a6fef729c 100644
--- a/src/test/test_relaycell.c
+++ b/src/test/test_relaycell.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Tor Project, Inc. */
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* Unit tests for handling different kinds of relay cell */
@@ -87,24 +87,24 @@ test_relaycell_resolved(void *arg)
srm_ncalls = mum_ncalls = 0; \
} while (0)
#define ASSERT_MARK_CALLED(reason) do { \
- tt_int_op(mum_ncalls, ==, 1); \
- tt_ptr_op(mum_conn, ==, entryconn); \
- tt_int_op(mum_endreason, ==, (reason)); \
+ tt_int_op(mum_ncalls, OP_EQ, 1); \
+ tt_ptr_op(mum_conn, OP_EQ, entryconn); \
+ tt_int_op(mum_endreason, OP_EQ, (reason)); \
} while (0)
#define ASSERT_RESOLVED_CALLED(atype, answer, ttl, expires) do { \
- tt_int_op(srm_ncalls, ==, 1); \
- tt_ptr_op(srm_conn, ==, entryconn); \
- tt_int_op(srm_atype, ==, (atype)); \
+ tt_int_op(srm_ncalls, OP_EQ, 1); \
+ tt_ptr_op(srm_conn, OP_EQ, entryconn); \
+ tt_int_op(srm_atype, OP_EQ, (atype)); \
if (answer) { \
- tt_int_op(srm_alen, ==, sizeof(answer)-1); \
- tt_int_op(srm_alen, <, 512); \
- tt_int_op(srm_answer_is_set, ==, 1); \
- tt_mem_op(srm_answer, ==, answer, sizeof(answer)-1); \
+ tt_int_op(srm_alen, OP_EQ, sizeof(answer)-1); \
+ tt_int_op(srm_alen, OP_LT, 512); \
+ tt_int_op(srm_answer_is_set, OP_EQ, 1); \
+ tt_mem_op(srm_answer, OP_EQ, answer, sizeof(answer)-1); \
} else { \
- tt_int_op(srm_answer_is_set, ==, 0); \
+ tt_int_op(srm_answer_is_set, OP_EQ, 0); \
} \
- tt_int_op(srm_ttl, ==, ttl); \
- tt_i64_op((int64_t)srm_expires, ==, (int64_t)expires); \
+ tt_int_op(srm_ttl, OP_EQ, ttl); \
+ tt_i64_op(srm_expires, OP_EQ, expires); \
} while (0)
(void)arg;
@@ -130,21 +130,21 @@ test_relaycell_resolved(void *arg)
/* Try with connection in non-RESOLVE_WAIT state: cell gets ignored */
MOCK_RESET();
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
- tt_int_op(srm_ncalls, ==, 0);
- tt_int_op(mum_ncalls, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(srm_ncalls, OP_EQ, 0);
+ tt_int_op(mum_ncalls, OP_EQ, 0);
/* Now put it in the right state. */
ENTRY_TO_CONN(entryconn)->state = AP_CONN_STATE_RESOLVE_WAIT;
entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE;
- entryconn->ipv4_traffic_ok = 1;
- entryconn->ipv6_traffic_ok = 1;
- entryconn->prefer_ipv6_traffic = 0;
+ entryconn->entry_cfg.ipv4_traffic = 1;
+ entryconn->entry_cfg.ipv6_traffic = 1;
+ entryconn->entry_cfg.prefer_ipv6 = 0;
/* We prefer ipv4, so we should get the first ipv4 answer */
MOCK_RESET();
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x7f\x00\x01\x02", 256, -1);
@@ -153,16 +153,16 @@ test_relaycell_resolved(void *arg)
MOCK_RESET();
options->ClientDNSRejectInternalAddresses = 1;
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1);
/* now prefer ipv6, and get the first ipv6 answer */
- entryconn->prefer_ipv6_traffic = 1;
+ entryconn->entry_cfg.prefer_ipv6 = 1;
MOCK_RESET();
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV6,
@@ -174,7 +174,7 @@ test_relaycell_resolved(void *arg)
MOCK_RESET();
SET_CELL("\x04\x04\x12\x00\x00\x01\x00\x00\x02\x00");
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_IPV4, "\x12\x00\x00\x01", 512, -1);
@@ -182,19 +182,19 @@ test_relaycell_resolved(void *arg)
/* But if we don't allow IPv4, we report nothing if the cell contains only
* ipv4 */
MOCK_RESET();
- entryconn->ipv4_traffic_ok = 0;
+ entryconn->entry_cfg.ipv4_traffic = 0;
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR, NULL, -1, -1);
/* If we wanted hostnames, we report nothing, since we only had IPs. */
MOCK_RESET();
- entryconn->ipv4_traffic_ok = 1;
+ entryconn->entry_cfg.ipv4_traffic = 1;
entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE_PTR;
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR, NULL, -1, -1);
@@ -203,7 +203,7 @@ test_relaycell_resolved(void *arg)
MOCK_RESET();
SET_CELL("\x00\x0fwww.example.com\x00\x01\x00\x00");
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_HOSTNAME, "www.example.com", 65536, -1);
@@ -213,9 +213,9 @@ test_relaycell_resolved(void *arg)
entryconn->socks_request->command = SOCKS_COMMAND_RESOLVE;
SET_CELL("\x04\x04\x01\x02\x03\x04"); /* no ttl */
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL);
- tt_int_op(srm_ncalls, ==, 0);
+ tt_int_op(srm_ncalls, OP_EQ, 0);
/* error on all addresses private */
MOCK_RESET();
@@ -224,7 +224,7 @@ test_relaycell_resolved(void *arg)
/* IPv4: 192.168.1.1, ttl 256 */
"\x04\x04\xc0\xa8\x01\x01\x00\x00\x01\x00");
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_TORPROTOCOL);
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, 0, TIME_MAX);
@@ -232,7 +232,7 @@ test_relaycell_resolved(void *arg)
MOCK_RESET();
SET_CELL("\xf0\x15" "quiet and meaningless" "\x00\x00\x0f\xff");
r = connection_edge_process_resolved_cell(edgeconn, &cell, &rh);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
ASSERT_MARK_CALLED(END_STREAM_REASON_DONE|
END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
ASSERT_RESOLVED_CALLED(RESOLVED_TYPE_ERROR_TRANSIENT, NULL, -1, -1);
diff --git a/src/test/test_replay.c b/src/test/test_replay.c
index b48f582f5e..a02c160365 100644
--- a/src/test/test_replay.c
+++ b/src/test/test_replay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Tor Project, Inc. */
+/* Copyright (c) 2012-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#define REPLAYCACHE_PRIVATE
@@ -18,12 +18,13 @@ static const char *test_buffer =
" mollit anim id est laborum.";
static void
-test_replaycache_alloc(void)
+test_replaycache_alloc(void *arg)
{
replaycache_t *r = NULL;
+ (void)arg;
r = replaycache_new(600, 300);
- test_assert(r != NULL);
+ tt_assert(r != NULL);
done:
if (r) replaycache_free(r);
@@ -32,21 +33,22 @@ test_replaycache_alloc(void)
}
static void
-test_replaycache_badalloc(void)
+test_replaycache_badalloc(void *arg)
{
replaycache_t *r = NULL;
/* Negative horizon should fail */
+ (void)arg;
r = replaycache_new(-600, 300);
- test_assert(r == NULL);
+ tt_assert(r == NULL);
/* Negative interval should get adjusted to zero */
r = replaycache_new(600, -300);
- test_assert(r != NULL);
- test_eq(r->scrub_interval, 0);
+ tt_assert(r != NULL);
+ tt_int_op(r->scrub_interval,OP_EQ, 0);
replaycache_free(r);
/* Negative horizon and negative interval should still fail */
r = replaycache_new(-600, -300);
- test_assert(r == NULL);
+ tt_assert(r == NULL);
done:
if (r) replaycache_free(r);
@@ -55,35 +57,37 @@ test_replaycache_badalloc(void)
}
static void
-test_replaycache_free_null(void)
+test_replaycache_free_null(void *arg)
{
+ (void)arg;
replaycache_free(NULL);
/* Assert that we're here without horrible death */
- test_assert(1);
+ tt_assert(1);
done:
return;
}
static void
-test_replaycache_miss(void)
+test_replaycache_miss(void *arg)
{
replaycache_t *r = NULL;
int result;
+ (void)arg;
r = replaycache_new(600, 300);
- test_assert(r != NULL);
+ tt_assert(r != NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
/* poke the bad-parameter error case too */
result =
replaycache_add_and_test_internal(1200, NULL, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
done:
if (r) replaycache_free(r);
@@ -92,23 +96,24 @@ test_replaycache_miss(void)
}
static void
-test_replaycache_hit(void)
+test_replaycache_hit(void *arg)
{
replaycache_t *r = NULL;
int result;
+ (void)arg;
r = replaycache_new(600, 300);
- test_assert(r != NULL);
+ tt_assert(r != NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
result =
replaycache_add_and_test_internal(1300, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 1);
+ tt_int_op(result,OP_EQ, 1);
done:
if (r) replaycache_free(r);
@@ -117,28 +122,29 @@ test_replaycache_hit(void)
}
static void
-test_replaycache_age(void)
+test_replaycache_age(void *arg)
{
replaycache_t *r = NULL;
int result;
+ (void)arg;
r = replaycache_new(600, 300);
- test_assert(r != NULL);
+ tt_assert(r != NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
result =
replaycache_add_and_test_internal(1300, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 1);
+ tt_int_op(result,OP_EQ, 1);
result =
replaycache_add_and_test_internal(3000, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
done:
if (r) replaycache_free(r);
@@ -147,25 +153,26 @@ test_replaycache_age(void)
}
static void
-test_replaycache_elapsed(void)
+test_replaycache_elapsed(void *arg)
{
replaycache_t *r = NULL;
int result;
time_t elapsed;
+ (void)arg;
r = replaycache_new(600, 300);
- test_assert(r != NULL);
+ tt_assert(r != NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
result =
replaycache_add_and_test_internal(1300, r, test_buffer,
strlen(test_buffer), &elapsed);
- test_eq(result, 1);
- test_eq(elapsed, 100);
+ tt_int_op(result,OP_EQ, 1);
+ tt_int_op(elapsed,OP_EQ, 100);
done:
if (r) replaycache_free(r);
@@ -174,28 +181,29 @@ test_replaycache_elapsed(void)
}
static void
-test_replaycache_noexpire(void)
+test_replaycache_noexpire(void *arg)
{
replaycache_t *r = NULL;
int result;
+ (void)arg;
r = replaycache_new(0, 0);
- test_assert(r != NULL);
+ tt_assert(r != NULL);
result =
replaycache_add_and_test_internal(1200, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
result =
replaycache_add_and_test_internal(1300, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 1);
+ tt_int_op(result,OP_EQ, 1);
result =
replaycache_add_and_test_internal(3000, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 1);
+ tt_int_op(result,OP_EQ, 1);
done:
if (r) replaycache_free(r);
@@ -204,24 +212,25 @@ test_replaycache_noexpire(void)
}
static void
-test_replaycache_scrub(void)
+test_replaycache_scrub(void *arg)
{
replaycache_t *r = NULL;
int result;
+ (void)arg;
r = replaycache_new(600, 300);
- test_assert(r != NULL);
+ tt_assert(r != NULL);
/* Set up like in test_replaycache_hit() */
result =
replaycache_add_and_test_internal(100, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
result =
replaycache_add_and_test_internal(200, r, test_buffer,
strlen(test_buffer), NULL);
- test_eq(result, 1);
+ tt_int_op(result,OP_EQ, 1);
/*
* Poke a few replaycache_scrub_if_needed_internal() error cases that
@@ -231,12 +240,12 @@ test_replaycache_scrub(void)
/* Null cache */
replaycache_scrub_if_needed_internal(300, NULL);
/* Assert we're still here */
- test_assert(1);
+ tt_assert(1);
/* Make sure we hit the aging-out case too */
replaycache_scrub_if_needed_internal(1500, r);
/* Assert that we aged it */
- test_eq(digestmap_size(r->digests_seen), 0);
+ tt_int_op(digestmap_size(r->digests_seen),OP_EQ, 0);
done:
if (r) replaycache_free(r);
@@ -245,29 +254,30 @@ test_replaycache_scrub(void)
}
static void
-test_replaycache_future(void)
+test_replaycache_future(void *arg)
{
replaycache_t *r = NULL;
int result;
time_t elapsed = 0;
+ (void)arg;
r = replaycache_new(600, 300);
- test_assert(r != NULL);
+ tt_assert(r != NULL);
/* Set up like in test_replaycache_hit() */
result =
replaycache_add_and_test_internal(100, r, test_buffer,
strlen(test_buffer), &elapsed);
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
/* elapsed should still be 0, since it wasn't written */
- test_eq(elapsed, 0);
+ tt_int_op(elapsed,OP_EQ, 0);
result =
replaycache_add_and_test_internal(200, r, test_buffer,
strlen(test_buffer), &elapsed);
- test_eq(result, 1);
+ tt_int_op(result,OP_EQ, 1);
/* elapsed should be the time since the last hit */
- test_eq(elapsed, 100);
+ tt_int_op(elapsed,OP_EQ, 100);
/*
* Now let's turn the clock back to get coverage on the cache entry from the
@@ -277,9 +287,9 @@ test_replaycache_future(void)
replaycache_add_and_test_internal(150, r, test_buffer,
strlen(test_buffer), &elapsed);
/* We should still get a hit */
- test_eq(result, 1);
+ tt_int_op(result,OP_EQ, 1);
/* ...but it shouldn't let us see a negative elapsed time */
- test_eq(elapsed, 0);
+ tt_int_op(elapsed,OP_EQ, 0);
done:
if (r) replaycache_free(r);
@@ -288,7 +298,7 @@ test_replaycache_future(void)
}
static void
-test_replaycache_realtime(void)
+test_replaycache_realtime(void *arg)
{
replaycache_t *r = NULL;
/*
@@ -299,26 +309,27 @@ test_replaycache_realtime(void)
int result;
/* Test the realtime as well as *_internal() entry points */
+ (void)arg;
r = replaycache_new(600, 300);
- test_assert(r != NULL);
+ tt_assert(r != NULL);
/* This should miss */
result =
replaycache_add_and_test(r, test_buffer, strlen(test_buffer));
- test_eq(result, 0);
+ tt_int_op(result,OP_EQ, 0);
/* This should hit */
result =
replaycache_add_and_test(r, test_buffer, strlen(test_buffer));
- test_eq(result, 1);
+ tt_int_op(result,OP_EQ, 1);
/* This should hit and return a small elapsed time */
result =
replaycache_add_test_and_elapsed(r, test_buffer,
strlen(test_buffer), &elapsed);
- test_eq(result, 1);
- test_assert(elapsed >= 0);
- test_assert(elapsed <= 5);
+ tt_int_op(result,OP_EQ, 1);
+ tt_assert(elapsed >= 0);
+ tt_assert(elapsed <= 5);
/* Scrub it to exercise that entry point too */
replaycache_scrub_if_needed(r);
@@ -329,7 +340,7 @@ test_replaycache_realtime(void)
}
#define REPLAYCACHE_LEGACY(name) \
- { #name, legacy_test_helper, 0, &legacy_setup, test_replaycache_ ## name }
+ { #name, test_replaycache_ ## name , 0, NULL, NULL }
struct testcase_t replaycache_tests[] = {
REPLAYCACHE_LEGACY(alloc),
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c
index 182e0f6f87..60b6bb5a72 100644
--- a/src/test/test_routerkeys.c
+++ b/src/test/test_routerkeys.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -33,38 +33,38 @@ test_routerkeys_write_fingerprint(void *arg)
set_server_identity_key(key);
set_client_identity_key(crypto_pk_dup_key(key));
- tt_int_op(0, ==, check_private_dir(ddir, CPD_CREATE, NULL));
- tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),==,0);
+ tt_int_op(0, OP_EQ, check_private_dir(ddir, CPD_CREATE, NULL));
+ tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),OP_EQ,0);
/* Write fingerprint file */
- tt_int_op(0, ==, router_write_fingerprint(0));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(0));
cp = read_file_to_str(get_fname("write_fingerprint/fingerprint"),
0, NULL);
crypto_pk_get_fingerprint(key, fp, 0);
tor_asprintf(&cp2, "haflinger %s\n", fp);
- tt_str_op(cp, ==, cp2);
+ tt_str_op(cp, OP_EQ, cp2);
tor_free(cp);
tor_free(cp2);
/* Write hashed-fingerprint file */
- tt_int_op(0, ==, router_write_fingerprint(1));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(1));
cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
0, NULL);
crypto_pk_get_hashed_fingerprint(key, fp);
tor_asprintf(&cp2, "haflinger %s\n", fp);
- tt_str_op(cp, ==, cp2);
+ tt_str_op(cp, OP_EQ, cp2);
tor_free(cp);
tor_free(cp2);
/* Replace outdated file */
write_str_to_file(get_fname("write_fingerprint/hashed-fingerprint"),
"junk goes here", 0);
- tt_int_op(0, ==, router_write_fingerprint(1));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(1));
cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
0, NULL);
crypto_pk_get_hashed_fingerprint(key, fp);
tor_asprintf(&cp2, "haflinger %s\n", fp);
- tt_str_op(cp, ==, cp2);
+ tt_str_op(cp, OP_EQ, cp2);
tor_free(cp);
tor_free(cp2);
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
new file mode 100644
index 0000000000..381a592c5b
--- /dev/null
+++ b/src/test/test_routerlist.c
@@ -0,0 +1,103 @@
+/* Copyright (c) 2014, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define ROUTERLIST_PRIVATE
+#include "or.h"
+#include "routerlist.h"
+#include "directory.h"
+#include "test.h"
+
+/* 4 digests + 3 sep + pre + post + NULL */
+static char output[4*BASE64_DIGEST256_LEN+3+2+2+1];
+
+static void
+mock_get_from_dirserver(uint8_t dir_purpose, uint8_t router_purpose,
+ const char *resource, int pds_flags)
+{
+ (void)dir_purpose;
+ (void)router_purpose;
+ (void)pds_flags;
+ tt_assert(resource);
+ strlcpy(output, resource, sizeof(output));
+ done:
+ ;
+}
+
+static void
+test_routerlist_initiate_descriptor_downloads(void *arg)
+{
+ const char *prose = "unhurried and wise, we perceive.";
+ smartlist_t *digests = smartlist_new();
+ (void)arg;
+
+ for (int i = 0; i < 20; i++) {
+ smartlist_add(digests, (char*)prose);
+ }
+
+ MOCK(directory_get_from_dirserver, mock_get_from_dirserver);
+ initiate_descriptor_downloads(NULL, DIR_PURPOSE_FETCH_MICRODESC,
+ digests, 3, 7, 0);
+ UNMOCK(directory_get_from_dirserver);
+
+ tt_str_op(output, OP_EQ, "d/"
+ "dW5odXJyaWVkIGFuZCB3aXNlLCB3ZSBwZXJjZWl2ZS4-"
+ "dW5odXJyaWVkIGFuZCB3aXNlLCB3ZSBwZXJjZWl2ZS4-"
+ "dW5odXJyaWVkIGFuZCB3aXNlLCB3ZSBwZXJjZWl2ZS4-"
+ "dW5odXJyaWVkIGFuZCB3aXNlLCB3ZSBwZXJjZWl2ZS4"
+ ".z");
+
+ done:
+ smartlist_free(digests);
+}
+
+static int count = 0;
+
+static void
+mock_initiate_descriptor_downloads(const routerstatus_t *source,
+ int purpose, smartlist_t *digests,
+ int lo, int hi, int pds_flags)
+{
+ (void)source;
+ (void)purpose;
+ (void)digests;
+ (void)pds_flags;
+ (void)hi;
+ (void)lo;
+ count += 1;
+}
+
+static void
+test_routerlist_launch_descriptor_downloads(void *arg)
+{
+ smartlist_t *downloadable = smartlist_new();
+ time_t now = time(NULL);
+ char *cp;
+ (void)arg;
+
+ for (int i = 0; i < 100; i++) {
+ cp = tor_malloc(DIGEST256_LEN);
+ tt_assert(cp);
+ crypto_rand(cp, DIGEST256_LEN);
+ smartlist_add(downloadable, cp);
+ }
+
+ MOCK(initiate_descriptor_downloads, mock_initiate_descriptor_downloads);
+ launch_descriptor_downloads(DIR_PURPOSE_FETCH_MICRODESC, downloadable,
+ NULL, now);
+ tt_int_op(3, ==, count);
+ UNMOCK(initiate_descriptor_downloads);
+
+ done:
+ SMARTLIST_FOREACH(downloadable, char *, cp1, tor_free(cp1));
+ smartlist_free(downloadable);
+}
+
+#define NODE(name, flags) \
+ { #name, test_routerlist_##name, (flags), NULL, NULL }
+
+struct testcase_t routerlist_tests[] = {
+ NODE(initiate_descriptor_downloads, 0),
+ NODE(launch_descriptor_downloads, 0),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c
new file mode 100644
index 0000000000..9bd0c125c3
--- /dev/null
+++ b/src/test/test_routerset.c
@@ -0,0 +1,2122 @@
+#define ROUTERSET_PRIVATE
+
+#include "or.h"
+#include "geoip.h"
+#include "routerset.h"
+#include "routerparse.h"
+#include "policies.h"
+#include "nodelist.h"
+#include "test.h"
+
+#define NS_MODULE routerset
+
+#define NS_SUBMODULE routerset_new
+
+/*
+ * Functional (blackbox) test to determine that each member of the routerset
+ * is non-NULL
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *rs;
+ (void)arg;
+
+ rs = routerset_new();
+
+ tt_ptr_op(rs, OP_NE, NULL);
+ tt_ptr_op(rs->list, OP_NE, NULL);
+ tt_ptr_op(rs->names, OP_NE, NULL);
+ tt_ptr_op(rs->digests, OP_NE, NULL);
+ tt_ptr_op(rs->policies, OP_NE, NULL);
+ tt_ptr_op(rs->country_names, OP_NE, NULL);
+
+ done:
+ routerset_free(rs);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_get_countryname
+
+/*
+ * Functional test to strip the braces from a "{xx}" country code string.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ const char *input;
+ char *name;
+ (void)arg;
+
+ /* strlen(c) < 4 */
+ input = "xxx";
+ name = routerset_get_countryname(input);
+ tt_ptr_op(name, OP_EQ, NULL);
+ tor_free(name);
+
+ /* c[0] != '{' */
+ input = "xxx}";
+ name = routerset_get_countryname(input);
+ tt_ptr_op(name, OP_EQ, NULL);
+ tor_free(name);
+
+ /* c[3] != '}' */
+ input = "{xxx";
+ name = routerset_get_countryname(input);
+ tt_ptr_op(name, OP_EQ, NULL);
+ tor_free(name);
+
+ /* tor_strlower */
+ input = "{XX}";
+ name = routerset_get_countryname(input);
+ tt_str_op(name, OP_EQ, "xx");
+ tor_free(name);
+
+ input = "{xx}";
+ name = routerset_get_countryname(input);
+ tt_str_op(name, OP_EQ, "xx");
+ done:
+ tor_free(name);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_refresh_counties, geoip_not_loaded)
+
+/*
+ * Structural (whitebox) test for routerset_refresh_counties, when the GeoIP DB
+ * is not loaded.
+ */
+
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+NS_DECL(int, geoip_get_n_countries, (void));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ (void)arg;
+
+ NS_MOCK(geoip_is_loaded);
+ NS_MOCK(geoip_get_n_countries);
+
+ routerset_refresh_countries(set);
+
+ tt_ptr_op(set->countries, OP_EQ, NULL);
+ tt_int_op(set->n_countries, OP_EQ, 0);
+ tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
+ tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 0);
+
+ done:
+ NS_UNMOCK(geoip_is_loaded);
+ NS_UNMOCK(geoip_get_n_countries);
+ routerset_free(set);
+}
+
+static int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+ (void)family;
+ CALLED(geoip_is_loaded)++;
+
+ return 0;
+}
+
+static int
+NS(geoip_get_n_countries)(void)
+{
+ CALLED(geoip_get_n_countries)++;
+
+ return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_refresh_counties, no_countries)
+
+/*
+ * Structural test for routerset_refresh_counties, when there are no countries.
+ */
+
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+NS_DECL(int, geoip_get_n_countries, (void));
+NS_DECL(country_t, geoip_get_country, (const char *country));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ (void)arg;
+
+ NS_MOCK(geoip_is_loaded);
+ NS_MOCK(geoip_get_n_countries);
+ NS_MOCK(geoip_get_country);
+
+ routerset_refresh_countries(set);
+
+ tt_ptr_op(set->countries, OP_NE, NULL);
+ tt_int_op(set->n_countries, OP_EQ, 1);
+ tt_int_op((unsigned int)(*set->countries), OP_EQ, 0);
+ tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
+ tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 1);
+ tt_int_op(CALLED(geoip_get_country), OP_EQ, 0);
+
+ done:
+ NS_UNMOCK(geoip_is_loaded);
+ NS_UNMOCK(geoip_get_n_countries);
+ NS_UNMOCK(geoip_get_country);
+ routerset_free(set);
+}
+
+static int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+ (void)family;
+ CALLED(geoip_is_loaded)++;
+
+ return 1;
+}
+
+static int
+NS(geoip_get_n_countries)(void)
+{
+ CALLED(geoip_get_n_countries)++;
+
+ return 1;
+}
+
+static country_t
+NS(geoip_get_country)(const char *countrycode)
+{
+ (void)countrycode;
+ CALLED(geoip_get_country)++;
+
+ return 1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_refresh_counties, one_valid_country)
+
+/*
+ * Structural test for routerset_refresh_counties, with one valid country.
+ */
+
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+NS_DECL(int, geoip_get_n_countries, (void));
+NS_DECL(country_t, geoip_get_country, (const char *country));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ (void)arg;
+
+ NS_MOCK(geoip_is_loaded);
+ NS_MOCK(geoip_get_n_countries);
+ NS_MOCK(geoip_get_country);
+ smartlist_add(set->country_names, tor_strndup("foo", 3));
+
+ routerset_refresh_countries(set);
+
+ tt_ptr_op(set->countries, OP_NE, NULL);
+ tt_int_op(set->n_countries, OP_EQ, 2);
+ tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
+ tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 1);
+ tt_int_op(CALLED(geoip_get_country), OP_EQ, 1);
+ tt_int_op((unsigned int)(*set->countries), OP_NE, 0);
+
+ done:
+ NS_UNMOCK(geoip_is_loaded);
+ NS_UNMOCK(geoip_get_n_countries);
+ NS_UNMOCK(geoip_get_country);
+ routerset_free(set);
+}
+
+static int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+ (void)family;
+ CALLED(geoip_is_loaded)++;
+
+ return 1;
+}
+
+static int
+NS(geoip_get_n_countries)(void)
+{
+ CALLED(geoip_get_n_countries)++;
+
+ return 2;
+}
+
+static country_t
+NS(geoip_get_country)(const char *countrycode)
+{
+ (void)countrycode;
+ CALLED(geoip_get_country)++;
+
+ return 1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_refresh_counties, one_invalid_country)
+
+/*
+ * Structural test for routerset_refresh_counties, with one invalid
+ * country code..
+ */
+
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+NS_DECL(int, geoip_get_n_countries, (void));
+NS_DECL(country_t, geoip_get_country, (const char *country));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ (void)arg;
+
+ NS_MOCK(geoip_is_loaded);
+ NS_MOCK(geoip_get_n_countries);
+ NS_MOCK(geoip_get_country);
+ smartlist_add(set->country_names, tor_strndup("foo", 3));
+
+ routerset_refresh_countries(set);
+
+ tt_ptr_op(set->countries, OP_NE, NULL);
+ tt_int_op(set->n_countries, OP_EQ, 2);
+ tt_int_op(CALLED(geoip_is_loaded), OP_EQ, 1);
+ tt_int_op(CALLED(geoip_get_n_countries), OP_EQ, 1);
+ tt_int_op(CALLED(geoip_get_country), OP_EQ, 1);
+ tt_int_op((unsigned int)(*set->countries), OP_EQ, 0);
+
+ done:
+ NS_UNMOCK(geoip_is_loaded);
+ NS_UNMOCK(geoip_get_n_countries);
+ NS_UNMOCK(geoip_get_country);
+ routerset_free(set);
+}
+
+static int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+ (void)family;
+ CALLED(geoip_is_loaded)++;
+
+ return 1;
+}
+
+static int
+NS(geoip_get_n_countries)(void)
+{
+ CALLED(geoip_get_n_countries)++;
+
+ return 2;
+}
+
+static country_t
+NS(geoip_get_country)(const char *countrycode)
+{
+ (void)countrycode;
+ CALLED(geoip_get_country)++;
+
+ return -1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, malformed)
+
+/*
+ * Functional test, with a malformed string to parse.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ const char *s = "_";
+ int r;
+ (void)arg;
+
+ r = routerset_parse(set, s, "");
+
+ tt_int_op(r, OP_EQ, -1);
+
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, valid_hexdigest)
+
+/*
+ * Functional test for routerset_parse, that routerset_parse returns 0
+ * on a valid hexdigest entry.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set;
+ const char *s;
+ int r;
+ (void)arg;
+
+ set = routerset_new();
+ s = "$0000000000000000000000000000000000000000";
+ r = routerset_parse(set, s, "");
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(digestmap_isempty(set->digests), OP_NE, 1);
+
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, valid_nickname)
+
+/*
+ * Functional test for routerset_parse, when given a valid nickname as input.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set;
+ const char *s;
+ int r;
+ (void)arg;
+
+ set = routerset_new();
+ s = "fred";
+ r = routerset_parse(set, s, "");
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(strmap_isempty(set->names), OP_NE, 1);
+
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, get_countryname)
+
+/*
+ * Functional test for routerset_parse, when given a valid countryname.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set;
+ const char *s;
+ int r;
+ (void)arg;
+
+ set = routerset_new();
+ s = "{cc}";
+ r = routerset_parse(set, s, "");
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(set->country_names), OP_NE, 0);
+
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_parse, policy)
+
+/*
+ * Structural test for routerset_parse, when given a valid policy.
+ */
+
+NS_DECL(addr_policy_t *, router_parse_addr_policy_item_from_string,
+ (const char *s, int assume_action));
+
+addr_policy_t *NS(mock_addr_policy);
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set;
+ const char *s;
+ int r;
+ (void)arg;
+
+ NS_MOCK(router_parse_addr_policy_item_from_string);
+ NS(mock_addr_policy) = tor_malloc_zero(sizeof(addr_policy_t));
+
+ set = routerset_new();
+ s = "*";
+ r = routerset_parse(set, s, "");
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(smartlist_len(set->policies), OP_NE, 0);
+ tt_int_op(CALLED(router_parse_addr_policy_item_from_string), OP_EQ, 1);
+
+ done:
+ routerset_free(set);
+}
+
+addr_policy_t *
+NS(router_parse_addr_policy_item_from_string)(const char *s, int assume_action)
+{
+ (void)s;
+ (void)assume_action;
+ CALLED(router_parse_addr_policy_item_from_string)++;
+
+ return NS(mock_addr_policy);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_union, source_bad)
+
+/*
+ * Structural test for routerset_union, when given a bad source argument.
+ */
+
+NS_DECL(smartlist_t *, smartlist_new, (void));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set, *bad_set;
+ (void)arg;
+
+ set = routerset_new();
+ bad_set = routerset_new();
+ smartlist_free(bad_set->list);
+ bad_set->list = NULL;
+
+ NS_MOCK(smartlist_new);
+
+ routerset_union(set, NULL);
+ tt_int_op(CALLED(smartlist_new), OP_EQ, 0);
+
+ routerset_union(set, bad_set);
+ tt_int_op(CALLED(smartlist_new), OP_EQ, 0);
+
+ done:
+ NS_UNMOCK(smartlist_new);
+ routerset_free(set);
+
+ /* Just recreate list, so we can simply use routerset_free. */
+ bad_set->list = smartlist_new();
+ routerset_free(bad_set);
+}
+
+static smartlist_t *
+NS(smartlist_new)(void)
+{
+ CALLED(smartlist_new)++;
+
+ return NULL;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_union, one)
+
+/*
+ * Functional test for routerset_union.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *src = routerset_new();
+ routerset_t *tgt;
+ (void)arg;
+
+ tgt = routerset_new();
+ smartlist_add(src->list, tor_strdup("{xx}"));
+ routerset_union(tgt, src);
+
+ tt_int_op(smartlist_len(tgt->list), OP_NE, 0);
+
+ done:
+ routerset_free(src);
+ routerset_free(tgt);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_is_list
+
+/*
+ * Functional tests for routerset_is_list.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set;
+ addr_policy_t *policy;
+ int is_list;
+ (void)arg;
+
+ /* len(set->country_names) == 0, len(set->policies) == 0 */
+ set = routerset_new();
+ is_list = routerset_is_list(set);
+ routerset_free(set);
+ set = NULL;
+ tt_int_op(is_list, OP_NE, 0);
+
+ /* len(set->country_names) != 0, len(set->policies) == 0 */
+ set = routerset_new();
+ smartlist_add(set->country_names, tor_strndup("foo", 3));
+ is_list = routerset_is_list(set);
+ routerset_free(set);
+ set = NULL;
+ tt_int_op(is_list, OP_EQ, 0);
+
+ /* len(set->country_names) == 0, len(set->policies) != 0 */
+ set = routerset_new();
+ policy = tor_malloc_zero(sizeof(addr_policy_t));
+ smartlist_add(set->policies, (void *)policy);
+ is_list = routerset_is_list(set);
+ routerset_free(set);
+ set = NULL;
+ tt_int_op(is_list, OP_EQ, 0);
+
+ /* len(set->country_names) != 0, len(set->policies) != 0 */
+ set = routerset_new();
+ smartlist_add(set->country_names, tor_strndup("foo", 3));
+ policy = tor_malloc_zero(sizeof(addr_policy_t));
+ smartlist_add(set->policies, (void *)policy);
+ is_list = routerset_is_list(set);
+ routerset_free(set);
+ set = NULL;
+ tt_int_op(is_list, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_needs_geoip
+
+/*
+ * Functional tests for routerset_needs_geoip.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ const routerset_t *set;
+ int needs_geoip;
+ (void)arg;
+
+ set = NULL;
+ needs_geoip = routerset_needs_geoip(set);
+ tt_int_op(needs_geoip, OP_EQ, 0);
+
+ set = routerset_new();
+ needs_geoip = routerset_needs_geoip(set);
+ routerset_free((routerset_t *)set);
+ tt_int_op(needs_geoip, OP_EQ, 0);
+ set = NULL;
+
+ set = routerset_new();
+ smartlist_add(set->country_names, tor_strndup("xx", 2));
+ needs_geoip = routerset_needs_geoip(set);
+ routerset_free((routerset_t *)set);
+ set = NULL;
+ tt_int_op(needs_geoip, OP_NE, 0);
+
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_is_empty
+
+/*
+ * Functional tests for routerset_is_empty.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = NULL;
+ int is_empty;
+ (void)arg;
+
+ is_empty = routerset_is_empty(set);
+ tt_int_op(is_empty, OP_NE, 0);
+
+ set = routerset_new();
+ is_empty = routerset_is_empty(set);
+ routerset_free(set);
+ set = NULL;
+ tt_int_op(is_empty, OP_NE, 0);
+
+ set = routerset_new();
+ smartlist_add(set->list, tor_strdup("{xx}"));
+ is_empty = routerset_is_empty(set);
+ routerset_free(set);
+ set = NULL;
+ tt_int_op(is_empty, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, null_set_or_null_set_list)
+
+/*
+ * Functional test for routerset_contains, when given a NULL set or the
+ * set has a NULL list.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = NULL;
+ int contains;
+ (void)arg;
+
+ contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
+
+ tt_int_op(contains, OP_EQ, 0);
+
+ set = tor_malloc_zero(sizeof(routerset_t));
+ set->list = NULL;
+ contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
+ tor_free(set);
+ tt_int_op(contains, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_nickname)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset but a
+ * NULL nickname.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ char *nickname = NULL;
+ int contains;
+ (void)arg;
+
+ contains = routerset_contains(set, NULL, 0, nickname, NULL, 0);
+ routerset_free(set);
+
+ tt_int_op(contains, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_nickname)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the nickname is in the routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ const char *nickname;
+ int contains;
+ (void)arg;
+
+ nickname = "Foo"; /* This tests the lowercase comparison as well. */
+ strmap_set_lc(set->names, nickname, (void *)1);
+ contains = routerset_contains(set, NULL, 0, nickname, NULL, 0);
+ routerset_free(set);
+
+ tt_int_op(contains, OP_EQ, 4);
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_nickname)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the nickname is not in the routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int contains;
+ (void)arg;
+
+ strmap_set_lc(set->names, "bar", (void *)1);
+ contains = routerset_contains(set, NULL, 0, "foo", NULL, 0);
+ routerset_free(set);
+
+ tt_int_op(contains, OP_EQ, 0);
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_digest)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the digest is contained in the routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int contains;
+ uint8_t foo[20] = { 2, 3, 4 };
+ (void)arg;
+
+ digestmap_set(set->digests, (const char*)foo, (void *)1);
+ contains = routerset_contains(set, NULL, 0, NULL, (const char*)foo, 0);
+ routerset_free(set);
+
+ tt_int_op(contains, OP_EQ, 4);
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_digest)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the digest is not contained in the routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int contains;
+ uint8_t bar[20] = { 9, 10, 11, 55 };
+ uint8_t foo[20] = { 1, 2, 3, 4};
+ (void)arg;
+
+ digestmap_set(set->digests, (const char*)bar, (void *)1);
+ contains = routerset_contains(set, NULL, 0, NULL, (const char*)foo, 0);
+ routerset_free(set);
+
+ tt_int_op(contains, OP_EQ, 0);
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_digest)
+
+/*
+ * Functional test for routerset_contains, when given a valid routerset
+ * and the digest is NULL.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int contains;
+ uint8_t bar[20] = { 9, 10, 11, 55 };
+ (void)arg;
+
+ digestmap_set(set->digests, (const char*)bar, (void *)1);
+ contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
+ routerset_free(set);
+
+ tt_int_op(contains, OP_EQ, 0);
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_addr)
+
+/*
+ * Structural test for routerset_contains, when given a valid routerset
+ * and the address is rejected by policy.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+ (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+
+static tor_addr_t MOCK_TOR_ADDR;
+#define MOCK_TOR_ADDR_PTR (&MOCK_TOR_ADDR)
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ tor_addr_t *addr = MOCK_TOR_ADDR_PTR;
+ int contains;
+ (void)arg;
+
+ NS_MOCK(compare_tor_addr_to_addr_policy);
+
+ contains = routerset_contains(set, addr, 0, NULL, NULL, 0);
+ routerset_free(set);
+
+ tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
+ tt_int_op(contains, OP_EQ, 3);
+
+ done:
+ ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy)
+{
+ (void)port;
+ (void)policy;
+ CALLED(compare_tor_addr_to_addr_policy)++;
+ tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
+ return ADDR_POLICY_REJECTED;
+
+ done:
+ return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_no_addr)
+
+/*
+ * Structural test for routerset_contains, when given a valid routerset
+ * and the address is not rejected by policy.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+ (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ tor_addr_t *addr = MOCK_TOR_ADDR_PTR;
+ int contains;
+ (void)arg;
+
+ NS_MOCK(compare_tor_addr_to_addr_policy);
+
+ contains = routerset_contains(set, addr, 0, NULL, NULL, 0);
+ routerset_free(set);
+
+ tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
+ tt_int_op(contains, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy)
+{
+ (void)port;
+ (void)policy;
+ CALLED(compare_tor_addr_to_addr_policy)++;
+ tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
+
+ return ADDR_POLICY_ACCEPTED;
+
+ done:
+ return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, set_and_null_addr)
+
+/*
+ * Structural test for routerset_contains, when given a valid routerset
+ * and the address is NULL.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+ (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int contains;
+ (void)arg;
+
+ NS_MOCK(compare_tor_addr_to_addr_policy);
+
+ contains = routerset_contains(set, NULL, 0, NULL, NULL, 0);
+ routerset_free(set);
+
+ tt_int_op(contains, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy)
+{
+ (void)port;
+ (void)policy;
+ CALLED(compare_tor_addr_to_addr_policy)++;
+ tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
+
+ return ADDR_POLICY_ACCEPTED;
+
+ done:
+ return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, countries_no_geoip)
+
+/*
+ * Structural test for routerset_contains, when there is no matching country
+ * for the address.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+ (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int contains = 1;
+ (void)arg;
+
+ NS_MOCK(compare_tor_addr_to_addr_policy);
+ NS_MOCK(geoip_get_country_by_addr);
+
+ set->countries = bitarray_init_zero(1);
+ bitarray_set(set->countries, 1);
+ contains = routerset_contains(set, MOCK_TOR_ADDR_PTR, 0, NULL, NULL, -1);
+ routerset_free(set);
+
+ tt_int_op(contains, OP_EQ, 0);
+ tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
+ tt_int_op(CALLED(geoip_get_country_by_addr), OP_EQ, 1);
+
+ done:
+ ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy)
+{
+ (void)port;
+ (void)policy;
+ CALLED(compare_tor_addr_to_addr_policy)++;
+ tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
+
+ done:
+ return ADDR_POLICY_ACCEPTED;
+}
+
+int
+NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+{
+ CALLED(geoip_get_country_by_addr)++;
+ tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
+
+ done:
+ return -1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains, countries_geoip)
+
+/*
+ * Structural test for routerset_contains, when there a matching country
+ * for the address.
+ */
+
+NS_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy,
+ (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy));
+NS_DECL(int, geoip_get_country_by_addr, (const tor_addr_t *addr));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int contains = 1;
+ (void)arg;
+
+ NS_MOCK(compare_tor_addr_to_addr_policy);
+ NS_MOCK(geoip_get_country_by_addr);
+
+ set->n_countries = 2;
+ set->countries = bitarray_init_zero(1);
+ bitarray_set(set->countries, 1);
+ contains = routerset_contains(set, MOCK_TOR_ADDR_PTR, 0, NULL, NULL, -1);
+ routerset_free(set);
+
+ tt_int_op(contains, OP_EQ, 2);
+ tt_int_op(CALLED(compare_tor_addr_to_addr_policy), OP_EQ, 1);
+ tt_int_op(CALLED(geoip_get_country_by_addr), OP_EQ, 1);
+
+ done:
+ ;
+}
+
+addr_policy_result_t
+NS(compare_tor_addr_to_addr_policy)(const tor_addr_t *addr, uint16_t port,
+ const smartlist_t *policy)
+{
+ (void)port;
+ (void)policy;
+ CALLED(compare_tor_addr_to_addr_policy)++;
+ tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
+
+ done:
+ return ADDR_POLICY_ACCEPTED;
+}
+
+int
+NS(geoip_get_country_by_addr)(const tor_addr_t *addr)
+{
+ CALLED(geoip_get_country_by_addr)++;
+ tt_ptr_op(addr, OP_EQ, MOCK_TOR_ADDR_PTR);
+
+ done:
+ return 1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, only_flag_and_no_ccs)
+
+/*
+ * Functional test for routerset_add_unknown_ccs, where only_if_some_cc_set
+ * is set and there are no country names.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ routerset_t **setp = &set;
+ int r;
+ (void)arg;
+
+ r = routerset_add_unknown_ccs(setp, 1);
+
+ tt_int_op(r, OP_EQ, 0);
+
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, creates_set)
+
+/*
+ * Functional test for routerset_add_unknown_ccs, where the set argument
+ * is created if passed in as NULL.
+ */
+
+/* The mock is only used to stop the test from asserting erroneously. */
+NS_DECL(country_t, geoip_get_country, (const char *country));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = NULL;
+ routerset_t **setp = &set;
+ int r;
+ (void)arg;
+
+ NS_MOCK(geoip_get_country);
+
+ r = routerset_add_unknown_ccs(setp, 0);
+
+ tt_ptr_op(*setp, OP_NE, NULL);
+ tt_int_op(r, OP_EQ, 0);
+
+ done:
+ if (set != NULL)
+ routerset_free(set);
+}
+
+country_t
+NS(geoip_get_country)(const char *country)
+{
+ (void)country;
+ CALLED(geoip_get_country)++;
+
+ return -1;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, add_unknown)
+
+/*
+ * Structural test for routerset_add_unknown_ccs, that the "{??}"
+ * country code is added to the list.
+ */
+
+NS_DECL(country_t, geoip_get_country, (const char *country));
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ routerset_t **setp = &set;
+ int r;
+ (void)arg;
+
+ NS_MOCK(geoip_get_country);
+ NS_MOCK(geoip_is_loaded);
+
+ r = routerset_add_unknown_ccs(setp, 0);
+
+ tt_int_op(r, OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(set->country_names, "??"), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(set->list, "{??}"), OP_EQ, 1);
+
+ done:
+ if (set != NULL)
+ routerset_free(set);
+}
+
+country_t
+NS(geoip_get_country)(const char *country)
+{
+ int arg_is_qq, arg_is_a1;
+
+ CALLED(geoip_get_country)++;
+
+ arg_is_qq = !strcmp(country, "??");
+ arg_is_a1 = !strcmp(country, "A1");
+
+ tt_int_op(arg_is_qq || arg_is_a1, OP_EQ, 1);
+
+ if (arg_is_qq)
+ return 1;
+
+ done:
+ return -1;
+}
+
+int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+ CALLED(geoip_is_loaded)++;
+
+ tt_int_op(family, OP_EQ, AF_INET);
+
+ done:
+ return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_add_unknown_ccs, add_a1)
+
+/*
+ * Structural test for routerset_add_unknown_ccs, that the "{a1}"
+ * country code is added to the list.
+ */
+
+NS_DECL(country_t, geoip_get_country, (const char *country));
+NS_DECL(int, geoip_is_loaded, (sa_family_t family));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ routerset_t **setp = &set;
+ int r;
+ (void)arg;
+
+ NS_MOCK(geoip_get_country);
+ NS_MOCK(geoip_is_loaded);
+
+ r = routerset_add_unknown_ccs(setp, 0);
+
+ tt_int_op(r, OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(set->country_names, "a1"), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(set->list, "{a1}"), OP_EQ, 1);
+
+ done:
+ if (set != NULL)
+ routerset_free(set);
+}
+
+country_t
+NS(geoip_get_country)(const char *country)
+{
+ int arg_is_qq, arg_is_a1;
+
+ CALLED(geoip_get_country)++;
+
+ arg_is_qq = !strcmp(country, "??");
+ arg_is_a1 = !strcmp(country, "A1");
+
+ tt_int_op(arg_is_qq || arg_is_a1, OP_EQ, 1);
+
+ if (arg_is_a1)
+ return 1;
+
+ done:
+ return -1;
+}
+
+int
+NS(geoip_is_loaded)(sa_family_t family)
+{
+ CALLED(geoip_is_loaded)++;
+
+ tt_int_op(family, OP_EQ, AF_INET);
+
+ done:
+ return 0;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_contains_extendinfo
+
+/*
+ * Functional test for routerset_contains_extendinfo.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ extend_info_t ei;
+ int r;
+ const char *nickname = "foo";
+ (void)arg;
+
+ memset(&ei, 0, sizeof(ei));
+ strmap_set_lc(set->names, nickname, (void *)1);
+ strncpy(ei.nickname, nickname, sizeof(ei.nickname) - 1);
+ ei.nickname[sizeof(ei.nickname) - 1] = '\0';
+
+ r = routerset_contains_extendinfo(set, &ei);
+
+ tt_int_op(r, OP_EQ, 4);
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_contains_router
+
+/*
+ * Functional test for routerset_contains_router.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ routerinfo_t ri;
+ country_t country = 1;
+ int r;
+ const char *nickname = "foo";
+ (void)arg;
+
+ memset(&ri, 0, sizeof(ri));
+ strmap_set_lc(set->names, nickname, (void *)1);
+ ri.nickname = (char *)nickname;
+
+ r = routerset_contains_router(set, &ri, country);
+
+ tt_int_op(r, OP_EQ, 4);
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_contains_routerstatus
+
+/*
+ * Functional test for routerset_contains_routerstatus.
+ */
+
+// XXX: This is a bit brief. It only populates and tests the nickname fields
+// ie., enough to make the containment check succeed. Perhaps it should do
+// a bit more or test a bit more.
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ routerstatus_t rs;
+ country_t country = 1;
+ int r;
+ const char *nickname = "foo";
+ (void)arg;
+
+ memset(&rs, 0, sizeof(rs));
+ strmap_set_lc(set->names, nickname, (void *)1);
+ strncpy(rs.nickname, nickname, sizeof(rs.nickname) - 1);
+ rs.nickname[sizeof(rs.nickname) - 1] = '\0';
+
+ r = routerset_contains_routerstatus(set, &rs, country);
+
+ tt_int_op(r, OP_EQ, 4);
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains_node, none)
+
+/*
+ * Functional test for routerset_contains_node, when the node has no
+ * routerset or routerinfo.
+ */
+
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int r;
+ (void)arg;
+
+ NS(mock_node).ri = NULL;
+ NS(mock_node).rs = NULL;
+
+ r = routerset_contains_node(set, &NS(mock_node));
+ tt_int_op(r, OP_EQ, 0);
+
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains_node, routerstatus)
+
+/*
+ * Functional test for routerset_contains_node, when the node has a
+ * routerset and no routerinfo.
+ */
+
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int r;
+ const char *nickname = "foo";
+ routerstatus_t rs;
+ (void)arg;
+
+ strmap_set_lc(set->names, nickname, (void *)1);
+
+ strncpy(rs.nickname, nickname, sizeof(rs.nickname) - 1);
+ rs.nickname[sizeof(rs.nickname) - 1] = '\0';
+ NS(mock_node).ri = NULL;
+ NS(mock_node).rs = &rs;
+
+ r = routerset_contains_node(set, &NS(mock_node));
+
+ tt_int_op(r, OP_EQ, 4);
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_contains_node, routerinfo)
+
+/*
+ * Functional test for routerset_contains_node, when the node has no
+ * routerset and a routerinfo.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ int r;
+ const char *nickname = "foo";
+ routerinfo_t ri;
+ node_t mock_node;
+ (void)arg;
+
+ strmap_set_lc(set->names, nickname, (void *)1);
+
+ ri.nickname = (char *)nickname;
+ mock_node.ri = &ri;
+ mock_node.rs = NULL;
+
+ r = routerset_contains_node(set, &mock_node);
+
+ tt_int_op(r, OP_EQ, 4);
+ done:
+ routerset_free(set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, no_routerset)
+
+/*
+ * Functional test for routerset_get_all_nodes, when routerset is NULL or
+ * the routerset list is NULL.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ smartlist_t *out = smartlist_new();
+ routerset_t *set = NULL;
+ (void)arg;
+
+ tt_int_op(smartlist_len(out), OP_EQ, 0);
+ routerset_get_all_nodes(out, NULL, NULL, 0);
+
+ tt_int_op(smartlist_len(out), OP_EQ, 0);
+
+ set = routerset_new();
+ smartlist_free(set->list);
+ routerset_get_all_nodes(out, NULL, NULL, 0);
+ tt_int_op(smartlist_len(out), OP_EQ, 0);
+
+ /* Just recreate list, so we can simply use routerset_free. */
+ set->list = smartlist_new();
+
+ done:
+ routerset_free(set);
+ smartlist_free(out);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list_with_no_nodes)
+
+/*
+ * Structural test for routerset_get_all_nodes, when the routerset list
+ * is empty.
+ */
+
+NS_DECL(const node_t *, node_get_by_nickname,
+ (const char *nickname, int warn_if_unused));
+const char *NS(mock_nickname);
+
+static void
+NS(test_main)(void *arg)
+{
+ smartlist_t *out = smartlist_new();
+ routerset_t *set = routerset_new();
+ int out_len;
+ (void)arg;
+
+ NS_MOCK(node_get_by_nickname);
+
+ NS(mock_nickname) = "foo";
+ smartlist_add(set->list, tor_strdup(NS(mock_nickname)));
+
+ routerset_get_all_nodes(out, set, NULL, 0);
+ out_len = smartlist_len(out);
+
+ smartlist_free(out);
+ routerset_free(set);
+
+ tt_int_op(out_len, OP_EQ, 0);
+ tt_int_op(CALLED(node_get_by_nickname), OP_EQ, 1);
+
+ done:
+ ;
+}
+
+const node_t *
+NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
+{
+ CALLED(node_get_by_nickname)++;
+ tt_str_op(nickname, OP_EQ, NS(mock_nickname));
+ tt_int_op(warn_if_unused, OP_EQ, 1);
+
+ done:
+ return NULL;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list_flag_not_running)
+
+/*
+ * Structural test for routerset_get_all_nodes, with the running_only flag
+ * is set but the nodes are not running.
+ */
+
+NS_DECL(const node_t *, node_get_by_nickname,
+ (const char *nickname, int warn_if_unused));
+const char *NS(mock_nickname);
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+ smartlist_t *out = smartlist_new();
+ routerset_t *set = routerset_new();
+ int out_len;
+ (void)arg;
+
+ NS_MOCK(node_get_by_nickname);
+
+ NS(mock_node).is_running = 0;
+ NS(mock_nickname) = "foo";
+ smartlist_add(set->list, tor_strdup(NS(mock_nickname)));
+
+ routerset_get_all_nodes(out, set, NULL, 1);
+ out_len = smartlist_len(out);
+
+ smartlist_free(out);
+ routerset_free(set);
+
+ tt_int_op(out_len, OP_EQ, 0);
+ tt_int_op(CALLED(node_get_by_nickname), OP_EQ, 1);
+
+ done:
+ ;
+}
+
+const node_t *
+NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
+{
+ CALLED(node_get_by_nickname)++;
+ tt_str_op(nickname, OP_EQ, NS(mock_nickname));
+ tt_int_op(warn_if_unused, OP_EQ, 1);
+
+ done:
+ return &NS(mock_node);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, list)
+
+/*
+ * Structural test for routerset_get_all_nodes.
+ */
+
+NS_DECL(const node_t *, node_get_by_nickname,
+ (const char *nickname, int warn_if_unused));
+char *NS(mock_nickname);
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+ smartlist_t *out = smartlist_new();
+ routerset_t *set = routerset_new();
+ int out_len;
+ node_t *ent;
+ (void)arg;
+
+ NS_MOCK(node_get_by_nickname);
+
+ NS(mock_nickname) = tor_strdup("foo");
+ smartlist_add(set->list, NS(mock_nickname));
+
+ routerset_get_all_nodes(out, set, NULL, 0);
+ out_len = smartlist_len(out);
+ ent = (node_t *)smartlist_get(out, 0);
+
+ smartlist_free(out);
+ routerset_free(set);
+
+ tt_int_op(out_len, OP_EQ, 1);
+ tt_ptr_op(ent, OP_EQ, &NS(mock_node));
+ tt_int_op(CALLED(node_get_by_nickname), OP_EQ, 1);
+
+ done:
+ ;
+}
+
+const node_t *
+NS(node_get_by_nickname)(const char *nickname, int warn_if_unused)
+{
+ CALLED(node_get_by_nickname)++;
+ tt_str_op(nickname, OP_EQ, NS(mock_nickname));
+ tt_int_op(warn_if_unused, OP_EQ, 1);
+
+ done:
+ return &NS(mock_node);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, nodelist_with_no_nodes)
+
+/*
+ * Structural test for routerset_get_all_nodes, when the nodelist has no nodes.
+ */
+
+NS_DECL(smartlist_t *, nodelist_get_list, (void));
+
+smartlist_t *NS(mock_smartlist);
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ smartlist_t *out = smartlist_new();
+ int r;
+ (void)arg;
+
+ NS_MOCK(nodelist_get_list);
+
+ smartlist_add(set->country_names, tor_strdup("{xx}"));
+ NS(mock_smartlist) = smartlist_new();
+
+ routerset_get_all_nodes(out, set, NULL, 1);
+ r = smartlist_len(out);
+ routerset_free(set);
+ smartlist_free(out);
+ smartlist_free(NS(mock_smartlist));
+
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(CALLED(nodelist_get_list), OP_EQ, 1);
+
+ done:
+ ;
+}
+
+smartlist_t *
+NS(nodelist_get_list)(void)
+{
+ CALLED(nodelist_get_list)++;
+
+ return NS(mock_smartlist);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_get_all_nodes, nodelist_flag_not_running)
+
+/*
+ * Structural test for routerset_get_all_nodes, with a non-list routerset
+ * the running_only flag is set, but the nodes are not running.
+ */
+
+NS_DECL(smartlist_t *, nodelist_get_list, (void));
+
+smartlist_t *NS(mock_smartlist);
+node_t NS(mock_node);
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ smartlist_t *out = smartlist_new();
+ int r;
+ (void)arg;
+
+ NS_MOCK(nodelist_get_list);
+
+ smartlist_add(set->country_names, tor_strdup("{xx}"));
+ NS(mock_smartlist) = smartlist_new();
+ NS(mock_node).is_running = 0;
+ smartlist_add(NS(mock_smartlist), (void *)&NS(mock_node));
+
+ routerset_get_all_nodes(out, set, NULL, 1);
+ r = smartlist_len(out);
+ routerset_free(set);
+ smartlist_free(out);
+ smartlist_free(NS(mock_smartlist));
+
+ tt_int_op(r, OP_EQ, 0);
+ tt_int_op(CALLED(nodelist_get_list), OP_EQ, 1);
+
+ done:
+ ;
+}
+
+smartlist_t *
+NS(nodelist_get_list)(void)
+{
+ CALLED(nodelist_get_list)++;
+
+ return NS(mock_smartlist);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_subtract_nodes
+
+/*
+ * Functional test for routerset_subtract_nodes.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = routerset_new();
+ smartlist_t *list = smartlist_new();
+ const char *nickname = "foo";
+ routerinfo_t ri;
+ node_t mock_node;
+ (void)arg;
+
+ strmap_set_lc(set->names, nickname, (void *)1);
+
+ ri.nickname = (char *)nickname;
+ mock_node.rs = NULL;
+ mock_node.ri = &ri;
+ smartlist_add(list, (void *)&mock_node);
+
+ tt_int_op(smartlist_len(list), OP_NE, 0);
+ routerset_subtract_nodes(list, set);
+
+ tt_int_op(smartlist_len(list), OP_EQ, 0);
+ done:
+ routerset_free(set);
+ smartlist_free(list);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_subtract_nodes, null_routerset)
+
+/*
+ * Functional test for routerset_subtract_nodes, with a NULL routerset.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = NULL;
+ smartlist_t *list = smartlist_new();
+ const char *nickname = "foo";
+ routerinfo_t ri;
+ node_t mock_node;
+ (void)arg;
+
+ ri.nickname = (char *)nickname;
+ mock_node.ri = &ri;
+ smartlist_add(list, (void *)&mock_node);
+
+ tt_int_op(smartlist_len(list), OP_NE, 0);
+ routerset_subtract_nodes(list, set);
+
+ tt_int_op(smartlist_len(list), OP_NE, 0);
+ done:
+ routerset_free(set);
+ smartlist_free(list);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_to_string
+
+/*
+ * Functional test for routerset_to_string.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *set = NULL;
+ char *s = NULL;
+ (void)arg;
+
+ set = NULL;
+ s = routerset_to_string(set);
+ tt_str_op(s, OP_EQ, "");
+ tor_free(s);
+
+ set = routerset_new();
+ s = routerset_to_string(set);
+ tt_str_op(s, OP_EQ, "");
+ tor_free(s);
+ routerset_free(set); set = NULL;
+
+ set = routerset_new();
+ smartlist_add(set->list, tor_strndup("a", 1));
+ s = routerset_to_string(set);
+ tt_str_op(s, OP_EQ, "a");
+ tor_free(s);
+ routerset_free(set); set = NULL;
+
+ set = routerset_new();
+ smartlist_add(set->list, tor_strndup("a", 1));
+ smartlist_add(set->list, tor_strndup("b", 1));
+ s = routerset_to_string(set);
+ tt_str_op(s, OP_EQ, "a,b");
+ tor_free(s);
+ routerset_free(set); set = NULL;
+
+ done:
+ tor_free(s);
+ routerset_free((routerset_t *)set);
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, empty_empty)
+
+/*
+ * Functional test for routerset_equal, with both routersets empty.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *a = routerset_new(), *b = routerset_new();
+ int r;
+ (void)arg;
+
+ r = routerset_equal(a, b);
+ routerset_free(a);
+ routerset_free(b);
+
+ tt_int_op(r, OP_EQ, 1);
+
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, empty_not_empty)
+
+/*
+ * Functional test for routerset_equal, with one routersets empty.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *a = routerset_new(), *b = routerset_new();
+ int r;
+ (void)arg;
+
+ smartlist_add(b->list, tor_strdup("{xx}"));
+ r = routerset_equal(a, b);
+ routerset_free(a);
+ routerset_free(b);
+
+ tt_int_op(r, OP_EQ, 0);
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, differing_lengths)
+
+/*
+ * Functional test for routerset_equal, with the routersets having
+ * differing lengths.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *a = routerset_new(), *b = routerset_new();
+ int r;
+ (void)arg;
+
+ smartlist_add(a->list, tor_strdup("{aa}"));
+ smartlist_add(b->list, tor_strdup("{b1}"));
+ smartlist_add(b->list, tor_strdup("{b2}"));
+ r = routerset_equal(a, b);
+ routerset_free(a);
+ routerset_free(b);
+
+ tt_int_op(r, OP_EQ, 0);
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, unequal)
+
+/*
+ * Functional test for routerset_equal, with the routersets being
+ * different.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *a = routerset_new(), *b = routerset_new();
+ int r;
+ (void)arg;
+
+ smartlist_add(a->list, tor_strdup("foo"));
+ smartlist_add(b->list, tor_strdup("bar"));
+ r = routerset_equal(a, b);
+ routerset_free(a);
+ routerset_free(b);
+
+ tt_int_op(r, OP_EQ, 0);
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_equal, equal)
+
+/*
+ * Functional test for routerset_equal, with the routersets being
+ * equal.
+ */
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *a = routerset_new(), *b = routerset_new();
+ int r;
+ (void)arg;
+
+ smartlist_add(a->list, tor_strdup("foo"));
+ smartlist_add(b->list, tor_strdup("foo"));
+ r = routerset_equal(a, b);
+ routerset_free(a);
+ routerset_free(b);
+
+ tt_int_op(r, OP_EQ, 1);
+ done:
+ ;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE ASPECT(routerset_free, null_routerset)
+
+/*
+ * Structural test for routerset_free, where the routerset is NULL.
+ */
+
+NS_DECL(void, smartlist_free, (smartlist_t *sl));
+
+static void
+NS(test_main)(void *arg)
+{
+ (void)arg;
+
+ NS_MOCK(smartlist_free);
+
+ routerset_free(NULL);
+
+ tt_int_op(CALLED(smartlist_free), OP_EQ, 0);
+
+ done:
+ ;
+}
+
+void
+NS(smartlist_free)(smartlist_t *s)
+{
+ (void)s;
+ CALLED(smartlist_free)++;
+}
+
+#undef NS_SUBMODULE
+#define NS_SUBMODULE routerset_free
+
+/*
+ * Structural test for routerset_free.
+ */
+
+NS_DECL(void, smartlist_free, (smartlist_t *sl));
+NS_DECL(void, strmap_free,(strmap_t *map, void (*free_val)(void*)));
+NS_DECL(void, digestmap_free, (digestmap_t *map, void (*free_val)(void*)));
+
+static void
+NS(test_main)(void *arg)
+{
+ routerset_t *routerset = routerset_new();
+ (void)arg;
+
+ NS_MOCK(smartlist_free);
+ NS_MOCK(strmap_free);
+ NS_MOCK(digestmap_free);
+
+ routerset_free(routerset);
+
+ tt_int_op(CALLED(smartlist_free), OP_NE, 0);
+ tt_int_op(CALLED(strmap_free), OP_NE, 0);
+ tt_int_op(CALLED(digestmap_free), OP_NE, 0);
+
+ done:
+ ;
+}
+
+void
+NS(smartlist_free)(smartlist_t *s)
+{
+ CALLED(smartlist_free)++;
+ smartlist_free__real(s);
+}
+
+void
+NS(strmap_free)(strmap_t *map, void (*free_val)(void*))
+{
+ CALLED(strmap_free)++;
+ strmap_free__real(map, free_val);
+}
+
+void
+NS(digestmap_free)(digestmap_t *map, void (*free_val)(void*))
+{
+ CALLED(digestmap_free)++;
+ digestmap_free__real(map, free_val);
+}
+
+#undef NS_SUBMODULE
+
+struct testcase_t routerset_tests[] = {
+ TEST_CASE(routerset_new),
+ TEST_CASE(routerset_get_countryname),
+ TEST_CASE(routerset_is_list),
+ TEST_CASE(routerset_needs_geoip),
+ TEST_CASE(routerset_is_empty),
+ TEST_CASE_ASPECT(routerset_contains, null_set_or_null_set_list),
+ TEST_CASE_ASPECT(routerset_contains, set_and_nickname),
+ TEST_CASE_ASPECT(routerset_contains, set_and_null_nickname),
+ TEST_CASE_ASPECT(routerset_contains, set_and_no_nickname),
+ TEST_CASE_ASPECT(routerset_contains, set_and_digest),
+ TEST_CASE_ASPECT(routerset_contains, set_and_no_digest),
+ TEST_CASE_ASPECT(routerset_contains, set_and_null_digest),
+ TEST_CASE_ASPECT(routerset_contains, set_and_addr),
+ TEST_CASE_ASPECT(routerset_contains, set_and_no_addr),
+ TEST_CASE_ASPECT(routerset_contains, set_and_null_addr),
+ TEST_CASE_ASPECT(routerset_contains, countries_no_geoip),
+ TEST_CASE_ASPECT(routerset_contains, countries_geoip),
+ TEST_CASE_ASPECT(routerset_add_unknown_ccs, only_flag_and_no_ccs),
+ TEST_CASE_ASPECT(routerset_add_unknown_ccs, creates_set),
+ TEST_CASE_ASPECT(routerset_add_unknown_ccs, add_unknown),
+ TEST_CASE_ASPECT(routerset_add_unknown_ccs, add_a1),
+ TEST_CASE(routerset_contains_extendinfo),
+ TEST_CASE(routerset_contains_router),
+ TEST_CASE(routerset_contains_routerstatus),
+ TEST_CASE_ASPECT(routerset_contains_node, none),
+ TEST_CASE_ASPECT(routerset_contains_node, routerinfo),
+ TEST_CASE_ASPECT(routerset_contains_node, routerstatus),
+ TEST_CASE_ASPECT(routerset_get_all_nodes, no_routerset),
+ TEST_CASE_ASPECT(routerset_get_all_nodes, list_with_no_nodes),
+ TEST_CASE_ASPECT(routerset_get_all_nodes, list_flag_not_running),
+ TEST_CASE_ASPECT(routerset_get_all_nodes, list),
+ TEST_CASE_ASPECT(routerset_get_all_nodes, nodelist_with_no_nodes),
+ TEST_CASE_ASPECT(routerset_get_all_nodes, nodelist_flag_not_running),
+ TEST_CASE_ASPECT(routerset_refresh_counties, geoip_not_loaded),
+ TEST_CASE_ASPECT(routerset_refresh_counties, no_countries),
+ TEST_CASE_ASPECT(routerset_refresh_counties, one_valid_country),
+ TEST_CASE_ASPECT(routerset_refresh_counties, one_invalid_country),
+ TEST_CASE_ASPECT(routerset_union, source_bad),
+ TEST_CASE_ASPECT(routerset_union, one),
+ TEST_CASE_ASPECT(routerset_parse, malformed),
+ TEST_CASE_ASPECT(routerset_parse, valid_hexdigest),
+ TEST_CASE_ASPECT(routerset_parse, valid_nickname),
+ TEST_CASE_ASPECT(routerset_parse, get_countryname),
+ TEST_CASE_ASPECT(routerset_parse, policy),
+ TEST_CASE(routerset_subtract_nodes),
+ TEST_CASE_ASPECT(routerset_subtract_nodes, null_routerset),
+ TEST_CASE(routerset_to_string),
+ TEST_CASE_ASPECT(routerset_equal, empty_empty),
+ TEST_CASE_ASPECT(routerset_equal, empty_not_empty),
+ TEST_CASE_ASPECT(routerset_equal, differing_lengths),
+ TEST_CASE_ASPECT(routerset_equal, unequal),
+ TEST_CASE_ASPECT(routerset_equal, equal),
+ TEST_CASE_ASPECT(routerset_free, null_routerset),
+ TEST_CASE(routerset_free),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
new file mode 100644
index 0000000000..73a422088f
--- /dev/null
+++ b/src/test/test_scheduler.c
@@ -0,0 +1,763 @@
+/* Copyright (c) 2014-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include <math.h>
+
+#include "orconfig.h"
+
+/* Libevent stuff */
+#ifdef HAVE_EVENT2_EVENT_H
+#include <event2/event.h>
+#else
+#include <event.h>
+#endif
+
+#define TOR_CHANNEL_INTERNAL_
+#define CHANNEL_PRIVATE_
+#include "or.h"
+#include "compat_libevent.h"
+#include "channel.h"
+#define SCHEDULER_PRIVATE_
+#include "scheduler.h"
+
+/* Test suite stuff */
+#include "test.h"
+#include "fakechans.h"
+
+/* Statics in scheduler.c exposed to the test suite */
+extern smartlist_t *channels_pending;
+extern struct event *run_sched_ev;
+extern uint64_t queue_heuristic;
+extern time_t queue_heuristic_timestamp;
+
+/* Event base for scheduelr tests */
+static struct event_base *mock_event_base = NULL;
+
+/* Statics controlling mocks */
+static circuitmux_t *mock_ccm_tgt_1 = NULL;
+static circuitmux_t *mock_ccm_tgt_2 = NULL;
+
+static circuitmux_t *mock_cgp_tgt_1 = NULL;
+static const circuitmux_policy_t *mock_cgp_val_1 = NULL;
+static circuitmux_t *mock_cgp_tgt_2 = NULL;
+static const circuitmux_policy_t *mock_cgp_val_2 = NULL;
+static int scheduler_compare_channels_mock_ctr = 0;
+static int scheduler_run_mock_ctr = 0;
+
+static void channel_flush_some_cells_mock_free_all(void);
+static void channel_flush_some_cells_mock_set(channel_t *chan,
+ ssize_t num_cells);
+
+/* Setup for mock event stuff */
+static void mock_event_free_all(void);
+static void mock_event_init(void);
+
+/* Mocks used by scheduler tests */
+static ssize_t channel_flush_some_cells_mock(channel_t *chan,
+ ssize_t num_cells);
+static int circuitmux_compare_muxes_mock(circuitmux_t *cmux_1,
+ circuitmux_t *cmux_2);
+static const circuitmux_policy_t * circuitmux_get_policy_mock(
+ circuitmux_t *cmux);
+static int scheduler_compare_channels_mock(const void *c1_v,
+ const void *c2_v);
+static void scheduler_run_noop_mock(void);
+static struct event_base * tor_libevent_get_base_mock(void);
+
+/* Scheduler test cases */
+static void test_scheduler_channel_states(void *arg);
+static void test_scheduler_compare_channels(void *arg);
+static void test_scheduler_initfree(void *arg);
+static void test_scheduler_loop(void *arg);
+static void test_scheduler_queue_heuristic(void *arg);
+
+/* Mock event init/free */
+
+/* Shamelessly stolen from compat_libevent.c */
+#define V(major, minor, patch) \
+ (((major) << 24) | ((minor) << 16) | ((patch) << 8))
+
+static void
+mock_event_free_all(void)
+{
+ tt_assert(mock_event_base != NULL);
+
+ if (mock_event_base) {
+ event_base_free(mock_event_base);
+ mock_event_base = NULL;
+ }
+
+ tt_ptr_op(mock_event_base, ==, NULL);
+
+ done:
+ return;
+}
+
+static void
+mock_event_init(void)
+{
+#ifdef HAVE_EVENT2_EVENT_H
+ struct event_config *cfg = NULL;
+#endif
+
+ tt_ptr_op(mock_event_base, ==, NULL);
+
+ /*
+ * Really cut down from tor_libevent_initialize of
+ * src/common/compat_libevent.c to kill config dependencies
+ */
+
+ if (!mock_event_base) {
+#ifdef HAVE_EVENT2_EVENT_H
+ cfg = event_config_new();
+#if LIBEVENT_VERSION_NUMBER >= V(2,0,9)
+ /* We can enable changelist support with epoll, since we don't give
+ * Libevent any dup'd fds. This lets us avoid some syscalls. */
+ event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
+#endif
+ mock_event_base = event_base_new_with_config(cfg);
+ event_config_free(cfg);
+#else
+ mock_event_base = event_init();
+#endif
+ }
+
+ tt_assert(mock_event_base != NULL);
+
+ done:
+ return;
+}
+
+/* Mocks */
+
+typedef struct {
+ const channel_t *chan;
+ ssize_t cells;
+} flush_mock_channel_t;
+
+static smartlist_t *chans_for_flush_mock = NULL;
+
+static void
+channel_flush_some_cells_mock_free_all(void)
+{
+ if (chans_for_flush_mock) {
+ SMARTLIST_FOREACH_BEGIN(chans_for_flush_mock,
+ flush_mock_channel_t *,
+ flush_mock_ch) {
+ SMARTLIST_DEL_CURRENT(chans_for_flush_mock, flush_mock_ch);
+ tor_free(flush_mock_ch);
+ } SMARTLIST_FOREACH_END(flush_mock_ch);
+
+ smartlist_free(chans_for_flush_mock);
+ chans_for_flush_mock = NULL;
+ }
+}
+
+static void
+channel_flush_some_cells_mock_set(channel_t *chan, ssize_t num_cells)
+{
+ flush_mock_channel_t *flush_mock_ch = NULL;
+
+ if (!chan) return;
+ if (num_cells <= 0) return;
+
+ if (!chans_for_flush_mock) {
+ chans_for_flush_mock = smartlist_new();
+ }
+
+ SMARTLIST_FOREACH_BEGIN(chans_for_flush_mock,
+ flush_mock_channel_t *,
+ flush_mock_ch) {
+ if (flush_mock_ch != NULL && flush_mock_ch->chan != NULL) {
+ if (flush_mock_ch->chan == chan) {
+ /* Found it */
+ flush_mock_ch->cells = num_cells;
+ break;
+ }
+ } else {
+ /* That shouldn't be there... */
+ SMARTLIST_DEL_CURRENT(chans_for_flush_mock, flush_mock_ch);
+ tor_free(flush_mock_ch);
+ }
+ } SMARTLIST_FOREACH_END(flush_mock_ch);
+
+ if (!flush_mock_ch) {
+ /* The loop didn't find it */
+ flush_mock_ch = tor_malloc_zero(sizeof(*flush_mock_ch));
+ flush_mock_ch->chan = chan;
+ flush_mock_ch->cells = num_cells;
+ smartlist_add(chans_for_flush_mock, flush_mock_ch);
+ }
+}
+
+static ssize_t
+channel_flush_some_cells_mock(channel_t *chan, ssize_t num_cells)
+{
+ ssize_t flushed = 0, max;
+ char unlimited = 0;
+ flush_mock_channel_t *found = NULL;
+
+ tt_assert(chan != NULL);
+ if (chan) {
+ if (num_cells < 0) {
+ num_cells = 0;
+ unlimited = 1;
+ }
+
+ /* Check if we have it */
+ if (chans_for_flush_mock != NULL) {
+ SMARTLIST_FOREACH_BEGIN(chans_for_flush_mock,
+ flush_mock_channel_t *,
+ flush_mock_ch) {
+ if (flush_mock_ch != NULL && flush_mock_ch->chan != NULL) {
+ if (flush_mock_ch->chan == chan) {
+ /* Found it */
+ found = flush_mock_ch;
+ break;
+ }
+ } else {
+ /* That shouldn't be there... */
+ SMARTLIST_DEL_CURRENT(chans_for_flush_mock, flush_mock_ch);
+ tor_free(flush_mock_ch);
+ }
+ } SMARTLIST_FOREACH_END(flush_mock_ch);
+
+ if (found) {
+ /* We found one */
+ if (found->cells < 0) found->cells = 0;
+
+ if (unlimited) max = found->cells;
+ else max = MIN(found->cells, num_cells);
+
+ flushed += max;
+ found->cells -= max;
+
+ if (found->cells <= 0) {
+ smartlist_remove(chans_for_flush_mock, found);
+ tor_free(found);
+ }
+ }
+ }
+ }
+
+ done:
+ return flushed;
+}
+
+static int
+circuitmux_compare_muxes_mock(circuitmux_t *cmux_1,
+ circuitmux_t *cmux_2)
+{
+ int result = 0;
+
+ tt_assert(cmux_1 != NULL);
+ tt_assert(cmux_2 != NULL);
+
+ if (cmux_1 != cmux_2) {
+ if (cmux_1 == mock_ccm_tgt_1 && cmux_2 == mock_ccm_tgt_2) result = -1;
+ else if (cmux_1 == mock_ccm_tgt_2 && cmux_2 == mock_ccm_tgt_1) {
+ result = 1;
+ } else {
+ if (cmux_1 == mock_ccm_tgt_1 || cmux_1 == mock_ccm_tgt_2) result = -1;
+ else if (cmux_2 == mock_ccm_tgt_1 || cmux_2 == mock_ccm_tgt_2) {
+ result = 1;
+ } else {
+ result = circuitmux_compare_muxes__real(cmux_1, cmux_2);
+ }
+ }
+ }
+ /* else result = 0 always */
+
+ done:
+ return result;
+}
+
+static const circuitmux_policy_t *
+circuitmux_get_policy_mock(circuitmux_t *cmux)
+{
+ const circuitmux_policy_t *result = NULL;
+
+ tt_assert(cmux != NULL);
+ if (cmux) {
+ if (cmux == mock_cgp_tgt_1) result = mock_cgp_val_1;
+ else if (cmux == mock_cgp_tgt_2) result = mock_cgp_val_2;
+ else result = circuitmux_get_policy__real(cmux);
+ }
+
+ done:
+ return result;
+}
+
+static int
+scheduler_compare_channels_mock(const void *c1_v,
+ const void *c2_v)
+{
+ uintptr_t p1, p2;
+
+ p1 = (uintptr_t)(c1_v);
+ p2 = (uintptr_t)(c2_v);
+
+ ++scheduler_compare_channels_mock_ctr;
+
+ if (p1 == p2) return 0;
+ else if (p1 < p2) return 1;
+ else return -1;
+}
+
+static void
+scheduler_run_noop_mock(void)
+{
+ ++scheduler_run_mock_ctr;
+}
+
+static struct event_base *
+tor_libevent_get_base_mock(void)
+{
+ return mock_event_base;
+}
+
+/* Test cases */
+
+static void
+test_scheduler_channel_states(void *arg)
+{
+ channel_t *ch1 = NULL, *ch2 = NULL;
+ int old_count;
+
+ (void)arg;
+
+ /* Set up libevent and scheduler */
+
+ mock_event_init();
+ MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
+ scheduler_init();
+ /*
+ * Install the compare channels mock so we can test
+ * scheduler_touch_channel().
+ */
+ MOCK(scheduler_compare_channels, scheduler_compare_channels_mock);
+ /*
+ * Disable scheduler_run so we can just check the state transitions
+ * without having to make everything it might call work too.
+ */
+ MOCK(scheduler_run, scheduler_run_noop_mock);
+
+ tt_int_op(smartlist_len(channels_pending), ==, 0);
+
+ /* Set up a fake channel */
+ ch1 = new_fake_channel();
+ tt_assert(ch1);
+
+ /* Start it off in OPENING */
+ ch1->state = CHANNEL_STATE_OPENING;
+ /* We'll need a cmux */
+ ch1->cmux = circuitmux_alloc();
+ /* Try to register it */
+ channel_register(ch1);
+ tt_assert(ch1->registered);
+
+ /* It should start off in SCHED_CHAN_IDLE */
+ tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_IDLE);
+
+ /* Now get another one */
+ ch2 = new_fake_channel();
+ tt_assert(ch2);
+ ch2->state = CHANNEL_STATE_OPENING;
+ ch2->cmux = circuitmux_alloc();
+ channel_register(ch2);
+ tt_assert(ch2->registered);
+
+ /* Send it to SCHED_CHAN_WAITING_TO_WRITE */
+ scheduler_channel_has_waiting_cells(ch1);
+ tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_WAITING_TO_WRITE);
+
+ /* This should send it to SCHED_CHAN_PENDING */
+ scheduler_channel_wants_writes(ch1);
+ tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), ==, 1);
+
+ /* Now send ch2 to SCHED_CHAN_WAITING_FOR_CELLS */
+ scheduler_channel_wants_writes(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+
+ /* Drop ch2 back to idle */
+ scheduler_channel_doesnt_want_writes(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_IDLE);
+
+ /* ...and back to SCHED_CHAN_WAITING_FOR_CELLS */
+ scheduler_channel_wants_writes(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+
+ /* ...and this should kick ch2 into SCHED_CHAN_PENDING */
+ scheduler_channel_has_waiting_cells(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), ==, 2);
+
+ /* This should send ch2 to SCHED_CHAN_WAITING_TO_WRITE */
+ scheduler_channel_doesnt_want_writes(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_TO_WRITE);
+ tt_int_op(smartlist_len(channels_pending), ==, 1);
+
+ /* ...and back to SCHED_CHAN_PENDING */
+ scheduler_channel_wants_writes(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), ==, 2);
+
+ /* Now we exercise scheduler_touch_channel */
+ old_count = scheduler_compare_channels_mock_ctr;
+ scheduler_touch_channel(ch1);
+ tt_assert(scheduler_compare_channels_mock_ctr > old_count);
+
+ /* Close */
+ channel_mark_for_close(ch1);
+ tt_int_op(ch1->state, ==, CHANNEL_STATE_CLOSING);
+ channel_mark_for_close(ch2);
+ tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSING);
+ channel_closed(ch1);
+ tt_int_op(ch1->state, ==, CHANNEL_STATE_CLOSED);
+ ch1 = NULL;
+ channel_closed(ch2);
+ tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSED);
+ ch2 = NULL;
+
+ /* Shut things down */
+
+ channel_free_all();
+ scheduler_free_all();
+ mock_event_free_all();
+
+ done:
+ tor_free(ch1);
+ tor_free(ch2);
+
+ UNMOCK(scheduler_compare_channels);
+ UNMOCK(scheduler_run);
+ UNMOCK(tor_libevent_get_base);
+
+ return;
+}
+
+static void
+test_scheduler_compare_channels(void *arg)
+{
+ /* We don't actually need whole fake channels... */
+ channel_t c1, c2;
+ /* ...and some dummy circuitmuxes too */
+ circuitmux_t *cm1 = NULL, *cm2 = NULL;
+ int result;
+
+ (void)arg;
+
+ /* We can't actually see sizeof(circuitmux_t) from here */
+ cm1 = tor_malloc_zero(sizeof(void *));
+ cm2 = tor_malloc_zero(sizeof(void *));
+
+ c1.cmux = cm1;
+ c2.cmux = cm2;
+
+ /* Configure circuitmux_get_policy() mock */
+ mock_cgp_tgt_1 = cm1;
+ /*
+ * This is to test the different-policies case, which uses the policy
+ * cast to an intptr_t as an arbitrary but definite thing to compare.
+ */
+ mock_cgp_val_1 = (const circuitmux_policy_t *)(1);
+ mock_cgp_tgt_2 = cm2;
+ mock_cgp_val_2 = (const circuitmux_policy_t *)(2);
+
+ MOCK(circuitmux_get_policy, circuitmux_get_policy_mock);
+
+ /* Now set up circuitmux_compare_muxes() mock using cm1/cm2 */
+ mock_ccm_tgt_1 = cm1;
+ mock_ccm_tgt_2 = cm2;
+ MOCK(circuitmux_compare_muxes, circuitmux_compare_muxes_mock);
+
+ /* Equal-channel case */
+ result = scheduler_compare_channels(&c1, &c1);
+ tt_int_op(result, ==, 0);
+
+ /* Distinct channels, distinct policies */
+ result = scheduler_compare_channels(&c1, &c2);
+ tt_int_op(result, ==, -1);
+ result = scheduler_compare_channels(&c2, &c1);
+ tt_int_op(result, ==, 1);
+
+ /* Distinct channels, same policy */
+ mock_cgp_val_2 = mock_cgp_val_1;
+ result = scheduler_compare_channels(&c1, &c2);
+ tt_int_op(result, ==, -1);
+ result = scheduler_compare_channels(&c2, &c1);
+ tt_int_op(result, ==, 1);
+
+ done:
+
+ UNMOCK(circuitmux_compare_muxes);
+ mock_ccm_tgt_1 = NULL;
+ mock_ccm_tgt_2 = NULL;
+
+ UNMOCK(circuitmux_get_policy);
+ mock_cgp_tgt_1 = NULL;
+ mock_cgp_val_1 = NULL;
+ mock_cgp_tgt_2 = NULL;
+ mock_cgp_val_2 = NULL;
+
+ tor_free(cm1);
+ tor_free(cm2);
+
+ return;
+}
+
+static void
+test_scheduler_initfree(void *arg)
+{
+ (void)arg;
+
+ tt_ptr_op(channels_pending, ==, NULL);
+ tt_ptr_op(run_sched_ev, ==, NULL);
+
+ mock_event_init();
+ MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
+
+ scheduler_init();
+
+ tt_assert(channels_pending != NULL);
+ tt_assert(run_sched_ev != NULL);
+
+ scheduler_free_all();
+
+ UNMOCK(tor_libevent_get_base);
+ mock_event_free_all();
+
+ tt_ptr_op(channels_pending, ==, NULL);
+ tt_ptr_op(run_sched_ev, ==, NULL);
+
+ done:
+ return;
+}
+
+static void
+test_scheduler_loop(void *arg)
+{
+ channel_t *ch1 = NULL, *ch2 = NULL;
+
+ (void)arg;
+
+ /* Set up libevent and scheduler */
+
+ mock_event_init();
+ MOCK(tor_libevent_get_base, tor_libevent_get_base_mock);
+ scheduler_init();
+ /*
+ * Install the compare channels mock so we can test
+ * scheduler_touch_channel().
+ */
+ MOCK(scheduler_compare_channels, scheduler_compare_channels_mock);
+ /*
+ * Disable scheduler_run so we can just check the state transitions
+ * without having to make everything it might call work too.
+ */
+ MOCK(scheduler_run, scheduler_run_noop_mock);
+
+ tt_int_op(smartlist_len(channels_pending), ==, 0);
+
+ /* Set up a fake channel */
+ ch1 = new_fake_channel();
+ tt_assert(ch1);
+
+ /* Start it off in OPENING */
+ ch1->state = CHANNEL_STATE_OPENING;
+ /* We'll need a cmux */
+ ch1->cmux = circuitmux_alloc();
+ /* Try to register it */
+ channel_register(ch1);
+ tt_assert(ch1->registered);
+ /* Finish opening it */
+ channel_change_state(ch1, CHANNEL_STATE_OPEN);
+
+ /* It should start off in SCHED_CHAN_IDLE */
+ tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_IDLE);
+
+ /* Now get another one */
+ ch2 = new_fake_channel();
+ tt_assert(ch2);
+ ch2->state = CHANNEL_STATE_OPENING;
+ ch2->cmux = circuitmux_alloc();
+ channel_register(ch2);
+ tt_assert(ch2->registered);
+ /*
+ * Don't open ch2; then channel_num_cells_writeable() will return
+ * zero and we'll get coverage of that exception case in scheduler_run()
+ */
+
+ tt_int_op(ch1->state, ==, CHANNEL_STATE_OPEN);
+ tt_int_op(ch2->state, ==, CHANNEL_STATE_OPENING);
+
+ /* Send it to SCHED_CHAN_WAITING_TO_WRITE */
+ scheduler_channel_has_waiting_cells(ch1);
+ tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_WAITING_TO_WRITE);
+
+ /* This should send it to SCHED_CHAN_PENDING */
+ scheduler_channel_wants_writes(ch1);
+ tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), ==, 1);
+
+ /* Now send ch2 to SCHED_CHAN_WAITING_FOR_CELLS */
+ scheduler_channel_wants_writes(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+
+ /* Drop ch2 back to idle */
+ scheduler_channel_doesnt_want_writes(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_IDLE);
+
+ /* ...and back to SCHED_CHAN_WAITING_FOR_CELLS */
+ scheduler_channel_wants_writes(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+
+ /* ...and this should kick ch2 into SCHED_CHAN_PENDING */
+ scheduler_channel_has_waiting_cells(ch2);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), ==, 2);
+
+ /*
+ * Now we've got two pending channels and need to fire off
+ * scheduler_run(); first, unmock it.
+ */
+
+ UNMOCK(scheduler_run);
+
+ scheduler_run();
+
+ /* Now re-mock it */
+ MOCK(scheduler_run, scheduler_run_noop_mock);
+
+ /*
+ * Assert that they're still in the states we left and aren't still
+ * pending
+ */
+ tt_int_op(ch1->state, ==, CHANNEL_STATE_OPEN);
+ tt_int_op(ch2->state, ==, CHANNEL_STATE_OPENING);
+ tt_assert(ch1->scheduler_state != SCHED_CHAN_PENDING);
+ tt_assert(ch2->scheduler_state != SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), ==, 0);
+
+ /* Now, finish opening ch2, and get both back to pending */
+ channel_change_state(ch2, CHANNEL_STATE_OPEN);
+ scheduler_channel_wants_writes(ch1);
+ scheduler_channel_wants_writes(ch2);
+ scheduler_channel_has_waiting_cells(ch1);
+ scheduler_channel_has_waiting_cells(ch2);
+ tt_int_op(ch1->state, ==, CHANNEL_STATE_OPEN);
+ tt_int_op(ch2->state, ==, CHANNEL_STATE_OPEN);
+ tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_PENDING);
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_PENDING);
+ tt_int_op(smartlist_len(channels_pending), ==, 2);
+
+ /* Now, set up the channel_flush_some_cells() mock */
+ MOCK(channel_flush_some_cells, channel_flush_some_cells_mock);
+ /*
+ * 16 cells on ch1 means it'll completely drain into the 32 cells
+ * fakechan's num_cells_writeable() returns.
+ */
+ channel_flush_some_cells_mock_set(ch1, 16);
+ /*
+ * This one should get sent back to pending, since num_cells_writeable()
+ * will still return non-zero.
+ */
+ channel_flush_some_cells_mock_set(ch2, 48);
+
+ /*
+ * And re-run the scheduler_run() loop with non-zero returns from
+ * channel_flush_some_cells() this time.
+ */
+ UNMOCK(scheduler_run);
+
+ scheduler_run();
+
+ /* Now re-mock it */
+ MOCK(scheduler_run, scheduler_run_noop_mock);
+
+ /*
+ * ch1 should have gone to SCHED_CHAN_WAITING_FOR_CELLS, with 16 flushed
+ * and 32 writeable.
+ */
+ tt_int_op(ch1->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+ /*
+ * ...ch2 should also have gone to SCHED_CHAN_WAITING_FOR_CELLS, with
+ * channel_more_to_flush() returning false and channel_num_cells_writeable()
+ * > 0/
+ */
+ tt_int_op(ch2->scheduler_state, ==, SCHED_CHAN_WAITING_FOR_CELLS);
+
+ /* Close */
+ channel_mark_for_close(ch1);
+ tt_int_op(ch1->state, ==, CHANNEL_STATE_CLOSING);
+ channel_mark_for_close(ch2);
+ tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSING);
+ channel_closed(ch1);
+ tt_int_op(ch1->state, ==, CHANNEL_STATE_CLOSED);
+ ch1 = NULL;
+ channel_closed(ch2);
+ tt_int_op(ch2->state, ==, CHANNEL_STATE_CLOSED);
+ ch2 = NULL;
+
+ /* Shut things down */
+ channel_flush_some_cells_mock_free_all();
+ channel_free_all();
+ scheduler_free_all();
+ mock_event_free_all();
+
+ done:
+ tor_free(ch1);
+ tor_free(ch2);
+
+ UNMOCK(channel_flush_some_cells);
+ UNMOCK(scheduler_compare_channels);
+ UNMOCK(scheduler_run);
+ UNMOCK(tor_libevent_get_base);
+}
+
+static void
+test_scheduler_queue_heuristic(void *arg)
+{
+ time_t now = approx_time();
+ uint64_t qh;
+
+ (void)arg;
+
+ queue_heuristic = 0;
+ queue_heuristic_timestamp = 0;
+
+ /* Not yet inited case */
+ scheduler_update_queue_heuristic(now - 180);
+ tt_u64_op(queue_heuristic, ==, 0);
+ tt_int_op(queue_heuristic_timestamp, ==, now - 180);
+
+ queue_heuristic = 1000000000L;
+ queue_heuristic_timestamp = now - 120;
+
+ scheduler_update_queue_heuristic(now - 119);
+ tt_u64_op(queue_heuristic, ==, 500000000L);
+ tt_int_op(queue_heuristic_timestamp, ==, now - 119);
+
+ scheduler_update_queue_heuristic(now - 116);
+ tt_u64_op(queue_heuristic, ==, 62500000L);
+ tt_int_op(queue_heuristic_timestamp, ==, now - 116);
+
+ qh = scheduler_get_queue_heuristic();
+ tt_u64_op(qh, ==, 0);
+
+ done:
+ return;
+}
+
+struct testcase_t scheduler_tests[] = {
+ { "channel_states", test_scheduler_channel_states, TT_FORK, NULL, NULL },
+ { "compare_channels", test_scheduler_compare_channels,
+ TT_FORK, NULL, NULL },
+ { "initfree", test_scheduler_initfree, TT_FORK, NULL, NULL },
+ { "loop", test_scheduler_loop, TT_FORK, NULL, NULL },
+ { "queue_heuristic", test_scheduler_queue_heuristic,
+ TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_slow.c b/src/test/test_slow.c
new file mode 100644
index 0000000000..32386b485e
--- /dev/null
+++ b/src/test/test_slow.c
@@ -0,0 +1,29 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_slow.c
+ * \brief Slower unit tests for many pieces of the lower level Tor modules.
+ **/
+
+#include "orconfig.h"
+
+#include <stdio.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "or.h"
+#include "test.h"
+
+extern struct testcase_t slow_crypto_tests[];
+extern struct testcase_t slow_util_tests[];
+
+struct testgroup_t testgroups[] = {
+ { "slow/crypto/", slow_crypto_tests },
+ { "slow/util/", slow_util_tests },
+ END_OF_GROUPS
+};
+
diff --git a/src/test/test_socks.c b/src/test/test_socks.c
index 4ce61e068b..465e427930 100644
--- a/src/test/test_socks.c
+++ b/src/test/test_socks.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "or.h"
@@ -61,10 +61,10 @@ test_socks_4_unsupported_commands(void *ptr)
/* SOCKS 4 Send BIND [02] to IP address 2.2.2.2:4369 */
ADD_DATA(buf, "\x04\x02\x11\x11\x02\x02\x02\x02\x00");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
get_options()->SafeSocks) == -1);
- test_eq(4, socks->socks_version);
- test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
+ tt_int_op(4,OP_EQ, socks->socks_version);
+ tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */
done:
;
@@ -76,49 +76,49 @@ test_socks_4_supported_commands(void *ptr)
{
SOCKS_TEST_INIT();
- test_eq(0, buf_datalen(buf));
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
/* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4370 */
ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x03\x00");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
get_options()->SafeSocks) == 1);
- test_eq(4, socks->socks_version);
- test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
- test_eq(SOCKS_COMMAND_CONNECT, socks->command);
- test_streq("2.2.2.3", socks->address);
- test_eq(4370, socks->port);
- test_assert(socks->got_auth == 0);
- test_assert(! socks->username);
-
- test_eq(0, buf_datalen(buf));
+ tt_int_op(4,OP_EQ, socks->socks_version);
+ tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */
+ tt_int_op(SOCKS_COMMAND_CONNECT,OP_EQ, socks->command);
+ tt_str_op("2.2.2.3",OP_EQ, socks->address);
+ tt_int_op(4370,OP_EQ, socks->port);
+ tt_assert(socks->got_auth == 0);
+ tt_assert(! socks->username);
+
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
socks_request_clear(socks);
/* SOCKS 4 Send CONNECT [01] to IP address 2.2.2.2:4369 with userid*/
ADD_DATA(buf, "\x04\x01\x11\x12\x02\x02\x02\x04me\x00");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
get_options()->SafeSocks) == 1);
- test_eq(4, socks->socks_version);
- test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
- test_eq(SOCKS_COMMAND_CONNECT, socks->command);
- test_streq("2.2.2.4", socks->address);
- test_eq(4370, socks->port);
- test_assert(socks->got_auth == 1);
- test_assert(socks->username);
- test_eq(2, socks->usernamelen);
- test_memeq("me", socks->username, 2);
-
- test_eq(0, buf_datalen(buf));
+ tt_int_op(4,OP_EQ, socks->socks_version);
+ tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */
+ tt_int_op(SOCKS_COMMAND_CONNECT,OP_EQ, socks->command);
+ tt_str_op("2.2.2.4",OP_EQ, socks->address);
+ tt_int_op(4370,OP_EQ, socks->port);
+ tt_assert(socks->got_auth == 1);
+ tt_assert(socks->username);
+ tt_int_op(2,OP_EQ, socks->usernamelen);
+ tt_mem_op("me",OP_EQ, socks->username, 2);
+
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
socks_request_clear(socks);
/* SOCKS 4a Send RESOLVE [F0] request for torproject.org */
ADD_DATA(buf, "\x04\xF0\x01\x01\x00\x00\x00\x02me\x00torproject.org\x00");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
get_options()->SafeSocks) == 1);
- test_eq(4, socks->socks_version);
- test_eq(0, socks->replylen); /* XXX: shouldn't tor reply? */
- test_streq("torproject.org", socks->address);
+ tt_int_op(4,OP_EQ, socks->socks_version);
+ tt_int_op(0,OP_EQ, socks->replylen); /* XXX: shouldn't tor reply? */
+ tt_str_op("torproject.org",OP_EQ, socks->address);
- test_eq(0, buf_datalen(buf));
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
done:
;
@@ -133,33 +133,43 @@ test_socks_5_unsupported_commands(void *ptr)
/* SOCKS 5 Send unsupported BIND [02] command */
ADD_DATA(buf, "\x05\x02\x00\x01");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 0);
- test_eq(0, buf_datalen(buf));
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, 0);
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
ADD_DATA(buf, "\x05\x02\x00\x01\x02\x02\x02\x01\x01\x01");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), -1);
- /* XXX: shouldn't tor reply 'command not supported' [07]? */
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, -1);
+
+ tt_int_op(5,OP_EQ,socks->socks_version);
+ tt_int_op(10,OP_EQ,socks->replylen);
+ tt_int_op(5,OP_EQ,socks->reply[0]);
+ tt_int_op(SOCKS5_COMMAND_NOT_SUPPORTED,OP_EQ,socks->reply[1]);
+ tt_int_op(1,OP_EQ,socks->reply[3]);
buf_clear(buf);
socks_request_clear(socks);
/* SOCKS 5 Send unsupported UDP_ASSOCIATE [03] command */
- ADD_DATA(buf, "\x05\x03\x00\x01\x02");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 0);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(2, socks->reply[1]);
+ ADD_DATA(buf, "\x05\x02\x00\x01");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, 0);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
ADD_DATA(buf, "\x05\x03\x00\x01\x02\x02\x02\x01\x01\x01");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), -1);
- /* XXX: shouldn't tor reply 'command not supported' [07]? */
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, -1);
+
+ tt_int_op(5,OP_EQ,socks->socks_version);
+ tt_int_op(10,OP_EQ,socks->replylen);
+ tt_int_op(5,OP_EQ,socks->reply[0]);
+ tt_int_op(SOCKS5_COMMAND_NOT_SUPPORTED,OP_EQ,socks->reply[1]);
+ tt_int_op(1,OP_EQ,socks->reply[3]);
done:
;
@@ -173,64 +183,100 @@ test_socks_5_supported_commands(void *ptr)
/* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */
ADD_DATA(buf, "\x05\x01\x00");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 0);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, 0);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
ADD_DATA(buf, "\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 1);
- test_streq("2.2.2.2", socks->address);
- test_eq(4369, socks->port);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, 1);
+ tt_str_op("2.2.2.2",OP_EQ, socks->address);
+ tt_int_op(4369,OP_EQ, socks->port);
- test_eq(0, buf_datalen(buf));
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
socks_request_clear(socks);
/* SOCKS 5 Send CONNECT [01] to FQDN torproject.org:4369 */
ADD_DATA(buf, "\x05\x01\x00");
ADD_DATA(buf, "\x05\x01\x00\x03\x0Etorproject.org\x11\x11");
- test_eq(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
- get_options()->SafeSocks), 1);
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, 1);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
- test_streq("torproject.org", socks->address);
- test_eq(4369, socks->port);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
+ tt_str_op("torproject.org",OP_EQ, socks->address);
+ tt_int_op(4369,OP_EQ, socks->port);
- test_eq(0, buf_datalen(buf));
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
socks_request_clear(socks);
/* SOCKS 5 Send RESOLVE [F0] request for torproject.org:4369 */
ADD_DATA(buf, "\x05\x01\x00");
ADD_DATA(buf, "\x05\xF0\x00\x03\x0Etorproject.org\x01\x02");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
get_options()->SafeSocks) == 1);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
- test_streq("torproject.org", socks->address);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
+ tt_str_op("torproject.org",OP_EQ, socks->address);
+
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Should reject RESOLVE [F0] request for IPv4 address
+ * string if SafeSocks is enabled. */
+
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF0\x00\x03\x07");
+ ADD_DATA(buf, "8.8.8.8");
+ ADD_DATA(buf, "\x01\x02");
+ tt_assert(fetch_from_buf_socks(buf,socks,get_options()->TestSocks,1)
+ == -1);
+
+ tt_int_op(5,OP_EQ,socks->socks_version);
+ tt_int_op(10,OP_EQ,socks->replylen);
+ tt_int_op(5,OP_EQ,socks->reply[0]);
+ tt_int_op(SOCKS5_NOT_ALLOWED,OP_EQ,socks->reply[1]);
+ tt_int_op(1,OP_EQ,socks->reply[3]);
+
+ socks_request_clear(socks);
+
+ /* SOCKS 5 should reject RESOLVE [F0] reject for IPv6 address
+ * string if SafeSocks is enabled. */
+
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF0\x00\x03\x27");
+ ADD_DATA(buf, "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+ ADD_DATA(buf, "\x01\x02");
+ tt_assert(fetch_from_buf_socks(buf,socks,get_options()->TestSocks,1)
+ == -1);
+
+ tt_int_op(5,OP_EQ,socks->socks_version);
+ tt_int_op(10,OP_EQ,socks->replylen);
+ tt_int_op(5,OP_EQ,socks->reply[0]);
+ tt_int_op(SOCKS5_NOT_ALLOWED,OP_EQ,socks->reply[1]);
+ tt_int_op(1,OP_EQ,socks->reply[3]);
- test_eq(0, buf_datalen(buf));
socks_request_clear(socks);
/* SOCKS 5 Send RESOLVE_PTR [F1] for IP address 2.2.2.5 */
ADD_DATA(buf, "\x05\x01\x00");
ADD_DATA(buf, "\x05\xF1\x00\x01\x02\x02\x02\x05\x01\x03");
- test_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ tt_assert(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
get_options()->SafeSocks) == 1);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(0, socks->reply[1]);
- test_streq("2.2.2.5", socks->address);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
+ tt_str_op("2.2.2.5",OP_EQ, socks->address);
- test_eq(0, buf_datalen(buf));
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
done:
;
@@ -244,30 +290,30 @@ test_socks_5_no_authenticate(void *ptr)
/*SOCKS 5 No Authentication */
ADD_DATA(buf,"\x05\x01\x00");
- test_assert(!fetch_from_buf_socks(buf, socks,
+ tt_assert(!fetch_from_buf_socks(buf, socks,
get_options()->TestSocks,
get_options()->SafeSocks));
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(SOCKS_NO_AUTH, socks->reply[1]);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(SOCKS_NO_AUTH,OP_EQ, socks->reply[1]);
- test_eq(0, buf_datalen(buf));
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
/*SOCKS 5 Send username/password anyway - pretend to be broken */
ADD_DATA(buf,"\x01\x02\x01\x01\x02\x01\x01");
- test_assert(!fetch_from_buf_socks(buf, socks,
+ tt_assert(!fetch_from_buf_socks(buf, socks,
get_options()->TestSocks,
get_options()->SafeSocks));
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(1, socks->reply[0]);
- test_eq(0, socks->reply[1]);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(1,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
- test_eq(2, socks->usernamelen);
- test_eq(2, socks->passwordlen);
+ tt_int_op(2,OP_EQ, socks->usernamelen);
+ tt_int_op(2,OP_EQ, socks->passwordlen);
- test_memeq("\x01\x01", socks->username, 2);
- test_memeq("\x01\x01", socks->password, 2);
+ tt_mem_op("\x01\x01",OP_EQ, socks->username, 2);
+ tt_mem_op("\x01\x01",OP_EQ, socks->password, 2);
done:
;
@@ -282,31 +328,31 @@ test_socks_5_authenticate(void *ptr)
/* SOCKS 5 Negotiate username/password authentication */
ADD_DATA(buf, "\x05\x01\x02");
- test_assert(!fetch_from_buf_socks(buf, socks,
+ tt_assert(!fetch_from_buf_socks(buf, socks,
get_options()->TestSocks,
get_options()->SafeSocks));
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(SOCKS_USER_PASS, socks->reply[1]);
- test_eq(5, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(SOCKS_USER_PASS,OP_EQ, socks->reply[1]);
+ tt_int_op(5,OP_EQ, socks->socks_version);
- test_eq(0, buf_datalen(buf));
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
/* SOCKS 5 Send username/password */
ADD_DATA(buf, "\x01\x02me\x08mypasswd");
- test_assert(!fetch_from_buf_socks(buf, socks,
+ tt_assert(!fetch_from_buf_socks(buf, socks,
get_options()->TestSocks,
get_options()->SafeSocks));
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(1, socks->reply[0]);
- test_eq(0, socks->reply[1]);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(1,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
- test_eq(2, socks->usernamelen);
- test_eq(8, socks->passwordlen);
+ tt_int_op(2,OP_EQ, socks->usernamelen);
+ tt_int_op(8,OP_EQ, socks->passwordlen);
- test_memeq("me", socks->username, 2);
- test_memeq("mypasswd", socks->password, 8);
+ tt_mem_op("me",OP_EQ, socks->username, 2);
+ tt_mem_op("mypasswd",OP_EQ, socks->password, 8);
done:
;
@@ -321,34 +367,34 @@ test_socks_5_authenticate_with_data(void *ptr)
/* SOCKS 5 Negotiate username/password authentication */
ADD_DATA(buf, "\x05\x01\x02");
- test_assert(!fetch_from_buf_socks(buf, socks,
+ tt_assert(!fetch_from_buf_socks(buf, socks,
get_options()->TestSocks,
get_options()->SafeSocks));
- test_eq(2, socks->replylen);
- test_eq(5, socks->reply[0]);
- test_eq(SOCKS_USER_PASS, socks->reply[1]);
- test_eq(5, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(5,OP_EQ, socks->reply[0]);
+ tt_int_op(SOCKS_USER_PASS,OP_EQ, socks->reply[1]);
+ tt_int_op(5,OP_EQ, socks->socks_version);
- test_eq(0, buf_datalen(buf));
+ tt_int_op(0,OP_EQ, buf_datalen(buf));
/* SOCKS 5 Send username/password */
/* SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369 */
ADD_DATA(buf, "\x01\x02me\x03you\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
- test_assert(fetch_from_buf_socks(buf, socks,
+ tt_assert(fetch_from_buf_socks(buf, socks,
get_options()->TestSocks,
get_options()->SafeSocks) == 1);
- test_eq(5, socks->socks_version);
- test_eq(2, socks->replylen);
- test_eq(1, socks->reply[0]);
- test_eq(0, socks->reply[1]);
+ tt_int_op(5,OP_EQ, socks->socks_version);
+ tt_int_op(2,OP_EQ, socks->replylen);
+ tt_int_op(1,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
- test_streq("2.2.2.2", socks->address);
- test_eq(4369, socks->port);
+ tt_str_op("2.2.2.2",OP_EQ, socks->address);
+ tt_int_op(4369,OP_EQ, socks->port);
- test_eq(2, socks->usernamelen);
- test_eq(3, socks->passwordlen);
- test_memeq("me", socks->username, 2);
- test_memeq("you", socks->password, 3);
+ tt_int_op(2,OP_EQ, socks->usernamelen);
+ tt_int_op(3,OP_EQ, socks->passwordlen);
+ tt_mem_op("me",OP_EQ, socks->username, 2);
+ tt_mem_op("you",OP_EQ, socks->password, 3);
done:
;
@@ -362,13 +408,85 @@ test_socks_5_auth_before_negotiation(void *ptr)
/* SOCKS 5 Send username/password */
ADD_DATA(buf, "\x01\x02me\x02me");
- test_assert(fetch_from_buf_socks(buf, socks,
+ tt_assert(fetch_from_buf_socks(buf, socks,
get_options()->TestSocks,
get_options()->SafeSocks) == -1);
- test_eq(0, socks->socks_version);
- test_eq(0, socks->replylen);
- test_eq(0, socks->reply[0]);
- test_eq(0, socks->reply[1]);
+ tt_int_op(0,OP_EQ, socks->socks_version);
+ tt_int_op(0,OP_EQ, socks->replylen);
+ tt_int_op(0,OP_EQ, socks->reply[0]);
+ tt_int_op(0,OP_EQ, socks->reply[1]);
+
+ done:
+ ;
+}
+
+/** Perform malformed SOCKS 5 commands */
+static void
+test_socks_5_malformed_commands(void *ptr)
+{
+ SOCKS_TEST_INIT();
+
+ /* XXX: Stringified address length > MAX_SOCKS_ADDR_LEN will never happen */
+
+ /** SOCKS 5 Send CONNECT [01] to IP address 2.2.2.2:4369, with SafeSocks set
+ */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\x01\x00\x01\x02\x02\x02\x02\x11\x11");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks, 1),
+ OP_EQ, -1);
+
+ tt_int_op(5,OP_EQ,socks->socks_version);
+ tt_int_op(10,OP_EQ,socks->replylen);
+ tt_int_op(5,OP_EQ,socks->reply[0]);
+ tt_int_op(SOCKS5_NOT_ALLOWED,OP_EQ,socks->reply[1]);
+ tt_int_op(1,OP_EQ,socks->reply[3]);
+
+ buf_clear(buf);
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send RESOLVE_PTR [F1] for FQDN torproject.org */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\xF1\x00\x03\x0Etorproject.org\x11\x11");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, -1);
+
+ tt_int_op(5,OP_EQ,socks->socks_version);
+ tt_int_op(10,OP_EQ,socks->replylen);
+ tt_int_op(5,OP_EQ,socks->reply[0]);
+ tt_int_op(SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED,OP_EQ,socks->reply[1]);
+ tt_int_op(1,OP_EQ,socks->reply[3]);
+
+ buf_clear(buf);
+ socks_request_clear(socks);
+
+ /* XXX: len + 1 > MAX_SOCKS_ADDR_LEN (FQDN request) will never happen */
+
+ /* SOCKS 5 Send CONNECT [01] to FQDN """"".com */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\x01\x00\x03\x09\"\"\"\"\".com\x11\x11");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, -1);
+
+ tt_int_op(5,OP_EQ,socks->socks_version);
+ tt_int_op(10,OP_EQ,socks->replylen);
+ tt_int_op(5,OP_EQ,socks->reply[0]);
+ tt_int_op(SOCKS5_GENERAL_ERROR,OP_EQ,socks->reply[1]);
+ tt_int_op(1,OP_EQ,socks->reply[3]);
+
+ buf_clear(buf);
+ socks_request_clear(socks);
+
+ /* SOCKS 5 Send CONNECT [01] to address type 0x23 */
+ ADD_DATA(buf, "\x05\x01\x00");
+ ADD_DATA(buf, "\x05\x01\x00\x23\x02\x02\x02\x02\x11\x11");
+ tt_int_op(fetch_from_buf_socks(buf, socks, get_options()->TestSocks,
+ get_options()->SafeSocks),OP_EQ, -1);
+
+ tt_int_op(5,OP_EQ,socks->socks_version);
+ tt_int_op(10,OP_EQ,socks->replylen);
+ tt_int_op(5,OP_EQ,socks->reply[0]);
+ tt_int_op(SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED,OP_EQ,socks->reply[1]);
+ tt_int_op(1,OP_EQ,socks->reply[3]);
done:
;
@@ -387,6 +505,7 @@ struct testcase_t socks_tests[] = {
SOCKSENT(5_auth_before_negotiation),
SOCKSENT(5_authenticate),
SOCKSENT(5_authenticate_with_data),
+ SOCKSENT(5_malformed_commands),
END_OF_TESTCASES
};
diff --git a/src/test/test_status.c b/src/test/test_status.c
index 46dd473132..cbc8af188c 100644
--- a/src/test/test_status.c
+++ b/src/test/test_status.c
@@ -30,27 +30,24 @@
* global circuits.
*/
-struct global_circuitlist_s mock_global_circuitlist =
- TOR_LIST_HEAD_INITIALIZER(global_circuitlist);
+static smartlist_t * mock_global_circuitlist = NULL;
-NS_DECL(struct global_circuitlist_s *, circuit_get_global_list, (void));
+NS_DECL(smartlist_t *, circuit_get_global_list, (void));
static void
NS(test_main)(void *arg)
{
/* Choose origin_circuit_t wlog. */
origin_circuit_t *mock_circuit1, *mock_circuit2;
- circuit_t *circ, *tmp;
int expected_circuits = 2, actual_circuits;
(void)arg;
mock_circuit1 = tor_malloc_zero(sizeof(origin_circuit_t));
mock_circuit2 = tor_malloc_zero(sizeof(origin_circuit_t));
- TOR_LIST_INSERT_HEAD(
- &mock_global_circuitlist, TO_CIRCUIT(mock_circuit1), head);
- TOR_LIST_INSERT_HEAD(
- &mock_global_circuitlist, TO_CIRCUIT(mock_circuit2), head);
+ mock_global_circuitlist = smartlist_new();
+ smartlist_add(mock_global_circuitlist, TO_CIRCUIT(mock_circuit1));
+ smartlist_add(mock_global_circuitlist, TO_CIRCUIT(mock_circuit2));
NS_MOCK(circuit_get_global_list);
@@ -58,17 +55,18 @@ NS(test_main)(void *arg)
tt_assert(expected_circuits == actual_circuits);
- done:
- TOR_LIST_FOREACH_SAFE(
- circ, NS(circuit_get_global_list)(), head, tmp);
- tor_free(circ);
- NS_UNMOCK(circuit_get_global_list);
+ done:
+ tor_free(mock_circuit1);
+ tor_free(mock_circuit2);
+ smartlist_free(mock_global_circuitlist);
+ mock_global_circuitlist = NULL;
+ NS_UNMOCK(circuit_get_global_list);
}
-static struct global_circuitlist_s *
+static smartlist_t *
NS(circuit_get_global_list)(void)
{
- return &mock_global_circuitlist;
+ return mock_global_circuitlist;
}
#undef NS_SUBMODULE
@@ -88,62 +86,62 @@ NS(test_main)(void *arg)
expected = "0:00 hours";
actual = secs_to_uptime(0);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "0:00 hours";
actual = secs_to_uptime(1);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "0:01 hours";
actual = secs_to_uptime(60);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "0:59 hours";
actual = secs_to_uptime(60 * 59);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1:00 hours";
actual = secs_to_uptime(60 * 60);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "23:59 hours";
actual = secs_to_uptime(60 * 60 * 23 + 60 * 59);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1 day 0:00 hours";
actual = secs_to_uptime(60 * 60 * 23 + 60 * 60);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1 day 0:00 hours";
actual = secs_to_uptime(86400 + 1);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1 day 0:01 hours";
actual = secs_to_uptime(86400 + 60);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "10 days 0:00 hours";
actual = secs_to_uptime(86400 * 10);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "10 days 0:00 hours";
actual = secs_to_uptime(864000 + 1);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "10 days 0:01 hours";
actual = secs_to_uptime(864000 + 60);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
done:
@@ -169,62 +167,62 @@ NS(test_main)(void *arg)
expected = "0 kB";
actual = bytes_to_usage(0);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "0 kB";
actual = bytes_to_usage(1);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1 kB";
actual = bytes_to_usage(1024);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1023 kB";
actual = bytes_to_usage((1 << 20) - 1);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1.00 MB";
actual = bytes_to_usage((1 << 20));
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1.00 MB";
actual = bytes_to_usage((1 << 20) + 5242);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1.01 MB";
actual = bytes_to_usage((1 << 20) + 5243);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1024.00 MB";
actual = bytes_to_usage((1 << 30) - 1);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1.00 GB";
actual = bytes_to_usage((1 << 30));
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1.00 GB";
actual = bytes_to_usage((1 << 30) + 5368709);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "1.01 GB";
actual = bytes_to_usage((1 << 30) + 5368710);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
expected = "10.00 GB";
actual = bytes_to_usage((U64_LITERAL(1) << 30) * 10L);
- tt_str_op(actual, ==, expected);
+ tt_str_op(actual, OP_EQ, expected);
tor_free(actual);
done:
@@ -242,7 +240,6 @@ NS(test_main)(void *arg)
NS_DECL(double, tls_get_write_overhead_ratio, (void));
NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(const or_options_t *, get_options, (void));
NS_DECL(int, public_server_mode, (const or_options_t *options));
NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
@@ -254,19 +251,17 @@ NS(test_main)(void *arg)
NS_MOCK(tls_get_write_overhead_ratio);
NS_MOCK(we_are_hibernating);
- NS_MOCK(get_options);
NS_MOCK(public_server_mode);
NS_MOCK(router_get_my_routerinfo);
expected = -1;
actual = log_heartbeat(0);
- tt_int_op(actual, ==, expected);
+ tt_int_op(actual, OP_EQ, expected);
done:
NS_UNMOCK(tls_get_write_overhead_ratio);
NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(get_options);
NS_UNMOCK(public_server_mode);
NS_UNMOCK(router_get_my_routerinfo);
}
@@ -283,12 +278,6 @@ NS(we_are_hibernating)(void)
return 0;
}
-static const or_options_t *
-NS(get_options)(void)
-{
- return NULL;
-}
-
static int
NS(public_server_mode)(const or_options_t *options)
{
@@ -313,7 +302,6 @@ NS(router_get_my_routerinfo)(void)
NS_DECL(double, tls_get_write_overhead_ratio, (void));
NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(const or_options_t *, get_options, (void));
NS_DECL(int, public_server_mode, (const or_options_t *options));
NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
NS_DECL(const node_t *, node_get_by_id, (const char *identity_digest));
@@ -333,7 +321,6 @@ NS(test_main)(void *arg)
NS_MOCK(tls_get_write_overhead_ratio);
NS_MOCK(we_are_hibernating);
- NS_MOCK(get_options);
NS_MOCK(public_server_mode);
NS_MOCK(router_get_my_routerinfo);
NS_MOCK(node_get_by_id);
@@ -349,13 +336,12 @@ NS(test_main)(void *arg)
expected = 0;
actual = log_heartbeat(0);
- tt_int_op(actual, ==, expected);
- tt_int_op(CALLED(logv), ==, 3);
+ tt_int_op(actual, OP_EQ, expected);
+ tt_int_op(CALLED(logv), OP_EQ, 5);
done:
NS_UNMOCK(tls_get_write_overhead_ratio);
NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(get_options);
NS_UNMOCK(public_server_mode);
NS_UNMOCK(router_get_my_routerinfo);
NS_UNMOCK(node_get_by_id);
@@ -376,12 +362,6 @@ NS(we_are_hibernating)(void)
return 0;
}
-static const or_options_t *
-NS(get_options)(void)
-{
- return NULL;
-}
-
static int
NS(public_server_mode)(const or_options_t *options)
{
@@ -413,39 +393,48 @@ NS(logv)(int severity, log_domain_mask_t domain,
switch (CALLED(logv))
{
case 0:
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==,
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
"Heartbeat: It seems like we are not in the cached consensus.");
break;
case 1:
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==,
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
"Heartbeat: Tor's uptime is %s, with %d circuits open. "
"I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
break;
case 2:
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(
- strstr(funcname, "rep_hist_log_circuit_handshake_stats"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==,
+ tt_int_op(severity, OP_EQ, LOG_INFO);
+ break;
+ case 3:
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "rep_hist_log_circuit_handshake_stats"),
+ OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
"Circuit handshake stats since last time: %d/%d TAP, %d/%d NTor.");
- tt_int_op(va_arg(ap, int), ==, 1); /* handshakes assigned (TAP) */
- tt_int_op(va_arg(ap, int), ==, 1); /* handshakes requested (TAP) */
- tt_int_op(va_arg(ap, int), ==, 1); /* handshakes assigned (NTOR) */
- tt_int_op(va_arg(ap, int), ==, 1); /* handshakes requested (NTOR) */
+ tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes assigned (TAP) */
+ tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes requested (TAP) */
+ tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes assigned (NTOR) */
+ tt_int_op(va_arg(ap, int), OP_EQ, 1); /* handshakes requested (NTOR) */
+ break;
+ case 4:
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "rep_hist_log_link_protocol_counts"),
+ OP_NE, NULL);
break;
default:
tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
@@ -474,7 +463,6 @@ NS(server_mode)(const or_options_t *options)
NS_DECL(double, tls_get_write_overhead_ratio, (void));
NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(const or_options_t *, get_options, (void));
NS_DECL(int, public_server_mode, (const or_options_t *options));
NS_DECL(long, get_uptime, (void));
NS_DECL(uint64_t, get_bytes_read, (void));
@@ -483,6 +471,8 @@ NS_DECL(void, logv, (int severity, log_domain_mask_t domain,
const char *funcname, const char *suffix, const char *format, va_list ap));
NS_DECL(int, server_mode, (const or_options_t *options));
+static int NS(n_msgs) = 0;
+
static void
NS(test_main)(void *arg)
{
@@ -491,7 +481,6 @@ NS(test_main)(void *arg)
NS_MOCK(tls_get_write_overhead_ratio);
NS_MOCK(we_are_hibernating);
- NS_MOCK(get_options);
NS_MOCK(public_server_mode);
NS_MOCK(get_uptime);
NS_MOCK(get_bytes_read);
@@ -504,12 +493,12 @@ NS(test_main)(void *arg)
expected = 0;
actual = log_heartbeat(0);
- tt_int_op(actual, ==, expected);
+ tt_int_op(actual, OP_EQ, expected);
+ tt_int_op(NS(n_msgs), OP_EQ, 1);
done:
NS_UNMOCK(tls_get_write_overhead_ratio);
NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(get_options);
NS_UNMOCK(public_server_mode);
NS_UNMOCK(get_uptime);
NS_UNMOCK(get_bytes_read);
@@ -530,12 +519,6 @@ NS(we_are_hibernating)(void)
return 1;
}
-static const or_options_t *
-NS(get_options)(void)
-{
- return NULL;
-}
-
static int
NS(public_server_mode)(const or_options_t *options)
{
@@ -566,18 +549,22 @@ static void
NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
const char *suffix, const char *format, va_list ap)
{
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==,
+ if (severity == LOG_INFO)
+ return;
+ ++NS(n_msgs);
+
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
"Heartbeat: Tor's uptime is %s, with %d circuits open. "
"I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), ==, " We are currently hibernating.");
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), OP_EQ, " We are currently hibernating.");
done:
;
@@ -601,7 +588,6 @@ NS(server_mode)(const or_options_t *options)
NS_DECL(double, tls_get_write_overhead_ratio, (void));
NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(const or_options_t *, get_options, (void));
NS_DECL(int, public_server_mode, (const or_options_t *options));
NS_DECL(long, get_uptime, (void));
NS_DECL(uint64_t, get_bytes_read, (void));
@@ -624,7 +610,6 @@ NS(test_main)(void *arg)
NS_MOCK(tls_get_write_overhead_ratio);
NS_MOCK(we_are_hibernating);
- NS_MOCK(get_options);
NS_MOCK(public_server_mode);
NS_MOCK(get_uptime);
NS_MOCK(get_bytes_read);
@@ -640,13 +625,12 @@ NS(test_main)(void *arg)
expected = 0;
actual = log_heartbeat(0);
- tt_int_op(actual, ==, expected);
- tt_int_op(CALLED(logv), ==, 2);
+ tt_int_op(actual, OP_EQ, expected);
+ tt_int_op(CALLED(logv), OP_EQ, 3);
done:
NS_UNMOCK(tls_get_write_overhead_ratio);
NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(get_options);
NS_UNMOCK(public_server_mode);
NS_UNMOCK(get_uptime);
NS_UNMOCK(get_bytes_read);
@@ -671,15 +655,6 @@ NS(we_are_hibernating)(void)
return 0;
}
-static const or_options_t *
-NS(get_options)(void)
-{
- NS(mock_options) = tor_malloc_zero(sizeof(or_options_t));
- NS(mock_options)->AccountingMax = 0;
-
- return NS(mock_options);
-}
-
static int
NS(public_server_mode)(const or_options_t *options)
{
@@ -713,34 +688,38 @@ NS(logv)(int severity, log_domain_mask_t domain,
switch (CALLED(logv))
{
case 0:
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==,
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
"Heartbeat: Tor's uptime is %s, with %d circuits open. "
"I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
break;
case 1:
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_accounting"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==,
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_accounting"), OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
"Heartbeat: Accounting enabled. Sent: %s / %s, Received: %s / %s. "
"The current accounting interval ends on %s, in %s.");
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_sent */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_max */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_rcvd */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* acc_max */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_sent */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_max */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_rcvd */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* acc_max */
/* format_local_iso_time uses local tz, just check mins and secs. */
- tt_ptr_op(strstr(va_arg(ap, char *), ":01:00"), !=, NULL); /* end_buf */
- tt_str_op(va_arg(ap, char *), ==, "0:01 hours"); /* remaining */
+ tt_ptr_op(strstr(va_arg(ap, char *), ":01:00"),
+ OP_NE, NULL); /* end_buf */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0:01 hours"); /* remaining */
+ break;
+ case 2:
+ tt_int_op(severity, OP_EQ, LOG_INFO);
break;
default:
tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
@@ -793,7 +772,6 @@ NS(get_or_state)(void)
NS_DECL(double, tls_get_write_overhead_ratio, (void));
NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(const or_options_t *, get_options, (void));
NS_DECL(int, public_server_mode, (const or_options_t *options));
NS_DECL(long, get_uptime, (void));
NS_DECL(uint64_t, get_bytes_read, (void));
@@ -811,7 +789,6 @@ NS(test_main)(void *arg)
NS_MOCK(tls_get_write_overhead_ratio);
NS_MOCK(we_are_hibernating);
- NS_MOCK(get_options);
NS_MOCK(public_server_mode);
NS_MOCK(get_uptime);
NS_MOCK(get_bytes_read);
@@ -822,19 +799,18 @@ NS(test_main)(void *arg)
log_global_min_severity_ = LOG_DEBUG;
stats_n_data_bytes_packaged = RELAY_PAYLOAD_SIZE;
- stats_n_data_cells_packaged = 1;
+ stats_n_data_cells_packaged = 2;
expected = 0;
actual = log_heartbeat(0);
- tt_int_op(actual, ==, expected);
- tt_int_op(CALLED(logv), ==, 2);
+ tt_int_op(actual, OP_EQ, expected);
+ tt_int_op(CALLED(logv), OP_EQ, 2);
done:
stats_n_data_bytes_packaged = 0;
stats_n_data_cells_packaged = 0;
NS_UNMOCK(tls_get_write_overhead_ratio);
NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(get_options);
NS_UNMOCK(public_server_mode);
NS_UNMOCK(get_uptime);
NS_UNMOCK(get_bytes_read);
@@ -856,12 +832,6 @@ NS(we_are_hibernating)(void)
return 0;
}
-static const or_options_t *
-NS(get_options)(void)
-{
- return NULL;
-}
-
static int
NS(public_server_mode)(const or_options_t *options)
{
@@ -895,27 +865,29 @@ NS(logv)(int severity, log_domain_mask_t domain, const char *funcname,
switch (CALLED(logv))
{
case 0:
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==,
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
"Heartbeat: Tor's uptime is %s, with %d circuits open. "
"I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
break;
case 1:
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==,
- "Average packaged cell fullness: %2.3f%%");
- tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, ==, 1);
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
+ "Average packaged cell fullness: %2.3f%%. "
+ "TLS write overhead: %.f%%");
+ tt_double_op(fabs(va_arg(ap, double) - 50.0), <=, DBL_EPSILON);
+ tt_double_op(fabs(va_arg(ap, double) - 0.0), <=, DBL_EPSILON);
break;
default:
tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
@@ -952,7 +924,6 @@ NS(accounting_is_enabled)(const or_options_t *options)
NS_DECL(double, tls_get_write_overhead_ratio, (void));
NS_DECL(int, we_are_hibernating, (void));
-NS_DECL(const or_options_t *, get_options, (void));
NS_DECL(int, public_server_mode, (const or_options_t *options));
NS_DECL(long, get_uptime, (void));
NS_DECL(uint64_t, get_bytes_read, (void));
@@ -970,7 +941,6 @@ NS(test_main)(void *arg)
NS_MOCK(tls_get_write_overhead_ratio);
NS_MOCK(we_are_hibernating);
- NS_MOCK(get_options);
NS_MOCK(public_server_mode);
NS_MOCK(get_uptime);
NS_MOCK(get_bytes_read);
@@ -984,13 +954,12 @@ NS(test_main)(void *arg)
expected = 0;
actual = log_heartbeat(0);
- tt_int_op(actual, ==, expected);
- tt_int_op(CALLED(logv), ==, 2);
+ tt_int_op(actual, OP_EQ, expected);
+ tt_int_op(CALLED(logv), OP_EQ, 2);
done:
NS_UNMOCK(tls_get_write_overhead_ratio);
NS_UNMOCK(we_are_hibernating);
- NS_UNMOCK(get_options);
NS_UNMOCK(public_server_mode);
NS_UNMOCK(get_uptime);
NS_UNMOCK(get_bytes_read);
@@ -1012,12 +981,6 @@ NS(we_are_hibernating)(void)
return 0;
}
-static const or_options_t *
-NS(get_options)(void)
-{
- return NULL;
-}
-
static int
NS(public_server_mode)(const or_options_t *options)
{
@@ -1051,26 +1014,29 @@ NS(logv)(int severity, log_domain_mask_t domain,
switch (CALLED(logv))
{
case 0:
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==,
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
"Heartbeat: Tor's uptime is %s, with %d circuits open. "
"I've sent %s and received %s.%s");
- tt_str_op(va_arg(ap, char *), ==, "0:00 hours"); /* uptime */
- tt_int_op(va_arg(ap, int), ==, 0); /* count_circuits() */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_sent */
- tt_str_op(va_arg(ap, char *), ==, "0 kB"); /* bw_rcvd */
- tt_str_op(va_arg(ap, char *), ==, ""); /* hibernating */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0:00 hours"); /* uptime */
+ tt_int_op(va_arg(ap, int), OP_EQ, 0); /* count_circuits() */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_sent */
+ tt_str_op(va_arg(ap, char *), OP_EQ, "0 kB"); /* bw_rcvd */
+ tt_str_op(va_arg(ap, char *), OP_EQ, ""); /* hibernating */
break;
case 1:
- tt_int_op(severity, ==, LOG_NOTICE);
- tt_int_op(domain, ==, LD_HEARTBEAT);
- tt_ptr_op(strstr(funcname, "log_heartbeat"), !=, NULL);
- tt_ptr_op(suffix, ==, NULL);
- tt_str_op(format, ==, "TLS write overhead: %.f%%");
- tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, ==, 1);
+ tt_int_op(severity, OP_EQ, LOG_NOTICE);
+ tt_int_op(domain, OP_EQ, LD_HEARTBEAT);
+ tt_ptr_op(strstr(funcname, "log_heartbeat"), OP_NE, NULL);
+ tt_ptr_op(suffix, OP_EQ, NULL);
+ tt_str_op(format, OP_EQ,
+ "Average packaged cell fullness: %2.3f%%. "
+ "TLS write overhead: %.f%%");
+ tt_int_op(fabs(va_arg(ap, double) - 100.0) <= DBL_EPSILON, OP_EQ, 1);
+ tt_double_op(fabs(va_arg(ap, double) - 100.0), <=, DBL_EPSILON);
break;
default:
tt_abort_msg("unexpected call to logv()"); // TODO: prettyprint args
diff --git a/src/test/test_threads.c b/src/test/test_threads.c
new file mode 100644
index 0000000000..2ac08d4d28
--- /dev/null
+++ b/src/test/test_threads.c
@@ -0,0 +1,316 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#include "or.h"
+#include "compat_threads.h"
+#include "test.h"
+
+/** mutex for thread test to stop the threads hitting data at the same time. */
+static tor_mutex_t *thread_test_mutex_ = NULL;
+/** mutexes for the thread test to make sure that the threads have to
+ * interleave somewhat. */
+static tor_mutex_t *thread_test_start1_ = NULL,
+ *thread_test_start2_ = NULL;
+/** Shared strmap for the thread test. */
+static strmap_t *thread_test_strmap_ = NULL;
+/** The name of thread1 for the thread test */
+static char *thread1_name_ = NULL;
+/** The name of thread2 for the thread test */
+static char *thread2_name_ = NULL;
+
+static int thread_fns_failed = 0;
+
+static unsigned long thread_fn_tid1, thread_fn_tid2;
+
+static void thread_test_func_(void* _s) ATTR_NORETURN;
+
+/** How many iterations have the threads in the unit test run? */
+static int t1_count = 0, t2_count = 0;
+
+/** Helper function for threading unit tests: This function runs in a
+ * subthread. It grabs its own mutex (start1 or start2) to make sure that it
+ * should start, then it repeatedly alters _test_thread_strmap protected by
+ * thread_test_mutex_. */
+static void
+thread_test_func_(void* _s)
+{
+ char *s = _s;
+ int i, *count;
+ tor_mutex_t *m;
+ char buf[64];
+ char **cp;
+ if (!strcmp(s, "thread 1")) {
+ m = thread_test_start1_;
+ cp = &thread1_name_;
+ count = &t1_count;
+ thread_fn_tid1 = tor_get_thread_id();
+ } else {
+ m = thread_test_start2_;
+ cp = &thread2_name_;
+ count = &t2_count;
+ thread_fn_tid2 = tor_get_thread_id();
+ }
+
+ tor_snprintf(buf, sizeof(buf), "%lu", tor_get_thread_id());
+ *cp = tor_strdup(buf);
+
+ tor_mutex_acquire(m);
+
+ for (i=0; i<10000; ++i) {
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_set(thread_test_strmap_, "last to run", *cp);
+ ++*count;
+ tor_mutex_release(thread_test_mutex_);
+ }
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_set(thread_test_strmap_, s, *cp);
+ if (in_main_thread())
+ ++thread_fns_failed;
+ tor_mutex_release(thread_test_mutex_);
+
+ tor_mutex_release(m);
+
+ spawn_exit();
+}
+
+/** Run unit tests for threading logic. */
+static void
+test_threads_basic(void *arg)
+{
+ char *s1 = NULL, *s2 = NULL;
+ int done = 0, timedout = 0;
+ time_t started;
+#ifndef _WIN32
+ struct timeval tv;
+ tv.tv_sec=0;
+ tv.tv_usec=100*1000;
+#endif
+ (void) arg;
+
+ set_main_thread();
+
+ thread_test_mutex_ = tor_mutex_new();
+ thread_test_start1_ = tor_mutex_new();
+ thread_test_start2_ = tor_mutex_new();
+ thread_test_strmap_ = strmap_new();
+ s1 = tor_strdup("thread 1");
+ s2 = tor_strdup("thread 2");
+ tor_mutex_acquire(thread_test_start1_);
+ tor_mutex_acquire(thread_test_start2_);
+ spawn_func(thread_test_func_, s1);
+ spawn_func(thread_test_func_, s2);
+ tor_mutex_release(thread_test_start2_);
+ tor_mutex_release(thread_test_start1_);
+ started = time(NULL);
+ while (!done) {
+ tor_mutex_acquire(thread_test_mutex_);
+ strmap_assert_ok(thread_test_strmap_);
+ if (strmap_get(thread_test_strmap_, "thread 1") &&
+ strmap_get(thread_test_strmap_, "thread 2")) {
+ done = 1;
+ } else if (time(NULL) > started + 150) {
+ timedout = done = 1;
+ }
+ tor_mutex_release(thread_test_mutex_);
+#ifndef _WIN32
+ /* Prevent the main thread from starving the worker threads. */
+ select(0, NULL, NULL, NULL, &tv);
+#endif
+ }
+ tor_mutex_acquire(thread_test_start1_);
+ tor_mutex_release(thread_test_start1_);
+ tor_mutex_acquire(thread_test_start2_);
+ tor_mutex_release(thread_test_start2_);
+
+ tor_mutex_free(thread_test_mutex_);
+
+ if (timedout) {
+ printf("\nTimed out: %d %d", t1_count, t2_count);
+ tt_assert(strmap_get(thread_test_strmap_, "thread 1"));
+ tt_assert(strmap_get(thread_test_strmap_, "thread 2"));
+ tt_assert(!timedout);
+ }
+
+ /* different thread IDs. */
+ tt_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"),
+ strmap_get(thread_test_strmap_, "thread 2")));
+ tt_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"),
+ strmap_get(thread_test_strmap_, "last to run")) ||
+ !strcmp(strmap_get(thread_test_strmap_, "thread 2"),
+ strmap_get(thread_test_strmap_, "last to run")));
+
+ tt_int_op(thread_fns_failed, ==, 0);
+ tt_int_op(thread_fn_tid1, !=, thread_fn_tid2);
+
+ done:
+ tor_free(s1);
+ tor_free(s2);
+ tor_free(thread1_name_);
+ tor_free(thread2_name_);
+ if (thread_test_strmap_)
+ strmap_free(thread_test_strmap_, NULL);
+ if (thread_test_start1_)
+ tor_mutex_free(thread_test_start1_);
+ if (thread_test_start2_)
+ tor_mutex_free(thread_test_start2_);
+}
+
+typedef struct cv_testinfo_s {
+ tor_cond_t *cond;
+ tor_mutex_t *mutex;
+ int value;
+ int addend;
+ int shutdown;
+ int n_shutdown;
+ int n_wakeups;
+ int n_timeouts;
+ int n_threads;
+ const struct timeval *tv;
+} cv_testinfo_t;
+
+static cv_testinfo_t *
+cv_testinfo_new(void)
+{
+ cv_testinfo_t *i = tor_malloc_zero(sizeof(*i));
+ i->cond = tor_cond_new();
+ i->mutex = tor_mutex_new_nonrecursive();
+ return i;
+}
+
+static void
+cv_testinfo_free(cv_testinfo_t *i)
+{
+ if (!i)
+ return;
+ tor_cond_free(i->cond);
+ tor_mutex_free(i->mutex);
+ tor_free(i);
+}
+
+static void cv_test_thr_fn_(void *arg) ATTR_NORETURN;
+
+static void
+cv_test_thr_fn_(void *arg)
+{
+ cv_testinfo_t *i = arg;
+ int tid, r;
+
+ tor_mutex_acquire(i->mutex);
+ tid = i->n_threads++;
+ tor_mutex_release(i->mutex);
+ (void) tid;
+
+ tor_mutex_acquire(i->mutex);
+ while (1) {
+ if (i->addend) {
+ i->value += i->addend;
+ i->addend = 0;
+ }
+
+ if (i->shutdown) {
+ ++i->n_shutdown;
+ i->shutdown = 0;
+ tor_mutex_release(i->mutex);
+ spawn_exit();
+ }
+ r = tor_cond_wait(i->cond, i->mutex, i->tv);
+ ++i->n_wakeups;
+ if (r == 1) {
+ ++i->n_timeouts;
+ tor_mutex_release(i->mutex);
+ spawn_exit();
+ }
+ }
+}
+
+static void
+test_threads_conditionvar(void *arg)
+{
+ cv_testinfo_t *ti=NULL;
+ const struct timeval msec100 = { 0, 100*1000 };
+ const int timeout = !strcmp(arg, "tv");
+
+ ti = cv_testinfo_new();
+ if (timeout) {
+ ti->tv = &msec100;
+ }
+ spawn_func(cv_test_thr_fn_, ti);
+ spawn_func(cv_test_thr_fn_, ti);
+ spawn_func(cv_test_thr_fn_, ti);
+ spawn_func(cv_test_thr_fn_, ti);
+
+ tor_mutex_acquire(ti->mutex);
+ ti->addend = 7;
+ ti->shutdown = 1;
+ tor_cond_signal_one(ti->cond);
+ tor_mutex_release(ti->mutex);
+
+#define SPIN() \
+ while (1) { \
+ tor_mutex_acquire(ti->mutex); \
+ if (ti->addend == 0) { \
+ break; \
+ } \
+ tor_mutex_release(ti->mutex); \
+ }
+
+ SPIN();
+
+ ti->addend = 30;
+ ti->shutdown = 1;
+ tor_cond_signal_all(ti->cond);
+ tor_mutex_release(ti->mutex);
+ SPIN();
+
+ ti->addend = 1000;
+ if (! timeout) ti->shutdown = 1;
+ tor_cond_signal_one(ti->cond);
+ tor_mutex_release(ti->mutex);
+ SPIN();
+ ti->addend = 300;
+ if (! timeout) ti->shutdown = 1;
+ tor_cond_signal_all(ti->cond);
+ tor_mutex_release(ti->mutex);
+
+ SPIN();
+ tor_mutex_release(ti->mutex);
+
+ tt_int_op(ti->value, ==, 1337);
+ if (!timeout) {
+ tt_int_op(ti->n_shutdown, ==, 4);
+ } else {
+#ifdef _WIN32
+ Sleep(500); /* msec */
+#elif defined(HAVE_USLEEP)
+ usleep(500*1000); /* usec */
+#else
+ {
+ struct tv = { 0, 500*1000 };
+ select(0, NULL, NULL, NULL, &tv);
+ }
+#endif
+ tor_mutex_acquire(ti->mutex);
+ tt_int_op(ti->n_shutdown, ==, 2);
+ tt_int_op(ti->n_timeouts, ==, 2);
+ tor_mutex_release(ti->mutex);
+ }
+
+ done:
+ cv_testinfo_free(ti);
+}
+
+#define THREAD_TEST(name) \
+ { #name, test_threads_##name, TT_FORK, NULL, NULL }
+
+struct testcase_t thread_tests[] = {
+ THREAD_TEST(basic),
+ { "conditionvar", test_threads_conditionvar, TT_FORK,
+ &passthrough_setup, (void*)"no-tv" },
+ { "conditionvar_timeout", test_threads_conditionvar, TT_FORK,
+ &passthrough_setup, (void*)"tv" },
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_util.c b/src/test/test_util.c
index 225fb790f9..51e9e761ab 100644
--- a/src/test/test_util.c
+++ b/src/test/test_util.c
@@ -1,20 +1,16 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#define COMPAT_PRIVATE
#define CONTROL_PRIVATE
-#define MEMPOOL_PRIVATE
#define UTIL_PRIVATE
#include "or.h"
#include "config.h"
#include "control.h"
#include "test.h"
-#ifdef ENABLE_MEMPOOLS
-#include "mempool.h"
-#endif /* ENABLE_MEMPOOLS */
#include "memarea.h"
#include "util_process.h"
@@ -22,6 +18,7 @@
#include <tchar.h>
#endif
#include <math.h>
+#include <ctype.h>
/* XXXX this is a minimal wrapper to make the unit tests compile with the
* changed tor_timegm interface. */
@@ -52,20 +49,20 @@ test_util_read_until_eof_impl(const char *fname, size_t file_len,
crypto_rand(test_str, file_len);
r = write_bytes_to_file(fifo_name, test_str, file_len, 1);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
fd = open(fifo_name, O_RDONLY|O_BINARY);
- tt_int_op(fd, >=, 0);
+ tt_int_op(fd, OP_GE, 0);
str = read_file_to_str_until_eof(fd, read_limit, &sz);
tt_assert(str != NULL);
if (read_limit < file_len)
- tt_int_op(sz, ==, read_limit);
+ tt_int_op(sz, OP_EQ, read_limit);
else
- tt_int_op(sz, ==, file_len);
+ tt_int_op(sz, OP_EQ, file_len);
- test_mem_op(test_str, ==, str, sz);
- test_assert(str[sz] == '\0');
+ tt_mem_op(test_str, OP_EQ, str, sz);
+ tt_int_op(str[sz], OP_EQ, '\0');
done:
unlink(fifo_name);
@@ -87,6 +84,20 @@ test_util_read_file_eof_tiny_limit(void *arg)
}
static void
+test_util_read_file_eof_one_loop_a(void *arg)
+{
+ (void)arg;
+ test_util_read_until_eof_impl("tor_test_fifo_1ka", 1024, 1023);
+}
+
+static void
+test_util_read_file_eof_one_loop_b(void *arg)
+{
+ (void)arg;
+ test_util_read_until_eof_impl("tor_test_fifo_1kb", 1024, 1024);
+}
+
+static void
test_util_read_file_eof_two_loops(void *arg)
{
(void)arg;
@@ -98,6 +109,14 @@ test_util_read_file_eof_two_loops(void *arg)
}
static void
+test_util_read_file_eof_two_loops_b(void *arg)
+{
+ (void)arg;
+
+ test_util_read_until_eof_impl("tor_test_fifo_2kb", 2048, 2048);
+}
+
+static void
test_util_read_file_eof_zero_bytes(void *arg)
{
(void)arg;
@@ -145,17 +164,17 @@ test_util_write_chunks_to_file(void *arg)
// write a known string to a file where the tempfile will be
r = write_bytes_to_file(tempname, temp_str, temp_str_len, 1);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
// call write_chunks_to_file
r = write_chunks_to_file(fname, chunks, 1, 0);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
// assert the file has been written (expected size)
str = read_file_to_str(fname, RFTS_BIN, &st);
tt_assert(str != NULL);
- tt_u64_op((uint64_t)st.st_size, ==, data_str_len);
- test_mem_op(data_str, ==, str, data_str_len);
+ tt_u64_op((uint64_t)st.st_size, OP_EQ, data_str_len);
+ tt_mem_op(data_str, OP_EQ, str, data_str_len);
tor_free(str);
// assert that the tempfile is removed (should not leave artifacts)
@@ -164,7 +183,7 @@ test_util_write_chunks_to_file(void *arg)
// Remove old testfile for second test
r = unlink(fname);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
tor_free(fname);
tor_free(tempname);
@@ -176,24 +195,24 @@ test_util_write_chunks_to_file(void *arg)
// write a known string to a file where the tempfile will be
r = write_bytes_to_file(tempname, temp_str, temp_str_len, 1);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
// call write_chunks_to_file with no_tempfile = true
r = write_chunks_to_file(fname, chunks, 1, 1);
- tt_int_op(r, ==, 0);
+ tt_int_op(r, OP_EQ, 0);
// assert the file has been written (expected size)
str = read_file_to_str(fname, RFTS_BIN, &st);
tt_assert(str != NULL);
- tt_u64_op((uint64_t)st.st_size, ==, data_str_len);
- test_mem_op(data_str, ==, str, data_str_len);
+ tt_u64_op((uint64_t)st.st_size, OP_EQ, data_str_len);
+ tt_mem_op(data_str, OP_EQ, str, data_str_len);
tor_free(str);
// assert the tempfile still contains the known string
str = read_file_to_str(tempname, RFTS_BIN, &st);
tt_assert(str != NULL);
- tt_u64_op((uint64_t)st.st_size, ==, temp_str_len);
- test_mem_op(temp_str, ==, str, temp_str_len);
+ tt_u64_op((uint64_t)st.st_size, OP_EQ, temp_str_len);
+ tt_mem_op(temp_str, OP_EQ, str, temp_str_len);
done:
unlink(fname);
@@ -206,11 +225,24 @@ test_util_write_chunks_to_file(void *arg)
tor_free(temp_str);
}
+#define _TFE(a, b, f) tt_int_op((a).f, OP_EQ, (b).f)
+/** test the minimum set of struct tm fields needed for a unique epoch value
+ * this is also the set we use to test tor_timegm */
+#define TM_EQUAL(a, b) \
+ TT_STMT_BEGIN \
+ _TFE(a, b, tm_year); \
+ _TFE(a, b, tm_mon ); \
+ _TFE(a, b, tm_mday); \
+ _TFE(a, b, tm_hour); \
+ _TFE(a, b, tm_min ); \
+ _TFE(a, b, tm_sec ); \
+ TT_STMT_END
+
static void
-test_util_time(void)
+test_util_time(void *arg)
{
struct timeval start, end;
- struct tm a_time;
+ struct tm a_time, b_time;
char timestr[128];
time_t t_res;
int i;
@@ -218,117 +250,352 @@ test_util_time(void)
/* Test tv_udiff */
+ (void)arg;
start.tv_sec = 5;
start.tv_usec = 5000;
end.tv_sec = 5;
end.tv_usec = 5000;
- test_eq(0L, tv_udiff(&start, &end));
+ tt_int_op(0L,OP_EQ, tv_udiff(&start, &end));
end.tv_usec = 7000;
- test_eq(2000L, tv_udiff(&start, &end));
+ tt_int_op(2000L,OP_EQ, tv_udiff(&start, &end));
end.tv_sec = 6;
- test_eq(1002000L, tv_udiff(&start, &end));
+ tt_int_op(1002000L,OP_EQ, tv_udiff(&start, &end));
end.tv_usec = 0;
- test_eq(995000L, tv_udiff(&start, &end));
+ tt_int_op(995000L,OP_EQ, tv_udiff(&start, &end));
end.tv_sec = 4;
- test_eq(-1005000L, tv_udiff(&start, &end));
+ tt_int_op(-1005000L,OP_EQ, tv_udiff(&start, &end));
- /* Test tor_timegm */
+ /* Test tor_timegm & tor_gmtime_r */
/* The test values here are confirmed to be correct on a platform
- * with a working timegm. */
+ * with a working timegm & gmtime_r. */
+
+ /* Start with known-zero a_time and b_time.
+ * This avoids passing uninitialised values to TM_EQUAL in a_time.
+ * Zeroing may not be needed for b_time, as long as tor_gmtime_r
+ * never reads the existing values in the structure.
+ * But we really don't want intermittently failing tests. */
+ memset(&a_time, 0, sizeof(struct tm));
+ memset(&b_time, 0, sizeof(struct tm));
+
a_time.tm_year = 2003-1900;
a_time.tm_mon = 7;
a_time.tm_mday = 30;
a_time.tm_hour = 6;
a_time.tm_min = 14;
a_time.tm_sec = 55;
- test_eq((time_t) 1062224095UL, tor_timegm(&a_time));
+ t_res = 1062224095UL;
+ tt_int_op(t_res, OP_EQ, tor_timegm(&a_time));
+ tor_gmtime_r(&t_res, &b_time);
+ TM_EQUAL(a_time, b_time);
+
a_time.tm_year = 2004-1900; /* Try a leap year, after feb. */
- test_eq((time_t) 1093846495UL, tor_timegm(&a_time));
+ t_res = 1093846495UL;
+ tt_int_op(t_res, OP_EQ, tor_timegm(&a_time));
+ tor_gmtime_r(&t_res, &b_time);
+ TM_EQUAL(a_time, b_time);
+
a_time.tm_mon = 1; /* Try a leap year, in feb. */
a_time.tm_mday = 10;
- test_eq((time_t) 1076393695UL, tor_timegm(&a_time));
+ t_res = 1076393695UL;
+ tt_int_op(t_res, OP_EQ, tor_timegm(&a_time));
+ tor_gmtime_r(&t_res, &b_time);
+ TM_EQUAL(a_time, b_time);
+
a_time.tm_mon = 0;
- a_time.tm_mday = 10;
- test_eq((time_t) 1073715295UL, tor_timegm(&a_time));
+ t_res = 1073715295UL;
+ tt_int_op(t_res, OP_EQ, tor_timegm(&a_time));
+ tor_gmtime_r(&t_res, &b_time);
+ TM_EQUAL(a_time, b_time);
+
+ /* Test tor_timegm out of range */
+
+ /* year */
+
+ /* Wrong year < 1970 */
+ a_time.tm_year = 1969-1900;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_year = -1-1900;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+#if SIZEOF_INT == 4 || SIZEOF_INT == 8
+ a_time.tm_year = -1*(1 << 16);
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ /* one of the smallest tm_year values my 64 bit system supports:
+ * t_res = -9223372036854775LL without clamping */
+ a_time.tm_year = -292275055-1900;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_year = INT32_MIN;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+#endif
+
+#if SIZEOF_INT == 8
+ a_time.tm_year = -1*(1 << 48);
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ /* while unlikely, the system's gmtime(_r) could return
+ * a "correct" retrospective gregorian negative year value,
+ * which I'm pretty sure is:
+ * -1*(2^63)/60/60/24*2000/730485 + 1970 = -292277022657
+ * 730485 is the number of days in two millenia, including leap days */
+ a_time.tm_year = -292277022657-1900;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_year = INT64_MIN;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+#endif
+
+ /* Wrong year >= INT32_MAX - 1900 */
+#if SIZEOF_INT == 4 || SIZEOF_INT == 8
+ a_time.tm_year = INT32_MAX-1900;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_year = INT32_MAX;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+#endif
+
+#if SIZEOF_INT == 8
+ /* one of the largest tm_year values my 64 bit system supports */
+ a_time.tm_year = 292278994-1900;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ /* while unlikely, the system's gmtime(_r) could return
+ * a "correct" proleptic gregorian year value,
+ * which I'm pretty sure is:
+ * (2^63-1)/60/60/24*2000/730485 + 1970 = 292277026596
+ * 730485 is the number of days in two millenia, including leap days */
+ a_time.tm_year = 292277026596-1900;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_year = INT64_MAX-1900;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_year = INT64_MAX;
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+#endif
+
+ /* month */
+ a_time.tm_year = 2007-1900; /* restore valid year */
+
a_time.tm_mon = 12; /* Wrong month, it's 0-based */
- a_time.tm_mday = 10;
- test_eq((time_t) -1, tor_timegm(&a_time));
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
a_time.tm_mon = -1; /* Wrong month */
- a_time.tm_mday = 10;
- test_eq((time_t) -1, tor_timegm(&a_time));
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ /* day */
+ a_time.tm_mon = 6; /* Try July */
+ a_time.tm_mday = 32; /* Wrong day */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_mon = 5; /* Try June */
+ a_time.tm_mday = 31; /* Wrong day */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_year = 2008-1900; /* Try a leap year */
+ a_time.tm_mon = 1; /* in feb. */
+ a_time.tm_mday = 30; /* Wrong day */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_year = 2011-1900; /* Try a non-leap year */
+ a_time.tm_mon = 1; /* in feb. */
+ a_time.tm_mday = 29; /* Wrong day */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_mday = 0; /* Wrong day, it's 1-based (to be different) */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ /* hour */
+ a_time.tm_mday = 3; /* restore valid month day */
+
+ a_time.tm_hour = 24; /* Wrong hour, it's 0-based */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_hour = -1; /* Wrong hour */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ /* minute */
+ a_time.tm_hour = 22; /* restore valid hour */
+
+ a_time.tm_min = 60; /* Wrong minute, it's 0-based */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_min = -1; /* Wrong minute */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ /* second */
+ a_time.tm_min = 37; /* restore valid minute */
+
+ a_time.tm_sec = 61; /* Wrong second: 0-based with leap seconds */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ a_time.tm_sec = -1; /* Wrong second */
+ tt_int_op((time_t) -1,OP_EQ, tor_timegm(&a_time));
+
+ /* Test tor_gmtime_r out of range */
+
+ /* time_t < 0 yields a year clamped to 1 or 1970,
+ * depending on whether the implementation of the system gmtime(_r)
+ * sets struct tm (1) or not (1970) */
+ t_res = -1;
+ tor_gmtime_r(&t_res, &b_time);
+ tt_assert(b_time.tm_year == (1970-1900) ||
+ b_time.tm_year == (1969-1900));
+
+ if (sizeof(time_t) == 4 || sizeof(time_t) == 8) {
+ t_res = -1*(1 << 30);
+ tor_gmtime_r(&t_res, &b_time);
+ tt_assert(b_time.tm_year == (1970-1900) ||
+ b_time.tm_year == (1935-1900));
+
+ t_res = INT32_MIN;
+ tor_gmtime_r(&t_res, &b_time);
+ tt_assert(b_time.tm_year == (1970-1900) ||
+ b_time.tm_year == (1901-1900));
+ }
+
+#if SIZEOF_TIME_T == 8
+ {
+ /* one of the smallest tm_year values my 64 bit system supports:
+ * b_time.tm_year == (-292275055LL-1900LL) without clamping */
+ t_res = -9223372036854775LL;
+ tor_gmtime_r(&t_res, &b_time);
+ tt_assert(b_time.tm_year == (1970-1900) ||
+ b_time.tm_year == (1-1900));
+
+ /* while unlikely, the system's gmtime(_r) could return
+ * a "correct" retrospective gregorian negative year value,
+ * which I'm pretty sure is:
+ * -1*(2^63)/60/60/24*2000/730485 + 1970 = -292277022657
+ * 730485 is the number of days in two millenia, including leap days
+ * (int64_t)b_time.tm_year == (-292277022657LL-1900LL) without clamping */
+ t_res = INT64_MIN;
+ tor_gmtime_r(&t_res, &b_time);
+ tt_assert(b_time.tm_year == (1970-1900) ||
+ b_time.tm_year == (1-1900));
+ }
+#endif
+
+ /* time_t >= INT_MAX yields a year clamped to 2037 or 9999,
+ * depending on whether the implementation of the system gmtime(_r)
+ * sets struct tm (9999) or not (2037) */
+#if SIZEOF_TIME_T == 4 || SIZEOF_TIME_T == 8
+ {
+ t_res = 3*(1 << 29);
+ tor_gmtime_r(&t_res, &b_time);
+ tt_assert(b_time.tm_year == (2021-1900));
+
+ t_res = INT32_MAX;
+ tor_gmtime_r(&t_res, &b_time);
+ tt_assert(b_time.tm_year == (2037-1900) ||
+ b_time.tm_year == (2038-1900));
+ }
+#endif
+
+#if SIZEOF_TIME_T == 8
+ {
+ /* one of the largest tm_year values my 64 bit system supports:
+ * b_time.tm_year == (292278994L-1900L) without clamping */
+ t_res = 9223372036854775LL;
+ tor_gmtime_r(&t_res, &b_time);
+ tt_assert(b_time.tm_year == (2037-1900) ||
+ b_time.tm_year == (9999-1900));
+
+ /* while unlikely, the system's gmtime(_r) could return
+ * a "correct" proleptic gregorian year value,
+ * which I'm pretty sure is:
+ * (2^63-1)/60/60/24*2000/730485 + 1970 = 292277026596
+ * 730485 is the number of days in two millenia, including leap days
+ * (int64_t)b_time.tm_year == (292277026596L-1900L) without clamping */
+ t_res = INT64_MAX;
+ tor_gmtime_r(&t_res, &b_time);
+ tt_assert(b_time.tm_year == (2037-1900) ||
+ b_time.tm_year == (9999-1900));
+ }
+#endif
/* Test {format,parse}_rfc1123_time */
format_rfc1123_time(timestr, 0);
- test_streq("Thu, 01 Jan 1970 00:00:00 GMT", timestr);
+ tt_str_op("Thu, 01 Jan 1970 00:00:00 GMT",OP_EQ, timestr);
format_rfc1123_time(timestr, (time_t)1091580502UL);
- test_streq("Wed, 04 Aug 2004 00:48:22 GMT", timestr);
+ tt_str_op("Wed, 04 Aug 2004 00:48:22 GMT",OP_EQ, timestr);
t_res = 0;
i = parse_rfc1123_time(timestr, &t_res);
- test_eq(0,i);
- test_eq(t_res, (time_t)1091580502UL);
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
/* The timezone doesn't matter */
t_res = 0;
- test_eq(0, parse_rfc1123_time("Wed, 04 Aug 2004 00:48:22 ZUL", &t_res));
- test_eq(t_res, (time_t)1091580502UL);
- test_eq(-1, parse_rfc1123_time("Wed, zz Aug 2004 99-99x99 GMT", &t_res));
- test_eq(-1, parse_rfc1123_time("Wed, 32 Mar 2011 00:00:00 GMT", &t_res));
- test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 24:00:00 GMT", &t_res));
- test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:60:00 GMT", &t_res));
- test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:62 GMT", &t_res));
- test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 1969 23:59:59 GMT", &t_res));
- test_eq(-1, parse_rfc1123_time("Wed, 30 Ene 2011 23:59:59 GMT", &t_res));
- test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:59 GM", &t_res));
-
-#if 0
- /* This fails, I imagine it's important and should be fixed? */
- test_eq(-1, parse_rfc1123_time("Wed, 29 Feb 2011 16:00:00 GMT", &t_res));
- /* Why is this string valid (ie. the test fails because it doesn't
- return -1)? */
- test_eq(-1, parse_rfc1123_time("Wed, 30 Mar 2011 23:59:61 GMT", &t_res));
-#endif
+ tt_int_op(0,OP_EQ,
+ parse_rfc1123_time("Wed, 04 Aug 2004 00:48:22 ZUL", &t_res));
+ tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, zz Aug 2004 99-99x99 GMT", &t_res));
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, 32 Mar 2011 00:00:00 GMT", &t_res));
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, 30 Mar 2011 24:00:00 GMT", &t_res));
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, 30 Mar 2011 23:60:00 GMT", &t_res));
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, 30 Mar 2011 23:59:62 GMT", &t_res));
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, 30 Mar 1969 23:59:59 GMT", &t_res));
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, 30 Ene 2011 23:59:59 GMT", &t_res));
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, 30 Mar 2011 23:59:59 GM", &t_res));
+
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, 29 Feb 2011 16:00:00 GMT", &t_res));
+ tt_int_op(-1,OP_EQ,
+ parse_rfc1123_time("Wed, 30 Mar 2011 23:59:61 GMT", &t_res));
/* Test parse_iso_time */
t_res = 0;
i = parse_iso_time("", &t_res);
- test_eq(-1, i);
+ tt_int_op(-1,OP_EQ, i);
t_res = 0;
i = parse_iso_time("2004-08-32 00:48:22", &t_res);
- test_eq(-1, i);
+ tt_int_op(-1,OP_EQ, i);
t_res = 0;
i = parse_iso_time("1969-08-03 00:48:22", &t_res);
- test_eq(-1, i);
+ tt_int_op(-1,OP_EQ, i);
t_res = 0;
i = parse_iso_time("2004-08-04 00:48:22", &t_res);
- test_eq(0,i);
- test_eq(t_res, (time_t)1091580502UL);
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
t_res = 0;
i = parse_iso_time("2004-8-4 0:48:22", &t_res);
- test_eq(0, i);
- test_eq(t_res, (time_t)1091580502UL);
- test_eq(-1, parse_iso_time("2004-08-zz 99-99x99 GMT", &t_res));
- test_eq(-1, parse_iso_time("2011-03-32 00:00:00 GMT", &t_res));
- test_eq(-1, parse_iso_time("2011-03-30 24:00:00 GMT", &t_res));
- test_eq(-1, parse_iso_time("2011-03-30 23:60:00 GMT", &t_res));
- test_eq(-1, parse_iso_time("2011-03-30 23:59:62 GMT", &t_res));
- test_eq(-1, parse_iso_time("1969-03-30 23:59:59 GMT", &t_res));
- test_eq(-1, parse_iso_time("2011-00-30 23:59:59 GMT", &t_res));
- test_eq(-1, parse_iso_time("2147483647-08-29 14:00:00", &t_res));
- test_eq(-1, parse_iso_time("2011-03-30 23:59", &t_res));
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(t_res,OP_EQ, (time_t)1091580502UL);
+ tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-zz 99-99x99", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-32 00:00:00", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 24:00:00", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 23:60:00", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 23:59:62", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("1969-03-30 23:59:59", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2011-00-30 23:59:59", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2147483647-08-29 14:00:00", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2011-03-30 23:59", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22.100", &t_res));
+ tt_int_op(-1,OP_EQ, parse_iso_time("2004-08-04 00:48:22XYZ", &t_res));
/* Test tor_gettimeofday */
@@ -341,14 +608,14 @@ test_util_time(void)
/* now make sure time works. */
tor_gettimeofday(&end);
/* We might've timewarped a little. */
- tt_int_op(tv_udiff(&start, &end), >=, -5000);
+ tt_int_op(tv_udiff(&start, &end), OP_GE, -5000);
/* Test format_iso_time */
tv.tv_sec = (time_t)1326296338;
tv.tv_usec = 3060;
format_iso_time(timestr, (time_t)tv.tv_sec);
- test_streq("2012-01-11 15:38:58", timestr);
+ tt_str_op("2012-01-11 15:38:58",OP_EQ, timestr);
/* The output of format_local_iso_time will vary by timezone, and setting
our timezone for testing purposes would be a nontrivial flaky pain.
Skip this test for now.
@@ -356,11 +623,11 @@ test_util_time(void)
test_streq("2012-01-11 10:38:58", timestr);
*/
format_iso_time_nospace(timestr, (time_t)tv.tv_sec);
- test_streq("2012-01-11T15:38:58", timestr);
- test_eq(strlen(timestr), ISO_TIME_LEN);
+ tt_str_op("2012-01-11T15:38:58",OP_EQ, timestr);
+ tt_int_op(strlen(timestr),OP_EQ, ISO_TIME_LEN);
format_iso_time_nospace_usec(timestr, &tv);
- test_streq("2012-01-11T15:38:58.003060", timestr);
- test_eq(strlen(timestr), ISO_TIME_USEC_LEN);
+ tt_str_op("2012-01-11T15:38:58.003060",OP_EQ, timestr);
+ tt_int_op(strlen(timestr),OP_EQ, ISO_TIME_USEC_LEN);
done:
;
@@ -375,61 +642,74 @@ test_util_parse_http_time(void *arg)
#define T(s) do { \
format_iso_time(b, tor_timegm(&a_time)); \
- tt_str_op(b, ==, (s)); \
+ tt_str_op(b, OP_EQ, (s)); \
b[0]='\0'; \
} while (0)
/* Test parse_http_time */
- test_eq(-1, parse_http_time("", &a_time));
- test_eq(-1, parse_http_time("Sunday, 32 Aug 2004 00:48:22 GMT", &a_time));
- test_eq(-1, parse_http_time("Sunday, 3 Aug 1869 00:48:22 GMT", &a_time));
- test_eq(-1, parse_http_time("Sunday, 32-Aug-94 00:48:22 GMT", &a_time));
- test_eq(-1, parse_http_time("Sunday, 3-Ago-04 00:48:22", &a_time));
- test_eq(-1, parse_http_time("Sunday, August the third", &a_time));
- test_eq(-1, parse_http_time("Wednesday,,04 Aug 1994 00:48:22 GMT", &a_time));
-
- test_eq(0, parse_http_time("Wednesday, 04 Aug 1994 00:48:22 GMT", &a_time));
- test_eq((time_t)775961302UL, tor_timegm(&a_time));
+ tt_int_op(-1,OP_EQ,
+ parse_http_time("", &a_time));
+ tt_int_op(-1,OP_EQ,
+ parse_http_time("Sunday, 32 Aug 2004 00:48:22 GMT", &a_time));
+ tt_int_op(-1,OP_EQ,
+ parse_http_time("Sunday, 3 Aug 1869 00:48:22 GMT", &a_time));
+ tt_int_op(-1,OP_EQ,
+ parse_http_time("Sunday, 32-Aug-94 00:48:22 GMT", &a_time));
+ tt_int_op(-1,OP_EQ,
+ parse_http_time("Sunday, 3-Ago-04 00:48:22", &a_time));
+ tt_int_op(-1,OP_EQ,
+ parse_http_time("Sunday, August the third", &a_time));
+ tt_int_op(-1,OP_EQ,
+ parse_http_time("Wednesday,,04 Aug 1994 00:48:22 GMT", &a_time));
+
+ tt_int_op(0,OP_EQ,
+ parse_http_time("Wednesday, 04 Aug 1994 00:48:22 GMT", &a_time));
+ tt_int_op((time_t)775961302UL,OP_EQ, tor_timegm(&a_time));
T("1994-08-04 00:48:22");
- test_eq(0, parse_http_time("Wednesday, 4 Aug 1994 0:48:22 GMT", &a_time));
- test_eq((time_t)775961302UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ,
+ parse_http_time("Wednesday, 4 Aug 1994 0:48:22 GMT", &a_time));
+ tt_int_op((time_t)775961302UL,OP_EQ, tor_timegm(&a_time));
T("1994-08-04 00:48:22");
- test_eq(0, parse_http_time("Miercoles, 4 Aug 1994 0:48:22 GMT", &a_time));
- test_eq((time_t)775961302UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ,
+ parse_http_time("Miercoles, 4 Aug 1994 0:48:22 GMT", &a_time));
+ tt_int_op((time_t)775961302UL,OP_EQ, tor_timegm(&a_time));
T("1994-08-04 00:48:22");
- test_eq(0, parse_http_time("Wednesday, 04-Aug-94 00:48:22 GMT", &a_time));
- test_eq((time_t)775961302UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ,
+ parse_http_time("Wednesday, 04-Aug-94 00:48:22 GMT", &a_time));
+ tt_int_op((time_t)775961302UL,OP_EQ, tor_timegm(&a_time));
T("1994-08-04 00:48:22");
- test_eq(0, parse_http_time("Wednesday, 4-Aug-94 0:48:22 GMT", &a_time));
- test_eq((time_t)775961302UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ,
+ parse_http_time("Wednesday, 4-Aug-94 0:48:22 GMT", &a_time));
+ tt_int_op((time_t)775961302UL,OP_EQ, tor_timegm(&a_time));
T("1994-08-04 00:48:22");
- test_eq(0, parse_http_time("Miercoles, 4-Aug-94 0:48:22 GMT", &a_time));
- test_eq((time_t)775961302UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ,
+ parse_http_time("Miercoles, 4-Aug-94 0:48:22 GMT", &a_time));
+ tt_int_op((time_t)775961302UL,OP_EQ, tor_timegm(&a_time));
T("1994-08-04 00:48:22");
- test_eq(0, parse_http_time("Wed Aug 04 00:48:22 1994", &a_time));
- test_eq((time_t)775961302UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ, parse_http_time("Wed Aug 04 00:48:22 1994", &a_time));
+ tt_int_op((time_t)775961302UL,OP_EQ, tor_timegm(&a_time));
T("1994-08-04 00:48:22");
- test_eq(0, parse_http_time("Wed Aug 4 0:48:22 1994", &a_time));
- test_eq((time_t)775961302UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ, parse_http_time("Wed Aug 4 0:48:22 1994", &a_time));
+ tt_int_op((time_t)775961302UL,OP_EQ, tor_timegm(&a_time));
T("1994-08-04 00:48:22");
- test_eq(0, parse_http_time("Mie Aug 4 0:48:22 1994", &a_time));
- test_eq((time_t)775961302UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ, parse_http_time("Mie Aug 4 0:48:22 1994", &a_time));
+ tt_int_op((time_t)775961302UL,OP_EQ, tor_timegm(&a_time));
T("1994-08-04 00:48:22");
- test_eq(0, parse_http_time("Sun, 1 Jan 2012 00:00:00 GMT", &a_time));
- test_eq((time_t)1325376000UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ,parse_http_time("Sun, 1 Jan 2012 00:00:00 GMT", &a_time));
+ tt_int_op((time_t)1325376000UL,OP_EQ, tor_timegm(&a_time));
T("2012-01-01 00:00:00");
- test_eq(0, parse_http_time("Mon, 31 Dec 2012 00:00:00 GMT", &a_time));
- test_eq((time_t)1356912000UL, tor_timegm(&a_time));
+ tt_int_op(0,OP_EQ,parse_http_time("Mon, 31 Dec 2012 00:00:00 GMT", &a_time));
+ tt_int_op((time_t)1356912000UL,OP_EQ, tor_timegm(&a_time));
T("2012-12-31 00:00:00");
- test_eq(-1, parse_http_time("2004-08-zz 99-99x99 GMT", &a_time));
- test_eq(-1, parse_http_time("2011-03-32 00:00:00 GMT", &a_time));
- test_eq(-1, parse_http_time("2011-03-30 24:00:00 GMT", &a_time));
- test_eq(-1, parse_http_time("2011-03-30 23:60:00 GMT", &a_time));
- test_eq(-1, parse_http_time("2011-03-30 23:59:62 GMT", &a_time));
- test_eq(-1, parse_http_time("1969-03-30 23:59:59 GMT", &a_time));
- test_eq(-1, parse_http_time("2011-00-30 23:59:59 GMT", &a_time));
- test_eq(-1, parse_http_time("2011-03-30 23:59", &a_time));
+ tt_int_op(-1,OP_EQ, parse_http_time("2004-08-zz 99-99x99 GMT", &a_time));
+ tt_int_op(-1,OP_EQ, parse_http_time("2011-03-32 00:00:00 GMT", &a_time));
+ tt_int_op(-1,OP_EQ, parse_http_time("2011-03-30 24:00:00 GMT", &a_time));
+ tt_int_op(-1,OP_EQ, parse_http_time("2011-03-30 23:60:00 GMT", &a_time));
+ tt_int_op(-1,OP_EQ, parse_http_time("2011-03-30 23:59:62 GMT", &a_time));
+ tt_int_op(-1,OP_EQ, parse_http_time("1969-03-30 23:59:59 GMT", &a_time));
+ tt_int_op(-1,OP_EQ, parse_http_time("2011-00-30 23:59:59 GMT", &a_time));
+ tt_int_op(-1,OP_EQ, parse_http_time("2011-03-30 23:59", &a_time));
#undef T
done:
@@ -437,13 +717,14 @@ test_util_parse_http_time(void *arg)
}
static void
-test_util_config_line(void)
+test_util_config_line(void *arg)
{
char buf[1024];
char *k=NULL, *v=NULL;
const char *str;
/* Test parse_config_line_from_str */
+ (void)arg;
strlcpy(buf, "k v\n" " key value with spaces \n" "keykey val\n"
"k2\n"
"k3 \n" "\n" " \n" "#comment\n"
@@ -463,110 +744,110 @@ test_util_config_line(void)
str = buf;
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k");
- test_streq(v, "v");
+ tt_str_op(k,OP_EQ, "k");
+ tt_str_op(v,OP_EQ, "v");
tor_free(k); tor_free(v);
- test_assert(!strcmpstart(str, "key value with"));
+ tt_assert(!strcmpstart(str, "key value with"));
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "key");
- test_streq(v, "value with spaces");
+ tt_str_op(k,OP_EQ, "key");
+ tt_str_op(v,OP_EQ, "value with spaces");
tor_free(k); tor_free(v);
- test_assert(!strcmpstart(str, "keykey"));
+ tt_assert(!strcmpstart(str, "keykey"));
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "keykey");
- test_streq(v, "val");
+ tt_str_op(k,OP_EQ, "keykey");
+ tt_str_op(v,OP_EQ, "val");
tor_free(k); tor_free(v);
- test_assert(!strcmpstart(str, "k2\n"));
+ tt_assert(!strcmpstart(str, "k2\n"));
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k2");
- test_streq(v, "");
+ tt_str_op(k,OP_EQ, "k2");
+ tt_str_op(v,OP_EQ, "");
tor_free(k); tor_free(v);
- test_assert(!strcmpstart(str, "k3 \n"));
+ tt_assert(!strcmpstart(str, "k3 \n"));
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k3");
- test_streq(v, "");
+ tt_str_op(k,OP_EQ, "k3");
+ tt_str_op(v,OP_EQ, "");
tor_free(k); tor_free(v);
- test_assert(!strcmpstart(str, "#comment"));
+ tt_assert(!strcmpstart(str, "#comment"));
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k4");
- test_streq(v, "");
+ tt_str_op(k,OP_EQ, "k4");
+ tt_str_op(v,OP_EQ, "");
tor_free(k); tor_free(v);
- test_assert(!strcmpstart(str, "k5#abc"));
+ tt_assert(!strcmpstart(str, "k5#abc"));
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k5");
- test_streq(v, "");
+ tt_str_op(k,OP_EQ, "k5");
+ tt_str_op(v,OP_EQ, "");
tor_free(k); tor_free(v);
- test_assert(!strcmpstart(str, "k6"));
+ tt_assert(!strcmpstart(str, "k6"));
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k6");
- test_streq(v, "val");
+ tt_str_op(k,OP_EQ, "k6");
+ tt_str_op(v,OP_EQ, "val");
tor_free(k); tor_free(v);
- test_assert(!strcmpstart(str, "kseven"));
+ tt_assert(!strcmpstart(str, "kseven"));
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "kseven");
- test_streq(v, "a quoted \'string");
+ tt_str_op(k,OP_EQ, "kseven");
+ tt_str_op(v,OP_EQ, "a quoted \'string");
tor_free(k); tor_free(v);
- test_assert(!strcmpstart(str, "k8 "));
+ tt_assert(!strcmpstart(str, "k8 "));
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k8");
- test_streq(v, "a quoted\n\"str\\ing\t\x01\x01\x01\"");
+ tt_str_op(k,OP_EQ, "k8");
+ tt_str_op(v,OP_EQ, "a quoted\n\"str\\ing\t\x01\x01\x01\"");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k9");
- test_streq(v, "a line that spans two lines.");
+ tt_str_op(k,OP_EQ, "k9");
+ tt_str_op(v,OP_EQ, "a line that spans two lines.");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k10");
- test_streq(v, "more than one continuation");
+ tt_str_op(k,OP_EQ, "k10");
+ tt_str_op(v,OP_EQ, "more than one continuation");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k11");
- test_streq(v, "continuation at the start");
+ tt_str_op(k,OP_EQ, "k11");
+ tt_str_op(v,OP_EQ, "continuation at the start");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k12");
- test_streq(v, "line with a embedded");
+ tt_str_op(k,OP_EQ, "k12");
+ tt_str_op(v,OP_EQ, "line with a embedded");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k13");
- test_streq(v, "continuation at the very start");
+ tt_str_op(k,OP_EQ, "k13");
+ tt_str_op(v,OP_EQ, "continuation at the very start");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k14");
- test_streq(v, "a line that has a comment and" );
+ tt_str_op(k,OP_EQ, "k14");
+ tt_str_op(v,OP_EQ, "a line that has a comment and" );
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k15");
- test_streq(v, "this should be the next new line");
+ tt_str_op(k,OP_EQ, "k15");
+ tt_str_op(v,OP_EQ, "this should be the next new line");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k16");
- test_streq(v, "a line that has a comment and" );
+ tt_str_op(k,OP_EQ, "k16");
+ tt_str_op(v,OP_EQ, "a line that has a comment and" );
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k17");
- test_streq(v, "this should be the next new line");
+ tt_str_op(k,OP_EQ, "k17");
+ tt_str_op(v,OP_EQ, "this should be the next new line");
tor_free(k); tor_free(v);
- test_streq(str, "");
+ tt_str_op(str,OP_EQ, "");
done:
tor_free(k);
@@ -574,7 +855,7 @@ test_util_config_line(void)
}
static void
-test_util_config_line_quotes(void)
+test_util_config_line_quotes(void *arg)
{
char buf1[1024];
char buf2[128];
@@ -584,6 +865,7 @@ test_util_config_line_quotes(void)
const char *str;
/* Test parse_config_line_from_str */
+ (void)arg;
strlcpy(buf1, "kTrailingSpace \"quoted value\" \n"
"kTrailingGarbage \"quoted value\"trailing garbage\n"
, sizeof(buf1));
@@ -596,30 +878,30 @@ test_util_config_line_quotes(void)
str = buf1;
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "kTrailingSpace");
- test_streq(v, "quoted value");
+ tt_str_op(k,OP_EQ, "kTrailingSpace");
+ tt_str_op(v,OP_EQ, "quoted value");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_eq_ptr(str, NULL);
+ tt_ptr_op(str,OP_EQ, NULL);
tor_free(k); tor_free(v);
str = buf2;
str = parse_config_line_from_str(str, &k, &v);
- test_eq_ptr(str, NULL);
+ tt_ptr_op(str,OP_EQ, NULL);
tor_free(k); tor_free(v);
str = buf3;
str = parse_config_line_from_str(str, &k, &v);
- test_eq_ptr(str, NULL);
+ tt_ptr_op(str,OP_EQ, NULL);
tor_free(k); tor_free(v);
str = buf4;
str = parse_config_line_from_str(str, &k, &v);
- test_eq_ptr(str, NULL);
+ tt_ptr_op(str,OP_EQ, NULL);
tor_free(k); tor_free(v);
done:
@@ -628,13 +910,14 @@ test_util_config_line_quotes(void)
}
static void
-test_util_config_line_comment_character(void)
+test_util_config_line_comment_character(void *arg)
{
char buf[1024];
char *k=NULL, *v=NULL;
const char *str;
/* Test parse_config_line_from_str */
+ (void)arg;
strlcpy(buf, "k1 \"# in quotes\"\n"
"k2 some value # some comment\n"
"k3 /home/user/myTorNetwork#2\n" /* Testcase for #1323 */
@@ -642,16 +925,16 @@ test_util_config_line_comment_character(void)
str = buf;
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k1");
- test_streq(v, "# in quotes");
+ tt_str_op(k,OP_EQ, "k1");
+ tt_str_op(v,OP_EQ, "# in quotes");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "k2");
- test_streq(v, "some value");
+ tt_str_op(k,OP_EQ, "k2");
+ tt_str_op(v,OP_EQ, "some value");
tor_free(k); tor_free(v);
- test_streq(str, "k3 /home/user/myTorNetwork#2\n");
+ tt_str_op(str,OP_EQ, "k3 /home/user/myTorNetwork#2\n");
#if 0
str = parse_config_line_from_str(str, &k, &v);
@@ -668,7 +951,7 @@ test_util_config_line_comment_character(void)
}
static void
-test_util_config_line_escaped_content(void)
+test_util_config_line_escaped_content(void *arg)
{
char buf1[1024];
char buf2[128];
@@ -680,6 +963,7 @@ test_util_config_line_escaped_content(void)
const char *str;
/* Test parse_config_line_from_str */
+ (void)arg;
strlcpy(buf1, "HexadecimalLower \"\\x2a\"\n"
"HexadecimalUpper \"\\x2A\"\n"
"HexadecimalUpperX \"\\X2A\"\n"
@@ -711,91 +995,91 @@ test_util_config_line_escaped_content(void)
str = buf1;
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "HexadecimalLower");
- test_streq(v, "*");
+ tt_str_op(k,OP_EQ, "HexadecimalLower");
+ tt_str_op(v,OP_EQ, "*");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "HexadecimalUpper");
- test_streq(v, "*");
+ tt_str_op(k,OP_EQ, "HexadecimalUpper");
+ tt_str_op(v,OP_EQ, "*");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "HexadecimalUpperX");
- test_streq(v, "*");
+ tt_str_op(k,OP_EQ, "HexadecimalUpperX");
+ tt_str_op(v,OP_EQ, "*");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "Octal");
- test_streq(v, "*");
+ tt_str_op(k,OP_EQ, "Octal");
+ tt_str_op(v,OP_EQ, "*");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "Newline");
- test_streq(v, "\n");
+ tt_str_op(k,OP_EQ, "Newline");
+ tt_str_op(v,OP_EQ, "\n");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "Tab");
- test_streq(v, "\t");
+ tt_str_op(k,OP_EQ, "Tab");
+ tt_str_op(v,OP_EQ, "\t");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "CarriageReturn");
- test_streq(v, "\r");
+ tt_str_op(k,OP_EQ, "CarriageReturn");
+ tt_str_op(v,OP_EQ, "\r");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "DoubleQuote");
- test_streq(v, "\"");
+ tt_str_op(k,OP_EQ, "DoubleQuote");
+ tt_str_op(v,OP_EQ, "\"");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "SimpleQuote");
- test_streq(v, "'");
+ tt_str_op(k,OP_EQ, "SimpleQuote");
+ tt_str_op(v,OP_EQ, "'");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "Backslash");
- test_streq(v, "\\");
+ tt_str_op(k,OP_EQ, "Backslash");
+ tt_str_op(v,OP_EQ, "\\");
tor_free(k); tor_free(v);
str = parse_config_line_from_str(str, &k, &v);
- test_streq(k, "Mix");
- test_streq(v, "This is a \"star\":\t'*'\nAnd second line");
+ tt_str_op(k,OP_EQ, "Mix");
+ tt_str_op(v,OP_EQ, "This is a \"star\":\t'*'\nAnd second line");
tor_free(k); tor_free(v);
- test_streq(str, "");
+ tt_str_op(str,OP_EQ, "");
str = buf2;
str = parse_config_line_from_str(str, &k, &v);
- test_eq_ptr(str, NULL);
+ tt_ptr_op(str,OP_EQ, NULL);
tor_free(k); tor_free(v);
str = buf3;
str = parse_config_line_from_str(str, &k, &v);
- test_eq_ptr(str, NULL);
+ tt_ptr_op(str,OP_EQ, NULL);
tor_free(k); tor_free(v);
str = buf4;
str = parse_config_line_from_str(str, &k, &v);
- test_eq_ptr(str, NULL);
+ tt_ptr_op(str,OP_EQ, NULL);
tor_free(k); tor_free(v);
#if 0
str = buf5;
str = parse_config_line_from_str(str, &k, &v);
- test_eq_ptr(str, NULL);
+ tt_ptr_op(str, OP_EQ, NULL);
tor_free(k); tor_free(v);
#endif
str = buf6;
str = parse_config_line_from_str(str, &k, &v);
- test_eq_ptr(str, NULL);
+ tt_ptr_op(str,OP_EQ, NULL);
tor_free(k); tor_free(v);
done:
@@ -805,46 +1089,47 @@ test_util_config_line_escaped_content(void)
#ifndef _WIN32
static void
-test_util_expand_filename(void)
+test_util_expand_filename(void *arg)
{
char *str;
+ (void)arg;
setenv("HOME", "/home/itv", 1); /* For "internal test value" */
str = expand_filename("");
- test_streq("", str);
+ tt_str_op("",OP_EQ, str);
tor_free(str);
str = expand_filename("/normal/path");
- test_streq("/normal/path", str);
+ tt_str_op("/normal/path",OP_EQ, str);
tor_free(str);
str = expand_filename("/normal/trailing/path/");
- test_streq("/normal/trailing/path/", str);
+ tt_str_op("/normal/trailing/path/",OP_EQ, str);
tor_free(str);
str = expand_filename("~");
- test_streq("/home/itv/", str);
+ tt_str_op("/home/itv/",OP_EQ, str);
tor_free(str);
str = expand_filename("$HOME/nodice");
- test_streq("$HOME/nodice", str);
+ tt_str_op("$HOME/nodice",OP_EQ, str);
tor_free(str);
str = expand_filename("~/");
- test_streq("/home/itv/", str);
+ tt_str_op("/home/itv/",OP_EQ, str);
tor_free(str);
str = expand_filename("~/foobarqux");
- test_streq("/home/itv/foobarqux", str);
+ tt_str_op("/home/itv/foobarqux",OP_EQ, str);
tor_free(str);
str = expand_filename("~/../../etc/passwd");
- test_streq("/home/itv/../../etc/passwd", str);
+ tt_str_op("/home/itv/../../etc/passwd",OP_EQ, str);
tor_free(str);
str = expand_filename("~/trailing/");
- test_streq("/home/itv/trailing/", str);
+ tt_str_op("/home/itv/trailing/",OP_EQ, str);
tor_free(str);
/* Ideally we'd test ~anotheruser, but that's shady to test (we'd
have to somehow inject/fake the get_user_homedir call) */
@@ -853,15 +1138,15 @@ test_util_expand_filename(void)
setenv("HOME", "/home/itv/", 1);
str = expand_filename("~");
- test_streq("/home/itv/", str);
+ tt_str_op("/home/itv/",OP_EQ, str);
tor_free(str);
str = expand_filename("~/");
- test_streq("/home/itv/", str);
+ tt_str_op("/home/itv/",OP_EQ, str);
tor_free(str);
str = expand_filename("~/foo");
- test_streq("/home/itv/foo", str);
+ tt_str_op("/home/itv/foo",OP_EQ, str);
tor_free(str);
/* Try with empty $HOME */
@@ -869,15 +1154,15 @@ test_util_expand_filename(void)
setenv("HOME", "", 1);
str = expand_filename("~");
- test_streq("/", str);
+ tt_str_op("/",OP_EQ, str);
tor_free(str);
str = expand_filename("~/");
- test_streq("/", str);
+ tt_str_op("/",OP_EQ, str);
tor_free(str);
str = expand_filename("~/foobar");
- test_streq("/foobar", str);
+ tt_str_op("/foobar",OP_EQ, str);
tor_free(str);
/* Try with $HOME unset */
@@ -885,15 +1170,15 @@ test_util_expand_filename(void)
unsetenv("HOME");
str = expand_filename("~");
- test_streq("/", str);
+ tt_str_op("/",OP_EQ, str);
tor_free(str);
str = expand_filename("~/");
- test_streq("/", str);
+ tt_str_op("/",OP_EQ, str);
tor_free(str);
str = expand_filename("~/foobar");
- test_streq("/foobar", str);
+ tt_str_op("/foobar",OP_EQ, str);
tor_free(str);
done:
@@ -903,37 +1188,38 @@ test_util_expand_filename(void)
/** Test tor_escape_str_for_pt_args(). */
static void
-test_util_escape_string_socks(void)
+test_util_escape_string_socks(void *arg)
{
char *escaped_string = NULL;
/** Simple backslash escape. */
+ (void)arg;
escaped_string = tor_escape_str_for_pt_args("This is a backslash: \\",";\\");
- test_assert(escaped_string);
- test_streq(escaped_string, "This is a backslash: \\\\");
+ tt_assert(escaped_string);
+ tt_str_op(escaped_string,OP_EQ, "This is a backslash: \\\\");
tor_free(escaped_string);
/** Simple semicolon escape. */
escaped_string = tor_escape_str_for_pt_args("First rule:Do not use ;",";\\");
- test_assert(escaped_string);
- test_streq(escaped_string, "First rule:Do not use \\;");
+ tt_assert(escaped_string);
+ tt_str_op(escaped_string,OP_EQ, "First rule:Do not use \\;");
tor_free(escaped_string);
/** Empty string. */
escaped_string = tor_escape_str_for_pt_args("", ";\\");
- test_assert(escaped_string);
- test_streq(escaped_string, "");
+ tt_assert(escaped_string);
+ tt_str_op(escaped_string,OP_EQ, "");
tor_free(escaped_string);
/** Escape all characters. */
escaped_string = tor_escape_str_for_pt_args(";\\;\\", ";\\");
- test_assert(escaped_string);
- test_streq(escaped_string, "\\;\\\\\\;\\\\");
+ tt_assert(escaped_string);
+ tt_str_op(escaped_string,OP_EQ, "\\;\\\\\\;\\\\");
tor_free(escaped_string);
escaped_string = tor_escape_str_for_pt_args(";", ";\\");
- test_assert(escaped_string);
- test_streq(escaped_string, "\\;");
+ tt_assert(escaped_string);
+ tt_str_op(escaped_string,OP_EQ, "\\;");
tor_free(escaped_string);
done:
@@ -944,288 +1230,291 @@ static void
test_util_string_is_key_value(void *ptr)
{
(void)ptr;
- test_assert(string_is_key_value(LOG_WARN, "key=value"));
- test_assert(string_is_key_value(LOG_WARN, "k=v"));
- test_assert(string_is_key_value(LOG_WARN, "key="));
- test_assert(string_is_key_value(LOG_WARN, "x="));
- test_assert(string_is_key_value(LOG_WARN, "xx="));
- test_assert(!string_is_key_value(LOG_WARN, "=value"));
- test_assert(!string_is_key_value(LOG_WARN, "=x"));
- test_assert(!string_is_key_value(LOG_WARN, "="));
+ tt_assert(string_is_key_value(LOG_WARN, "key=value"));
+ tt_assert(string_is_key_value(LOG_WARN, "k=v"));
+ tt_assert(string_is_key_value(LOG_WARN, "key="));
+ tt_assert(string_is_key_value(LOG_WARN, "x="));
+ tt_assert(string_is_key_value(LOG_WARN, "xx="));
+ tt_assert(!string_is_key_value(LOG_WARN, "=value"));
+ tt_assert(!string_is_key_value(LOG_WARN, "=x"));
+ tt_assert(!string_is_key_value(LOG_WARN, "="));
/* ??? */
- /* test_assert(!string_is_key_value(LOG_WARN, "===")); */
+ /* tt_assert(!string_is_key_value(LOG_WARN, "===")); */
done:
;
}
/** Test basic string functionality. */
static void
-test_util_strmisc(void)
+test_util_strmisc(void *arg)
{
char buf[1024];
int i;
char *cp, *cp_tmp = NULL;
/* Test strl operations */
- test_eq(5, strlcpy(buf, "Hello", 0));
- test_eq(5, strlcpy(buf, "Hello", 10));
- test_streq(buf, "Hello");
- test_eq(5, strlcpy(buf, "Hello", 6));
- test_streq(buf, "Hello");
- test_eq(5, strlcpy(buf, "Hello", 5));
- test_streq(buf, "Hell");
+ (void)arg;
+ tt_int_op(5,OP_EQ, strlcpy(buf, "Hello", 0));
+ tt_int_op(5,OP_EQ, strlcpy(buf, "Hello", 10));
+ tt_str_op(buf,OP_EQ, "Hello");
+ tt_int_op(5,OP_EQ, strlcpy(buf, "Hello", 6));
+ tt_str_op(buf,OP_EQ, "Hello");
+ tt_int_op(5,OP_EQ, strlcpy(buf, "Hello", 5));
+ tt_str_op(buf,OP_EQ, "Hell");
strlcpy(buf, "Hello", sizeof(buf));
- test_eq(10, strlcat(buf, "Hello", 5));
+ tt_int_op(10,OP_EQ, strlcat(buf, "Hello", 5));
/* Test strstrip() */
strlcpy(buf, "Testing 1 2 3", sizeof(buf));
tor_strstrip(buf, ",!");
- test_streq(buf, "Testing 1 2 3");
+ tt_str_op(buf,OP_EQ, "Testing 1 2 3");
strlcpy(buf, "!Testing 1 2 3?", sizeof(buf));
tor_strstrip(buf, "!? ");
- test_streq(buf, "Testing123");
+ tt_str_op(buf,OP_EQ, "Testing123");
strlcpy(buf, "!!!Testing 1 2 3??", sizeof(buf));
tor_strstrip(buf, "!? ");
- test_streq(buf, "Testing123");
+ tt_str_op(buf,OP_EQ, "Testing123");
/* Test parse_long */
/* Empty/zero input */
- test_eq(0L, tor_parse_long("",10,0,100,&i,NULL));
- test_eq(0, i);
- test_eq(0L, tor_parse_long("0",10,0,100,&i,NULL));
- test_eq(1, i);
+ tt_int_op(0L,OP_EQ, tor_parse_long("",10,0,100,&i,NULL));
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(0L,OP_EQ, tor_parse_long("0",10,0,100,&i,NULL));
+ tt_int_op(1,OP_EQ, i);
/* Normal cases */
- test_eq(10L, tor_parse_long("10",10,0,100,&i,NULL));
- test_eq(1, i);
- test_eq(10L, tor_parse_long("10",10,0,10,&i,NULL));
- test_eq(1, i);
- test_eq(10L, tor_parse_long("10",10,10,100,&i,NULL));
- test_eq(1, i);
- test_eq(-50L, tor_parse_long("-50",10,-100,100,&i,NULL));
- test_eq(1, i);
- test_eq(-50L, tor_parse_long("-50",10,-100,0,&i,NULL));
- test_eq(1, i);
- test_eq(-50L, tor_parse_long("-50",10,-50,0,&i,NULL));
- test_eq(1, i);
+ tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,100,&i,NULL));
+ tt_int_op(1,OP_EQ, i);
+ tt_int_op(10L,OP_EQ, tor_parse_long("10",10,0,10,&i,NULL));
+ tt_int_op(1,OP_EQ, i);
+ tt_int_op(10L,OP_EQ, tor_parse_long("10",10,10,100,&i,NULL));
+ tt_int_op(1,OP_EQ, i);
+ tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,100,&i,NULL));
+ tt_int_op(1,OP_EQ, i);
+ tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-100,0,&i,NULL));
+ tt_int_op(1,OP_EQ, i);
+ tt_int_op(-50L,OP_EQ, tor_parse_long("-50",10,-50,0,&i,NULL));
+ tt_int_op(1,OP_EQ, i);
/* Extra garbage */
- test_eq(0L, tor_parse_long("10m",10,0,100,&i,NULL));
- test_eq(0, i);
- test_eq(0L, tor_parse_long("-50 plus garbage",10,-100,100,&i,NULL));
- test_eq(0, i);
- test_eq(10L, tor_parse_long("10m",10,0,100,&i,&cp));
- test_eq(1, i);
- test_streq(cp, "m");
- test_eq(-50L, tor_parse_long("-50 plus garbage",10,-100,100,&i,&cp));
- test_eq(1, i);
- test_streq(cp, " plus garbage");
+ tt_int_op(0L,OP_EQ, tor_parse_long("10m",10,0,100,&i,NULL));
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(0L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,NULL));
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(10L,OP_EQ, tor_parse_long("10m",10,0,100,&i,&cp));
+ tt_int_op(1,OP_EQ, i);
+ tt_str_op(cp,OP_EQ, "m");
+ tt_int_op(-50L,OP_EQ, tor_parse_long("-50 plus garbage",10,-100,100,&i,&cp));
+ tt_int_op(1,OP_EQ, i);
+ tt_str_op(cp,OP_EQ, " plus garbage");
/* Out of bounds */
- test_eq(0L, tor_parse_long("10",10,50,100,&i,NULL));
- test_eq(0, i);
- test_eq(0L, tor_parse_long("-50",10,0,100,&i,NULL));
- test_eq(0, i);
+ tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,100,&i,NULL));
+ tt_int_op(0,OP_EQ, i);
+ tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,0,100,&i,NULL));
+ tt_int_op(0,OP_EQ, i);
/* Base different than 10 */
- test_eq(2L, tor_parse_long("10",2,0,100,NULL,NULL));
- test_eq(0L, tor_parse_long("2",2,0,100,NULL,NULL));
- test_eq(0L, tor_parse_long("10",-2,0,100,NULL,NULL));
- test_eq(68284L, tor_parse_long("10abc",16,0,70000,NULL,NULL));
- test_eq(68284L, tor_parse_long("10ABC",16,0,70000,NULL,NULL));
- test_eq(0, tor_parse_long("10ABC",-1,0,70000,&i,NULL));
- test_eq(i, 0);
+ tt_int_op(2L,OP_EQ, tor_parse_long("10",2,0,100,NULL,NULL));
+ tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL));
+ tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL));
+ tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL));
+ tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL));
+ tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL));
+ tt_int_op(i,OP_EQ, 0);
/* Test parse_ulong */
- test_eq(0UL, tor_parse_ulong("",10,0,100,NULL,NULL));
- test_eq(0UL, tor_parse_ulong("0",10,0,100,NULL,NULL));
- test_eq(10UL, tor_parse_ulong("10",10,0,100,NULL,NULL));
- test_eq(0UL, tor_parse_ulong("10",10,50,100,NULL,NULL));
- test_eq(10UL, tor_parse_ulong("10",10,0,10,NULL,NULL));
- test_eq(10UL, tor_parse_ulong("10",10,10,100,NULL,NULL));
- test_eq(0UL, tor_parse_ulong("8",8,0,100,NULL,NULL));
- test_eq(50UL, tor_parse_ulong("50",10,50,100,NULL,NULL));
- test_eq(0UL, tor_parse_ulong("-50",10,-100,100,NULL,NULL));
- test_eq(0UL, tor_parse_ulong("50",-1,50,100,&i,NULL));
- test_eq(0, i);
+ tt_int_op(0UL,OP_EQ, tor_parse_ulong("",10,0,100,NULL,NULL));
+ tt_int_op(0UL,OP_EQ, tor_parse_ulong("0",10,0,100,NULL,NULL));
+ tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,100,NULL,NULL));
+ tt_int_op(0UL,OP_EQ, tor_parse_ulong("10",10,50,100,NULL,NULL));
+ tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,0,10,NULL,NULL));
+ tt_int_op(10UL,OP_EQ, tor_parse_ulong("10",10,10,100,NULL,NULL));
+ tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL));
+ tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL));
+ tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,-100,100,NULL,NULL));
+ tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL));
+ tt_int_op(0,OP_EQ, i);
/* Test parse_uint64 */
- test_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp));
- test_eq(1, i);
- test_streq(cp, " x");
- test_assert(U64_LITERAL(12345678901) ==
+ tt_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp));
+ tt_int_op(1,OP_EQ, i);
+ tt_str_op(cp,OP_EQ, " x");
+ tt_assert(U64_LITERAL(12345678901) ==
tor_parse_uint64("12345678901",10,0,UINT64_MAX, &i, &cp));
- test_eq(1, i);
- test_streq(cp, "");
- test_assert(U64_LITERAL(0) ==
+ tt_int_op(1,OP_EQ, i);
+ tt_str_op(cp,OP_EQ, "");
+ tt_assert(U64_LITERAL(0) ==
tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp));
- test_eq(0, i);
- test_assert(U64_LITERAL(0) ==
+ tt_int_op(0,OP_EQ, i);
+ tt_assert(U64_LITERAL(0) ==
tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp));
- test_eq(0, i);
+ tt_int_op(0,OP_EQ, i);
{
/* Test parse_double */
double d = tor_parse_double("10", 0, UINT64_MAX,&i,NULL);
- test_eq(1, i);
- test_assert(DBL_TO_U64(d) == 10);
+ tt_int_op(1,OP_EQ, i);
+ tt_assert(DBL_TO_U64(d) == 10);
d = tor_parse_double("0", 0, UINT64_MAX,&i,NULL);
- test_eq(1, i);
- test_assert(DBL_TO_U64(d) == 0);
+ tt_int_op(1,OP_EQ, i);
+ tt_assert(DBL_TO_U64(d) == 0);
d = tor_parse_double(" ", 0, UINT64_MAX,&i,NULL);
- test_eq(0, i);
+ tt_int_op(0,OP_EQ, i);
d = tor_parse_double(".0a", 0, UINT64_MAX,&i,NULL);
- test_eq(0, i);
+ tt_int_op(0,OP_EQ, i);
d = tor_parse_double(".0a", 0, UINT64_MAX,&i,&cp);
- test_eq(1, i);
+ tt_int_op(1,OP_EQ, i);
d = tor_parse_double("-.0", 0, UINT64_MAX,&i,NULL);
- test_eq(1, i);
- test_assert(DBL_TO_U64(d) == 0);
+ tt_int_op(1,OP_EQ, i);
+ tt_assert(DBL_TO_U64(d) == 0);
d = tor_parse_double("-10", -100.0, 100.0,&i,NULL);
- test_eq(1, i);
- test_eq(-10.0, d);
+ tt_int_op(1,OP_EQ, i);
+ tt_int_op(-10.0,OP_EQ, d);
}
{
/* Test tor_parse_* where we overflow/underflow the underlying type. */
/* This string should overflow 64-bit ints. */
#define TOOBIG "100000000000000000000000000"
- test_eq(0L, tor_parse_long(TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL));
- test_eq(i, 0);
- test_eq(0L, tor_parse_long("-"TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL));
- test_eq(i, 0);
- test_eq(0UL, tor_parse_ulong(TOOBIG, 10, 0, ULONG_MAX, &i, NULL));
- test_eq(i, 0);
- tt_u64_op(U64_LITERAL(0), ==, tor_parse_uint64(TOOBIG, 10,
+ tt_int_op(0L, OP_EQ,
+ tor_parse_long(TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL));
+ tt_int_op(i,OP_EQ, 0);
+ tt_int_op(0L,OP_EQ,
+ tor_parse_long("-"TOOBIG, 10, LONG_MIN, LONG_MAX, &i, NULL));
+ tt_int_op(i,OP_EQ, 0);
+ tt_int_op(0UL,OP_EQ, tor_parse_ulong(TOOBIG, 10, 0, ULONG_MAX, &i, NULL));
+ tt_int_op(i,OP_EQ, 0);
+ tt_u64_op(U64_LITERAL(0), OP_EQ, tor_parse_uint64(TOOBIG, 10,
0, UINT64_MAX, &i, NULL));
- test_eq(i, 0);
+ tt_int_op(i,OP_EQ, 0);
}
/* Test snprintf */
/* Returning -1 when there's not enough room in the output buffer */
- test_eq(-1, tor_snprintf(buf, 0, "Foo"));
- test_eq(-1, tor_snprintf(buf, 2, "Foo"));
- test_eq(-1, tor_snprintf(buf, 3, "Foo"));
- test_neq(-1, tor_snprintf(buf, 4, "Foo"));
+ tt_int_op(-1,OP_EQ, tor_snprintf(buf, 0, "Foo"));
+ tt_int_op(-1,OP_EQ, tor_snprintf(buf, 2, "Foo"));
+ tt_int_op(-1,OP_EQ, tor_snprintf(buf, 3, "Foo"));
+ tt_int_op(-1,OP_NE, tor_snprintf(buf, 4, "Foo"));
/* Always NUL-terminate the output */
tor_snprintf(buf, 5, "abcdef");
- test_eq(0, buf[4]);
+ tt_int_op(0,OP_EQ, buf[4]);
tor_snprintf(buf, 10, "abcdef");
- test_eq(0, buf[6]);
+ tt_int_op(0,OP_EQ, buf[6]);
/* uint64 */
tor_snprintf(buf, sizeof(buf), "x!"U64_FORMAT"!x",
U64_PRINTF_ARG(U64_LITERAL(12345678901)));
- test_streq("x!12345678901!x", buf);
+ tt_str_op("x!12345678901!x",OP_EQ, buf);
/* Test str{,case}cmpstart */
- test_assert(strcmpstart("abcdef", "abcdef")==0);
- test_assert(strcmpstart("abcdef", "abc")==0);
- test_assert(strcmpstart("abcdef", "abd")<0);
- test_assert(strcmpstart("abcdef", "abb")>0);
- test_assert(strcmpstart("ab", "abb")<0);
- test_assert(strcmpstart("ab", "")==0);
- test_assert(strcmpstart("ab", "ab ")<0);
- test_assert(strcasecmpstart("abcdef", "abCdEF")==0);
- test_assert(strcasecmpstart("abcDeF", "abc")==0);
- test_assert(strcasecmpstart("abcdef", "Abd")<0);
- test_assert(strcasecmpstart("Abcdef", "abb")>0);
- test_assert(strcasecmpstart("ab", "Abb")<0);
- test_assert(strcasecmpstart("ab", "")==0);
- test_assert(strcasecmpstart("ab", "ab ")<0);
+ tt_assert(strcmpstart("abcdef", "abcdef")==0);
+ tt_assert(strcmpstart("abcdef", "abc")==0);
+ tt_assert(strcmpstart("abcdef", "abd")<0);
+ tt_assert(strcmpstart("abcdef", "abb")>0);
+ tt_assert(strcmpstart("ab", "abb")<0);
+ tt_assert(strcmpstart("ab", "")==0);
+ tt_assert(strcmpstart("ab", "ab ")<0);
+ tt_assert(strcasecmpstart("abcdef", "abCdEF")==0);
+ tt_assert(strcasecmpstart("abcDeF", "abc")==0);
+ tt_assert(strcasecmpstart("abcdef", "Abd")<0);
+ tt_assert(strcasecmpstart("Abcdef", "abb")>0);
+ tt_assert(strcasecmpstart("ab", "Abb")<0);
+ tt_assert(strcasecmpstart("ab", "")==0);
+ tt_assert(strcasecmpstart("ab", "ab ")<0);
/* Test str{,case}cmpend */
- test_assert(strcmpend("abcdef", "abcdef")==0);
- test_assert(strcmpend("abcdef", "def")==0);
- test_assert(strcmpend("abcdef", "deg")<0);
- test_assert(strcmpend("abcdef", "dee")>0);
- test_assert(strcmpend("ab", "aab")>0);
- test_assert(strcasecmpend("AbcDEF", "abcdef")==0);
- test_assert(strcasecmpend("abcdef", "dEF")==0);
- test_assert(strcasecmpend("abcdef", "Deg")<0);
- test_assert(strcasecmpend("abcDef", "dee")>0);
- test_assert(strcasecmpend("AB", "abb")<0);
+ tt_assert(strcmpend("abcdef", "abcdef")==0);
+ tt_assert(strcmpend("abcdef", "def")==0);
+ tt_assert(strcmpend("abcdef", "deg")<0);
+ tt_assert(strcmpend("abcdef", "dee")>0);
+ tt_assert(strcmpend("ab", "aab")>0);
+ tt_assert(strcasecmpend("AbcDEF", "abcdef")==0);
+ tt_assert(strcasecmpend("abcdef", "dEF")==0);
+ tt_assert(strcasecmpend("abcdef", "Deg")<0);
+ tt_assert(strcasecmpend("abcDef", "dee")>0);
+ tt_assert(strcasecmpend("AB", "abb")<0);
/* Test digest_is_zero */
memset(buf,0,20);
buf[20] = 'x';
- test_assert(tor_digest_is_zero(buf));
+ tt_assert(tor_digest_is_zero(buf));
buf[19] = 'x';
- test_assert(!tor_digest_is_zero(buf));
+ tt_assert(!tor_digest_is_zero(buf));
/* Test mem_is_zero */
memset(buf,0,128);
buf[128] = 'x';
- test_assert(tor_mem_is_zero(buf, 10));
- test_assert(tor_mem_is_zero(buf, 20));
- test_assert(tor_mem_is_zero(buf, 128));
- test_assert(!tor_mem_is_zero(buf, 129));
+ tt_assert(tor_mem_is_zero(buf, 10));
+ tt_assert(tor_mem_is_zero(buf, 20));
+ tt_assert(tor_mem_is_zero(buf, 128));
+ tt_assert(!tor_mem_is_zero(buf, 129));
buf[60] = (char)255;
- test_assert(!tor_mem_is_zero(buf, 128));
+ tt_assert(!tor_mem_is_zero(buf, 128));
buf[0] = (char)1;
- test_assert(!tor_mem_is_zero(buf, 10));
+ tt_assert(!tor_mem_is_zero(buf, 10));
/* Test 'escaped' */
- test_assert(NULL == escaped(NULL));
- test_streq("\"\"", escaped(""));
- test_streq("\"abcd\"", escaped("abcd"));
- test_streq("\"\\\\ \\n\\r\\t\\\"\\'\"", escaped("\\ \n\r\t\"'"));
- test_streq("\"unnecessary \\'backslashes\\'\"",
+ tt_assert(NULL == escaped(NULL));
+ tt_str_op("\"\"",OP_EQ, escaped(""));
+ tt_str_op("\"abcd\"",OP_EQ, escaped("abcd"));
+ tt_str_op("\"\\\\ \\n\\r\\t\\\"\\'\"",OP_EQ, escaped("\\ \n\r\t\"'"));
+ tt_str_op("\"unnecessary \\'backslashes\\'\"",OP_EQ,
escaped("unnecessary \'backslashes\'"));
/* Non-printable characters appear as octal */
- test_streq("\"z\\001abc\\277d\"", escaped("z\001abc\277d"));
- test_streq("\"z\\336\\255 ;foo\"", escaped("z\xde\xad\x20;foo"));
+ tt_str_op("\"z\\001abc\\277d\"",OP_EQ, escaped("z\001abc\277d"));
+ tt_str_op("\"z\\336\\255 ;foo\"",OP_EQ, escaped("z\xde\xad\x20;foo"));
/* Test strndup and memdup */
{
const char *s = "abcdefghijklmnopqrstuvwxyz";
cp_tmp = tor_strndup(s, 30);
- test_streq(cp_tmp, s); /* same string, */
- test_neq_ptr(cp_tmp, s); /* but different pointers. */
+ tt_str_op(cp_tmp,OP_EQ, s); /* same string, */
+ tt_ptr_op(cp_tmp,OP_NE,s); /* but different pointers. */
tor_free(cp_tmp);
cp_tmp = tor_strndup(s, 5);
- test_streq(cp_tmp, "abcde");
+ tt_str_op(cp_tmp,OP_EQ, "abcde");
tor_free(cp_tmp);
s = "a\0b\0c\0d\0e\0";
cp_tmp = tor_memdup(s,10);
- test_memeq(cp_tmp, s, 10); /* same ram, */
- test_neq_ptr(cp_tmp, s); /* but different pointers. */
+ tt_mem_op(cp_tmp,OP_EQ, s, 10); /* same ram, */
+ tt_ptr_op(cp_tmp,OP_NE,s); /* but different pointers. */
tor_free(cp_tmp);
}
/* Test str-foo functions */
cp_tmp = tor_strdup("abcdef");
- test_assert(tor_strisnonupper(cp_tmp));
+ tt_assert(tor_strisnonupper(cp_tmp));
cp_tmp[3] = 'D';
- test_assert(!tor_strisnonupper(cp_tmp));
+ tt_assert(!tor_strisnonupper(cp_tmp));
tor_strupper(cp_tmp);
- test_streq(cp_tmp, "ABCDEF");
+ tt_str_op(cp_tmp,OP_EQ, "ABCDEF");
tor_strlower(cp_tmp);
- test_streq(cp_tmp, "abcdef");
- test_assert(tor_strisnonupper(cp_tmp));
- test_assert(tor_strisprint(cp_tmp));
+ tt_str_op(cp_tmp,OP_EQ, "abcdef");
+ tt_assert(tor_strisnonupper(cp_tmp));
+ tt_assert(tor_strisprint(cp_tmp));
cp_tmp[3] = 3;
- test_assert(!tor_strisprint(cp_tmp));
+ tt_assert(!tor_strisprint(cp_tmp));
tor_free(cp_tmp);
/* Test memmem and memstr */
{
const char *haystack = "abcde";
- test_assert(!tor_memmem(haystack, 5, "ef", 2));
- test_eq_ptr(tor_memmem(haystack, 5, "cd", 2), haystack + 2);
- test_eq_ptr(tor_memmem(haystack, 5, "cde", 3), haystack + 2);
- test_assert(!tor_memmem(haystack, 4, "cde", 3));
+ tt_assert(!tor_memmem(haystack, 5, "ef", 2));
+ tt_ptr_op(tor_memmem(haystack, 5, "cd", 2),OP_EQ, haystack + 2);
+ tt_ptr_op(tor_memmem(haystack, 5, "cde", 3),OP_EQ, haystack + 2);
+ tt_assert(!tor_memmem(haystack, 4, "cde", 3));
haystack = "ababcad";
- test_eq_ptr(tor_memmem(haystack, 7, "abc", 3), haystack + 2);
- test_eq_ptr(tor_memmem(haystack, 7, "ad", 2), haystack + 5);
- test_eq_ptr(tor_memmem(haystack, 7, "cad", 3), haystack + 4);
- test_assert(!tor_memmem(haystack, 7, "dadad", 5));
- test_assert(!tor_memmem(haystack, 7, "abcdefghij", 10));
+ tt_ptr_op(tor_memmem(haystack, 7, "abc", 3),OP_EQ, haystack + 2);
+ tt_ptr_op(tor_memmem(haystack, 7, "ad", 2),OP_EQ, haystack + 5);
+ tt_ptr_op(tor_memmem(haystack, 7, "cad", 3),OP_EQ, haystack + 4);
+ tt_assert(!tor_memmem(haystack, 7, "dadad", 5));
+ tt_assert(!tor_memmem(haystack, 7, "abcdefghij", 10));
/* memstr */
- test_eq_ptr(tor_memstr(haystack, 7, "abc"), haystack + 2);
- test_eq_ptr(tor_memstr(haystack, 7, "cad"), haystack + 4);
- test_assert(!tor_memstr(haystack, 6, "cad"));
- test_assert(!tor_memstr(haystack, 7, "cadd"));
- test_assert(!tor_memstr(haystack, 7, "fe"));
- test_assert(!tor_memstr(haystack, 7, "ababcade"));
+ tt_ptr_op(tor_memstr(haystack, 7, "abc"),OP_EQ, haystack + 2);
+ tt_ptr_op(tor_memstr(haystack, 7, "cad"),OP_EQ, haystack + 4);
+ tt_assert(!tor_memstr(haystack, 6, "cad"));
+ tt_assert(!tor_memstr(haystack, 7, "cadd"));
+ tt_assert(!tor_memstr(haystack, 7, "fe"));
+ tt_assert(!tor_memstr(haystack, 7, "ababcade"));
}
/* Test hex_str */
@@ -1234,271 +1523,134 @@ test_util_strmisc(void)
size_t i;
for (i = 0; i < sizeof(binary_data); ++i)
binary_data[i] = i;
- test_streq(hex_str(binary_data, 0), "");
- test_streq(hex_str(binary_data, 1), "00");
- test_streq(hex_str(binary_data, 17), "000102030405060708090A0B0C0D0E0F10");
- test_streq(hex_str(binary_data, 32),
+ tt_str_op(hex_str(binary_data, 0),OP_EQ, "");
+ tt_str_op(hex_str(binary_data, 1),OP_EQ, "00");
+ tt_str_op(hex_str(binary_data, 17),OP_EQ,
+ "000102030405060708090A0B0C0D0E0F10");
+ tt_str_op(hex_str(binary_data, 32),OP_EQ,
"000102030405060708090A0B0C0D0E0F"
"101112131415161718191A1B1C1D1E1F");
- test_streq(hex_str(binary_data, 34),
+ tt_str_op(hex_str(binary_data, 34),OP_EQ,
"000102030405060708090A0B0C0D0E0F"
"101112131415161718191A1B1C1D1E1F");
/* Repeat these tests for shorter strings after longer strings
have been tried, to make sure we're correctly terminating strings */
- test_streq(hex_str(binary_data, 1), "00");
- test_streq(hex_str(binary_data, 0), "");
+ tt_str_op(hex_str(binary_data, 1),OP_EQ, "00");
+ tt_str_op(hex_str(binary_data, 0),OP_EQ, "");
}
/* Test strcmp_opt */
- tt_int_op(strcmp_opt("", "foo"), <, 0);
- tt_int_op(strcmp_opt("", ""), ==, 0);
- tt_int_op(strcmp_opt("foo", ""), >, 0);
+ tt_int_op(strcmp_opt("", "foo"), OP_LT, 0);
+ tt_int_op(strcmp_opt("", ""), OP_EQ, 0);
+ tt_int_op(strcmp_opt("foo", ""), OP_GT, 0);
- tt_int_op(strcmp_opt(NULL, ""), <, 0);
- tt_int_op(strcmp_opt(NULL, NULL), ==, 0);
- tt_int_op(strcmp_opt("", NULL), >, 0);
+ tt_int_op(strcmp_opt(NULL, ""), OP_LT, 0);
+ tt_int_op(strcmp_opt(NULL, NULL), OP_EQ, 0);
+ tt_int_op(strcmp_opt("", NULL), OP_GT, 0);
- tt_int_op(strcmp_opt(NULL, "foo"), <, 0);
- tt_int_op(strcmp_opt("foo", NULL), >, 0);
+ tt_int_op(strcmp_opt(NULL, "foo"), OP_LT, 0);
+ tt_int_op(strcmp_opt("foo", NULL), OP_GT, 0);
/* Test strcmp_len */
- tt_int_op(strcmp_len("foo", "bar", 3), >, 0);
- tt_int_op(strcmp_len("foo", "bar", 2), <, 0); /* First len, then lexical */
- tt_int_op(strcmp_len("foo2", "foo1", 4), >, 0);
- tt_int_op(strcmp_len("foo2", "foo1", 3), <, 0); /* Really stop at len */
- tt_int_op(strcmp_len("foo2", "foo", 3), ==, 0); /* Really stop at len */
- tt_int_op(strcmp_len("blah", "", 4), >, 0);
- tt_int_op(strcmp_len("blah", "", 0), ==, 0);
+ tt_int_op(strcmp_len("foo", "bar", 3), OP_GT, 0);
+ tt_int_op(strcmp_len("foo", "bar", 2), OP_LT, 0);
+ tt_int_op(strcmp_len("foo2", "foo1", 4), OP_GT, 0);
+ tt_int_op(strcmp_len("foo2", "foo1", 3), OP_LT, 0); /* Really stop at len */
+ tt_int_op(strcmp_len("foo2", "foo", 3), OP_EQ, 0); /* Really stop at len */
+ tt_int_op(strcmp_len("blah", "", 4), OP_GT, 0);
+ tt_int_op(strcmp_len("blah", "", 0), OP_EQ, 0);
done:
tor_free(cp_tmp);
}
static void
-test_util_pow2(void)
+test_util_pow2(void *arg)
{
/* Test tor_log2(). */
- test_eq(tor_log2(64), 6);
- test_eq(tor_log2(65), 6);
- test_eq(tor_log2(63), 5);
- test_eq(tor_log2(0), 0); /* incorrect mathematically, but as specified */
- test_eq(tor_log2(1), 0);
- test_eq(tor_log2(2), 1);
- test_eq(tor_log2(3), 1);
- test_eq(tor_log2(4), 2);
- test_eq(tor_log2(5), 2);
- test_eq(tor_log2(U64_LITERAL(40000000000000000)), 55);
- test_eq(tor_log2(UINT64_MAX), 63);
+ (void)arg;
+ tt_int_op(tor_log2(64),OP_EQ, 6);
+ tt_int_op(tor_log2(65),OP_EQ, 6);
+ tt_int_op(tor_log2(63),OP_EQ, 5);
+ /* incorrect mathematically, but as specified: */
+ tt_int_op(tor_log2(0),OP_EQ, 0);
+ tt_int_op(tor_log2(1),OP_EQ, 0);
+ tt_int_op(tor_log2(2),OP_EQ, 1);
+ tt_int_op(tor_log2(3),OP_EQ, 1);
+ tt_int_op(tor_log2(4),OP_EQ, 2);
+ tt_int_op(tor_log2(5),OP_EQ, 2);
+ tt_int_op(tor_log2(U64_LITERAL(40000000000000000)),OP_EQ, 55);
+ tt_int_op(tor_log2(UINT64_MAX),OP_EQ, 63);
/* Test round_to_power_of_2 */
- tt_u64_op(round_to_power_of_2(120), ==, 128);
- tt_u64_op(round_to_power_of_2(128), ==, 128);
- tt_u64_op(round_to_power_of_2(130), ==, 128);
- tt_u64_op(round_to_power_of_2(U64_LITERAL(40000000000000000)), ==,
+ tt_u64_op(round_to_power_of_2(120), OP_EQ, 128);
+ tt_u64_op(round_to_power_of_2(128), OP_EQ, 128);
+ tt_u64_op(round_to_power_of_2(130), OP_EQ, 128);
+ tt_u64_op(round_to_power_of_2(U64_LITERAL(40000000000000000)), OP_EQ,
U64_LITERAL(1)<<55);
- tt_u64_op(round_to_power_of_2(U64_LITERAL(0xffffffffffffffff)), ==,
+ tt_u64_op(round_to_power_of_2(U64_LITERAL(0xffffffffffffffff)), OP_EQ,
U64_LITERAL(1)<<63);
- tt_u64_op(round_to_power_of_2(0), ==, 1);
- tt_u64_op(round_to_power_of_2(1), ==, 1);
- tt_u64_op(round_to_power_of_2(2), ==, 2);
- tt_u64_op(round_to_power_of_2(3), ==, 2);
- tt_u64_op(round_to_power_of_2(4), ==, 4);
- tt_u64_op(round_to_power_of_2(5), ==, 4);
- tt_u64_op(round_to_power_of_2(6), ==, 4);
- tt_u64_op(round_to_power_of_2(7), ==, 8);
+ tt_u64_op(round_to_power_of_2(0), OP_EQ, 1);
+ tt_u64_op(round_to_power_of_2(1), OP_EQ, 1);
+ tt_u64_op(round_to_power_of_2(2), OP_EQ, 2);
+ tt_u64_op(round_to_power_of_2(3), OP_EQ, 2);
+ tt_u64_op(round_to_power_of_2(4), OP_EQ, 4);
+ tt_u64_op(round_to_power_of_2(5), OP_EQ, 4);
+ tt_u64_op(round_to_power_of_2(6), OP_EQ, 4);
+ tt_u64_op(round_to_power_of_2(7), OP_EQ, 8);
done:
;
}
-/** mutex for thread test to stop the threads hitting data at the same time. */
-static tor_mutex_t *thread_test_mutex_ = NULL;
-/** mutexes for the thread test to make sure that the threads have to
- * interleave somewhat. */
-static tor_mutex_t *thread_test_start1_ = NULL,
- *thread_test_start2_ = NULL;
-/** Shared strmap for the thread test. */
-static strmap_t *thread_test_strmap_ = NULL;
-/** The name of thread1 for the thread test */
-static char *thread1_name_ = NULL;
-/** The name of thread2 for the thread test */
-static char *thread2_name_ = NULL;
-
-static void thread_test_func_(void* _s) ATTR_NORETURN;
-
-/** How many iterations have the threads in the unit test run? */
-static int t1_count = 0, t2_count = 0;
-
-/** Helper function for threading unit tests: This function runs in a
- * subthread. It grabs its own mutex (start1 or start2) to make sure that it
- * should start, then it repeatedly alters _test_thread_strmap protected by
- * thread_test_mutex_. */
-static void
-thread_test_func_(void* _s)
-{
- char *s = _s;
- int i, *count;
- tor_mutex_t *m;
- char buf[64];
- char **cp;
- if (!strcmp(s, "thread 1")) {
- m = thread_test_start1_;
- cp = &thread1_name_;
- count = &t1_count;
- } else {
- m = thread_test_start2_;
- cp = &thread2_name_;
- count = &t2_count;
- }
-
- tor_snprintf(buf, sizeof(buf), "%lu", tor_get_thread_id());
- *cp = tor_strdup(buf);
-
- tor_mutex_acquire(m);
-
- for (i=0; i<10000; ++i) {
- tor_mutex_acquire(thread_test_mutex_);
- strmap_set(thread_test_strmap_, "last to run", *cp);
- ++*count;
- tor_mutex_release(thread_test_mutex_);
- }
- tor_mutex_acquire(thread_test_mutex_);
- strmap_set(thread_test_strmap_, s, *cp);
- tor_mutex_release(thread_test_mutex_);
-
- tor_mutex_release(m);
-
- spawn_exit();
-}
-
-/** Run unit tests for threading logic. */
-static void
-test_util_threads(void)
-{
- char *s1 = NULL, *s2 = NULL;
- int done = 0, timedout = 0;
- time_t started;
-#ifndef _WIN32
- struct timeval tv;
- tv.tv_sec=0;
- tv.tv_usec=100*1000;
-#endif
-#ifndef TOR_IS_MULTITHREADED
- /* Skip this test if we aren't threading. We should be threading most
- * everywhere by now. */
- if (1)
- return;
-#endif
- thread_test_mutex_ = tor_mutex_new();
- thread_test_start1_ = tor_mutex_new();
- thread_test_start2_ = tor_mutex_new();
- thread_test_strmap_ = strmap_new();
- s1 = tor_strdup("thread 1");
- s2 = tor_strdup("thread 2");
- tor_mutex_acquire(thread_test_start1_);
- tor_mutex_acquire(thread_test_start2_);
- spawn_func(thread_test_func_, s1);
- spawn_func(thread_test_func_, s2);
- tor_mutex_release(thread_test_start2_);
- tor_mutex_release(thread_test_start1_);
- started = time(NULL);
- while (!done) {
- tor_mutex_acquire(thread_test_mutex_);
- strmap_assert_ok(thread_test_strmap_);
- if (strmap_get(thread_test_strmap_, "thread 1") &&
- strmap_get(thread_test_strmap_, "thread 2")) {
- done = 1;
- } else if (time(NULL) > started + 150) {
- timedout = done = 1;
- }
- tor_mutex_release(thread_test_mutex_);
-#ifndef _WIN32
- /* Prevent the main thread from starving the worker threads. */
- select(0, NULL, NULL, NULL, &tv);
-#endif
- }
- tor_mutex_acquire(thread_test_start1_);
- tor_mutex_release(thread_test_start1_);
- tor_mutex_acquire(thread_test_start2_);
- tor_mutex_release(thread_test_start2_);
-
- tor_mutex_free(thread_test_mutex_);
-
- if (timedout) {
- printf("\nTimed out: %d %d", t1_count, t2_count);
- test_assert(strmap_get(thread_test_strmap_, "thread 1"));
- test_assert(strmap_get(thread_test_strmap_, "thread 2"));
- test_assert(!timedout);
- }
-
- /* different thread IDs. */
- test_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"),
- strmap_get(thread_test_strmap_, "thread 2")));
- test_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"),
- strmap_get(thread_test_strmap_, "last to run")) ||
- !strcmp(strmap_get(thread_test_strmap_, "thread 2"),
- strmap_get(thread_test_strmap_, "last to run")));
-
- done:
- tor_free(s1);
- tor_free(s2);
- tor_free(thread1_name_);
- tor_free(thread2_name_);
- if (thread_test_strmap_)
- strmap_free(thread_test_strmap_, NULL);
- if (thread_test_start1_)
- tor_mutex_free(thread_test_start1_);
- if (thread_test_start2_)
- tor_mutex_free(thread_test_start2_);
-}
-
/** Run unit tests for compression functions */
static void
-test_util_gzip(void)
+test_util_gzip(void *arg)
{
char *buf1=NULL, *buf2=NULL, *buf3=NULL, *cp1, *cp2;
const char *ccp2;
size_t len1, len2;
tor_zlib_state_t *state = NULL;
+ (void)arg;
buf1 = tor_strdup("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ");
- test_assert(detect_compression_method(buf1, strlen(buf1)) == UNKNOWN_METHOD);
+ tt_assert(detect_compression_method(buf1, strlen(buf1)) == UNKNOWN_METHOD);
if (is_gzip_supported()) {
- test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
+ tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
GZIP_METHOD));
- test_assert(buf2);
- test_assert(len1 < strlen(buf1));
- test_assert(detect_compression_method(buf2, len1) == GZIP_METHOD);
+ tt_assert(buf2);
+ tt_assert(len1 < strlen(buf1));
+ tt_assert(detect_compression_method(buf2, len1) == GZIP_METHOD);
- test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
+ tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
GZIP_METHOD, 1, LOG_INFO));
- test_assert(buf3);
- test_eq(strlen(buf1) + 1, len2);
- test_streq(buf1, buf3);
+ tt_assert(buf3);
+ tt_int_op(strlen(buf1) + 1,OP_EQ, len2);
+ tt_str_op(buf1,OP_EQ, buf3);
tor_free(buf2);
tor_free(buf3);
}
- test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
+ tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
ZLIB_METHOD));
- test_assert(buf2);
- test_assert(detect_compression_method(buf2, len1) == ZLIB_METHOD);
+ tt_assert(buf2);
+ tt_assert(detect_compression_method(buf2, len1) == ZLIB_METHOD);
- test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
+ tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1,
ZLIB_METHOD, 1, LOG_INFO));
- test_assert(buf3);
- test_eq(strlen(buf1) + 1, len2);
- test_streq(buf1, buf3);
+ tt_assert(buf3);
+ tt_int_op(strlen(buf1) + 1,OP_EQ, len2);
+ tt_str_op(buf1,OP_EQ, buf3);
/* Check whether we can uncompress concatenated, compressed strings. */
tor_free(buf3);
- buf2 = tor_realloc(buf2, len1*2);
+ buf2 = tor_reallocarray(buf2, len1, 2);
memcpy(buf2+len1, buf2, len1);
- test_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1*2,
+ tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf2, len1*2,
ZLIB_METHOD, 1, LOG_INFO));
- test_eq((strlen(buf1)+1)*2, len2);
- test_memeq(buf3,
+ tt_int_op((strlen(buf1)+1)*2,OP_EQ, len2);
+ tt_mem_op(buf3,OP_EQ,
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAAAAAAAAAAAAAAAAZ\0",
(strlen(buf1)+1)*2);
@@ -1510,7 +1662,7 @@ test_util_gzip(void)
/* Check whether we can uncompress partial strings. */
buf1 =
tor_strdup("String with low redundancy that won't be compressed much.");
- test_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
+ tt_assert(!tor_gzip_compress(&buf2, &len1, buf1, strlen(buf1)+1,
ZLIB_METHOD));
tt_assert(len1>16);
/* when we allow an incomplete string, we should succeed.*/
@@ -1530,28 +1682,29 @@ test_util_gzip(void)
tor_free(buf1);
tor_free(buf2);
tor_free(buf3);
- state = tor_zlib_new(1, ZLIB_METHOD);
+ state = tor_zlib_new(1, ZLIB_METHOD, HIGH_COMPRESSION);
tt_assert(state);
cp1 = buf1 = tor_malloc(1024);
len1 = 1024;
ccp2 = "ABCDEFGHIJABCDEFGHIJ";
len2 = 21;
- test_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 0)
+ tt_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 0)
== TOR_ZLIB_OK);
- test_eq(0, len2); /* Make sure we compressed it all. */
- test_assert(cp1 > buf1);
+ tt_int_op(0,OP_EQ, len2); /* Make sure we compressed it all. */
+ tt_assert(cp1 > buf1);
len2 = 0;
cp2 = cp1;
- test_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 1)
+ tt_assert(tor_zlib_process(state, &cp1, &len1, &ccp2, &len2, 1)
== TOR_ZLIB_DONE);
- test_eq(0, len2);
- test_assert(cp1 > cp2); /* Make sure we really added something. */
+ tt_int_op(0,OP_EQ, len2);
+ tt_assert(cp1 > cp2); /* Make sure we really added something. */
tt_assert(!tor_gzip_uncompress(&buf3, &len2, buf1, 1024-len1,
ZLIB_METHOD, 1, LOG_WARN));
- test_streq(buf3, "ABCDEFGHIJABCDEFGHIJ"); /*Make sure it compressed right.*/
- test_eq(21, len2);
+ /* Make sure it compressed right. */
+ tt_str_op(buf3, OP_EQ, "ABCDEFGHIJABCDEFGHIJ");
+ tt_int_op(21,OP_EQ, len2);
done:
if (state)
@@ -1563,7 +1716,7 @@ test_util_gzip(void)
/** Run unit tests for mmap() wrapper functionality. */
static void
-test_util_mmap(void)
+test_util_mmap(void *arg)
{
char *fname1 = tor_strdup(get_fname("mapped_1"));
char *fname2 = tor_strdup(get_fname("mapped_2"));
@@ -1572,56 +1725,57 @@ test_util_mmap(void)
char *buf = tor_malloc(17000);
tor_mmap_t *mapping = NULL;
+ (void)arg;
crypto_rand(buf, buflen);
mapping = tor_mmap_file(fname1);
- test_assert(! mapping);
+ tt_assert(! mapping);
write_str_to_file(fname1, "Short file.", 1);
mapping = tor_mmap_file(fname1);
- test_assert(mapping);
- test_eq(mapping->size, strlen("Short file."));
- test_streq(mapping->data, "Short file.");
+ tt_assert(mapping);
+ tt_int_op(mapping->size,OP_EQ, strlen("Short file."));
+ tt_str_op(mapping->data,OP_EQ, "Short file.");
#ifdef _WIN32
- tt_int_op(0, ==, tor_munmap_file(mapping));
+ tt_int_op(0, OP_EQ, tor_munmap_file(mapping));
mapping = NULL;
- test_assert(unlink(fname1) == 0);
+ tt_assert(unlink(fname1) == 0);
#else
/* make sure we can unlink. */
- test_assert(unlink(fname1) == 0);
- test_streq(mapping->data, "Short file.");
- tt_int_op(0, ==, tor_munmap_file(mapping));
+ tt_assert(unlink(fname1) == 0);
+ tt_str_op(mapping->data,OP_EQ, "Short file.");
+ tt_int_op(0, OP_EQ, tor_munmap_file(mapping));
mapping = NULL;
#endif
/* Now a zero-length file. */
write_str_to_file(fname1, "", 1);
mapping = tor_mmap_file(fname1);
- test_eq_ptr(mapping, NULL);
- test_eq(ERANGE, errno);
+ tt_ptr_op(mapping,OP_EQ, NULL);
+ tt_int_op(ERANGE,OP_EQ, errno);
unlink(fname1);
/* Make sure that we fail to map a no-longer-existent file. */
mapping = tor_mmap_file(fname1);
- test_assert(! mapping);
+ tt_assert(! mapping);
/* Now try a big file that stretches across a few pages and isn't aligned */
write_bytes_to_file(fname2, buf, buflen, 1);
mapping = tor_mmap_file(fname2);
- test_assert(mapping);
- test_eq(mapping->size, buflen);
- test_memeq(mapping->data, buf, buflen);
- tt_int_op(0, ==, tor_munmap_file(mapping));
+ tt_assert(mapping);
+ tt_int_op(mapping->size,OP_EQ, buflen);
+ tt_mem_op(mapping->data,OP_EQ, buf, buflen);
+ tt_int_op(0, OP_EQ, tor_munmap_file(mapping));
mapping = NULL;
/* Now try a big aligned file. */
write_bytes_to_file(fname3, buf, 16384, 1);
mapping = tor_mmap_file(fname3);
- test_assert(mapping);
- test_eq(mapping->size, 16384);
- test_memeq(mapping->data, buf, 16384);
- tt_int_op(0, ==, tor_munmap_file(mapping));
+ tt_assert(mapping);
+ tt_int_op(mapping->size,OP_EQ, 16384);
+ tt_mem_op(mapping->data,OP_EQ, buf, 16384);
+ tt_int_op(0, OP_EQ, tor_munmap_file(mapping));
mapping = NULL;
done:
@@ -1639,17 +1793,18 @@ test_util_mmap(void)
/** Run unit tests for escaping/unescaping data for use by controllers. */
static void
-test_util_control_formats(void)
+test_util_control_formats(void *arg)
{
char *out = NULL;
const char *inp =
"..This is a test\r\n.of the emergency \n..system.\r\n\rZ.\r\n";
size_t sz;
+ (void)arg;
sz = read_escaped_data(inp, strlen(inp), &out);
- test_streq(out,
+ tt_str_op(out,OP_EQ,
".This is a test\nof the emergency \n.system.\n\rZ.\n");
- test_eq(sz, strlen(out));
+ tt_int_op(sz,OP_EQ, strlen(out));
done:
tor_free(out);
@@ -1669,9 +1824,10 @@ test_util_control_formats(void)
} while (0)
static void
-test_util_sscanf(void)
+test_util_sscanf(void *arg)
{
unsigned u1, u2, u3;
+ unsigned long ulng;
char s1[20], s2[10], s3[10], ch;
int r;
long lng1,lng2;
@@ -1679,186 +1835,336 @@ test_util_sscanf(void)
double d1,d2,d3,d4;
/* Simple tests (malformed patterns, literal matching, ...) */
- test_eq(-1, tor_sscanf("123", "%i", &r)); /* %i is not supported */
- test_eq(-1, tor_sscanf("wrong", "%5c", s1)); /* %c cannot have a number. */
- test_eq(-1, tor_sscanf("hello", "%s", s1)); /* %s needs a number. */
- test_eq(-1, tor_sscanf("prettylongstring", "%999999s", s1));
+ (void)arg;
+ tt_int_op(-1,OP_EQ, tor_sscanf("123", "%i", &r)); /* %i is not supported */
+ tt_int_op(-1,OP_EQ,
+ tor_sscanf("wrong", "%5c", s1)); /* %c cannot have a number. */
+ tt_int_op(-1,OP_EQ, tor_sscanf("hello", "%s", s1)); /* %s needs a number. */
+ tt_int_op(-1,OP_EQ, tor_sscanf("prettylongstring", "%999999s", s1));
#if 0
/* GCC thinks these two are illegal. */
test_eq(-1, tor_sscanf("prettylongstring", "%0s", s1));
test_eq(0, tor_sscanf("prettylongstring", "%10s", NULL));
#endif
/* No '%'-strings: always "success" */
- test_eq(0, tor_sscanf("hello world", "hello world"));
- test_eq(0, tor_sscanf("hello world", "good bye"));
+ tt_int_op(0,OP_EQ, tor_sscanf("hello world", "hello world"));
+ tt_int_op(0,OP_EQ, tor_sscanf("hello world", "good bye"));
/* Excess data */
- test_eq(0, tor_sscanf("hello 3", "%u", &u1)); /* have to match the start */
- test_eq(0, tor_sscanf(" 3 hello", "%u", &u1));
- test_eq(0, tor_sscanf(" 3 hello", "%2u", &u1)); /* not even in this case */
- test_eq(1, tor_sscanf("3 hello", "%u", &u1)); /* but trailing is alright */
+ tt_int_op(0,OP_EQ,
+ tor_sscanf("hello 3", "%u", &u1)); /* have to match the start */
+ tt_int_op(0,OP_EQ, tor_sscanf(" 3 hello", "%u", &u1));
+ tt_int_op(0,OP_EQ,
+ tor_sscanf(" 3 hello", "%2u", &u1)); /* not even in this case */
+ tt_int_op(1,OP_EQ,
+ tor_sscanf("3 hello", "%u", &u1)); /* but trailing is alright */
/* Numbers (ie. %u) */
- test_eq(0, tor_sscanf("hello world 3", "hello worlb %u", &u1)); /* d vs b */
- test_eq(1, tor_sscanf("12345", "%u", &u1));
- test_eq(12345u, u1);
- test_eq(1, tor_sscanf("12346 ", "%u", &u1));
- test_eq(12346u, u1);
- test_eq(0, tor_sscanf(" 12347", "%u", &u1));
- test_eq(1, tor_sscanf(" 12348", " %u", &u1));
- test_eq(12348u, u1);
- test_eq(1, tor_sscanf("0", "%u", &u1));
- test_eq(0u, u1);
- test_eq(1, tor_sscanf("0000", "%u", &u2));
- test_eq(0u, u2);
- test_eq(0, tor_sscanf("", "%u", &u1)); /* absent number */
- test_eq(0, tor_sscanf("A", "%u", &u1)); /* bogus number */
- test_eq(0, tor_sscanf("-1", "%u", &u1)); /* negative number */
- test_eq(1, tor_sscanf("4294967295", "%u", &u1)); /* UINT32_MAX should work */
- test_eq(4294967295u, u1);
- test_eq(0, tor_sscanf("4294967296", "%u", &u1)); /* But not at 32 bits */
- test_eq(1, tor_sscanf("4294967296", "%9u", &u1)); /* but parsing only 9... */
- test_eq(429496729u, u1);
+ tt_int_op(0,OP_EQ,
+ tor_sscanf("hello world 3", "hello worlb %u", &u1)); /* d vs b */
+ tt_int_op(1,OP_EQ, tor_sscanf("12345", "%u", &u1));
+ tt_int_op(12345u,OP_EQ, u1);
+ tt_int_op(1,OP_EQ, tor_sscanf("12346 ", "%u", &u1));
+ tt_int_op(12346u,OP_EQ, u1);
+ tt_int_op(0,OP_EQ, tor_sscanf(" 12347", "%u", &u1));
+ tt_int_op(1,OP_EQ, tor_sscanf(" 12348", " %u", &u1));
+ tt_int_op(12348u,OP_EQ, u1);
+ tt_int_op(1,OP_EQ, tor_sscanf("0", "%u", &u1));
+ tt_int_op(0u,OP_EQ, u1);
+ tt_int_op(1,OP_EQ, tor_sscanf("0000", "%u", &u2));
+ tt_int_op(0u,OP_EQ, u2);
+ tt_int_op(0,OP_EQ, tor_sscanf("", "%u", &u1)); /* absent number */
+ tt_int_op(0,OP_EQ, tor_sscanf("A", "%u", &u1)); /* bogus number */
+ tt_int_op(0,OP_EQ, tor_sscanf("-1", "%u", &u1)); /* negative number */
/* Numbers with size (eg. %2u) */
- test_eq(0, tor_sscanf("-1", "%2u", &u1));
- test_eq(2, tor_sscanf("123456", "%2u%u", &u1, &u2));
- test_eq(12u, u1);
- test_eq(3456u, u2);
- test_eq(1, tor_sscanf("123456", "%8u", &u1));
- test_eq(123456u, u1);
- test_eq(1, tor_sscanf("123457 ", "%8u", &u1));
- test_eq(123457u, u1);
- test_eq(0, tor_sscanf(" 123456", "%8u", &u1));
- test_eq(3, tor_sscanf("!12:3:456", "!%2u:%2u:%3u", &u1, &u2, &u3));
- test_eq(12u, u1);
- test_eq(3u, u2);
- test_eq(456u, u3);
- test_eq(3, tor_sscanf("67:8:099", "%2u:%2u:%3u", &u1, &u2, &u3)); /* 0s */
- test_eq(67u, u1);
- test_eq(8u, u2);
- test_eq(99u, u3);
+ tt_int_op(0,OP_EQ, tor_sscanf("-1", "%2u", &u1));
+ tt_int_op(2,OP_EQ, tor_sscanf("123456", "%2u%u", &u1, &u2));
+ tt_int_op(12u,OP_EQ, u1);
+ tt_int_op(3456u,OP_EQ, u2);
+ tt_int_op(1,OP_EQ, tor_sscanf("123456", "%8u", &u1));
+ tt_int_op(123456u,OP_EQ, u1);
+ tt_int_op(1,OP_EQ, tor_sscanf("123457 ", "%8u", &u1));
+ tt_int_op(123457u,OP_EQ, u1);
+ tt_int_op(0,OP_EQ, tor_sscanf(" 123456", "%8u", &u1));
+ tt_int_op(3,OP_EQ, tor_sscanf("!12:3:456", "!%2u:%2u:%3u", &u1, &u2, &u3));
+ tt_int_op(12u,OP_EQ, u1);
+ tt_int_op(3u,OP_EQ, u2);
+ tt_int_op(456u,OP_EQ, u3);
+ tt_int_op(3,OP_EQ,
+ tor_sscanf("67:8:099", "%2u:%2u:%3u", &u1, &u2, &u3)); /* 0s */
+ tt_int_op(67u,OP_EQ, u1);
+ tt_int_op(8u,OP_EQ, u2);
+ tt_int_op(99u,OP_EQ, u3);
/* %u does not match space.*/
- test_eq(2, tor_sscanf("12:3: 45", "%2u:%2u:%3u", &u1, &u2, &u3));
- test_eq(12u, u1);
- test_eq(3u, u2);
+ tt_int_op(2,OP_EQ, tor_sscanf("12:3: 45", "%2u:%2u:%3u", &u1, &u2, &u3));
+ tt_int_op(12u,OP_EQ, u1);
+ tt_int_op(3u,OP_EQ, u2);
/* %u does not match negative numbers. */
- test_eq(2, tor_sscanf("67:8:-9", "%2u:%2u:%3u", &u1, &u2, &u3));
- test_eq(67u, u1);
- test_eq(8u, u2);
+ tt_int_op(2,OP_EQ, tor_sscanf("67:8:-9", "%2u:%2u:%3u", &u1, &u2, &u3));
+ tt_int_op(67u,OP_EQ, u1);
+ tt_int_op(8u,OP_EQ, u2);
/* Arbitrary amounts of 0-padding are okay */
- test_eq(3, tor_sscanf("12:03:000000000000000099", "%2u:%2u:%u",
+ tt_int_op(3,OP_EQ, tor_sscanf("12:03:000000000000000099", "%2u:%2u:%u",
&u1, &u2, &u3));
- test_eq(12u, u1);
- test_eq(3u, u2);
- test_eq(99u, u3);
+ tt_int_op(12u,OP_EQ, u1);
+ tt_int_op(3u,OP_EQ, u2);
+ tt_int_op(99u,OP_EQ, u3);
/* Hex (ie. %x) */
- test_eq(3, tor_sscanf("1234 02aBcdEf ff", "%x %x %x", &u1, &u2, &u3));
- test_eq(0x1234, u1);
- test_eq(0x2ABCDEF, u2);
- test_eq(0xFF, u3);
+ tt_int_op(3,OP_EQ,
+ tor_sscanf("1234 02aBcdEf ff", "%x %x %x", &u1, &u2, &u3));
+ tt_int_op(0x1234,OP_EQ, u1);
+ tt_int_op(0x2ABCDEF,OP_EQ, u2);
+ tt_int_op(0xFF,OP_EQ, u3);
/* Width works on %x */
- test_eq(3, tor_sscanf("f00dcafe444", "%4x%4x%u", &u1, &u2, &u3));
- test_eq(0xf00d, u1);
- test_eq(0xcafe, u2);
- test_eq(444, u3);
+ tt_int_op(3,OP_EQ, tor_sscanf("f00dcafe444", "%4x%4x%u", &u1, &u2, &u3));
+ tt_int_op(0xf00d,OP_EQ, u1);
+ tt_int_op(0xcafe,OP_EQ, u2);
+ tt_int_op(444,OP_EQ, u3);
/* Literal '%' (ie. '%%') */
- test_eq(1, tor_sscanf("99% fresh", "%3u%% fresh", &u1));
- test_eq(99, u1);
- test_eq(0, tor_sscanf("99 fresh", "%% %3u %s", &u1, s1));
- test_eq(1, tor_sscanf("99 fresh", "%3u%% %s", &u1, s1));
- test_eq(2, tor_sscanf("99 fresh", "%3u %5s %%", &u1, s1));
- test_eq(99, u1);
- test_streq(s1, "fresh");
- test_eq(1, tor_sscanf("% boo", "%% %3s", s1));
- test_streq("boo", s1);
+ tt_int_op(1,OP_EQ, tor_sscanf("99% fresh", "%3u%% fresh", &u1));
+ tt_int_op(99,OP_EQ, u1);
+ tt_int_op(0,OP_EQ, tor_sscanf("99 fresh", "%% %3u %s", &u1, s1));
+ tt_int_op(1,OP_EQ, tor_sscanf("99 fresh", "%3u%% %s", &u1, s1));
+ tt_int_op(2,OP_EQ, tor_sscanf("99 fresh", "%3u %5s %%", &u1, s1));
+ tt_int_op(99,OP_EQ, u1);
+ tt_str_op(s1,OP_EQ, "fresh");
+ tt_int_op(1,OP_EQ, tor_sscanf("% boo", "%% %3s", s1));
+ tt_str_op("boo",OP_EQ, s1);
/* Strings (ie. %s) */
- test_eq(2, tor_sscanf("hello", "%3s%7s", s1, s2));
- test_streq(s1, "hel");
- test_streq(s2, "lo");
- test_eq(2, tor_sscanf("WD40", "%2s%u", s3, &u1)); /* %s%u */
- test_streq(s3, "WD");
- test_eq(40, u1);
- test_eq(2, tor_sscanf("WD40", "%3s%u", s3, &u1)); /* %s%u */
- test_streq(s3, "WD4");
- test_eq(0, u1);
- test_eq(2, tor_sscanf("76trombones", "%6u%9s", &u1, s1)); /* %u%s */
- test_eq(76, u1);
- test_streq(s1, "trombones");
- test_eq(1, tor_sscanf("prettylongstring", "%999s", s1));
- test_streq(s1, "prettylongstring");
+ tt_int_op(2,OP_EQ, tor_sscanf("hello", "%3s%7s", s1, s2));
+ tt_str_op(s1,OP_EQ, "hel");
+ tt_str_op(s2,OP_EQ, "lo");
+ tt_int_op(2,OP_EQ, tor_sscanf("WD40", "%2s%u", s3, &u1)); /* %s%u */
+ tt_str_op(s3,OP_EQ, "WD");
+ tt_int_op(40,OP_EQ, u1);
+ tt_int_op(2,OP_EQ, tor_sscanf("WD40", "%3s%u", s3, &u1)); /* %s%u */
+ tt_str_op(s3,OP_EQ, "WD4");
+ tt_int_op(0,OP_EQ, u1);
+ tt_int_op(2,OP_EQ, tor_sscanf("76trombones", "%6u%9s", &u1, s1)); /* %u%s */
+ tt_int_op(76,OP_EQ, u1);
+ tt_str_op(s1,OP_EQ, "trombones");
+ tt_int_op(1,OP_EQ, tor_sscanf("prettylongstring", "%999s", s1));
+ tt_str_op(s1,OP_EQ, "prettylongstring");
/* %s doesn't eat spaces */
- test_eq(2, tor_sscanf("hello world", "%9s %9s", s1, s2));
- test_streq(s1, "hello");
- test_streq(s2, "world");
- test_eq(2, tor_sscanf("bye world?", "%9s %9s", s1, s2));
- test_streq(s1, "bye");
- test_streq(s2, "");
- test_eq(3, tor_sscanf("hi", "%9s%9s%3s", s1, s2, s3)); /* %s can be empty. */
- test_streq(s1, "hi");
- test_streq(s2, "");
- test_streq(s3, "");
-
- test_eq(3, tor_sscanf("1.2.3", "%u.%u.%u%c", &u1, &u2, &u3, &ch));
- test_eq(4, tor_sscanf("1.2.3 foobar", "%u.%u.%u%c", &u1, &u2, &u3, &ch));
- test_eq(' ', ch);
+ tt_int_op(2,OP_EQ, tor_sscanf("hello world", "%9s %9s", s1, s2));
+ tt_str_op(s1,OP_EQ, "hello");
+ tt_str_op(s2,OP_EQ, "world");
+ tt_int_op(2,OP_EQ, tor_sscanf("bye world?", "%9s %9s", s1, s2));
+ tt_str_op(s1,OP_EQ, "bye");
+ tt_str_op(s2,OP_EQ, "");
+ tt_int_op(3,OP_EQ,
+ tor_sscanf("hi", "%9s%9s%3s", s1, s2, s3)); /* %s can be empty. */
+ tt_str_op(s1,OP_EQ, "hi");
+ tt_str_op(s2,OP_EQ, "");
+ tt_str_op(s3,OP_EQ, "");
+
+ tt_int_op(3,OP_EQ, tor_sscanf("1.2.3", "%u.%u.%u%c", &u1, &u2, &u3, &ch));
+ tt_int_op(4,OP_EQ,
+ tor_sscanf("1.2.3 foobar", "%u.%u.%u%c", &u1, &u2, &u3, &ch));
+ tt_int_op(' ',OP_EQ, ch);
r = tor_sscanf("12345 -67890 -1", "%d %ld %d", &int1, &lng1, &int2);
- test_eq(r,3);
- test_eq(int1, 12345);
- test_eq(lng1, -67890);
- test_eq(int2, -1);
+ tt_int_op(r,OP_EQ, 3);
+ tt_int_op(int1,OP_EQ, 12345);
+ tt_int_op(lng1,OP_EQ, -67890);
+ tt_int_op(int2,OP_EQ, -1);
#if SIZEOF_INT == 4
+ /* %u */
+ /* UINT32_MAX should work */
+ tt_int_op(1,OP_EQ, tor_sscanf("4294967295", "%u", &u1));
+ tt_int_op(4294967295U,OP_EQ, u1);
+
+ /* But UINT32_MAX + 1 shouldn't work */
+ tt_int_op(0,OP_EQ, tor_sscanf("4294967296", "%u", &u1));
+ /* but parsing only 9... */
+ tt_int_op(1,OP_EQ, tor_sscanf("4294967296", "%9u", &u1));
+ tt_int_op(429496729U,OP_EQ, u1);
+
+ /* %x */
+ /* UINT32_MAX should work */
+ tt_int_op(1,OP_EQ, tor_sscanf("FFFFFFFF", "%x", &u1));
+ tt_int_op(0xFFFFFFFF,OP_EQ, u1);
+
+ /* But UINT32_MAX + 1 shouldn't work */
+ tt_int_op(0,OP_EQ, tor_sscanf("100000000", "%x", &u1));
+
+ /* %d */
+ /* INT32_MIN and INT32_MAX should work */
r = tor_sscanf("-2147483648. 2147483647.", "%d. %d.", &int1, &int2);
- test_eq(r,2);
- test_eq(int1, -2147483647-1);
- test_eq(int2, 2147483647);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(int1,OP_EQ, -2147483647 - 1);
+ tt_int_op(int2,OP_EQ, 2147483647);
+
+ /* But INT32_MIN - 1 and INT32_MAX + 1 shouldn't work */
+ r = tor_sscanf("-2147483649.", "%d.", &int1);
+ tt_int_op(r,OP_EQ, 0);
- r = tor_sscanf("-2147483679.", "%d.", &int1);
- test_eq(r,0);
+ r = tor_sscanf("2147483648.", "%d.", &int1);
+ tt_int_op(r,OP_EQ, 0);
- r = tor_sscanf("2147483678.", "%d.", &int1);
- test_eq(r,0);
+ /* and the first failure stops further processing */
+ r = tor_sscanf("-2147483648. 2147483648.",
+ "%d. %d.", &int1, &int2);
+ tt_int_op(r,OP_EQ, 1);
+
+ r = tor_sscanf("-2147483649. 2147483647.",
+ "%d. %d.", &int1, &int2);
+ tt_int_op(r,OP_EQ, 0);
+
+ r = tor_sscanf("2147483648. -2147483649.",
+ "%d. %d.", &int1, &int2);
+ tt_int_op(r,OP_EQ, 0);
#elif SIZEOF_INT == 8
+ /* %u */
+ /* UINT64_MAX should work */
+ tt_int_op(1,OP_EQ, tor_sscanf("18446744073709551615", "%u", &u1));
+ tt_int_op(18446744073709551615U,OP_EQ, u1);
+
+ /* But UINT64_MAX + 1 shouldn't work */
+ tt_int_op(0,OP_EQ, tor_sscanf("18446744073709551616", "%u", &u1));
+ /* but parsing only 19... */
+ tt_int_op(1,OP_EQ, tor_sscanf("18446744073709551616", "%19u", &u1));
+ tt_int_op(1844674407370955161U,OP_EQ, u1);
+
+ /* %x */
+ /* UINT64_MAX should work */
+ tt_int_op(1,OP_EQ, tor_sscanf("FFFFFFFFFFFFFFFF", "%x", &u1));
+ tt_int_op(0xFFFFFFFFFFFFFFFF,OP_EQ, u1);
+
+ /* But UINT64_MAX + 1 shouldn't work */
+ tt_int_op(0,OP_EQ, tor_sscanf("10000000000000000", "%x", &u1));
+
+ /* %d */
+ /* INT64_MIN and INT64_MAX should work */
r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
"%d. %d.", &int1, &int2);
- test_eq(r,2);
- test_eq(int1, -9223372036854775807-1);
- test_eq(int2, 9223372036854775807);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(int1,OP_EQ, -9223372036854775807 - 1);
+ tt_int_op(int2,OP_EQ, 9223372036854775807);
+ /* But INT64_MIN - 1 and INT64_MAX + 1 shouldn't work */
r = tor_sscanf("-9223372036854775809.", "%d.", &int1);
- test_eq(r,0);
+ tt_int_op(r,OP_EQ, 0);
r = tor_sscanf("9223372036854775808.", "%d.", &int1);
- test_eq(r,0);
+ tt_int_op(r,OP_EQ, 0);
+
+ /* and the first failure stops further processing */
+ r = tor_sscanf("-9223372036854775808. 9223372036854775808.",
+ "%d. %d.", &int1, &int2);
+ tt_int_op(r,OP_EQ, 1);
+
+ r = tor_sscanf("-9223372036854775809. 9223372036854775807.",
+ "%d. %d.", &int1, &int2);
+ tt_int_op(r,OP_EQ, 0);
+
+ r = tor_sscanf("9223372036854775808. -9223372036854775809.",
+ "%d. %d.", &int1, &int2);
+ tt_int_op(r,OP_EQ, 0);
#endif
#if SIZEOF_LONG == 4
+ /* %lu */
+ /* UINT32_MAX should work */
+ tt_int_op(1,OP_EQ, tor_sscanf("4294967295", "%lu", &ulng));
+ tt_int_op(4294967295UL,OP_EQ, ulng);
+
+ /* But UINT32_MAX + 1 shouldn't work */
+ tt_int_op(0,OP_EQ, tor_sscanf("4294967296", "%lu", &ulng));
+ /* but parsing only 9... */
+ tt_int_op(1,OP_EQ, tor_sscanf("4294967296", "%9lu", &ulng));
+ tt_int_op(429496729UL,OP_EQ, ulng);
+
+ /* %lx */
+ /* UINT32_MAX should work */
+ tt_int_op(1,OP_EQ, tor_sscanf("FFFFFFFF", "%lx", &ulng));
+ tt_int_op(0xFFFFFFFFUL,OP_EQ, ulng);
+
+ /* But UINT32_MAX + 1 shouldn't work */
+ tt_int_op(0,OP_EQ, tor_sscanf("100000000", "%lx", &ulng));
+
+ /* %ld */
+ /* INT32_MIN and INT32_MAX should work */
r = tor_sscanf("-2147483648. 2147483647.", "%ld. %ld.", &lng1, &lng2);
- test_eq(r,2);
- test_eq(lng1, -2147483647 - 1);
- test_eq(lng2, 2147483647);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(lng1,OP_EQ, -2147483647L - 1L);
+ tt_int_op(lng2,OP_EQ, 2147483647L);
+
+ /* But INT32_MIN - 1 and INT32_MAX + 1 shouldn't work */
+ r = tor_sscanf("-2147483649.", "%ld.", &lng1);
+ tt_int_op(r,OP_EQ, 0);
+
+ r = tor_sscanf("2147483648.", "%ld.", &lng1);
+ tt_int_op(r,OP_EQ, 0);
+
+ /* and the first failure stops further processing */
+ r = tor_sscanf("-2147483648. 2147483648.",
+ "%ld. %ld.", &lng1, &lng2);
+ tt_int_op(r,OP_EQ, 1);
+
+ r = tor_sscanf("-2147483649. 2147483647.",
+ "%ld. %ld.", &lng1, &lng2);
+ tt_int_op(r,OP_EQ, 0);
+
+ r = tor_sscanf("2147483648. -2147483649.",
+ "%ld. %ld.", &lng1, &lng2);
+ tt_int_op(r,OP_EQ, 0);
#elif SIZEOF_LONG == 8
+ /* %lu */
+ /* UINT64_MAX should work */
+ tt_int_op(1,OP_EQ, tor_sscanf("18446744073709551615", "%lu", &ulng));
+ tt_int_op(18446744073709551615UL,OP_EQ, ulng);
+
+ /* But UINT64_MAX + 1 shouldn't work */
+ tt_int_op(0,OP_EQ, tor_sscanf("18446744073709551616", "%lu", &ulng));
+ /* but parsing only 19... */
+ tt_int_op(1,OP_EQ, tor_sscanf("18446744073709551616", "%19lu", &ulng));
+ tt_int_op(1844674407370955161UL,OP_EQ, ulng);
+
+ /* %lx */
+ /* UINT64_MAX should work */
+ tt_int_op(1,OP_EQ, tor_sscanf("FFFFFFFFFFFFFFFF", "%lx", &ulng));
+ tt_int_op(0xFFFFFFFFFFFFFFFFUL,OP_EQ, ulng);
+
+ /* But UINT64_MAX + 1 shouldn't work */
+ tt_int_op(0,OP_EQ, tor_sscanf("10000000000000000", "%lx", &ulng));
+
+ /* %ld */
+ /* INT64_MIN and INT64_MAX should work */
r = tor_sscanf("-9223372036854775808. 9223372036854775807.",
"%ld. %ld.", &lng1, &lng2);
- test_eq(r,2);
- test_eq(lng1, -9223372036854775807L - 1);
- test_eq(lng2, 9223372036854775807L);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(lng1,OP_EQ, -9223372036854775807L - 1L);
+ tt_int_op(lng2,OP_EQ, 9223372036854775807L);
+
+ /* But INT64_MIN - 1 and INT64_MAX + 1 shouldn't work */
+ r = tor_sscanf("-9223372036854775809.", "%ld.", &lng1);
+ tt_int_op(r,OP_EQ, 0);
+ r = tor_sscanf("9223372036854775808.", "%ld.", &lng1);
+ tt_int_op(r,OP_EQ, 0);
+
+ /* and the first failure stops further processing */
r = tor_sscanf("-9223372036854775808. 9223372036854775808.",
"%ld. %ld.", &lng1, &lng2);
- test_eq(r,1);
- r = tor_sscanf("-9223372036854775809. 9223372036854775808.",
+ tt_int_op(r,OP_EQ, 1);
+
+ r = tor_sscanf("-9223372036854775809. 9223372036854775807.",
+ "%ld. %ld.", &lng1, &lng2);
+ tt_int_op(r,OP_EQ, 0);
+
+ r = tor_sscanf("9223372036854775808. -9223372036854775809.",
"%ld. %ld.", &lng1, &lng2);
- test_eq(r,0);
+ tt_int_op(r,OP_EQ, 0);
#endif
r = tor_sscanf("123.456 .000007 -900123123.2000787 00003.2",
"%lf %lf %lf %lf", &d1,&d2,&d3,&d4);
- test_eq(r,4);
+ tt_int_op(r,OP_EQ, 4);
test_feq(d1, 123.456);
test_feq(d2, .000007);
test_feq(d3, -900123123.2000787);
@@ -1868,137 +2174,508 @@ test_util_sscanf(void)
;
}
+#define tt_char_op(a,op,b) tt_assert_op_type(a,op,b,char,"%c")
+#define tt_ci_char_op(a,op,b) tt_char_op(tolower(a),op,tolower(b))
+
+#ifndef HAVE_STRNLEN
+static size_t
+strnlen(const char *s, size_t len)
+{
+ const char *p = memchr(s, 0, len);
+ if (!p)
+ return len;
+ return p - s;
+}
+#endif
+
static void
-test_util_path_is_relative(void)
+test_util_format_time_interval(void *arg)
{
- /* OS-independent tests */
- test_eq(1, path_is_relative(""));
- test_eq(1, path_is_relative("dir"));
- test_eq(1, path_is_relative("dir/"));
- test_eq(1, path_is_relative("./dir"));
- test_eq(1, path_is_relative("../dir"));
+ /* use the same sized buffer and integers as tor uses */
+#define DBUF_SIZE 64
+ char dbuf[DBUF_SIZE];
+#define T_ "%ld"
+ long sec, min, hour, day;
+
+ /* we don't care about the exact spelling of the
+ * second(s), minute(s), hour(s), day(s) labels */
+#define LABEL_SIZE 21
+#define L_ "%20s"
+ char label_s[LABEL_SIZE];
+ char label_m[LABEL_SIZE];
+ char label_h[LABEL_SIZE];
+ char label_d[LABEL_SIZE];
+
+#define TL_ T_ " " L_
- test_eq(0, path_is_relative("/"));
- test_eq(0, path_is_relative("/dir"));
- test_eq(0, path_is_relative("/dir/"));
+ int r;
+
+ (void)arg;
+
+ /* In these tests, we're not picky about
+ * spelling or abbreviations */
+
+ /* seconds: 0, 1, 9, 10, 59 */
+
+ /* ignore exact spelling of "second(s)"*/
+ format_time_interval(dbuf, sizeof(dbuf), 0);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &sec, label_s);
+ tt_int_op(r,OP_EQ, 2);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+ tt_int_op(sec,OP_EQ, 0);
+
+ format_time_interval(dbuf, sizeof(dbuf), 1);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &sec, label_s);
+ tt_int_op(r,OP_EQ, 2);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+ tt_int_op(sec,OP_EQ, 1);
+
+ format_time_interval(dbuf, sizeof(dbuf), 10);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &sec, label_s);
+ tt_int_op(r,OP_EQ, 2);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+ tt_int_op(sec,OP_EQ, 10);
+
+ format_time_interval(dbuf, sizeof(dbuf), 59);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &sec, label_s);
+ tt_int_op(r,OP_EQ, 2);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+ tt_int_op(sec,OP_EQ, 59);
+
+ /* negative seconds are reported as their absolute value */
+
+ format_time_interval(dbuf, sizeof(dbuf), -4);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &sec, label_s);
+ tt_int_op(r,OP_EQ, 2);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+ tt_int_op(sec,OP_EQ, 4);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+
+ format_time_interval(dbuf, sizeof(dbuf), -32);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &sec, label_s);
+ tt_int_op(r,OP_EQ, 2);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+ tt_int_op(sec,OP_EQ, 32);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+
+ /* minutes: 1:00, 1:01, 1:59, 2:00, 2:01, 59:59 */
+
+ /* ignore trailing "0 second(s)", if present */
+ format_time_interval(dbuf, sizeof(dbuf), 60);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &min, label_m);
+ tt_int_op(r,OP_EQ, 2);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ tt_int_op(min,OP_EQ, 1);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+
+ /* ignore exact spelling of "minute(s)," and "second(s)" */
+ format_time_interval(dbuf, sizeof(dbuf), 60 + 1);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &min, label_m, &sec, label_s);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(min,OP_EQ, 1);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ tt_int_op(sec,OP_EQ, 1);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+
+ format_time_interval(dbuf, sizeof(dbuf), 60*2 - 1);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &min, label_m, &sec, label_s);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(min,OP_EQ, 1);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ tt_int_op(sec,OP_EQ, 59);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+
+ /* ignore trailing "0 second(s)", if present */
+ format_time_interval(dbuf, sizeof(dbuf), 60*2);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &min, label_m);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(min,OP_EQ, 2);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+ /* ignore exact spelling of "minute(s)," and "second(s)" */
+ format_time_interval(dbuf, sizeof(dbuf), 60*2 + 1);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &min, label_m, &sec, label_s);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(min,OP_EQ, 2);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ tt_int_op(sec,OP_EQ, 1);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+
+ format_time_interval(dbuf, sizeof(dbuf), 60*60 - 1);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &min, label_m, &sec, label_s);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(min,OP_EQ, 59);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ tt_int_op(sec,OP_EQ, 59);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+
+ /* negative minutes are reported as their absolute value */
+
+ /* ignore trailing "0 second(s)", if present */
+ format_time_interval(dbuf, sizeof(dbuf), -3*60);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &min, label_m);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(min,OP_EQ, 3);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+ /* ignore exact spelling of "minute(s)," and "second(s)" */
+ format_time_interval(dbuf, sizeof(dbuf), -96);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &min, label_m, &sec, label_s);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(min,OP_EQ, 1);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ tt_int_op(sec,OP_EQ, 36);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+
+ format_time_interval(dbuf, sizeof(dbuf), -2815);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &min, label_m, &sec, label_s);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(min,OP_EQ, 46);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ tt_int_op(sec,OP_EQ, 55);
+ tt_ci_char_op(label_s[0],OP_EQ, 's');
+
+ /* hours: 1:00, 1:00:01, 1:01, 23:59, 23:59:59 */
+ /* always ignore trailing seconds, if present */
+
+ /* ignore trailing "0 minute(s)" etc., if present */
+ format_time_interval(dbuf, sizeof(dbuf), 60*60);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &hour, label_h);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(hour,OP_EQ, 1);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+
+ format_time_interval(dbuf, sizeof(dbuf), 60*60 + 1);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &hour, label_h);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(hour,OP_EQ, 1);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+
+ /* ignore exact spelling of "hour(s)," etc. */
+ format_time_interval(dbuf, sizeof(dbuf), 60*60 + 60);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(hour,OP_EQ, 1);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 1);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+ format_time_interval(dbuf, sizeof(dbuf), 24*60*60 - 60);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(hour,OP_EQ, 23);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 59);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+ format_time_interval(dbuf, sizeof(dbuf), 24*60*60 - 1);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(hour,OP_EQ, 23);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 59);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+ /* negative hours are reported as their absolute value */
+
+ /* ignore exact spelling of "hour(s)," etc., if present */
+ format_time_interval(dbuf, sizeof(dbuf), -2*60*60);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &hour, label_h);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(hour,OP_EQ, 2);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+
+ format_time_interval(dbuf, sizeof(dbuf), -75804);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(hour,OP_EQ, 21);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 3);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+ /* days: 1:00, 1:00:00:01, 1:00:01, 1:01 */
+ /* always ignore trailing seconds, if present */
+
+ /* ignore trailing "0 hours(s)" etc., if present */
+ format_time_interval(dbuf, sizeof(dbuf), 24*60*60);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &day, label_d);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(day,OP_EQ, 1);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+
+ format_time_interval(dbuf, sizeof(dbuf), 24*60*60 + 1);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_, &day, label_d);
+ tt_int_op(r,OP_EQ, 2);
+ tt_int_op(day,OP_EQ, 1);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+
+ /* ignore exact spelling of "days(s)," etc. */
+ format_time_interval(dbuf, sizeof(dbuf), 24*60*60 + 60);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_ " " TL_,
+ &day, label_d, &hour, label_h, &min, label_m);
+ if (r == -1) {
+ /* ignore 0 hours(s), if present */
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &day, label_d, &min, label_m);
+ }
+ tt_assert(r == 4 || r == 6);
+ tt_int_op(day,OP_EQ, 1);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+ if (r == 6) {
+ tt_int_op(hour,OP_EQ, 0);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ }
+ tt_int_op(min,OP_EQ, 1);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+ /* ignore trailing "0 minutes(s)" etc., if present */
+ format_time_interval(dbuf, sizeof(dbuf), 24*60*60 + 60*60);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_,
+ &day, label_d, &hour, label_h);
+ tt_int_op(r,OP_EQ, 4);
+ tt_int_op(day,OP_EQ, 1);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+ tt_int_op(hour,OP_EQ, 1);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+
+ /* negative days are reported as their absolute value */
+
+ format_time_interval(dbuf, sizeof(dbuf), -21936184);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_ " " TL_,
+ &day, label_d, &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 6);
+ tt_int_op(day,OP_EQ, 253);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+ tt_int_op(hour,OP_EQ, 21);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 23);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+ /* periods > 1 year are reported in days (warn?) */
+
+ /* ignore exact spelling of "days(s)," etc., if present */
+ format_time_interval(dbuf, sizeof(dbuf), 758635154);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_ " " TL_,
+ &day, label_d, &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 6);
+ tt_int_op(day,OP_EQ, 8780);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+ tt_int_op(hour,OP_EQ, 11);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 59);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+ /* negative periods > 1 year are reported in days (warn?) */
+
+ format_time_interval(dbuf, sizeof(dbuf), -1427014922);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_ " " TL_,
+ &day, label_d, &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 6);
+ tt_int_op(day,OP_EQ, 16516);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+ tt_int_op(hour,OP_EQ, 9);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 2);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+
+#if SIZEOF_LONG == 4 || SIZEOF_LONG == 8
+
+ /* We can try INT32_MIN/MAX */
+ /* Always ignore second(s) */
+
+ /* INT32_MAX */
+ format_time_interval(dbuf, sizeof(dbuf), 2147483647);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_ " " TL_,
+ &day, label_d, &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 6);
+ tt_int_op(day,OP_EQ, 24855);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+ tt_int_op(hour,OP_EQ, 3);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 14);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ /* and 7 seconds - ignored */
+
+ /* INT32_MIN: check that we get the absolute value of interval,
+ * which doesn't actually fit in int32_t.
+ * We expect INT32_MAX or INT32_MAX + 1 with 64 bit longs */
+ format_time_interval(dbuf, sizeof(dbuf), -2147483647L - 1L);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_ " " TL_,
+ &day, label_d, &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 6);
+ tt_int_op(day,OP_EQ, 24855);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+ tt_int_op(hour,OP_EQ, 3);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 14);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ /* and 7 or 8 seconds - ignored */
+
+#endif
+
+#if SIZEOF_LONG == 8
+
+ /* We can try INT64_MIN/MAX */
+ /* Always ignore second(s) */
+
+ /* INT64_MAX */
+ format_time_interval(dbuf, sizeof(dbuf), 9223372036854775807L);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_ " " TL_,
+ &day, label_d, &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 6);
+ tt_int_op(day,OP_EQ, 106751991167300L);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+ tt_int_op(hour,OP_EQ, 15);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 30);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ /* and 7 seconds - ignored */
+
+ /* INT64_MIN: check that we get the absolute value of interval,
+ * which doesn't actually fit in int64_t.
+ * We expect INT64_MAX */
+ format_time_interval(dbuf, sizeof(dbuf),
+ -9223372036854775807L - 1L);
+ tt_int_op(strnlen(dbuf, DBUF_SIZE),OP_LE, DBUF_SIZE - 1);
+ r = tor_sscanf(dbuf, TL_ " " TL_ " " TL_,
+ &day, label_d, &hour, label_h, &min, label_m);
+ tt_int_op(r,OP_EQ, 6);
+ tt_int_op(day,OP_EQ, 106751991167300L);
+ tt_ci_char_op(label_d[0],OP_EQ, 'd');
+ tt_int_op(hour,OP_EQ, 15);
+ tt_ci_char_op(label_h[0],OP_EQ, 'h');
+ tt_int_op(min,OP_EQ, 30);
+ tt_ci_char_op(label_m[0],OP_EQ, 'm');
+ /* and 7 or 8 seconds - ignored */
- /* Windows */
-#ifdef _WIN32
- /* I don't have Windows so I can't test this, hence the "#ifdef
- 0". These are tests that look useful, so please try to get them
- running and uncomment if it all works as it should */
- test_eq(1, path_is_relative("dir"));
- test_eq(1, path_is_relative("dir\\"));
- test_eq(1, path_is_relative("dir\\a:"));
- test_eq(1, path_is_relative("dir\\a:\\"));
- test_eq(1, path_is_relative("http:\\dir"));
-
- test_eq(0, path_is_relative("\\dir"));
- test_eq(0, path_is_relative("a:\\dir"));
- test_eq(0, path_is_relative("z:\\dir"));
#endif
done:
;
}
-#ifdef ENABLE_MEMPOOLS
+#undef tt_char_op
+#undef tt_ci_char_op
+#undef DBUF_SIZE
+#undef T_
+#undef LABEL_SIZE
+#undef L_
+#undef TL_
-/** Run unittests for memory pool allocator */
static void
-test_util_mempool(void)
+test_util_path_is_relative(void *arg)
{
- mp_pool_t *pool = NULL;
- smartlist_t *allocated = NULL;
- int i;
+ /* OS-independent tests */
+ (void)arg;
+ tt_int_op(1,OP_EQ, path_is_relative(""));
+ tt_int_op(1,OP_EQ, path_is_relative("dir"));
+ tt_int_op(1,OP_EQ, path_is_relative("dir/"));
+ tt_int_op(1,OP_EQ, path_is_relative("./dir"));
+ tt_int_op(1,OP_EQ, path_is_relative("../dir"));
- pool = mp_pool_new(1, 100);
- test_assert(pool);
- test_assert(pool->new_chunk_capacity >= 100);
- test_assert(pool->item_alloc_size >= sizeof(void*)+1);
- mp_pool_destroy(pool);
- pool = NULL;
-
- pool = mp_pool_new(241, 2500);
- test_assert(pool);
- test_assert(pool->new_chunk_capacity >= 10);
- test_assert(pool->item_alloc_size >= sizeof(void*)+241);
- test_eq(pool->item_alloc_size & 0x03, 0);
- test_assert(pool->new_chunk_capacity < 60);
-
- allocated = smartlist_new();
- for (i = 0; i < 20000; ++i) {
- if (smartlist_len(allocated) < 20 || crypto_rand_int(2)) {
- void *m = mp_pool_get(pool);
- memset(m, 0x09, 241);
- smartlist_add(allocated, m);
- //printf("%d: %p\n", i, m);
- //mp_pool_assert_ok(pool);
- } else {
- int idx = crypto_rand_int(smartlist_len(allocated));
- void *m = smartlist_get(allocated, idx);
- //printf("%d: free %p\n", i, m);
- smartlist_del(allocated, idx);
- mp_pool_release(m);
- //mp_pool_assert_ok(pool);
- }
- if (crypto_rand_int(777)==0)
- mp_pool_clean(pool, 1, 1);
+ tt_int_op(0,OP_EQ, path_is_relative("/"));
+ tt_int_op(0,OP_EQ, path_is_relative("/dir"));
+ tt_int_op(0,OP_EQ, path_is_relative("/dir/"));
- if (i % 777)
- mp_pool_assert_ok(pool);
- }
+ /* Windows */
+#ifdef _WIN32
+ /* I don't have Windows so I can't test this, hence the "#ifdef
+ 0". These are tests that look useful, so please try to get them
+ running and uncomment if it all works as it should */
+ tt_int_op(1,OP_EQ, path_is_relative("dir"));
+ tt_int_op(1,OP_EQ, path_is_relative("dir\\"));
+ tt_int_op(1,OP_EQ, path_is_relative("dir\\a:"));
+ tt_int_op(1,OP_EQ, path_is_relative("dir\\a:\\"));
+ tt_int_op(1,OP_EQ, path_is_relative("http:\\dir"));
+
+ tt_int_op(0,OP_EQ, path_is_relative("\\dir"));
+ tt_int_op(0,OP_EQ, path_is_relative("a:\\dir"));
+ tt_int_op(0,OP_EQ, path_is_relative("z:\\dir"));
+#endif
done:
- if (allocated) {
- SMARTLIST_FOREACH(allocated, void *, m, mp_pool_release(m));
- mp_pool_assert_ok(pool);
- mp_pool_clean(pool, 0, 0);
- mp_pool_assert_ok(pool);
- smartlist_free(allocated);
- }
-
- if (pool)
- mp_pool_destroy(pool);
+ ;
}
-#endif /* ENABLE_MEMPOOLS */
-
/** Run unittests for memory area allocator */
static void
-test_util_memarea(void)
+test_util_memarea(void *arg)
{
memarea_t *area = memarea_new();
char *p1, *p2, *p3, *p1_orig;
void *malloced_ptr = NULL;
int i;
- test_assert(area);
+ (void)arg;
+ tt_assert(area);
p1_orig = p1 = memarea_alloc(area,64);
p2 = memarea_alloc_zero(area,52);
p3 = memarea_alloc(area,11);
- test_assert(memarea_owns_ptr(area, p1));
- test_assert(memarea_owns_ptr(area, p2));
- test_assert(memarea_owns_ptr(area, p3));
+ tt_assert(memarea_owns_ptr(area, p1));
+ tt_assert(memarea_owns_ptr(area, p2));
+ tt_assert(memarea_owns_ptr(area, p3));
/* Make sure we left enough space. */
- test_assert(p1+64 <= p2);
- test_assert(p2+52 <= p3);
+ tt_assert(p1+64 <= p2);
+ tt_assert(p2+52 <= p3);
/* Make sure we aligned. */
- test_eq(((uintptr_t)p1) % sizeof(void*), 0);
- test_eq(((uintptr_t)p2) % sizeof(void*), 0);
- test_eq(((uintptr_t)p3) % sizeof(void*), 0);
- test_assert(!memarea_owns_ptr(area, p3+8192));
- test_assert(!memarea_owns_ptr(area, p3+30));
- test_assert(tor_mem_is_zero(p2, 52));
+ tt_int_op(((uintptr_t)p1) % sizeof(void*),OP_EQ, 0);
+ tt_int_op(((uintptr_t)p2) % sizeof(void*),OP_EQ, 0);
+ tt_int_op(((uintptr_t)p3) % sizeof(void*),OP_EQ, 0);
+ tt_assert(!memarea_owns_ptr(area, p3+8192));
+ tt_assert(!memarea_owns_ptr(area, p3+30));
+ tt_assert(tor_mem_is_zero(p2, 52));
/* Make sure we don't overalign. */
p1 = memarea_alloc(area, 1);
p2 = memarea_alloc(area, 1);
- test_eq_ptr(p1+sizeof(void*), p2);
+ tt_ptr_op(p1+sizeof(void*),OP_EQ, p2);
{
malloced_ptr = tor_malloc(64);
- test_assert(!memarea_owns_ptr(area, malloced_ptr));
+ tt_assert(!memarea_owns_ptr(area, malloced_ptr));
tor_free(malloced_ptr);
}
@@ -2007,18 +2684,18 @@ test_util_memarea(void)
malloced_ptr = tor_malloc(64);
crypto_rand((char*)malloced_ptr, 64);
p1 = memarea_memdup(area, malloced_ptr, 64);
- test_assert(p1 != malloced_ptr);
- test_memeq(p1, malloced_ptr, 64);
+ tt_assert(p1 != malloced_ptr);
+ tt_mem_op(p1,OP_EQ, malloced_ptr, 64);
tor_free(malloced_ptr);
}
/* memarea_strdup. */
p1 = memarea_strdup(area,"");
p2 = memarea_strdup(area, "abcd");
- test_assert(p1);
- test_assert(p2);
- test_streq(p1, "");
- test_streq(p2, "abcd");
+ tt_assert(p1);
+ tt_assert(p2);
+ tt_str_op(p1,OP_EQ, "");
+ tt_str_op(p2,OP_EQ, "abcd");
/* memarea_strndup. */
{
@@ -2027,33 +2704,33 @@ test_util_memarea(void)
size_t len = strlen(s);
p1 = memarea_strndup(area, s, 1000);
p2 = memarea_strndup(area, s, 10);
- test_streq(p1, s);
- test_assert(p2 >= p1 + len + 1);
- test_memeq(s, p2, 10);
- test_eq(p2[10], '\0');
+ tt_str_op(p1,OP_EQ, s);
+ tt_assert(p2 >= p1 + len + 1);
+ tt_mem_op(s,OP_EQ, p2, 10);
+ tt_int_op(p2[10],OP_EQ, '\0');
p3 = memarea_strndup(area, s, len);
- test_streq(p3, s);
+ tt_str_op(p3,OP_EQ, s);
p3 = memarea_strndup(area, s, len-1);
- test_memeq(s, p3, len-1);
- test_eq(p3[len-1], '\0');
+ tt_mem_op(s,OP_EQ, p3, len-1);
+ tt_int_op(p3[len-1],OP_EQ, '\0');
}
memarea_clear(area);
p1 = memarea_alloc(area, 1);
- test_eq_ptr(p1, p1_orig);
+ tt_ptr_op(p1,OP_EQ, p1_orig);
memarea_clear(area);
/* Check for running over an area's size. */
for (i = 0; i < 512; ++i) {
p1 = memarea_alloc(area, crypto_rand_int(5)+1);
- test_assert(memarea_owns_ptr(area, p1));
+ tt_assert(memarea_owns_ptr(area, p1));
}
memarea_assert_ok(area);
/* Make sure we can allocate a too-big object. */
p1 = memarea_alloc_zero(area, 9000);
p2 = memarea_alloc_zero(area, 16);
- test_assert(memarea_owns_ptr(area, p1));
- test_assert(memarea_owns_ptr(area, p2));
+ tt_assert(memarea_owns_ptr(area, p1));
+ tt_assert(memarea_owns_ptr(area, p2));
done:
memarea_drop_all(area);
@@ -2063,31 +2740,32 @@ test_util_memarea(void)
/** Run unit tests for utility functions to get file names relative to
* the data directory. */
static void
-test_util_datadir(void)
+test_util_datadir(void *arg)
{
char buf[1024];
char *f = NULL;
char *temp_dir = NULL;
+ (void)arg;
temp_dir = get_datadir_fname(NULL);
f = get_datadir_fname("state");
tor_snprintf(buf, sizeof(buf), "%s"PATH_SEPARATOR"state", temp_dir);
- test_streq(f, buf);
+ tt_str_op(f,OP_EQ, buf);
tor_free(f);
f = get_datadir_fname2("cache", "thingy");
tor_snprintf(buf, sizeof(buf),
"%s"PATH_SEPARATOR"cache"PATH_SEPARATOR"thingy", temp_dir);
- test_streq(f, buf);
+ tt_str_op(f,OP_EQ, buf);
tor_free(f);
f = get_datadir_fname2_suffix("cache", "thingy", ".foo");
tor_snprintf(buf, sizeof(buf),
"%s"PATH_SEPARATOR"cache"PATH_SEPARATOR"thingy.foo", temp_dir);
- test_streq(f, buf);
+ tt_str_op(f,OP_EQ, buf);
tor_free(f);
f = get_datadir_fname_suffix("cache", ".foo");
tor_snprintf(buf, sizeof(buf), "%s"PATH_SEPARATOR"cache.foo",
temp_dir);
- test_streq(f, buf);
+ tt_str_op(f,OP_EQ, buf);
done:
tor_free(f);
@@ -2095,13 +2773,14 @@ test_util_datadir(void)
}
static void
-test_util_strtok(void)
+test_util_strtok(void *arg)
{
char buf[128];
char buf2[128];
int i;
char *cp1, *cp2;
+ (void)arg;
for (i = 0; i < 3; i++) {
const char *pad1="", *pad2="";
switch (i) {
@@ -2118,8 +2797,8 @@ test_util_strtok(void)
}
tor_snprintf(buf, sizeof(buf), "%s", pad1);
tor_snprintf(buf2, sizeof(buf2), "%s", pad2);
- test_assert(NULL == tor_strtok_r_impl(buf, " ", &cp1));
- test_assert(NULL == tor_strtok_r_impl(buf2, ".!..;!", &cp2));
+ tt_assert(NULL == tor_strtok_r_impl(buf, " ", &cp1));
+ tt_assert(NULL == tor_strtok_r_impl(buf2, ".!..;!", &cp2));
tor_snprintf(buf, sizeof(buf),
"%sGraved on the dark in gestures of descent%s", pad1, pad1);
@@ -2127,43 +2806,43 @@ test_util_strtok(void)
"%sthey.seemed;;their!.own;most.perfect;monument%s",pad2,pad2);
/* -- "Year's End", Richard Wilbur */
- test_streq("Graved", tor_strtok_r_impl(buf, " ", &cp1));
- test_streq("they", tor_strtok_r_impl(buf2, ".!..;!", &cp2));
+ tt_str_op("Graved",OP_EQ, tor_strtok_r_impl(buf, " ", &cp1));
+ tt_str_op("they",OP_EQ, tor_strtok_r_impl(buf2, ".!..;!", &cp2));
#define S1() tor_strtok_r_impl(NULL, " ", &cp1)
#define S2() tor_strtok_r_impl(NULL, ".!..;!", &cp2)
- test_streq("on", S1());
- test_streq("the", S1());
- test_streq("dark", S1());
- test_streq("seemed", S2());
- test_streq("their", S2());
- test_streq("own", S2());
- test_streq("in", S1());
- test_streq("gestures", S1());
- test_streq("of", S1());
- test_streq("most", S2());
- test_streq("perfect", S2());
- test_streq("descent", S1());
- test_streq("monument", S2());
- test_eq_ptr(NULL, S1());
- test_eq_ptr(NULL, S2());
+ tt_str_op("on",OP_EQ, S1());
+ tt_str_op("the",OP_EQ, S1());
+ tt_str_op("dark",OP_EQ, S1());
+ tt_str_op("seemed",OP_EQ, S2());
+ tt_str_op("their",OP_EQ, S2());
+ tt_str_op("own",OP_EQ, S2());
+ tt_str_op("in",OP_EQ, S1());
+ tt_str_op("gestures",OP_EQ, S1());
+ tt_str_op("of",OP_EQ, S1());
+ tt_str_op("most",OP_EQ, S2());
+ tt_str_op("perfect",OP_EQ, S2());
+ tt_str_op("descent",OP_EQ, S1());
+ tt_str_op("monument",OP_EQ, S2());
+ tt_ptr_op(NULL,OP_EQ, S1());
+ tt_ptr_op(NULL,OP_EQ, S2());
}
buf[0] = 0;
- test_eq_ptr(NULL, tor_strtok_r_impl(buf, " ", &cp1));
- test_eq_ptr(NULL, tor_strtok_r_impl(buf, "!", &cp1));
+ tt_ptr_op(NULL,OP_EQ, tor_strtok_r_impl(buf, " ", &cp1));
+ tt_ptr_op(NULL,OP_EQ, tor_strtok_r_impl(buf, "!", &cp1));
strlcpy(buf, "Howdy!", sizeof(buf));
- test_streq("Howdy", tor_strtok_r_impl(buf, "!", &cp1));
- test_eq_ptr(NULL, tor_strtok_r_impl(NULL, "!", &cp1));
+ tt_str_op("Howdy",OP_EQ, tor_strtok_r_impl(buf, "!", &cp1));
+ tt_ptr_op(NULL,OP_EQ, tor_strtok_r_impl(NULL, "!", &cp1));
strlcpy(buf, " ", sizeof(buf));
- test_eq_ptr(NULL, tor_strtok_r_impl(buf, " ", &cp1));
+ tt_ptr_op(NULL,OP_EQ, tor_strtok_r_impl(buf, " ", &cp1));
strlcpy(buf, " ", sizeof(buf));
- test_eq_ptr(NULL, tor_strtok_r_impl(buf, " ", &cp1));
+ tt_ptr_op(NULL,OP_EQ, tor_strtok_r_impl(buf, " ", &cp1));
strlcpy(buf, "something ", sizeof(buf));
- test_streq("something", tor_strtok_r_impl(buf, " ", &cp1));
- test_eq_ptr(NULL, tor_strtok_r_impl(NULL, ";", &cp1));
+ tt_str_op("something",OP_EQ, tor_strtok_r_impl(buf, " ", &cp1));
+ tt_ptr_op(NULL,OP_EQ, tor_strtok_r_impl(NULL, ";", &cp1));
done:
;
}
@@ -2183,23 +2862,26 @@ test_util_find_str_at_start_of_line(void *ptr)
(void)ptr;
- test_eq_ptr(long_string, find_str_at_start_of_line(long_string, ""));
- test_eq_ptr(NULL, find_str_at_start_of_line(short_string, "nonsense"));
- test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "nonsense"));
- test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "\n"));
- test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "how "));
- test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "kitty"));
- test_eq_ptr(long_string, find_str_at_start_of_line(long_string, "h"));
- test_eq_ptr(long_string, find_str_at_start_of_line(long_string, "how"));
- test_eq_ptr(line2, find_str_at_start_of_line(long_string, "he"));
- test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hell"));
- test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hello k"));
- test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hello kitty\n"));
- test_eq_ptr(line2, find_str_at_start_of_line(long_string, "hello kitty\nt"));
- test_eq_ptr(line3, find_str_at_start_of_line(long_string, "third"));
- test_eq_ptr(line3, find_str_at_start_of_line(long_string, "third line"));
- test_eq_ptr(NULL, find_str_at_start_of_line(long_string, "third line\n"));
- test_eq_ptr(short_line2, find_str_at_start_of_line(short_string,
+ tt_ptr_op(long_string,OP_EQ, find_str_at_start_of_line(long_string, ""));
+ tt_ptr_op(NULL,OP_EQ, find_str_at_start_of_line(short_string, "nonsense"));
+ tt_ptr_op(NULL,OP_EQ, find_str_at_start_of_line(long_string, "nonsense"));
+ tt_ptr_op(NULL,OP_EQ, find_str_at_start_of_line(long_string, "\n"));
+ tt_ptr_op(NULL,OP_EQ, find_str_at_start_of_line(long_string, "how "));
+ tt_ptr_op(NULL,OP_EQ, find_str_at_start_of_line(long_string, "kitty"));
+ tt_ptr_op(long_string,OP_EQ, find_str_at_start_of_line(long_string, "h"));
+ tt_ptr_op(long_string,OP_EQ, find_str_at_start_of_line(long_string, "how"));
+ tt_ptr_op(line2,OP_EQ, find_str_at_start_of_line(long_string, "he"));
+ tt_ptr_op(line2,OP_EQ, find_str_at_start_of_line(long_string, "hell"));
+ tt_ptr_op(line2,OP_EQ, find_str_at_start_of_line(long_string, "hello k"));
+ tt_ptr_op(line2,OP_EQ,
+ find_str_at_start_of_line(long_string, "hello kitty\n"));
+ tt_ptr_op(line2,OP_EQ,
+ find_str_at_start_of_line(long_string, "hello kitty\nt"));
+ tt_ptr_op(line3,OP_EQ, find_str_at_start_of_line(long_string, "third"));
+ tt_ptr_op(line3,OP_EQ, find_str_at_start_of_line(long_string, "third line"));
+ tt_ptr_op(NULL, OP_EQ,
+ find_str_at_start_of_line(long_string, "third line\n"));
+ tt_ptr_op(short_line2,OP_EQ, find_str_at_start_of_line(short_string,
"second line\n"));
done:
;
@@ -2210,25 +2892,25 @@ test_util_string_is_C_identifier(void *ptr)
{
(void)ptr;
- test_eq(1, string_is_C_identifier("string_is_C_identifier"));
- test_eq(1, string_is_C_identifier("_string_is_C_identifier"));
- test_eq(1, string_is_C_identifier("_"));
- test_eq(1, string_is_C_identifier("i"));
- test_eq(1, string_is_C_identifier("_____"));
- test_eq(1, string_is_C_identifier("__00__"));
- test_eq(1, string_is_C_identifier("__init__"));
- test_eq(1, string_is_C_identifier("_0"));
- test_eq(1, string_is_C_identifier("_0string_is_C_identifier"));
- test_eq(1, string_is_C_identifier("_0"));
-
- test_eq(0, string_is_C_identifier("0_string_is_C_identifier"));
- test_eq(0, string_is_C_identifier("0"));
- test_eq(0, string_is_C_identifier(""));
- test_eq(0, string_is_C_identifier(";"));
- test_eq(0, string_is_C_identifier("i;"));
- test_eq(0, string_is_C_identifier("_;"));
- test_eq(0, string_is_C_identifier("í"));
- test_eq(0, string_is_C_identifier("ñ"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("string_is_C_identifier"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("_string_is_C_identifier"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("_"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("i"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("_____"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("__00__"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("__init__"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("_0"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("_0string_is_C_identifier"));
+ tt_int_op(1,OP_EQ, string_is_C_identifier("_0"));
+
+ tt_int_op(0,OP_EQ, string_is_C_identifier("0_string_is_C_identifier"));
+ tt_int_op(0,OP_EQ, string_is_C_identifier("0"));
+ tt_int_op(0,OP_EQ, string_is_C_identifier(""));
+ tt_int_op(0,OP_EQ, string_is_C_identifier(";"));
+ tt_int_op(0,OP_EQ, string_is_C_identifier("i;"));
+ tt_int_op(0,OP_EQ, string_is_C_identifier("_;"));
+ tt_int_op(0,OP_EQ, string_is_C_identifier("í"));
+ tt_int_op(0,OP_EQ, string_is_C_identifier("ñ"));
done:
;
@@ -2245,48 +2927,48 @@ test_util_asprintf(void *ptr)
/* simple string */
r = tor_asprintf(&cp, "simple string 100%% safe");
- test_assert(cp);
- test_streq("simple string 100% safe", cp);
- test_eq(strlen(cp), r);
+ tt_assert(cp);
+ tt_str_op("simple string 100% safe",OP_EQ, cp);
+ tt_int_op(strlen(cp),OP_EQ, r);
tor_free(cp);
/* empty string */
r = tor_asprintf(&cp, "%s", "");
- test_assert(cp);
- test_streq("", cp);
- test_eq(strlen(cp), r);
+ tt_assert(cp);
+ tt_str_op("",OP_EQ, cp);
+ tt_int_op(strlen(cp),OP_EQ, r);
tor_free(cp);
/* numbers (%i) */
r = tor_asprintf(&cp, "I like numbers-%2i, %i, etc.", -1, 2);
- test_assert(cp);
- test_streq("I like numbers--1, 2, etc.", cp);
- test_eq(strlen(cp), r);
+ tt_assert(cp);
+ tt_str_op("I like numbers--1, 2, etc.",OP_EQ, cp);
+ tt_int_op(strlen(cp),OP_EQ, r);
/* don't free cp; next test uses it. */
/* numbers (%d) */
r = tor_asprintf(&cp2, "First=%d, Second=%d", 101, 202);
- test_assert(cp2);
- test_eq(strlen(cp2), r);
- test_streq("First=101, Second=202", cp2);
- test_assert(cp != cp2);
+ tt_assert(cp2);
+ tt_int_op(strlen(cp2),OP_EQ, r);
+ tt_str_op("First=101, Second=202",OP_EQ, cp2);
+ tt_assert(cp != cp2);
tor_free(cp);
tor_free(cp2);
/* Glass-box test: a string exactly 128 characters long. */
r = tor_asprintf(&cp, "Lorem1: %sLorem2: %s", LOREMIPSUM, LOREMIPSUM);
- test_assert(cp);
- test_eq(128, r);
- test_assert(cp[128] == '\0');
- test_streq("Lorem1: "LOREMIPSUM"Lorem2: "LOREMIPSUM, cp);
+ tt_assert(cp);
+ tt_int_op(128,OP_EQ, r);
+ tt_int_op(cp[128], OP_EQ, '\0');
+ tt_str_op("Lorem1: "LOREMIPSUM"Lorem2: "LOREMIPSUM,OP_EQ, cp);
tor_free(cp);
/* String longer than 128 characters */
r = tor_asprintf(&cp, "1: %s 2: %s 3: %s",
LOREMIPSUM, LOREMIPSUM, LOREMIPSUM);
- test_assert(cp);
- test_eq(strlen(cp), r);
- test_streq("1: "LOREMIPSUM" 2: "LOREMIPSUM" 3: "LOREMIPSUM, cp);
+ tt_assert(cp);
+ tt_int_op(strlen(cp),OP_EQ, r);
+ tt_str_op("1: "LOREMIPSUM" 2: "LOREMIPSUM" 3: "LOREMIPSUM,OP_EQ, cp);
done:
tor_free(cp);
@@ -2307,9 +2989,9 @@ test_util_listdir(void *ptr)
dir1 = tor_strdup(get_fname("some-directory"));
dirname = tor_strdup(get_fname(NULL));
- test_eq(0, write_str_to_file(fname1, "X\n", 0));
- test_eq(0, write_str_to_file(fname2, "Y\n", 0));
- test_eq(0, write_str_to_file(fname3, "Z\n", 0));
+ tt_int_op(0,OP_EQ, write_str_to_file(fname1, "X\n", 0));
+ tt_int_op(0,OP_EQ, write_str_to_file(fname2, "Y\n", 0));
+ tt_int_op(0,OP_EQ, write_str_to_file(fname3, "Z\n", 0));
#ifdef _WIN32
r = mkdir(dir1);
#else
@@ -2322,15 +3004,15 @@ test_util_listdir(void *ptr)
}
dir_contents = tor_listdir(dirname);
- test_assert(dir_contents);
+ tt_assert(dir_contents);
/* make sure that each filename is listed. */
- test_assert(smartlist_contains_string_case(dir_contents, "hopscotch"));
- test_assert(smartlist_contains_string_case(dir_contents, "mumblety-peg"));
- test_assert(smartlist_contains_string_case(dir_contents, ".hidden-file"));
- test_assert(smartlist_contains_string_case(dir_contents, "some-directory"));
+ tt_assert(smartlist_contains_string_case(dir_contents, "hopscotch"));
+ tt_assert(smartlist_contains_string_case(dir_contents, "mumblety-peg"));
+ tt_assert(smartlist_contains_string_case(dir_contents, ".hidden-file"));
+ tt_assert(smartlist_contains_string_case(dir_contents, "some-directory"));
- test_assert(!smartlist_contains_string(dir_contents, "."));
- test_assert(!smartlist_contains_string(dir_contents, ".."));
+ tt_assert(!smartlist_contains_string(dir_contents, "."));
+ tt_assert(!smartlist_contains_string(dir_contents, ".."));
done:
tor_free(fname1);
@@ -2355,9 +3037,9 @@ test_util_parent_dir(void *ptr)
int ok; \
cp = tor_strdup(input); \
ok = get_parent_directory(cp); \
- tt_int_op(expect_ok, ==, ok); \
+ tt_int_op(expect_ok, OP_EQ, ok); \
if (ok==0) \
- tt_str_op(output, ==, cp); \
+ tt_str_op(output, OP_EQ, cp); \
tor_free(cp); \
} while (0);
@@ -2391,6 +3073,54 @@ test_util_parent_dir(void *ptr)
tor_free(cp);
}
+static void
+test_util_ftruncate(void *ptr)
+{
+ char *buf = NULL;
+ const char *fname;
+ int fd = -1;
+ const char *message = "Hello world";
+ const char *message2 = "Hola mundo";
+ struct stat st;
+
+ (void) ptr;
+
+ fname = get_fname("ftruncate");
+
+ fd = tor_open_cloexec(fname, O_WRONLY|O_CREAT, 0600);
+ tt_int_op(fd, OP_GE, 0);
+
+ /* Make the file be there. */
+ tt_int_op(strlen(message), OP_EQ, write_all(fd, message, strlen(message),0));
+ tt_int_op((int)tor_fd_getpos(fd), OP_EQ, strlen(message));
+ tt_int_op(0, OP_EQ, fstat(fd, &st));
+ tt_int_op((int)st.st_size, OP_EQ, strlen(message));
+
+ /* Truncate and see if it got truncated */
+ tt_int_op(0, OP_EQ, tor_ftruncate(fd));
+ tt_int_op((int)tor_fd_getpos(fd), OP_EQ, 0);
+ tt_int_op(0, OP_EQ, fstat(fd, &st));
+ tt_int_op((int)st.st_size, OP_EQ, 0);
+
+ /* Replace, and see if it got replaced */
+ tt_int_op(strlen(message2), OP_EQ,
+ write_all(fd, message2, strlen(message2), 0));
+ tt_int_op((int)tor_fd_getpos(fd), OP_EQ, strlen(message2));
+ tt_int_op(0, OP_EQ, fstat(fd, &st));
+ tt_int_op((int)st.st_size, OP_EQ, strlen(message2));
+
+ close(fd);
+ fd = -1;
+
+ buf = read_file_to_str(fname, 0, NULL);
+ tt_str_op(message2, OP_EQ, buf);
+
+ done:
+ if (fd >= 0)
+ close(fd);
+ tor_free(buf);
+}
+
#ifdef _WIN32
static void
test_util_load_win_lib(void *ptr)
@@ -2422,30 +3152,53 @@ test_util_exit_status(void *ptr)
(void)ptr;
clear_hex_errno(hex_errno);
+ tt_str_op("",OP_EQ, hex_errno);
+
+ clear_hex_errno(hex_errno);
n = format_helper_exit_status(0, 0, hex_errno);
- test_streq("0/0\n", hex_errno);
- test_eq(n, strlen(hex_errno));
+ tt_str_op("0/0\n",OP_EQ, hex_errno);
+ tt_int_op(n,OP_EQ, strlen(hex_errno));
+
+#if SIZEOF_INT == 4
clear_hex_errno(hex_errno);
n = format_helper_exit_status(0, 0x7FFFFFFF, hex_errno);
- test_streq("0/7FFFFFFF\n", hex_errno);
- test_eq(n, strlen(hex_errno));
+ tt_str_op("0/7FFFFFFF\n",OP_EQ, hex_errno);
+ tt_int_op(n,OP_EQ, strlen(hex_errno));
clear_hex_errno(hex_errno);
n = format_helper_exit_status(0xFF, -0x80000000, hex_errno);
- test_streq("FF/-80000000\n", hex_errno);
- test_eq(n, strlen(hex_errno));
- test_eq(n, HEX_ERRNO_SIZE);
+ tt_str_op("FF/-80000000\n",OP_EQ, hex_errno);
+ tt_int_op(n,OP_EQ, strlen(hex_errno));
+ tt_int_op(n,OP_EQ, HEX_ERRNO_SIZE);
+
+#elif SIZEOF_INT == 8
+
+ clear_hex_errno(hex_errno);
+ n = format_helper_exit_status(0, 0x7FFFFFFFFFFFFFFF, hex_errno);
+ tt_str_op("0/7FFFFFFFFFFFFFFF\n",OP_EQ, hex_errno);
+ tt_int_op(n,OP_EQ, strlen(hex_errno));
+
+ clear_hex_errno(hex_errno);
+ n = format_helper_exit_status(0xFF, -0x8000000000000000, hex_errno);
+ tt_str_op("FF/-8000000000000000\n",OP_EQ, hex_errno);
+ tt_int_op(n,OP_EQ, strlen(hex_errno));
+ tt_int_op(n,OP_EQ, HEX_ERRNO_SIZE);
+
+#endif
clear_hex_errno(hex_errno);
n = format_helper_exit_status(0x7F, 0, hex_errno);
- test_streq("7F/0\n", hex_errno);
- test_eq(n, strlen(hex_errno));
+ tt_str_op("7F/0\n",OP_EQ, hex_errno);
+ tt_int_op(n,OP_EQ, strlen(hex_errno));
clear_hex_errno(hex_errno);
n = format_helper_exit_status(0x08, -0x242, hex_errno);
- test_streq("8/-242\n", hex_errno);
- test_eq(n, strlen(hex_errno));
+ tt_str_op("8/-242\n",OP_EQ, hex_errno);
+ tt_int_op(n,OP_EQ, strlen(hex_errno));
+
+ clear_hex_errno(hex_errno);
+ tt_str_op("",OP_EQ, hex_errno);
done:
;
@@ -2453,8 +3206,9 @@ test_util_exit_status(void *ptr)
#endif
#ifndef _WIN32
-/** Check that fgets waits until a full line, and not return a partial line, on
- * a EAGAIN with a non-blocking pipe */
+/* Check that fgets with a non-blocking pipe returns partial lines and sets
+ * EAGAIN, returns full lines and sets no error, and returns NULL on EOF and
+ * sets no error */
static void
test_util_fgets_eagain(void *ptr)
{
@@ -2463,71 +3217,91 @@ test_util_fgets_eagain(void *ptr)
ssize_t retlen;
char *retptr;
FILE *test_stream = NULL;
- char buf[10];
+ char buf[4] = { 0 };
(void)ptr;
+ errno = 0;
+
/* Set up a pipe to test on */
retval = pipe(test_pipe);
- tt_int_op(retval, >=, 0);
+ tt_int_op(retval, OP_EQ, 0);
/* Set up the read-end to be non-blocking */
retval = fcntl(test_pipe[0], F_SETFL, O_NONBLOCK);
- tt_int_op(retval, >=, 0);
+ tt_int_op(retval, OP_EQ, 0);
/* Open it as a stdio stream */
test_stream = fdopen(test_pipe[0], "r");
- tt_ptr_op(test_stream, !=, NULL);
+ tt_ptr_op(test_stream, OP_NE, NULL);
/* Send in a partial line */
retlen = write(test_pipe[1], "A", 1);
- tt_int_op(retlen, ==, 1);
+ tt_int_op(retlen, OP_EQ, 1);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_want(retptr == NULL);
- tt_int_op(errno, ==, EAGAIN);
+ tt_int_op(errno, OP_EQ, EAGAIN);
+ tt_ptr_op(retptr, OP_EQ, buf);
+ tt_str_op(buf, OP_EQ, "A");
+ errno = 0;
/* Send in the rest */
retlen = write(test_pipe[1], "B\n", 2);
- tt_int_op(retlen, ==, 2);
+ tt_int_op(retlen, OP_EQ, 2);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_ptr_op(retptr, ==, buf);
- tt_str_op(buf, ==, "AB\n");
+ tt_int_op(errno, OP_EQ, 0);
+ tt_ptr_op(retptr, OP_EQ, buf);
+ tt_str_op(buf, OP_EQ, "B\n");
+ errno = 0;
/* Send in a full line */
retlen = write(test_pipe[1], "CD\n", 3);
- tt_int_op(retlen, ==, 3);
+ tt_int_op(retlen, OP_EQ, 3);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_ptr_op(retptr, ==, buf);
- tt_str_op(buf, ==, "CD\n");
+ tt_int_op(errno, OP_EQ, 0);
+ tt_ptr_op(retptr, OP_EQ, buf);
+ tt_str_op(buf, OP_EQ, "CD\n");
+ errno = 0;
/* Send in a partial line */
retlen = write(test_pipe[1], "E", 1);
- tt_int_op(retlen, ==, 1);
+ tt_int_op(retlen, OP_EQ, 1);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_ptr_op(retptr, ==, NULL);
- tt_int_op(errno, ==, EAGAIN);
+ tt_int_op(errno, OP_EQ, EAGAIN);
+ tt_ptr_op(retptr, OP_EQ, buf);
+ tt_str_op(buf, OP_EQ, "E");
+ errno = 0;
/* Send in the rest */
retlen = write(test_pipe[1], "F\n", 2);
- tt_int_op(retlen, ==, 2);
+ tt_int_op(retlen, OP_EQ, 2);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_ptr_op(retptr, ==, buf);
- tt_str_op(buf, ==, "EF\n");
+ tt_int_op(errno, OP_EQ, 0);
+ tt_ptr_op(retptr, OP_EQ, buf);
+ tt_str_op(buf, OP_EQ, "F\n");
+ errno = 0;
/* Send in a full line and close */
retlen = write(test_pipe[1], "GH", 2);
- tt_int_op(retlen, ==, 2);
+ tt_int_op(retlen, OP_EQ, 2);
retval = close(test_pipe[1]);
+ tt_int_op(retval, OP_EQ, 0);
test_pipe[1] = -1;
- tt_int_op(retval, ==, 0);
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_ptr_op(retptr, ==, buf);
- tt_str_op(buf, ==, "GH");
+ tt_int_op(errno, OP_EQ, 0);
+ tt_ptr_op(retptr, OP_EQ, buf);
+ tt_str_op(buf, OP_EQ, "GH");
+ errno = 0;
/* Check for EOF */
retptr = fgets(buf, sizeof(buf), test_stream);
- tt_ptr_op(retptr, ==, NULL);
- tt_int_op(feof(test_stream), >, 0);
+ tt_int_op(errno, OP_EQ, 0);
+ tt_ptr_op(retptr, OP_EQ, NULL);
+ retval = feof(test_stream);
+ tt_int_op(retval, OP_NE, 0);
+ errno = 0;
+
+ /* Check that buf is unchanged according to C99 and C11 */
+ tt_str_op(buf, OP_EQ, "GH");
done:
if (test_stream != NULL)
@@ -2539,315 +3313,6 @@ test_util_fgets_eagain(void *ptr)
}
#endif
-#ifndef BUILDDIR
-#define BUILDDIR "."
-#endif
-
-#ifdef _WIN32
-#define notify_pending_waitpid_callbacks() STMT_NIL
-#define TEST_CHILD "test-child.exe"
-#define EOL "\r\n"
-#else
-#define TEST_CHILD (BUILDDIR "/src/test/test-child")
-#define EOL "\n"
-#endif
-
-/** Helper function for testing tor_spawn_background */
-static void
-run_util_spawn_background(const char *argv[], const char *expected_out,
- const char *expected_err, int expected_exit,
- int expected_status)
-{
- int retval, exit_code;
- ssize_t pos;
- process_handle_t *process_handle=NULL;
- char stdout_buf[100], stderr_buf[100];
- int status;
-
- /* Start the program */
-#ifdef _WIN32
- status = tor_spawn_background(NULL, argv, NULL, &process_handle);
-#else
- status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
-#endif
-
- notify_pending_waitpid_callbacks();
-
- test_eq(expected_status, status);
- if (status == PROCESS_STATUS_ERROR) {
- tt_ptr_op(process_handle, ==, NULL);
- return;
- }
-
- test_assert(process_handle != NULL);
- test_eq(expected_status, process_handle->status);
-
-#ifndef _WIN32
- notify_pending_waitpid_callbacks();
- tt_ptr_op(process_handle->waitpid_cb, !=, NULL);
-#endif
-
-#ifdef _WIN32
- test_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
- test_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE);
-#else
- test_assert(process_handle->stdout_pipe >= 0);
- test_assert(process_handle->stderr_pipe >= 0);
-#endif
-
- /* Check stdout */
- pos = tor_read_all_from_process_stdout(process_handle, stdout_buf,
- sizeof(stdout_buf) - 1);
- tt_assert(pos >= 0);
- stdout_buf[pos] = '\0';
- test_eq(strlen(expected_out), pos);
- test_streq(expected_out, stdout_buf);
-
- notify_pending_waitpid_callbacks();
-
- /* Check it terminated correctly */
- retval = tor_get_exit_code(process_handle, 1, &exit_code);
- test_eq(PROCESS_EXIT_EXITED, retval);
- test_eq(expected_exit, exit_code);
- // TODO: Make test-child exit with something other than 0
-
-#ifndef _WIN32
- notify_pending_waitpid_callbacks();
- tt_ptr_op(process_handle->waitpid_cb, ==, NULL);
-#endif
-
- /* Check stderr */
- pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
- sizeof(stderr_buf) - 1);
- test_assert(pos >= 0);
- stderr_buf[pos] = '\0';
- test_streq(expected_err, stderr_buf);
- test_eq(strlen(expected_err), pos);
-
- notify_pending_waitpid_callbacks();
-
- done:
- if (process_handle)
- tor_process_handle_destroy(process_handle, 1);
-}
-
-/** Check that we can launch a process and read the output */
-static void
-test_util_spawn_background_ok(void *ptr)
-{
- const char *argv[] = {TEST_CHILD, "--test", NULL};
- const char *expected_out = "OUT"EOL "--test"EOL "SLEEPING"EOL "DONE" EOL;
- const char *expected_err = "ERR"EOL;
-
- (void)ptr;
-
- run_util_spawn_background(argv, expected_out, expected_err, 0,
- PROCESS_STATUS_RUNNING);
-}
-
-/** Check that failing to find the executable works as expected */
-static void
-test_util_spawn_background_fail(void *ptr)
-{
- const char *argv[] = {BUILDDIR "/src/test/no-such-file", "--test", NULL};
- const char *expected_err = "";
- char expected_out[1024];
- char code[32];
-#ifdef _WIN32
- const int expected_status = PROCESS_STATUS_ERROR;
-#else
- /* TODO: Once we can signal failure to exec, set this to be
- * PROCESS_STATUS_ERROR */
- const int expected_status = PROCESS_STATUS_RUNNING;
-#endif
-
- (void)ptr;
-
- tor_snprintf(code, sizeof(code), "%x/%x",
- 9 /* CHILD_STATE_FAILEXEC */ , ENOENT);
- tor_snprintf(expected_out, sizeof(expected_out),
- "ERR: Failed to spawn background process - code %s\n", code);
-
- run_util_spawn_background(argv, expected_out, expected_err, 255,
- expected_status);
-}
-
-/** Test that reading from a handle returns a partial read rather than
- * blocking */
-static void
-test_util_spawn_background_partial_read_impl(int exit_early)
-{
- const int expected_exit = 0;
- const int expected_status = PROCESS_STATUS_RUNNING;
-
- int retval, exit_code;
- ssize_t pos = -1;
- process_handle_t *process_handle=NULL;
- int status;
- char stdout_buf[100], stderr_buf[100];
-
- const char *argv[] = {TEST_CHILD, "--test", NULL};
- const char *expected_out[] = { "OUT" EOL "--test" EOL "SLEEPING" EOL,
- "DONE" EOL,
- NULL };
- const char *expected_err = "ERR" EOL;
-
-#ifndef _WIN32
- int eof = 0;
-#endif
- int expected_out_ctr;
-
- if (exit_early) {
- argv[1] = "--hang";
- expected_out[0] = "OUT"EOL "--hang"EOL "SLEEPING" EOL;
- }
-
- /* Start the program */
-#ifdef _WIN32
- status = tor_spawn_background(NULL, argv, NULL, &process_handle);
-#else
- status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
-#endif
- test_eq(expected_status, status);
- test_assert(process_handle);
- test_eq(expected_status, process_handle->status);
-
- /* Check stdout */
- for (expected_out_ctr = 0; expected_out[expected_out_ctr] != NULL;) {
-#ifdef _WIN32
- pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
- sizeof(stdout_buf) - 1, NULL);
-#else
- /* Check that we didn't read the end of file last time */
- test_assert(!eof);
- pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
- sizeof(stdout_buf) - 1, NULL, &eof);
-#endif
- log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
-
- /* We would have blocked, keep on trying */
- if (0 == pos)
- continue;
-
- test_assert(pos > 0);
- stdout_buf[pos] = '\0';
- test_streq(expected_out[expected_out_ctr], stdout_buf);
- test_eq(strlen(expected_out[expected_out_ctr]), pos);
- expected_out_ctr++;
- }
-
- if (exit_early) {
- tor_process_handle_destroy(process_handle, 1);
- process_handle = NULL;
- goto done;
- }
-
- /* The process should have exited without writing more */
-#ifdef _WIN32
- pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
- sizeof(stdout_buf) - 1,
- process_handle);
- test_eq(0, pos);
-#else
- if (!eof) {
- /* We should have got all the data, but maybe not the EOF flag */
- pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
- sizeof(stdout_buf) - 1,
- process_handle, &eof);
- test_eq(0, pos);
- test_assert(eof);
- }
- /* Otherwise, we got the EOF on the last read */
-#endif
-
- /* Check it terminated correctly */
- retval = tor_get_exit_code(process_handle, 1, &exit_code);
- test_eq(PROCESS_EXIT_EXITED, retval);
- test_eq(expected_exit, exit_code);
-
- // TODO: Make test-child exit with something other than 0
-
- /* Check stderr */
- pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
- sizeof(stderr_buf) - 1);
- test_assert(pos >= 0);
- stderr_buf[pos] = '\0';
- test_streq(expected_err, stderr_buf);
- test_eq(strlen(expected_err), pos);
-
- done:
- tor_process_handle_destroy(process_handle, 1);
-}
-
-static void
-test_util_spawn_background_partial_read(void *arg)
-{
- (void)arg;
- test_util_spawn_background_partial_read_impl(0);
-}
-
-static void
-test_util_spawn_background_exit_early(void *arg)
-{
- (void)arg;
- test_util_spawn_background_partial_read_impl(1);
-}
-
-static void
-test_util_spawn_background_waitpid_notify(void *arg)
-{
- int retval, exit_code;
- process_handle_t *process_handle=NULL;
- int status;
- int ms_timer;
-
- const char *argv[] = {TEST_CHILD, "--fast", NULL};
-
- (void) arg;
-
-#ifdef _WIN32
- status = tor_spawn_background(NULL, argv, NULL, &process_handle);
-#else
- status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
-#endif
-
- tt_int_op(status, ==, PROCESS_STATUS_RUNNING);
- tt_ptr_op(process_handle, !=, NULL);
-
- /* We're not going to look at the stdout/stderr output this time. Instead,
- * we're testing whether notify_pending_waitpid_calbacks() can report the
- * process exit (on unix) and/or whether tor_get_exit_code() can notice it
- * (on windows) */
-
-#ifndef _WIN32
- ms_timer = 30*1000;
- tt_ptr_op(process_handle->waitpid_cb, !=, NULL);
- while (process_handle->waitpid_cb && ms_timer > 0) {
- tor_sleep_msec(100);
- ms_timer -= 100;
- notify_pending_waitpid_callbacks();
- }
- tt_int_op(ms_timer, >, 0);
- tt_ptr_op(process_handle->waitpid_cb, ==, NULL);
-#endif
-
- ms_timer = 30*1000;
- while (((retval = tor_get_exit_code(process_handle, 0, &exit_code))
- == PROCESS_EXIT_RUNNING) && ms_timer > 0) {
- tor_sleep_msec(100);
- ms_timer -= 100;
- }
- tt_int_op(ms_timer, >, 0);
-
- tt_int_op(retval, ==, PROCESS_EXIT_EXITED);
-
- done:
- tor_process_handle_destroy(process_handle, 1);
-}
-
-#undef TEST_CHILD
-#undef EOL
-
/**
* Test for format_hex_number_sigsafe()
*/
@@ -2878,15 +3343,15 @@ test_util_format_hex_number(void *ptr)
for (i = 0; test_data[i].str != NULL; ++i) {
len = format_hex_number_sigsafe(test_data[i].x, buf, sizeof(buf));
- test_neq(len, 0);
- test_eq(len, strlen(buf));
- test_streq(buf, test_data[i].str);
+ tt_int_op(len,OP_NE, 0);
+ tt_int_op(len,OP_EQ, strlen(buf));
+ tt_str_op(buf,OP_EQ, test_data[i].str);
}
- test_eq(4, format_hex_number_sigsafe(0xffff, buf, 5));
- test_streq(buf, "FFFF");
- test_eq(0, format_hex_number_sigsafe(0xffff, buf, 4));
- test_eq(0, format_hex_number_sigsafe(0, buf, 1));
+ tt_int_op(4,OP_EQ, format_hex_number_sigsafe(0xffff, buf, 5));
+ tt_str_op(buf,OP_EQ, "FFFF");
+ tt_int_op(0,OP_EQ, format_hex_number_sigsafe(0xffff, buf, 4));
+ tt_int_op(0,OP_EQ, format_hex_number_sigsafe(0, buf, 1));
done:
return;
@@ -2922,21 +3387,21 @@ test_util_format_dec_number(void *ptr)
for (i = 0; test_data[i].str != NULL; ++i) {
len = format_dec_number_sigsafe(test_data[i].x, buf, sizeof(buf));
- test_neq(len, 0);
- test_eq(len, strlen(buf));
- test_streq(buf, test_data[i].str);
+ tt_int_op(len,OP_NE, 0);
+ tt_int_op(len,OP_EQ, strlen(buf));
+ tt_str_op(buf,OP_EQ, test_data[i].str);
len = format_dec_number_sigsafe(test_data[i].x, buf,
(int)(strlen(test_data[i].str) + 1));
- test_eq(len, strlen(buf));
- test_streq(buf, test_data[i].str);
+ tt_int_op(len,OP_EQ, strlen(buf));
+ tt_str_op(buf,OP_EQ, test_data[i].str);
}
- test_eq(4, format_dec_number_sigsafe(7331, buf, 5));
- test_streq(buf, "7331");
- test_eq(0, format_dec_number_sigsafe(7331, buf, 4));
- test_eq(1, format_dec_number_sigsafe(0, buf, 2));
- test_eq(0, format_dec_number_sigsafe(0, buf, 1));
+ tt_int_op(4,OP_EQ, format_dec_number_sigsafe(7331, buf, 5));
+ tt_str_op(buf,OP_EQ, "7331");
+ tt_int_op(0,OP_EQ, format_dec_number_sigsafe(7331, buf, 4));
+ tt_int_op(1,OP_EQ, format_dec_number_sigsafe(0, buf, 2));
+ tt_int_op(0,OP_EQ, format_dec_number_sigsafe(0, buf, 1));
done:
return;
@@ -2985,7 +3450,7 @@ test_util_join_win_cmdline(void *ptr)
for (i=0; cmdlines[i]!=NULL; i++) {
log_info(LD_GENERAL, "Joining argvs[%d], expecting <%s>", i, cmdlines[i]);
joined_argv = tor_join_win_cmdline(argvs[i]);
- test_streq(cmdlines[i], joined_argv);
+ tt_str_op(cmdlines[i],OP_EQ, joined_argv);
tor_free(joined_argv);
}
@@ -3040,17 +3505,17 @@ test_util_split_lines(void *ptr)
i, tests[i].orig_length);
SMARTLIST_FOREACH_BEGIN(sl, const char *, line) {
/* Check we have not got too many lines */
- test_assert(j < MAX_SPLIT_LINE_COUNT);
+ tt_int_op(MAX_SPLIT_LINE_COUNT, OP_GT, j);
/* Check that there actually should be a line here */
- test_assert(tests[i].split_line[j] != NULL);
+ tt_assert(tests[i].split_line[j] != NULL);
log_info(LD_GENERAL, "Line %d of test %d, should be <%s>",
j, i, tests[i].split_line[j]);
/* Check that the line is as expected */
- test_streq(line, tests[i].split_line[j]);
+ tt_str_op(line,OP_EQ, tests[i].split_line[j]);
j++;
} SMARTLIST_FOREACH_END(line);
/* Check that we didn't miss some lines */
- test_eq_ptr(NULL, tests[i].split_line[j]);
+ tt_ptr_op(NULL,OP_EQ, tests[i].split_line[j]);
tor_free(orig_line);
smartlist_free(sl);
sl = NULL;
@@ -3062,7 +3527,7 @@ test_util_split_lines(void *ptr)
}
static void
-test_util_di_ops(void)
+test_util_di_ops(void *arg)
{
#define LT -1
#define GT 1
@@ -3082,10 +3547,11 @@ test_util_di_ops(void)
int i;
+ (void)arg;
for (i = 0; examples[i].a; ++i) {
size_t len = strlen(examples[i].a);
int eq1, eq2, neq1, neq2, cmp1, cmp2;
- test_eq(len, strlen(examples[i].b));
+ tt_int_op(len,OP_EQ, strlen(examples[i].b));
/* We do all of the operations, with operands in both orders. */
eq1 = tor_memeq(examples[i].a, examples[i].b, len);
eq2 = tor_memeq(examples[i].b, examples[i].a, len);
@@ -3096,29 +3562,50 @@ test_util_di_ops(void)
/* Check for correctness of cmp1 */
if (cmp1 < 0 && examples[i].want_sign != LT)
- test_fail();
+ TT_DIE(("Assertion failed."));
else if (cmp1 > 0 && examples[i].want_sign != GT)
- test_fail();
+ TT_DIE(("Assertion failed."));
else if (cmp1 == 0 && examples[i].want_sign != EQ)
- test_fail();
+ TT_DIE(("Assertion failed."));
/* Check for consistency of everything else with cmp1 */
- test_eq(eq1, eq2);
- test_eq(neq1, neq2);
- test_eq(cmp1, -cmp2);
- test_eq(eq1, cmp1 == 0);
- test_eq(neq1, !eq1);
+ tt_int_op(eq1,OP_EQ, eq2);
+ tt_int_op(neq1,OP_EQ, neq2);
+ tt_int_op(cmp1,OP_EQ, -cmp2);
+ tt_int_op(eq1,OP_EQ, cmp1 == 0);
+ tt_int_op(neq1,OP_EQ, !eq1);
}
- tt_int_op(1, ==, safe_mem_is_zero("", 0));
- tt_int_op(1, ==, safe_mem_is_zero("", 1));
- tt_int_op(0, ==, safe_mem_is_zero("a", 1));
- tt_int_op(0, ==, safe_mem_is_zero("a", 2));
- tt_int_op(0, ==, safe_mem_is_zero("\0a", 2));
- tt_int_op(1, ==, safe_mem_is_zero("\0\0a", 2));
- tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0", 8));
- tt_int_op(1, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 8));
- tt_int_op(0, ==, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 9));
+ {
+ uint8_t zz = 0;
+ uint8_t ii = 0;
+ int z;
+
+ /* exhaustively test tor_memeq and tor_memcmp
+ * against each possible single-byte numeric difference
+ * some arithmetic bugs only appear with certain bit patterns */
+ for (z = 0; z < 256; z++) {
+ for (i = 0; i < 256; i++) {
+ ii = (uint8_t)i;
+ zz = (uint8_t)z;
+ tt_int_op(tor_memeq(&zz, &ii, 1),OP_EQ, zz == ii);
+ tt_int_op(tor_memcmp(&zz, &ii, 1) > 0 ? GT : EQ,OP_EQ,
+ zz > ii ? GT : EQ);
+ tt_int_op(tor_memcmp(&ii, &zz, 1) < 0 ? LT : EQ,OP_EQ,
+ ii < zz ? LT : EQ);
+ }
+ }
+ }
+
+ tt_int_op(1, OP_EQ, safe_mem_is_zero("", 0));
+ tt_int_op(1, OP_EQ, safe_mem_is_zero("", 1));
+ tt_int_op(0, OP_EQ, safe_mem_is_zero("a", 1));
+ tt_int_op(0, OP_EQ, safe_mem_is_zero("a", 2));
+ tt_int_op(0, OP_EQ, safe_mem_is_zero("\0a", 2));
+ tt_int_op(1, OP_EQ, safe_mem_is_zero("\0\0a", 2));
+ tt_int_op(1, OP_EQ, safe_mem_is_zero("\0\0\0\0\0\0\0\0", 8));
+ tt_int_op(1, OP_EQ, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 8));
+ tt_int_op(0, OP_EQ, safe_mem_is_zero("\0\0\0\0\0\0\0\0a", 9));
done:
;
@@ -3131,12 +3618,12 @@ static void
test_util_n_bits_set(void *ptr)
{
(void)ptr;
- test_eq(0, n_bits_set_u8(0));
- test_eq(1, n_bits_set_u8(1));
- test_eq(3, n_bits_set_u8(7));
- test_eq(1, n_bits_set_u8(8));
- test_eq(2, n_bits_set_u8(129));
- test_eq(8, n_bits_set_u8(255));
+ tt_int_op(0,OP_EQ, n_bits_set_u8(0));
+ tt_int_op(1,OP_EQ, n_bits_set_u8(1));
+ tt_int_op(3,OP_EQ, n_bits_set_u8(7));
+ tt_int_op(1,OP_EQ, n_bits_set_u8(8));
+ tt_int_op(2,OP_EQ, n_bits_set_u8(129));
+ tt_int_op(8,OP_EQ, n_bits_set_u8(255));
done:
;
}
@@ -3157,78 +3644,82 @@ test_util_eat_whitespace(void *ptr)
strlcpy(str, "fuubaar", sizeof(str));
for (i = 0; i < sizeof(ws); ++i) {
str[0] = ws[i];
- test_eq_ptr(str + 1, eat_whitespace(str));
- test_eq_ptr(str + 1, eat_whitespace_eos(str, str + strlen(str)));
- test_eq_ptr(str + 1, eat_whitespace_no_nl(str));
- test_eq_ptr(str + 1, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+ tt_ptr_op(str + 1,OP_EQ, eat_whitespace(str));
+ tt_ptr_op(str + 1,OP_EQ, eat_whitespace_eos(str, str + strlen(str)));
+ tt_ptr_op(str + 1,OP_EQ, eat_whitespace_no_nl(str));
+ tt_ptr_op(str + 1,OP_EQ, eat_whitespace_eos_no_nl(str, str + strlen(str)));
}
str[0] = '\n';
- test_eq_ptr(str + 1, eat_whitespace(str));
- test_eq_ptr(str + 1, eat_whitespace_eos(str, str + strlen(str)));
- test_eq_ptr(str, eat_whitespace_no_nl(str));
- test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+ tt_ptr_op(str + 1,OP_EQ, eat_whitespace(str));
+ tt_ptr_op(str + 1,OP_EQ, eat_whitespace_eos(str, str + strlen(str)));
+ tt_ptr_op(str,OP_EQ, eat_whitespace_no_nl(str));
+ tt_ptr_op(str,OP_EQ, eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Empty string */
strlcpy(str, "", sizeof(str));
- test_eq_ptr(str, eat_whitespace(str));
- test_eq_ptr(str, eat_whitespace_eos(str, str));
- test_eq_ptr(str, eat_whitespace_no_nl(str));
- test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str));
+ tt_ptr_op(str,OP_EQ, eat_whitespace(str));
+ tt_ptr_op(str,OP_EQ, eat_whitespace_eos(str, str));
+ tt_ptr_op(str,OP_EQ, eat_whitespace_no_nl(str));
+ tt_ptr_op(str,OP_EQ, eat_whitespace_eos_no_nl(str, str));
/* Only ws */
strlcpy(str, " \t\r\n", sizeof(str));
- test_eq_ptr(str + strlen(str), eat_whitespace(str));
- test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str)));
- test_eq_ptr(str + strlen(str) - 1,
+ tt_ptr_op(str + strlen(str),OP_EQ, eat_whitespace(str));
+ tt_ptr_op(str + strlen(str),OP_EQ,
+ eat_whitespace_eos(str, str + strlen(str)));
+ tt_ptr_op(str + strlen(str) - 1,OP_EQ,
eat_whitespace_no_nl(str));
- test_eq_ptr(str + strlen(str) - 1,
+ tt_ptr_op(str + strlen(str) - 1,OP_EQ,
eat_whitespace_eos_no_nl(str, str + strlen(str)));
strlcpy(str, " \t\r ", sizeof(str));
- test_eq_ptr(str + strlen(str), eat_whitespace(str));
- test_eq_ptr(str + strlen(str),
+ tt_ptr_op(str + strlen(str),OP_EQ, eat_whitespace(str));
+ tt_ptr_op(str + strlen(str),OP_EQ,
eat_whitespace_eos(str, str + strlen(str)));
- test_eq_ptr(str + strlen(str), eat_whitespace_no_nl(str));
- test_eq_ptr(str + strlen(str),
+ tt_ptr_op(str + strlen(str),OP_EQ, eat_whitespace_no_nl(str));
+ tt_ptr_op(str + strlen(str),OP_EQ,
eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Multiple ws */
strlcpy(str, "fuubaar", sizeof(str));
for (i = 0; i < sizeof(ws); ++i)
str[i] = ws[i];
- test_eq_ptr(str + sizeof(ws), eat_whitespace(str));
- test_eq_ptr(str + sizeof(ws), eat_whitespace_eos(str, str + strlen(str)));
- test_eq_ptr(str + sizeof(ws), eat_whitespace_no_nl(str));
- test_eq_ptr(str + sizeof(ws),
+ tt_ptr_op(str + sizeof(ws),OP_EQ, eat_whitespace(str));
+ tt_ptr_op(str + sizeof(ws),OP_EQ,
+ eat_whitespace_eos(str, str + strlen(str)));
+ tt_ptr_op(str + sizeof(ws),OP_EQ, eat_whitespace_no_nl(str));
+ tt_ptr_op(str + sizeof(ws),OP_EQ,
eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Eat comment */
strlcpy(str, "# Comment \n No Comment", sizeof(str));
- test_streq("No Comment", eat_whitespace(str));
- test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str)));
- test_eq_ptr(str, eat_whitespace_no_nl(str));
- test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+ tt_str_op("No Comment",OP_EQ, eat_whitespace(str));
+ tt_str_op("No Comment",OP_EQ, eat_whitespace_eos(str, str + strlen(str)));
+ tt_ptr_op(str,OP_EQ, eat_whitespace_no_nl(str));
+ tt_ptr_op(str,OP_EQ, eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Eat comment & ws mix */
strlcpy(str, " # \t Comment \n\t\nNo Comment", sizeof(str));
- test_streq("No Comment", eat_whitespace(str));
- test_streq("No Comment", eat_whitespace_eos(str, str + strlen(str)));
- test_eq_ptr(str + 1, eat_whitespace_no_nl(str));
- test_eq_ptr(str + 1, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+ tt_str_op("No Comment",OP_EQ, eat_whitespace(str));
+ tt_str_op("No Comment",OP_EQ, eat_whitespace_eos(str, str + strlen(str)));
+ tt_ptr_op(str + 1,OP_EQ, eat_whitespace_no_nl(str));
+ tt_ptr_op(str + 1,OP_EQ, eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Eat entire comment */
strlcpy(str, "#Comment", sizeof(str));
- test_eq_ptr(str + strlen(str), eat_whitespace(str));
- test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str)));
- test_eq_ptr(str, eat_whitespace_no_nl(str));
- test_eq_ptr(str, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+ tt_ptr_op(str + strlen(str),OP_EQ, eat_whitespace(str));
+ tt_ptr_op(str + strlen(str),OP_EQ,
+ eat_whitespace_eos(str, str + strlen(str)));
+ tt_ptr_op(str,OP_EQ, eat_whitespace_no_nl(str));
+ tt_ptr_op(str,OP_EQ, eat_whitespace_eos_no_nl(str, str + strlen(str)));
/* Blank line, then comment */
strlcpy(str, " \t\n # Comment", sizeof(str));
- test_eq_ptr(str + strlen(str), eat_whitespace(str));
- test_eq_ptr(str + strlen(str), eat_whitespace_eos(str, str + strlen(str)));
- test_eq_ptr(str + 2, eat_whitespace_no_nl(str));
- test_eq_ptr(str + 2, eat_whitespace_eos_no_nl(str, str + strlen(str)));
+ tt_ptr_op(str + strlen(str),OP_EQ, eat_whitespace(str));
+ tt_ptr_op(str + strlen(str),OP_EQ,
+ eat_whitespace_eos(str, str + strlen(str)));
+ tt_ptr_op(str + 2,OP_EQ, eat_whitespace_no_nl(str));
+ tt_ptr_op(str + 2,OP_EQ, eat_whitespace_eos_no_nl(str, str + strlen(str)));
done:
;
@@ -3267,11 +3758,11 @@ test_util_sl_new_from_text_lines(void *ptr)
smartlist_t *sl = smartlist_new_from_text_lines("foo\nbar\nbaz\n");
int sl_len = smartlist_len(sl);
- tt_want_int_op(sl_len, ==, 3);
+ tt_want_int_op(sl_len, OP_EQ, 3);
- if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo");
- if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), ==, "bar");
- if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), ==, "baz");
+ if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), OP_EQ, "foo");
+ if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), OP_EQ, "bar");
+ if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), OP_EQ, "baz");
SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
smartlist_free(sl);
@@ -3281,11 +3772,11 @@ test_util_sl_new_from_text_lines(void *ptr)
smartlist_t *sl = smartlist_new_from_text_lines("foo\nbar\nbaz");
int sl_len = smartlist_len(sl);
- tt_want_int_op(sl_len, ==, 3);
+ tt_want_int_op(sl_len, OP_EQ, 3);
- if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo");
- if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), ==, "bar");
- if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), ==, "baz");
+ if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), OP_EQ, "foo");
+ if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), OP_EQ, "bar");
+ if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), OP_EQ, "baz");
SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
smartlist_free(sl);
@@ -3295,9 +3786,9 @@ test_util_sl_new_from_text_lines(void *ptr)
smartlist_t *sl = smartlist_new_from_text_lines("foo");
int sl_len = smartlist_len(sl);
- tt_want_int_op(sl_len, ==, 1);
+ tt_want_int_op(sl_len, OP_EQ, 1);
- if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo");
+ if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), OP_EQ, "foo");
SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
smartlist_free(sl);
@@ -3307,7 +3798,7 @@ test_util_sl_new_from_text_lines(void *ptr)
smartlist_t *sl = smartlist_new_from_text_lines("");
int sl_len = smartlist_len(sl);
- tt_want_int_op(sl_len, ==, 0);
+ tt_want_int_op(sl_len, OP_EQ, 0);
SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
smartlist_free(sl);
@@ -3390,7 +3881,7 @@ test_util_make_environment(void *ptr)
smartlist_sort_strings(env_vars_sorted);
smartlist_sort_strings(env_vars_in_unixoid_env_block_sorted);
- tt_want_int_op(smartlist_len(env_vars_sorted), ==,
+ tt_want_int_op(smartlist_len(env_vars_sorted), OP_EQ,
smartlist_len(env_vars_in_unixoid_env_block_sorted));
{
int len = smartlist_len(env_vars_sorted);
@@ -3401,7 +3892,7 @@ test_util_make_environment(void *ptr)
}
for (i = 0; i < len; ++i) {
- tt_want_str_op(smartlist_get(env_vars_sorted, i), ==,
+ tt_want_str_op(smartlist_get(env_vars_sorted, i), OP_EQ,
smartlist_get(env_vars_in_unixoid_env_block_sorted, i));
}
}
@@ -3483,7 +3974,7 @@ test_util_set_env_var_in_sl(void *ptr)
smartlist_sort_strings(merged_env_vars);
smartlist_sort_strings(expected_resulting_env_vars);
- tt_want_int_op(smartlist_len(merged_env_vars), ==,
+ tt_want_int_op(smartlist_len(merged_env_vars), OP_EQ,
smartlist_len(expected_resulting_env_vars));
{
int len = smartlist_len(merged_env_vars);
@@ -3494,7 +3985,7 @@ test_util_set_env_var_in_sl(void *ptr)
}
for (i = 0; i < len; ++i) {
- tt_want_str_op(smartlist_get(merged_env_vars, i), ==,
+ tt_want_str_op(smartlist_get(merged_env_vars, i), OP_EQ,
smartlist_get(expected_resulting_env_vars, i));
}
}
@@ -3521,8 +4012,8 @@ test_util_weak_random(void *arg)
for (i = 1; i <= 256; ++i) {
for (j=0;j<100;++j) {
int r = tor_weak_random_range(&rng, i);
- tt_int_op(0, <=, r);
- tt_int_op(r, <, i);
+ tt_int_op(0, OP_LE, r);
+ tt_int_op(r, OP_LT, i);
}
}
@@ -3532,7 +4023,7 @@ test_util_weak_random(void *arg)
}
for (i=0;i<16;++i)
- tt_int_op(n[i], >, 0);
+ tt_int_op(n[i], OP_GT, 0);
done:
;
}
@@ -3544,9 +4035,9 @@ test_util_mathlog(void *arg)
(void) arg;
d = tor_mathlog(2.718281828);
- tt_double_op(fabs(d - 1.0), <, .000001);
+ tt_double_op(fabs(d - 1.0), OP_LT, .000001);
d = tor_mathlog(10);
- tt_double_op(fabs(d - 2.30258509), <, .000001);
+ tt_double_op(fabs(d - 2.30258509), OP_LT, .000001);
done:
;
}
@@ -3556,12 +4047,65 @@ test_util_round_to_next_multiple_of(void *arg)
{
(void)arg;
- test_assert(round_uint64_to_next_multiple_of(0,1) == 0);
- test_assert(round_uint64_to_next_multiple_of(0,7) == 0);
+ tt_u64_op(round_uint64_to_next_multiple_of(0,1), ==, 0);
+ tt_u64_op(round_uint64_to_next_multiple_of(0,7), ==, 0);
+
+ tt_u64_op(round_uint64_to_next_multiple_of(99,1), ==, 99);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,7), ==, 105);
+ tt_u64_op(round_uint64_to_next_multiple_of(99,9), ==, 99);
- test_assert(round_uint64_to_next_multiple_of(99,1) == 99);
- test_assert(round_uint64_to_next_multiple_of(99,7) == 105);
- test_assert(round_uint64_to_next_multiple_of(99,9) == 99);
+ tt_i64_op(round_int64_to_next_multiple_of(0,1), ==, 0);
+ tt_i64_op(round_int64_to_next_multiple_of(0,7), ==, 0);
+
+ tt_i64_op(round_int64_to_next_multiple_of(99,1), ==, 99);
+ tt_i64_op(round_int64_to_next_multiple_of(99,7), ==, 105);
+ tt_i64_op(round_int64_to_next_multiple_of(99,9), ==, 99);
+
+ tt_i64_op(round_int64_to_next_multiple_of(-99,1), ==, -99);
+ tt_i64_op(round_int64_to_next_multiple_of(-99,7), ==, -98);
+ tt_i64_op(round_int64_to_next_multiple_of(-99,9), ==, -99);
+
+ tt_i64_op(round_int64_to_next_multiple_of(INT64_MIN,2), ==, INT64_MIN);
+ tt_i64_op(round_int64_to_next_multiple_of(INT64_MAX,2), ==,
+ INT64_MAX-INT64_MAX%2);
+ done:
+ ;
+}
+
+static void
+test_util_laplace(void *arg)
+{
+ /* Sample values produced using Python's SciPy:
+ *
+ * >>> from scipy.stats import laplace
+ * >>> laplace.ppf([-0.01, 0.0, 0.01, 0.5, 0.51, 0.99, 1.0, 1.01],
+ ... loc = 24, scale = 24)
+ * array([ nan, -inf, -69.88855213, 24. ,
+ * 24.48486498, 117.88855213, inf, nan])
+ */
+ const double mu = 24.0, b = 24.0;
+ const double delta_f = 15.0, epsilon = 0.3; /* b = 15.0 / 0.3 = 50.0 */
+ (void)arg;
+
+ tt_i64_op(INT64_MIN, ==, sample_laplace_distribution(mu, b, 0.0));
+ tt_i64_op(-69, ==, sample_laplace_distribution(mu, b, 0.01));
+ tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.5));
+ tt_i64_op(24, ==, sample_laplace_distribution(mu, b, 0.51));
+ tt_i64_op(117, ==, sample_laplace_distribution(mu, b, 0.99));
+
+ /* >>> laplace.ppf([0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99],
+ * ... loc = 0, scale = 50)
+ * array([ -inf, -80.47189562, -34.65735903, 0. ,
+ * 34.65735903, 80.47189562, 195.60115027])
+ */
+ tt_i64_op(INT64_MIN + 20, ==,
+ add_laplace_noise(20, 0.0, delta_f, epsilon));
+ tt_i64_op(-60, ==, add_laplace_noise(20, 0.1, delta_f, epsilon));
+ tt_i64_op(-14, ==, add_laplace_noise(20, 0.25, delta_f, epsilon));
+ tt_i64_op(20, ==, add_laplace_noise(20, 0.5, delta_f, epsilon));
+ tt_i64_op(54, ==, add_laplace_noise(20, 0.75, delta_f, epsilon));
+ tt_i64_op(100, ==, add_laplace_noise(20, 0.9, delta_f, epsilon));
+ tt_i64_op(215, ==, add_laplace_noise(20, 0.99, delta_f, epsilon));
done:
;
@@ -3588,7 +4132,7 @@ test_util_strclear(void *arg)
}
#define UTIL_LEGACY(name) \
- { #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name }
+ { #name, test_util_ ## name , 0, NULL, NULL }
#define UTIL_TEST(name, flags) \
{ #name, test_util_ ## name, flags, NULL, NULL }
@@ -3630,36 +4174,36 @@ test_util_socket(void *arg)
fd2 = tor_open_socket_with_extensions(AF_INET, SOCK_STREAM, 0, 0, 1);
tt_assert(SOCKET_OK(fd1));
tt_assert(SOCKET_OK(fd2));
- tt_int_op(get_n_open_sockets(), ==, n + 2);
+ tt_int_op(get_n_open_sockets(), OP_EQ, n + 2);
//fd3 = tor_open_socket_with_extensions(AF_INET, SOCK_STREAM, 0, 1, 0);
//fd4 = tor_open_socket_with_extensions(AF_INET, SOCK_STREAM, 0, 1, 1);
fd3 = tor_open_socket(AF_INET, SOCK_STREAM, 0);
fd4 = tor_open_socket_nonblocking(AF_INET, SOCK_STREAM, 0);
tt_assert(SOCKET_OK(fd3));
tt_assert(SOCKET_OK(fd4));
- tt_int_op(get_n_open_sockets(), ==, n + 4);
+ tt_int_op(get_n_open_sockets(), OP_EQ, n + 4);
#ifdef CAN_CHECK_CLOEXEC
- tt_int_op(fd_is_cloexec(fd1), ==, 0);
- tt_int_op(fd_is_cloexec(fd2), ==, 0);
- tt_int_op(fd_is_cloexec(fd3), ==, 1);
- tt_int_op(fd_is_cloexec(fd4), ==, 1);
+ tt_int_op(fd_is_cloexec(fd1), OP_EQ, 0);
+ tt_int_op(fd_is_cloexec(fd2), OP_EQ, 0);
+ tt_int_op(fd_is_cloexec(fd3), OP_EQ, 1);
+ tt_int_op(fd_is_cloexec(fd4), OP_EQ, 1);
#endif
#ifdef CAN_CHECK_NONBLOCK
- tt_int_op(fd_is_nonblocking(fd1), ==, 0);
- tt_int_op(fd_is_nonblocking(fd2), ==, 1);
- tt_int_op(fd_is_nonblocking(fd3), ==, 0);
- tt_int_op(fd_is_nonblocking(fd4), ==, 1);
+ tt_int_op(fd_is_nonblocking(fd1), OP_EQ, 0);
+ tt_int_op(fd_is_nonblocking(fd2), OP_EQ, 1);
+ tt_int_op(fd_is_nonblocking(fd3), OP_EQ, 0);
+ tt_int_op(fd_is_nonblocking(fd4), OP_EQ, 1);
#endif
tor_close_socket(fd1);
tor_close_socket(fd2);
fd1 = fd2 = TOR_INVALID_SOCKET;
- tt_int_op(get_n_open_sockets(), ==, n + 2);
+ tt_int_op(get_n_open_sockets(), OP_EQ, n + 2);
tor_close_socket(fd3);
tor_close_socket(fd4);
fd3 = fd4 = TOR_INVALID_SOCKET;
- tt_int_op(get_n_open_sockets(), ==, n);
+ tt_int_op(get_n_open_sockets(), OP_EQ, n);
done:
if (SOCKET_OK(fd1))
@@ -3672,23 +4216,6 @@ test_util_socket(void *arg)
tor_close_socket(fd4);
}
-static void *
-socketpair_test_setup(const struct testcase_t *testcase)
-{
- return testcase->setup_data;
-}
-static int
-socketpair_test_cleanup(const struct testcase_t *testcase, void *ptr)
-{
- (void)testcase;
- (void)ptr;
- return 1;
-}
-
-static const struct testcase_setup_t socketpair_setup = {
- socketpair_test_setup, socketpair_test_cleanup
-};
-
/* Test for socketpair and ersatz_socketpair(). We test them both, since
* the latter is a tolerably good way to exersize tor_accept_socket(). */
static void
@@ -3701,17 +4228,17 @@ test_util_socketpair(void *arg)
tor_socket_t fds[2] = {TOR_INVALID_SOCKET, TOR_INVALID_SOCKET};
const int family = AF_UNIX;
- tt_int_op(0, ==, tor_socketpair_fn(family, SOCK_STREAM, 0, fds));
+ tt_int_op(0, OP_EQ, tor_socketpair_fn(family, SOCK_STREAM, 0, fds));
tt_assert(SOCKET_OK(fds[0]));
tt_assert(SOCKET_OK(fds[1]));
- tt_int_op(get_n_open_sockets(), ==, n + 2);
+ tt_int_op(get_n_open_sockets(), OP_EQ, n + 2);
#ifdef CAN_CHECK_CLOEXEC
- tt_int_op(fd_is_cloexec(fds[0]), ==, 1);
- tt_int_op(fd_is_cloexec(fds[1]), ==, 1);
+ tt_int_op(fd_is_cloexec(fds[0]), OP_EQ, 1);
+ tt_int_op(fd_is_cloexec(fds[1]), OP_EQ, 1);
#endif
#ifdef CAN_CHECK_NONBLOCK
- tt_int_op(fd_is_nonblocking(fds[0]), ==, 0);
- tt_int_op(fd_is_nonblocking(fds[1]), ==, 0);
+ tt_int_op(fd_is_nonblocking(fds[0]), OP_EQ, 0);
+ tt_int_op(fd_is_nonblocking(fds[1]), OP_EQ, 0);
#endif
done:
@@ -3730,18 +4257,18 @@ test_util_max_mem(void *arg)
r = get_total_system_memory(&memory1);
r2 = get_total_system_memory(&memory2);
- tt_int_op(r, ==, r2);
- tt_uint_op(memory2, ==, memory1);
+ tt_int_op(r, OP_EQ, r2);
+ tt_uint_op(memory2, OP_EQ, memory1);
TT_BLATHER(("System memory: "U64_FORMAT, U64_PRINTF_ARG(memory1)));
if (r==0) {
/* You have at least a megabyte. */
- tt_uint_op(memory1, >, (1<<20));
+ tt_uint_op(memory1, OP_GT, (1<<20));
} else {
/* You do not have a petabyte. */
#if SIZEOF_SIZE_T == SIZEOF_UINT64_T
- tt_u64_op(memory1, <, (U64_LITERAL(1)<<50));
+ tt_u64_op(memory1, OP_LT, (U64_LITERAL(1)<<50));
#endif
}
@@ -3749,6 +4276,52 @@ test_util_max_mem(void *arg)
;
}
+static void
+test_util_hostname_validation(void *arg)
+{
+ (void)arg;
+
+ // Lets try valid hostnames first.
+ tt_assert(string_is_valid_hostname("torproject.org"));
+ tt_assert(string_is_valid_hostname("ocw.mit.edu"));
+ tt_assert(string_is_valid_hostname("i.4cdn.org"));
+ tt_assert(string_is_valid_hostname("stanford.edu"));
+ tt_assert(string_is_valid_hostname("multiple-words-with-hypens.jp"));
+
+ // Subdomain name cannot start with '-'.
+ tt_assert(!string_is_valid_hostname("-torproject.org"));
+ tt_assert(!string_is_valid_hostname("subdomain.-domain.org"));
+ tt_assert(!string_is_valid_hostname("-subdomain.domain.org"));
+
+ // Hostnames cannot contain non-alphanumeric characters.
+ tt_assert(!string_is_valid_hostname("%%domain.\\org."));
+ tt_assert(!string_is_valid_hostname("***x.net"));
+ tt_assert(!string_is_valid_hostname("___abc.org"));
+ tt_assert(!string_is_valid_hostname("\xff\xffxyz.org"));
+ tt_assert(!string_is_valid_hostname("word1 word2.net"));
+
+ // XXX: do we allow single-label DNS names?
+
+ done:
+ return;
+}
+
+static void
+test_util_ipv4_validation(void *arg)
+{
+ (void)arg;
+
+ tt_assert(string_is_valid_ipv4_address("192.168.0.1"));
+ tt_assert(string_is_valid_ipv4_address("8.8.8.8"));
+
+ tt_assert(!string_is_valid_ipv4_address("abcd"));
+ tt_assert(!string_is_valid_ipv4_address("300.300.300.300"));
+ tt_assert(!string_is_valid_ipv4_address("8.8."));
+
+ done:
+ return;
+}
+
struct testcase_t util_tests[] = {
UTIL_LEGACY(time),
UTIL_TEST(parse_http_time, 0),
@@ -3765,36 +4338,30 @@ struct testcase_t util_tests[] = {
UTIL_LEGACY(pow2),
UTIL_LEGACY(gzip),
UTIL_LEGACY(datadir),
-#ifdef ENABLE_MEMPOOLS
- UTIL_LEGACY(mempool),
-#endif
UTIL_LEGACY(memarea),
UTIL_LEGACY(control_formats),
UTIL_LEGACY(mmap),
- UTIL_LEGACY(threads),
UTIL_LEGACY(sscanf),
+ UTIL_LEGACY(format_time_interval),
UTIL_LEGACY(path_is_relative),
UTIL_LEGACY(strtok),
UTIL_LEGACY(di_ops),
UTIL_TEST(round_to_next_multiple_of, 0),
+ UTIL_TEST(laplace, 0),
UTIL_TEST(strclear, 0),
UTIL_TEST(find_str_at_start_of_line, 0),
UTIL_TEST(string_is_C_identifier, 0),
UTIL_TEST(asprintf, 0),
UTIL_TEST(listdir, 0),
UTIL_TEST(parent_dir, 0),
+ UTIL_TEST(ftruncate, 0),
#ifdef _WIN32
UTIL_TEST(load_win_lib, 0),
#endif
#ifndef _WIN32
UTIL_TEST(exit_status, 0),
- UTIL_TEST(fgets_eagain, TT_SKIP),
+ UTIL_TEST(fgets_eagain, 0),
#endif
- UTIL_TEST(spawn_background_ok, 0),
- UTIL_TEST(spawn_background_fail, 0),
- UTIL_TEST(spawn_background_partial_read, 0),
- UTIL_TEST(spawn_background_exit_early, 0),
- UTIL_TEST(spawn_background_waitpid_notify, 0),
UTIL_TEST(format_hex_number, 0),
UTIL_TEST(format_dec_number, 0),
UTIL_TEST(join_win_cmdline, 0),
@@ -3806,17 +4373,22 @@ struct testcase_t util_tests[] = {
UTIL_TEST(make_environment, 0),
UTIL_TEST(set_env_var_in_sl, 0),
UTIL_TEST(read_file_eof_tiny_limit, 0),
+ UTIL_TEST(read_file_eof_one_loop_a, 0),
+ UTIL_TEST(read_file_eof_one_loop_b, 0),
UTIL_TEST(read_file_eof_two_loops, 0),
+ UTIL_TEST(read_file_eof_two_loops_b, 0),
UTIL_TEST(read_file_eof_zero_bytes, 0),
UTIL_TEST(write_chunks_to_file, 0),
UTIL_TEST(mathlog, 0),
UTIL_TEST(weak_random, 0),
UTIL_TEST(socket, TT_FORK),
- { "socketpair", test_util_socketpair, TT_FORK, &socketpair_setup,
+ { "socketpair", test_util_socketpair, TT_FORK, &passthrough_setup,
(void*)"0" },
{ "socketpair_ersatz", test_util_socketpair, TT_FORK,
- &socketpair_setup, (void*)"1" },
+ &passthrough_setup, (void*)"1" },
UTIL_TEST(max_mem, 0),
+ UTIL_TEST(hostname_validation, 0),
+ UTIL_TEST(ipv4_validation, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_util_slow.c b/src/test/test_util_slow.c
new file mode 100644
index 0000000000..a597ef3cbc
--- /dev/null
+++ b/src/test/test_util_slow.c
@@ -0,0 +1,389 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "orconfig.h"
+#define UTIL_PRIVATE
+#include "util.h"
+#include "util_process.h"
+#include "crypto.h"
+#include "torlog.h"
+#include "test.h"
+
+#ifndef BUILDDIR
+#define BUILDDIR "."
+#endif
+
+#ifdef _WIN32
+#define notify_pending_waitpid_callbacks() STMT_NIL
+#define TEST_CHILD "test-child.exe"
+#define EOL "\r\n"
+#else
+#define TEST_CHILD (BUILDDIR "/src/test/test-child")
+#define EOL "\n"
+#endif
+
+#ifdef _WIN32
+/* I've assumed Windows doesn't have the gap between fork and exec
+ * that causes the race condition on unix-like platforms */
+#define MATCH_PROCESS_STATUS(s1,s2) ((s1) == (s2))
+
+#else
+/* work around a race condition of the timing of SIGCHLD handler updates
+ * to the process_handle's fields, and checks of those fields
+ *
+ * TODO: Once we can signal failure to exec, change PROCESS_STATUS_RUNNING to
+ * PROCESS_STATUS_ERROR (and similarly with *_OR_NOTRUNNING) */
+#define PROCESS_STATUS_RUNNING_OR_NOTRUNNING (PROCESS_STATUS_RUNNING+1)
+#define IS_RUNNING_OR_NOTRUNNING(s) \
+ ((s) == PROCESS_STATUS_RUNNING || (s) == PROCESS_STATUS_NOTRUNNING)
+/* well, this is ugly */
+#define MATCH_PROCESS_STATUS(s1,s2) \
+ ( (s1) == (s2) \
+ ||((s1) == PROCESS_STATUS_RUNNING_OR_NOTRUNNING \
+ && IS_RUNNING_OR_NOTRUNNING(s2)) \
+ ||((s2) == PROCESS_STATUS_RUNNING_OR_NOTRUNNING \
+ && IS_RUNNING_OR_NOTRUNNING(s1)))
+
+#endif // _WIN32
+
+/** Helper function for testing tor_spawn_background */
+static void
+run_util_spawn_background(const char *argv[], const char *expected_out,
+ const char *expected_err, int expected_exit,
+ int expected_status)
+{
+ int retval, exit_code;
+ ssize_t pos;
+ process_handle_t *process_handle=NULL;
+ char stdout_buf[100], stderr_buf[100];
+ int status;
+
+ /* Start the program */
+#ifdef _WIN32
+ status = tor_spawn_background(NULL, argv, NULL, &process_handle);
+#else
+ status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
+#endif
+
+ notify_pending_waitpid_callbacks();
+
+ /* the race condition doesn't affect status,
+ * because status isn't updated by the SIGCHLD handler,
+ * but we still need to handle PROCESS_STATUS_RUNNING_OR_NOTRUNNING */
+ tt_assert(MATCH_PROCESS_STATUS(expected_status, status));
+ if (status == PROCESS_STATUS_ERROR) {
+ tt_ptr_op(process_handle, OP_EQ, NULL);
+ return;
+ }
+
+ tt_assert(process_handle != NULL);
+
+ /* When a spawned process forks, fails, then exits very quickly,
+ * (this typically occurs when exec fails)
+ * there is a race condition between the SIGCHLD handler
+ * updating the process_handle's fields, and this test
+ * checking the process status in those fields.
+ * The SIGCHLD update can occur before or after the code below executes.
+ * This causes intermittent failures in spawn_background_fail(),
+ * typically when the machine is under load.
+ * We use PROCESS_STATUS_RUNNING_OR_NOTRUNNING to avoid this issue. */
+
+ /* the race condition affects the change in
+ * process_handle->status from RUNNING to NOTRUNNING */
+ tt_assert(MATCH_PROCESS_STATUS(expected_status, process_handle->status));
+
+#ifndef _WIN32
+ notify_pending_waitpid_callbacks();
+ /* the race condition affects the change in
+ * process_handle->waitpid_cb to NULL,
+ * so we skip the check if expected_status is ambiguous,
+ * that is, PROCESS_STATUS_RUNNING_OR_NOTRUNNING */
+ tt_assert(process_handle->waitpid_cb != NULL
+ || expected_status == PROCESS_STATUS_RUNNING_OR_NOTRUNNING);
+#endif
+
+#ifdef _WIN32
+ tt_assert(process_handle->stdout_pipe != INVALID_HANDLE_VALUE);
+ tt_assert(process_handle->stderr_pipe != INVALID_HANDLE_VALUE);
+#else
+ tt_assert(process_handle->stdout_pipe >= 0);
+ tt_assert(process_handle->stderr_pipe >= 0);
+#endif
+
+ /* Check stdout */
+ pos = tor_read_all_from_process_stdout(process_handle, stdout_buf,
+ sizeof(stdout_buf) - 1);
+ tt_assert(pos >= 0);
+ stdout_buf[pos] = '\0';
+ tt_int_op(strlen(expected_out),OP_EQ, pos);
+ tt_str_op(expected_out,OP_EQ, stdout_buf);
+
+ notify_pending_waitpid_callbacks();
+
+ /* Check it terminated correctly */
+ retval = tor_get_exit_code(process_handle, 1, &exit_code);
+ tt_int_op(PROCESS_EXIT_EXITED,OP_EQ, retval);
+ tt_int_op(expected_exit,OP_EQ, exit_code);
+ // TODO: Make test-child exit with something other than 0
+
+#ifndef _WIN32
+ notify_pending_waitpid_callbacks();
+ tt_ptr_op(process_handle->waitpid_cb, OP_EQ, NULL);
+#endif
+
+ /* Check stderr */
+ pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
+ sizeof(stderr_buf) - 1);
+ tt_assert(pos >= 0);
+ stderr_buf[pos] = '\0';
+ tt_str_op(expected_err,OP_EQ, stderr_buf);
+ tt_int_op(strlen(expected_err),OP_EQ, pos);
+
+ notify_pending_waitpid_callbacks();
+
+ done:
+ if (process_handle)
+ tor_process_handle_destroy(process_handle, 1);
+}
+
+/** Check that we can launch a process and read the output */
+static void
+test_util_spawn_background_ok(void *ptr)
+{
+ const char *argv[] = {TEST_CHILD, "--test", NULL};
+ const char *expected_out = "OUT"EOL "--test"EOL "SLEEPING"EOL "DONE" EOL;
+ const char *expected_err = "ERR"EOL;
+
+ (void)ptr;
+
+ run_util_spawn_background(argv, expected_out, expected_err, 0,
+ PROCESS_STATUS_RUNNING);
+}
+
+/** Check that failing to find the executable works as expected */
+static void
+test_util_spawn_background_fail(void *ptr)
+{
+ const char *argv[] = {BUILDDIR "/src/test/no-such-file", "--test", NULL};
+ const char *expected_err = "";
+ char expected_out[1024];
+ char code[32];
+#ifdef _WIN32
+ const int expected_status = PROCESS_STATUS_ERROR;
+#else
+ /* TODO: Once we can signal failure to exec, set this to be
+ * PROCESS_STATUS_RUNNING_OR_ERROR */
+ const int expected_status = PROCESS_STATUS_RUNNING_OR_NOTRUNNING;
+#endif
+
+ memset(expected_out, 0xf0, sizeof(expected_out));
+ memset(code, 0xf0, sizeof(code));
+
+ (void)ptr;
+
+ tor_snprintf(code, sizeof(code), "%x/%x",
+ 9 /* CHILD_STATE_FAILEXEC */ , ENOENT);
+ tor_snprintf(expected_out, sizeof(expected_out),
+ "ERR: Failed to spawn background process - code %s\n", code);
+
+ run_util_spawn_background(argv, expected_out, expected_err, 255,
+ expected_status);
+}
+
+/** Test that reading from a handle returns a partial read rather than
+ * blocking */
+static void
+test_util_spawn_background_partial_read_impl(int exit_early)
+{
+ const int expected_exit = 0;
+ const int expected_status = PROCESS_STATUS_RUNNING;
+
+ int retval, exit_code;
+ ssize_t pos = -1;
+ process_handle_t *process_handle=NULL;
+ int status;
+ char stdout_buf[100], stderr_buf[100];
+
+ const char *argv[] = {TEST_CHILD, "--test", NULL};
+ const char *expected_out[] = { "OUT" EOL "--test" EOL "SLEEPING" EOL,
+ "DONE" EOL,
+ NULL };
+ const char *expected_err = "ERR" EOL;
+
+#ifndef _WIN32
+ int eof = 0;
+#endif
+ int expected_out_ctr;
+
+ if (exit_early) {
+ argv[1] = "--hang";
+ expected_out[0] = "OUT"EOL "--hang"EOL "SLEEPING" EOL;
+ }
+
+ /* Start the program */
+#ifdef _WIN32
+ status = tor_spawn_background(NULL, argv, NULL, &process_handle);
+#else
+ status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
+#endif
+ tt_int_op(expected_status,OP_EQ, status);
+ tt_assert(process_handle);
+ tt_int_op(expected_status,OP_EQ, process_handle->status);
+
+ /* Check stdout */
+ for (expected_out_ctr = 0; expected_out[expected_out_ctr] != NULL;) {
+#ifdef _WIN32
+ pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
+ sizeof(stdout_buf) - 1, NULL);
+#else
+ /* Check that we didn't read the end of file last time */
+ tt_assert(!eof);
+ pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
+ sizeof(stdout_buf) - 1, NULL, &eof);
+#endif
+ log_info(LD_GENERAL, "tor_read_all_handle() returned %d", (int)pos);
+
+ /* We would have blocked, keep on trying */
+ if (0 == pos)
+ continue;
+
+ tt_assert(pos > 0);
+ stdout_buf[pos] = '\0';
+ tt_str_op(expected_out[expected_out_ctr],OP_EQ, stdout_buf);
+ tt_int_op(strlen(expected_out[expected_out_ctr]),OP_EQ, pos);
+ expected_out_ctr++;
+ }
+
+ if (exit_early) {
+ tor_process_handle_destroy(process_handle, 1);
+ process_handle = NULL;
+ goto done;
+ }
+
+ /* The process should have exited without writing more */
+#ifdef _WIN32
+ pos = tor_read_all_handle(process_handle->stdout_pipe, stdout_buf,
+ sizeof(stdout_buf) - 1,
+ process_handle);
+ tt_int_op(0,OP_EQ, pos);
+#else
+ if (!eof) {
+ /* We should have got all the data, but maybe not the EOF flag */
+ pos = tor_read_all_handle(process_handle->stdout_handle, stdout_buf,
+ sizeof(stdout_buf) - 1,
+ process_handle, &eof);
+ tt_int_op(0,OP_EQ, pos);
+ tt_assert(eof);
+ }
+ /* Otherwise, we got the EOF on the last read */
+#endif
+
+ /* Check it terminated correctly */
+ retval = tor_get_exit_code(process_handle, 1, &exit_code);
+ tt_int_op(PROCESS_EXIT_EXITED,OP_EQ, retval);
+ tt_int_op(expected_exit,OP_EQ, exit_code);
+
+ // TODO: Make test-child exit with something other than 0
+
+ /* Check stderr */
+ pos = tor_read_all_from_process_stderr(process_handle, stderr_buf,
+ sizeof(stderr_buf) - 1);
+ tt_assert(pos >= 0);
+ stderr_buf[pos] = '\0';
+ tt_str_op(expected_err,OP_EQ, stderr_buf);
+ tt_int_op(strlen(expected_err),OP_EQ, pos);
+
+ done:
+ tor_process_handle_destroy(process_handle, 1);
+}
+
+static void
+test_util_spawn_background_partial_read(void *arg)
+{
+ (void)arg;
+ test_util_spawn_background_partial_read_impl(0);
+}
+
+static void
+test_util_spawn_background_exit_early(void *arg)
+{
+ (void)arg;
+ test_util_spawn_background_partial_read_impl(1);
+}
+
+static void
+test_util_spawn_background_waitpid_notify(void *arg)
+{
+ int retval, exit_code;
+ process_handle_t *process_handle=NULL;
+ int status;
+ int ms_timer;
+
+ const char *argv[] = {TEST_CHILD, "--fast", NULL};
+
+ (void) arg;
+
+#ifdef _WIN32
+ status = tor_spawn_background(NULL, argv, NULL, &process_handle);
+#else
+ status = tor_spawn_background(argv[0], argv, NULL, &process_handle);
+#endif
+
+ tt_int_op(status, OP_EQ, PROCESS_STATUS_RUNNING);
+ tt_ptr_op(process_handle, OP_NE, NULL);
+
+ /* We're not going to look at the stdout/stderr output this time. Instead,
+ * we're testing whether notify_pending_waitpid_calbacks() can report the
+ * process exit (on unix) and/or whether tor_get_exit_code() can notice it
+ * (on windows) */
+
+#ifndef _WIN32
+ ms_timer = 30*1000;
+ tt_ptr_op(process_handle->waitpid_cb, OP_NE, NULL);
+ while (process_handle->waitpid_cb && ms_timer > 0) {
+ tor_sleep_msec(100);
+ ms_timer -= 100;
+ notify_pending_waitpid_callbacks();
+ }
+ tt_int_op(ms_timer, OP_GT, 0);
+ tt_ptr_op(process_handle->waitpid_cb, OP_EQ, NULL);
+#endif
+
+ ms_timer = 30*1000;
+ while (((retval = tor_get_exit_code(process_handle, 0, &exit_code))
+ == PROCESS_EXIT_RUNNING) && ms_timer > 0) {
+ tor_sleep_msec(100);
+ ms_timer -= 100;
+ }
+ tt_int_op(ms_timer, OP_GT, 0);
+
+ tt_int_op(retval, OP_EQ, PROCESS_EXIT_EXITED);
+
+ done:
+ tor_process_handle_destroy(process_handle, 1);
+}
+
+#undef TEST_CHILD
+#undef EOL
+
+#undef MATCH_PROCESS_STATUS
+
+#ifndef _WIN32
+#undef PROCESS_STATUS_RUNNING_OR_NOTRUNNING
+#undef IS_RUNNING_OR_NOTRUNNING
+#endif
+
+#define UTIL_TEST(name, flags) \
+ { #name, test_util_ ## name, flags, NULL, NULL }
+
+struct testcase_t slow_util_tests[] = {
+ UTIL_TEST(spawn_background_ok, 0),
+ UTIL_TEST(spawn_background_fail, 0),
+ UTIL_TEST(spawn_background_partial_read, 0),
+ UTIL_TEST(spawn_background_exit_early, 0),
+ UTIL_TEST(spawn_background_waitpid_notify, 0),
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c
new file mode 100644
index 0000000000..aaff5069be
--- /dev/null
+++ b/src/test/test_workqueue.c
@@ -0,0 +1,409 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "or.h"
+#include "compat_threads.h"
+#include "onion.h"
+#include "workqueue.h"
+#include "crypto.h"
+#include "crypto_curve25519.h"
+#include "compat_libevent.h"
+
+#include <stdio.h>
+#ifdef HAVE_EVENT2_EVENT_H
+#include <event2/event.h>
+#else
+#include <event.h>
+#endif
+
+static int opt_verbose = 0;
+static int opt_n_threads = 8;
+static int opt_n_items = 10000;
+static int opt_n_inflight = 1000;
+static int opt_n_lowwater = 250;
+static int opt_n_cancel = 0;
+static int opt_ratio_rsa = 5;
+
+#ifdef TRACK_RESPONSES
+tor_mutex_t bitmap_mutex;
+int handled_len;
+bitarray_t *handled;
+#endif
+
+typedef struct state_s {
+ int magic;
+ int n_handled;
+ crypto_pk_t *rsa;
+ curve25519_secret_key_t ecdh;
+ int is_shutdown;
+} state_t;
+
+typedef struct rsa_work_s {
+ int serial;
+ uint8_t msg[128];
+ uint8_t msglen;
+} rsa_work_t;
+
+typedef struct ecdh_work_s {
+ int serial;
+ union {
+ curve25519_public_key_t pk;
+ uint8_t msg[32];
+ } u;
+} ecdh_work_t;
+
+static void
+mark_handled(int serial)
+{
+#ifdef TRACK_RESPONSES
+ tor_mutex_acquire(&bitmap_mutex);
+ tor_assert(serial < handled_len);
+ tor_assert(! bitarray_is_set(handled, serial));
+ bitarray_set(handled, serial);
+ tor_mutex_release(&bitmap_mutex);
+#else
+ (void)serial;
+#endif
+}
+
+static int
+workqueue_do_rsa(void *state, void *work)
+{
+ rsa_work_t *rw = work;
+ state_t *st = state;
+ crypto_pk_t *rsa = st->rsa;
+ uint8_t sig[256];
+ int len;
+
+ tor_assert(st->magic == 13371337);
+
+ len = crypto_pk_private_sign(rsa, (char*)sig, 256,
+ (char*)rw->msg, rw->msglen);
+ if (len < 0) {
+ rw->msglen = 0;
+ return WQ_RPL_ERROR;
+ }
+
+ memset(rw->msg, 0, sizeof(rw->msg));
+ rw->msglen = len;
+ memcpy(rw->msg, sig, len);
+ ++st->n_handled;
+
+ mark_handled(rw->serial);
+
+ return WQ_RPL_REPLY;
+}
+
+static int
+workqueue_do_shutdown(void *state, void *work)
+{
+ (void)state;
+ (void)work;
+ crypto_pk_free(((state_t*)state)->rsa);
+ tor_free(state);
+ return WQ_RPL_SHUTDOWN;
+}
+
+static int
+workqueue_do_ecdh(void *state, void *work)
+{
+ ecdh_work_t *ew = work;
+ uint8_t output[CURVE25519_OUTPUT_LEN];
+ state_t *st = state;
+
+ tor_assert(st->magic == 13371337);
+
+ curve25519_handshake(output, &st->ecdh, &ew->u.pk);
+ memcpy(ew->u.msg, output, CURVE25519_OUTPUT_LEN);
+ ++st->n_handled;
+ mark_handled(ew->serial);
+ return WQ_RPL_REPLY;
+}
+
+static void *
+new_state(void *arg)
+{
+ state_t *st;
+ (void)arg;
+
+ st = tor_malloc(sizeof(*st));
+ /* Every thread gets its own keys. not a problem for benchmarking */
+ st->rsa = crypto_pk_new();
+ if (crypto_pk_generate_key_with_bits(st->rsa, 1024) < 0) {
+ crypto_pk_free(st->rsa);
+ tor_free(st);
+ return NULL;
+ }
+ curve25519_secret_key_generate(&st->ecdh, 0);
+ st->magic = 13371337;
+ return st;
+}
+
+static void
+free_state(void *arg)
+{
+ state_t *st = arg;
+ crypto_pk_free(st->rsa);
+ tor_free(st);
+}
+
+static tor_weak_rng_t weak_rng;
+static int n_sent = 0;
+static int rsa_sent = 0;
+static int ecdh_sent = 0;
+static int n_received = 0;
+
+#ifdef TRACK_RESPONSES
+bitarray_t *received;
+#endif
+
+static void
+handle_reply(void *arg)
+{
+#ifdef TRACK_RESPONSES
+ rsa_work_t *rw = arg; /* Naughty cast, but only looking at serial. */
+ tor_assert(! bitarray_is_set(received, rw->serial));
+ bitarray_set(received,rw->serial);
+#endif
+
+ tor_free(arg);
+ ++n_received;
+}
+
+static workqueue_entry_t *
+add_work(threadpool_t *tp)
+{
+ int add_rsa =
+ opt_ratio_rsa == 0 ||
+ tor_weak_random_range(&weak_rng, opt_ratio_rsa) == 0;
+
+ if (add_rsa) {
+ rsa_work_t *w = tor_malloc_zero(sizeof(*w));
+ w->serial = n_sent++;
+ crypto_rand((char*)w->msg, 20);
+ w->msglen = 20;
+ ++rsa_sent;
+ return threadpool_queue_work(tp, workqueue_do_rsa, handle_reply, w);
+ } else {
+ ecdh_work_t *w = tor_malloc_zero(sizeof(*w));
+ w->serial = n_sent++;
+ /* Not strictly right, but this is just for benchmarks. */
+ crypto_rand((char*)w->u.pk.public_key, 32);
+ ++ecdh_sent;
+ return threadpool_queue_work(tp, workqueue_do_ecdh, handle_reply, w);
+ }
+}
+
+static int n_failed_cancel = 0;
+static int n_successful_cancel = 0;
+
+static int
+add_n_work_items(threadpool_t *tp, int n)
+{
+ int n_queued = 0;
+ int n_try_cancel = 0, i;
+ workqueue_entry_t **to_cancel;
+ workqueue_entry_t *ent;
+
+ to_cancel = tor_malloc(sizeof(workqueue_entry_t*) * opt_n_cancel);
+
+ while (n_queued++ < n) {
+ ent = add_work(tp);
+ if (! ent) {
+ tor_event_base_loopexit(tor_libevent_get_base(), NULL);
+ return -1;
+ }
+ if (n_try_cancel < opt_n_cancel &&
+ tor_weak_random_range(&weak_rng, n) < opt_n_cancel) {
+ to_cancel[n_try_cancel++] = ent;
+ }
+ }
+
+ for (i = 0; i < n_try_cancel; ++i) {
+ void *work = workqueue_entry_cancel(to_cancel[i]);
+ if (! work) {
+ n_failed_cancel++;
+ } else {
+ n_successful_cancel++;
+ tor_free(work);
+ }
+ }
+
+ tor_free(to_cancel);
+ return 0;
+}
+
+static int shutting_down = 0;
+
+static void
+replysock_readable_cb(tor_socket_t sock, short what, void *arg)
+{
+ threadpool_t *tp = arg;
+ replyqueue_t *rq = threadpool_get_replyqueue(tp);
+
+ int old_r = n_received;
+ (void) sock;
+ (void) what;
+
+ replyqueue_process(rq);
+ if (old_r == n_received)
+ return;
+
+ if (opt_verbose) {
+ printf("%d / %d", n_received, n_sent);
+ if (opt_n_cancel)
+ printf(" (%d cancelled, %d uncancellable)",
+ n_successful_cancel, n_failed_cancel);
+ puts("");
+ }
+#ifdef TRACK_RESPONSES
+ tor_mutex_acquire(&bitmap_mutex);
+ for (i = 0; i < opt_n_items; ++i) {
+ if (bitarray_is_set(received, i))
+ putc('o', stdout);
+ else if (bitarray_is_set(handled, i))
+ putc('!', stdout);
+ else
+ putc('.', stdout);
+ }
+ puts("");
+ tor_mutex_release(&bitmap_mutex);
+#endif
+
+ if (n_sent - (n_received+n_successful_cancel) < opt_n_lowwater) {
+ int n_to_send = n_received + opt_n_inflight - n_sent;
+ if (n_to_send > opt_n_items - n_sent)
+ n_to_send = opt_n_items - n_sent;
+ add_n_work_items(tp, n_to_send);
+ }
+
+ if (shutting_down == 0 &&
+ n_received+n_successful_cancel == n_sent &&
+ n_sent >= opt_n_items) {
+ shutting_down = 1;
+ threadpool_queue_update(tp, NULL,
+ workqueue_do_shutdown, NULL, NULL);
+ }
+}
+
+static void
+help(void)
+{
+ puts(
+ "Options:\n"
+ " -N <items> Run this many items of work\n"
+ " -T <threads> Use this many threads\n"
+ " -I <inflight> Have no more than this many requests queued at once\n"
+ " -L <lowwater> Add items whenever fewer than this many are pending\n"
+ " -C <cancel> Try to cancel N items of every batch that we add\n"
+ " -R <ratio> Make one out of this many items be a slow (RSA) one\n"
+ " --no-{eventfd2,eventfd,pipe2,pipe,socketpair}\n"
+ " Disable one of the alert_socket backends.");
+}
+
+int
+main(int argc, char **argv)
+{
+ replyqueue_t *rq;
+ threadpool_t *tp;
+ int i;
+ tor_libevent_cfg evcfg;
+ struct event *ev;
+ uint32_t as_flags = 0;
+
+ for (i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], "-v")) {
+ opt_verbose = 1;
+ } else if (!strcmp(argv[i], "-T") && i+1<argc) {
+ opt_n_threads = atoi(argv[++i]);
+ } else if (!strcmp(argv[i], "-N") && i+1<argc) {
+ opt_n_items = atoi(argv[++i]);
+ } else if (!strcmp(argv[i], "-I") && i+1<argc) {
+ opt_n_inflight = atoi(argv[++i]);
+ } else if (!strcmp(argv[i], "-L") && i+1<argc) {
+ opt_n_lowwater = atoi(argv[++i]);
+ } else if (!strcmp(argv[i], "-R") && i+1<argc) {
+ opt_ratio_rsa = atoi(argv[++i]);
+ } else if (!strcmp(argv[i], "-C") && i+1<argc) {
+ opt_n_cancel = atoi(argv[++i]);
+ } else if (!strcmp(argv[i], "--no-eventfd2")) {
+ as_flags |= ASOCKS_NOEVENTFD2;
+ } else if (!strcmp(argv[i], "--no-eventfd")) {
+ as_flags |= ASOCKS_NOEVENTFD;
+ } else if (!strcmp(argv[i], "--no-pipe2")) {
+ as_flags |= ASOCKS_NOPIPE2;
+ } else if (!strcmp(argv[i], "--no-pipe")) {
+ as_flags |= ASOCKS_NOPIPE;
+ } else if (!strcmp(argv[i], "--no-socketpair")) {
+ as_flags |= ASOCKS_NOSOCKETPAIR;
+ } else if (!strcmp(argv[i], "-h")) {
+ help();
+ return 0;
+ } else {
+ help();
+ return 1;
+ }
+ }
+ if (opt_n_threads < 1 ||
+ opt_n_items < 1 || opt_n_inflight < 1 || opt_n_lowwater < 0 ||
+ opt_n_cancel > opt_n_inflight ||
+ opt_ratio_rsa < 0) {
+ help();
+ return 1;
+ }
+
+ init_logging(1);
+ crypto_global_init(1, NULL, NULL);
+ crypto_seed_rng(1);
+
+ rq = replyqueue_new(as_flags);
+ tor_assert(rq);
+ tp = threadpool_new(opt_n_threads,
+ rq, new_state, free_state, NULL);
+ tor_assert(tp);
+
+ crypto_seed_weak_rng(&weak_rng);
+
+ memset(&evcfg, 0, sizeof(evcfg));
+ tor_libevent_initialize(&evcfg);
+
+ ev = tor_event_new(tor_libevent_get_base(),
+ replyqueue_get_socket(rq), EV_READ|EV_PERSIST,
+ replysock_readable_cb, tp);
+
+ event_add(ev, NULL);
+
+#ifdef TRACK_RESPONSES
+ handled = bitarray_init_zero(opt_n_items);
+ received = bitarray_init_zero(opt_n_items);
+ tor_mutex_init(&bitmap_mutex);
+ handled_len = opt_n_items;
+#endif
+
+ for (i = 0; i < opt_n_inflight; ++i) {
+ if (! add_work(tp)) {
+ puts("Couldn't add work.");
+ return 1;
+ }
+ }
+
+ {
+ struct timeval limit = { 30, 0 };
+ tor_event_base_loopexit(tor_libevent_get_base(), &limit);
+ }
+
+ event_base_loop(tor_libevent_get_base(), 0);
+
+ if (n_sent != opt_n_items || n_received+n_successful_cancel != n_sent) {
+ printf("%d vs %d\n", n_sent, opt_n_items);
+ printf("%d+%d vs %d\n", n_received, n_successful_cancel, n_sent);
+ puts("FAIL");
+ return 1;
+ } else {
+ puts("OK");
+ return 0;
+ }
+}
+
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
new file mode 100644
index 0000000000..403c83bdd2
--- /dev/null
+++ b/src/test/testing_common.c
@@ -0,0 +1,301 @@
+/* Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2015, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/* Ordinarily defined in tor_main.c; this bit is just here to provide one
+ * since we're not linking to tor_main.c */
+const char tor_git_revision[] = "";
+
+/**
+ * \file test_common.c
+ * \brief Common pieces to implement unit tests.
+ **/
+
+#include "orconfig.h"
+#include "or.h"
+#include "config.h"
+#include "rephist.h"
+#include "backtrace.h"
+#include "test.h"
+
+#include <stdio.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef _WIN32
+/* For mkdir() */
+#include <direct.h>
+#else
+#include <dirent.h>
+#endif
+
+#include "or.h"
+
+#ifdef USE_DMALLOC
+#include <dmalloc.h>
+#include <openssl/crypto.h>
+#include "main.h"
+#endif
+
+/** Temporary directory (set up by setup_directory) under which we store all
+ * our files during testing. */
+static char temp_dir[256];
+#ifdef _WIN32
+#define pid_t int
+#endif
+static pid_t temp_dir_setup_in_pid = 0;
+
+/** Select and create the temporary directory we'll use to run our unit tests.
+ * Store it in <b>temp_dir</b>. Exit immediately if we can't create it.
+ * idempotent. */
+static void
+setup_directory(void)
+{
+ static int is_setup = 0;
+ int r;
+ char rnd[256], rnd32[256];
+ if (is_setup) return;
+
+/* Due to base32 limitation needs to be a multiple of 5. */
+#define RAND_PATH_BYTES 5
+ crypto_rand(rnd, RAND_PATH_BYTES);
+ base32_encode(rnd32, sizeof(rnd32), rnd, RAND_PATH_BYTES);
+
+#ifdef _WIN32
+ {
+ char buf[MAX_PATH];
+ const char *tmp = buf;
+ const char *extra_backslash = "";
+ /* If this fails, we're probably screwed anyway */
+ if (!GetTempPathA(sizeof(buf),buf))
+ tmp = "c:\\windows\\temp\\";
+ if (strcmpend(tmp, "\\")) {
+ /* According to MSDN, it should be impossible for GetTempPath to give us
+ * an answer that doesn't end with \. But let's make sure. */
+ extra_backslash = "\\";
+ }
+ tor_snprintf(temp_dir, sizeof(temp_dir),
+ "%s%stor_test_%d_%s", tmp, extra_backslash,
+ (int)getpid(), rnd32);
+ r = mkdir(temp_dir);
+ }
+#else
+ tor_snprintf(temp_dir, sizeof(temp_dir), "/tmp/tor_test_%d_%s",
+ (int) getpid(), rnd32);
+ r = mkdir(temp_dir, 0700);
+ if (!r) {
+ /* undo sticky bit so tests don't get confused. */
+ r = chown(temp_dir, getuid(), getgid());
+ }
+#endif
+ if (r) {
+ fprintf(stderr, "Can't create directory %s:", temp_dir);
+ perror("");
+ exit(1);
+ }
+ is_setup = 1;
+ temp_dir_setup_in_pid = getpid();
+}
+
+/** Return a filename relative to our testing temporary directory */
+const char *
+get_fname(const char *name)
+{
+ static char buf[1024];
+ setup_directory();
+ if (!name)
+ return temp_dir;
+ tor_snprintf(buf,sizeof(buf),"%s/%s",temp_dir,name);
+ return buf;
+}
+
+/* Remove a directory and all of its subdirectories */
+static void
+rm_rf(const char *dir)
+{
+ struct stat st;
+ smartlist_t *elements;
+
+ elements = tor_listdir(dir);
+ if (elements) {
+ SMARTLIST_FOREACH_BEGIN(elements, const char *, cp) {
+ char *tmp = NULL;
+ tor_asprintf(&tmp, "%s"PATH_SEPARATOR"%s", dir, cp);
+ if (0 == stat(tmp,&st) && (st.st_mode & S_IFDIR)) {
+ rm_rf(tmp);
+ } else {
+ if (unlink(tmp)) {
+ fprintf(stderr, "Error removing %s: %s\n", tmp, strerror(errno));
+ }
+ }
+ tor_free(tmp);
+ } SMARTLIST_FOREACH_END(cp);
+ SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
+ smartlist_free(elements);
+ }
+ if (rmdir(dir))
+ fprintf(stderr, "Error removing directory %s: %s\n", dir, strerror(errno));
+}
+
+/** Remove all files stored under the temporary directory, and the directory
+ * itself. Called by atexit(). */
+static void
+remove_directory(void)
+{
+ if (getpid() != temp_dir_setup_in_pid) {
+ /* Only clean out the tempdir when the main process is exiting. */
+ return;
+ }
+
+ rm_rf(temp_dir);
+}
+
+/** Define this if unit tests spend too much time generating public keys*/
+#undef CACHE_GENERATED_KEYS
+
+static crypto_pk_t *pregen_keys[5] = {NULL, NULL, NULL, NULL, NULL};
+#define N_PREGEN_KEYS ARRAY_LENGTH(pregen_keys)
+
+/** Generate and return a new keypair for use in unit tests. If we're using
+ * the key cache optimization, we might reuse keys: we only guarantee that
+ * keys made with distinct values for <b>idx</b> are different. The value of
+ * <b>idx</b> must be at least 0, and less than N_PREGEN_KEYS. */
+crypto_pk_t *
+pk_generate(int idx)
+{
+ int res;
+#ifdef CACHE_GENERATED_KEYS
+ tor_assert(idx < N_PREGEN_KEYS);
+ if (! pregen_keys[idx]) {
+ pregen_keys[idx] = crypto_pk_new();
+ res = crypto_pk_generate_key(pregen_keys[idx]);
+ tor_assert(!res);
+ }
+ return crypto_pk_dup_key(pregen_keys[idx]);
+#else
+ crypto_pk_t *result;
+ (void) idx;
+ result = crypto_pk_new();
+ res = crypto_pk_generate_key(result);
+ tor_assert(!res);
+ return result;
+#endif
+}
+
+/** Free all storage used for the cached key optimization. */
+static void
+free_pregenerated_keys(void)
+{
+ unsigned idx;
+ for (idx = 0; idx < N_PREGEN_KEYS; ++idx) {
+ if (pregen_keys[idx]) {
+ crypto_pk_free(pregen_keys[idx]);
+ pregen_keys[idx] = NULL;
+ }
+ }
+}
+
+static void *
+passthrough_test_setup(const struct testcase_t *testcase)
+{
+ return testcase->setup_data;
+}
+static int
+passthrough_test_cleanup(const struct testcase_t *testcase, void *ptr)
+{
+ (void)testcase;
+ (void)ptr;
+ return 1;
+}
+
+const struct testcase_setup_t passthrough_setup = {
+ passthrough_test_setup, passthrough_test_cleanup
+};
+
+extern struct testgroup_t testgroups[];
+
+/** Main entry point for unit test code: parse the command line, and run
+ * some unit tests. */
+int
+main(int c, const char **v)
+{
+ or_options_t *options;
+ char *errmsg = NULL;
+ int i, i_out;
+ int loglevel = LOG_ERR;
+ int accel_crypto = 0;
+
+#ifdef USE_DMALLOC
+ {
+ int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_);
+ tor_assert(r);
+ }
+#endif
+
+ update_approx_time(time(NULL));
+ options = options_new();
+ tor_threads_init();
+ init_logging(1);
+ configure_backtrace_handler(get_version());
+
+ for (i_out = i = 1; i < c; ++i) {
+ if (!strcmp(v[i], "--warn")) {
+ loglevel = LOG_WARN;
+ } else if (!strcmp(v[i], "--notice")) {
+ loglevel = LOG_NOTICE;
+ } else if (!strcmp(v[i], "--info")) {
+ loglevel = LOG_INFO;
+ } else if (!strcmp(v[i], "--debug")) {
+ loglevel = LOG_DEBUG;
+ } else if (!strcmp(v[i], "--accel")) {
+ accel_crypto = 1;
+ } else {
+ v[i_out++] = v[i];
+ }
+ }
+ c = i_out;
+
+ {
+ log_severity_list_t s;
+ memset(&s, 0, sizeof(s));
+ set_log_severity_config(loglevel, LOG_ERR, &s);
+ add_stream_log(&s, "", fileno(stdout));
+ }
+
+ options->command = CMD_RUN_UNITTESTS;
+ if (crypto_global_init(accel_crypto, NULL, NULL)) {
+ printf("Can't initialize crypto subsystem; exiting.\n");
+ return 1;
+ }
+ crypto_set_tls_dh_prime(NULL);
+ crypto_seed_rng(1);
+ rep_hist_init();
+ network_init();
+ setup_directory();
+ options_init(options);
+ options->DataDirectory = tor_strdup(temp_dir);
+ options->EntryStatistics = 1;
+ if (set_options(options, &errmsg) < 0) {
+ printf("Failed to set initial options: %s\n", errmsg);
+ tor_free(errmsg);
+ return 1;
+ }
+
+ atexit(remove_directory);
+
+ int have_failed = (tinytest_main(c, v, testgroups) != 0);
+
+ free_pregenerated_keys();
+#ifdef USE_DMALLOC
+ tor_free_all(0);
+ dmalloc_log_unfreed();
+#endif
+
+ if (have_failed)
+ return 1;
+ else
+ return 0;
+}
+
diff --git a/src/test/zero_length_keys.sh b/src/test/zero_length_keys.sh
new file mode 100755
index 0000000000..2fd11d38bd
--- /dev/null
+++ b/src/test/zero_length_keys.sh
@@ -0,0 +1,120 @@
+#!/bin/sh
+# Check that tor regenerates keys when key files are zero-length
+# Test for bug #13111 - Tor fails to start if onion keys are zero length
+#
+# Usage:
+# ./zero_length_keys.sh
+# Run all the tests below
+# ./zero_length_keys.sh -z
+# Check tor will launch and regenerate zero-length keys
+# ./zero_length_keys.sh -d
+# Check tor regenerates deleted keys (existing behaviour)
+# ./zero_length_keys.sh -e
+# Check tor does not overwrite existing keys (existing behaviour)
+#
+# Exit Statuses:
+# 0: test succeeded - tor regenerated/kept the files
+# 1: test failed - tor did not regenerate/keep the files
+# 2: test failed - tor did not generate the key files on first run
+# 3: a command failed - the test could not be completed
+#
+
+if [ $# -lt 1 ]; then
+ echo "Testing that tor correctly handles zero-length keys"
+ "$0" -z && "$0" -d && "$0" -e
+ exit $?
+fi
+
+DATA_DIR=`mktemp -d -t tor_zero_length_keys.XXXXXX`
+if [ -z "$DATA_DIR" ]; then
+ echo "Failure: mktemp invocation returned empty string" >&2
+ exit 3
+fi
+if [ ! -d "$DATA_DIR" ]; then
+ echo "Failure: mktemp invocation result doesn't point to directory" >&2
+ exit 3
+fi
+trap "rm -rf '$DATA_DIR'" 0
+
+touch "$DATA_DIR"/empty_torrc
+
+# DisableNetwork means that the ORPort won't actually be opened.
+# 'ExitRelay 0' suppresses a warning.
+TOR="./src/or/tor --hush --DisableNetwork 1 --ShutdownWaitLength 0 --ORPort 12345 --ExitRelay 0 -f $DATA_DIR/empty_torrc"
+
+if [ -s "$DATA_DIR"/keys/secret_id_key ] && [ -s "$DATA_DIR"/keys/secret_onion_key ] &&
+ [ -s "$DATA_DIR"/keys/secret_onion_key_ntor ]; then
+ echo "Failure: Previous tor keys present in tor data directory" >&2
+ exit 3
+else
+ echo "Generating initial tor keys"
+ $TOR --DataDirectory "$DATA_DIR" --list-fingerprint
+
+ # tor must successfully generate non-zero-length key files
+ if [ -s "$DATA_DIR"/keys/secret_id_key ] && [ -s "$DATA_DIR"/keys/secret_onion_key ] &&
+ [ -s "$DATA_DIR"/keys/secret_onion_key_ntor ]; then
+ true #echo "tor generated the initial key files"
+ else
+ echo "Failure: tor failed to generate the initial key files"
+ exit 2
+ fi
+fi
+
+#ls -lh "$DATA_DIR"/keys/ || exit 3
+
+# backup and keep/delete/create zero-length files for the keys
+
+FILE_DESC="keeps existing"
+# make a backup
+cp -r "$DATA_DIR"/keys "$DATA_DIR"/keys.old
+
+# delete keys for -d or -z
+if [ "$1" != "-e" ]; then
+ FILE_DESC="regenerates deleted"
+ rm "$DATA_DIR"/keys/secret_id_key || exit 3
+ rm "$DATA_DIR"/keys/secret_onion_key || exit 3
+ rm "$DATA_DIR"/keys/secret_onion_key_ntor || exit 3
+fi
+
+# create empty files for -z
+if [ "$1" = "-z" ]; then
+ FILE_DESC="regenerates zero-length"
+ touch "$DATA_DIR"/keys/secret_id_key || exit 3
+ touch "$DATA_DIR"/keys/secret_onion_key || exit 3
+ touch "$DATA_DIR"/keys/secret_onion_key_ntor || exit 3
+fi
+
+echo "Running tor again to check if it $FILE_DESC keys"
+$TOR --DataDirectory "$DATA_DIR" --list-fingerprint
+
+#ls -lh "$DATA_DIR"/keys/ || exit 3
+
+# tor must always have non-zero-length key files
+if [ -s "$DATA_DIR"/keys/secret_id_key ] && [ -s "$DATA_DIR"/keys/secret_onion_key ] &&
+ [ -s "$DATA_DIR"/keys/secret_onion_key_ntor ]; then
+ # check if the keys are different to the old ones
+ diff -q -r "$DATA_DIR"/keys "$DATA_DIR"/keys.old > /dev/null
+ SAME_KEYS=$?
+ # if we're not testing existing keys,
+ # the current keys should be different to the old ones
+ if [ "$1" != "-e" ]; then
+ if [ $SAME_KEYS -ne 0 ]; then
+ echo "Success: test that tor $FILE_DESC key files: different keys"
+ exit 0
+ else
+ echo "Failure: test that tor $FILE_DESC key files: same keys"
+ exit 1
+ fi
+ else #[ "$1" == "-e" ]; then
+ if [ $SAME_KEYS -eq 0 ]; then
+ echo "Success: test that tor $FILE_DESC key files: same keys"
+ exit 0
+ else
+ echo "Failure: test that tor $FILE_DESC key files: different keys"
+ exit 1
+ fi
+ fi
+else
+ echo "Failure: test that tor $FILE_DESC key files: no key files"
+ exit 1
+fi
diff --git a/src/tools/tor-checkkey.c b/src/tools/tor-checkkey.c
index d50f12ed2a..e404b682cf 100644
--- a/src/tools/tor-checkkey.c
+++ b/src/tools/tor-checkkey.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2013, The Tor Project, Inc. */
+/* Copyright (c) 2008-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -21,7 +21,7 @@ main(int c, char **v)
int wantdigest=0;
int fname_idx;
char *fname=NULL;
- init_logging();
+ init_logging(1);
if (c < 2) {
fprintf(stderr, "Hi. I'm tor-checkkey. Tell me a filename that "
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c
index 41eb9dcb76..6369966869 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2013, The Tor Project, Inc. */
+ * Copyright (c) 2010-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h
index 2d924ce750..abc5e11857 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h
+++ b/src/tools/tor-fw-helper/tor-fw-helper-natpmp.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2013, The Tor Project, Inc. */
+ * Copyright (c) 2010-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-upnp.c b/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
index 692186d372..e5495c906e 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper-upnp.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2013, The Tor Project, Inc. */
+ * Copyright (c) 2010-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/tools/tor-fw-helper/tor-fw-helper-upnp.h b/src/tools/tor-fw-helper/tor-fw-helper-upnp.h
index b6c7ed8643..bc9476eb98 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper-upnp.h
+++ b/src/tools/tor-fw-helper/tor-fw-helper-upnp.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2013, The Tor Project, Inc. */
+ * Copyright (c) 2010-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/tools/tor-fw-helper/tor-fw-helper.c b/src/tools/tor-fw-helper/tor-fw-helper.c
index 84cc21e346..fdc0e1adea 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper.c
+++ b/src/tools/tor-fw-helper/tor-fw-helper.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2013, The Tor Project, Inc. */
+ * Copyright (c) 2010-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/tools/tor-fw-helper/tor-fw-helper.h b/src/tools/tor-fw-helper/tor-fw-helper.h
index 0b0d179935..4ebc75d8f7 100644
--- a/src/tools/tor-fw-helper/tor-fw-helper.h
+++ b/src/tools/tor-fw-helper/tor-fw-helper.h
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Jacob Appelbaum, Steven J. Murdoch.
- * Copyright (c) 2010-2013, The Tor Project, Inc. */
+ * Copyright (c) 2010-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c
index e799df5cad..c599822e07 100644
--- a/src/tools/tor-gencert.c
+++ b/src/tools/tor-gencert.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* Copyright (c) 2007-2015, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
@@ -134,18 +134,30 @@ parse_commandline(int argc, char **argv)
fprintf(stderr, "No argument to -i\n");
return 1;
}
+ if (identity_key_file) {
+ fprintf(stderr, "Duplicate values for -i\n");
+ return -1;
+ }
identity_key_file = tor_strdup(argv[++i]);
} else if (!strcmp(argv[i], "-s")) {
if (i+1>=argc) {
fprintf(stderr, "No argument to -s\n");
return 1;
}
+ if (signing_key_file) {
+ fprintf(stderr, "Duplicate values for -s\n");
+ return -1;
+ }
signing_key_file = tor_strdup(argv[++i]);
} else if (!strcmp(argv[i], "-c")) {
if (i+1>=argc) {
fprintf(stderr, "No argument to -c\n");
return 1;
}
+ if (certificate_file) {
+ fprintf(stderr, "Duplicate values for -c\n");
+ return -1;
+ }
certificate_file = tor_strdup(argv[++i]);
} else if (!strcmp(argv[i], "-m")) {
if (i+1>=argc) {
@@ -513,7 +525,7 @@ int
main(int argc, char **argv)
{
int r = 1;
- init_logging();
+ init_logging(1);
/* Don't bother using acceleration. */
if (crypto_global_init(0, NULL, NULL)) {
diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c
index 480c7e52ca..04815a63f7 100644
--- a/src/tools/tor-resolve.c
+++ b/src/tools/tor-resolve.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
- * Copyright (c) 2007-2013, The Tor Project, Inc.
+ * Copyright (c) 2007-2015, The Tor Project, Inc.
*/
/* See LICENSE for licensing information */
@@ -108,6 +108,18 @@ build_socks_resolve_request(char **out,
return len;
}
+static void
+onion_warning(const char *hostname)
+{
+ log_warn(LD_NET,
+ "%s is a hidden service; those don't have IP addresses. "
+ "You can use the AutomapHostsOnResolve option to have Tor return a "
+ "fake address for hidden services. Or you can have your "
+ "application send the address to Tor directly; we recommend an "
+ "application that uses SOCKS 5 with hostnames.",
+ hostname);
+}
+
/** Given a <b>len</b>-byte SOCKS4a response in <b>response</b>, set
* *<b>addr_out</b> to the address it contains (in host order).
* Return 0 on success, -1 on error.
@@ -137,10 +149,7 @@ parse_socks4a_resolve_response(const char *hostname,
if (status != 90) {
log_warn(LD_NET,"Got status response '%d': socks request failed.", status);
if (!strcasecmpend(hostname, ".onion")) {
- log_warn(LD_NET,
- "%s is a hidden service; those don't have IP addresses. "
- "To connect to a hidden service, you need to send the hostname "
- "to Tor; we suggest an application that uses SOCKS 4a.",hostname);
+ onion_warning(hostname);
return -1;
}
return -1;
@@ -276,11 +285,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
(unsigned)reply_buf[1],
socks5_reason_to_string(reply_buf[1]));
if (reply_buf[1] == 4 && !strcasecmpend(hostname, ".onion")) {
- log_warn(LD_NET,
- "%s is a hidden service; those don't have IP addresses. "
- "To connect to a hidden service, you need to send the hostname "
- "to Tor; we suggest an application that uses SOCKS 4a.",
- hostname);
+ onion_warning(hostname);
}
goto err;
}
@@ -326,8 +331,8 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
static void
usage(void)
{
- puts("Syntax: tor-resolve [-4] [-v] [-x] [-F] [-p port] "
- "hostname [sockshost:socksport]");
+ puts("Syntax: tor-resolve [-4] [-5] [-v] [-x] [-F] [-p port] "
+ "hostname [sockshost[:socksport]]");
exit(1);
}
@@ -344,7 +349,7 @@ main(int argc, char **argv)
char *result_hostname = NULL;
log_severity_list_t *s = tor_malloc_zero(sizeof(log_severity_list_t));
- init_logging();
+ init_logging(1);
sandbox_disable_getaddrinfo_cache();
arg = &argv[1];
diff --git a/src/trunnel/include.am b/src/trunnel/include.am
new file mode 100644
index 0000000000..c7ac1679d0
--- /dev/null
+++ b/src/trunnel/include.am
@@ -0,0 +1,29 @@
+
+noinst_LIBRARIES += \
+ src/trunnel/libor-trunnel.a
+
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += \
+ src/trunnel/libor-trunnel-testing.a
+endif
+
+AM_CPPFLAGS += -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel
+
+TRUNNELSOURCES = \
+ src/ext/trunnel/trunnel.c \
+ src/trunnel/pwbox.c
+
+TRUNNELHEADERS = \
+ src/ext/trunnel/trunnel.h \
+ src/ext/trunnel/trunnel-impl.h \
+ src/trunnel/trunnel-local.h \
+ src/trunnel/pwbox.h
+
+src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES)
+src_trunnel_libor_trunnel_a_CPPFLAGS = -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS)
+
+src_trunnel_libor_trunnel_testing_a_SOURCES = $(TRUNNELSOURCES)
+src_trunnel_libor_trunnel_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS)
+src_trunnel_libor_trunnel_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
+noinst_HEADERS+= $(TRUNNELHEADERS)
diff --git a/src/trunnel/pwbox.c b/src/trunnel/pwbox.c
new file mode 100644
index 0000000000..bfea3ac671
--- /dev/null
+++ b/src/trunnel/pwbox.c
@@ -0,0 +1,515 @@
+/* pwbox.c -- generated by Trunnel v1.2.
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+#include <stdlib.h>
+#include "trunnel-impl.h"
+
+#include "pwbox.h"
+
+#define TRUNNEL_SET_ERROR_CODE(obj) \
+ do { \
+ (obj)->trunnel_error_code_ = 1; \
+ } while (0)
+
+#if defined(__COVERITY__) || defined(__clang_analyzer__)
+/* If we're runnning a static analysis tool, we don't want it to complain
+ * that some of our remaining-bytes checks are dead-code. */
+int pwbox_deadcode_dummy__ = 0;
+#define OR_DEADCODE_DUMMY || pwbox_deadcode_dummy__
+#else
+#define OR_DEADCODE_DUMMY
+#endif
+
+#define CHECK_REMAINING(nbytes, label) \
+ do { \
+ if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \
+ goto label; \
+ } \
+ } while (0)
+
+pwbox_encoded_t *
+pwbox_encoded_new(void)
+{
+ pwbox_encoded_t *val = trunnel_calloc(1, sizeof(pwbox_encoded_t));
+ if (NULL == val)
+ return NULL;
+ val->fixedbytes0 = PWBOX0_CONST0;
+ val->fixedbytes1 = PWBOX0_CONST1;
+ return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+pwbox_encoded_clear(pwbox_encoded_t *obj)
+{
+ (void) obj;
+ TRUNNEL_DYNARRAY_WIPE(&obj->skey_header);
+ TRUNNEL_DYNARRAY_CLEAR(&obj->skey_header);
+ TRUNNEL_DYNARRAY_WIPE(&obj->data);
+ TRUNNEL_DYNARRAY_CLEAR(&obj->data);
+}
+
+void
+pwbox_encoded_free(pwbox_encoded_t *obj)
+{
+ if (obj == NULL)
+ return;
+ pwbox_encoded_clear(obj);
+ trunnel_memwipe(obj, sizeof(pwbox_encoded_t));
+ trunnel_free_(obj);
+}
+
+uint32_t
+pwbox_encoded_get_fixedbytes0(pwbox_encoded_t *inp)
+{
+ return inp->fixedbytes0;
+}
+int
+pwbox_encoded_set_fixedbytes0(pwbox_encoded_t *inp, uint32_t val)
+{
+ if (! ((val == PWBOX0_CONST0))) {
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+ }
+ inp->fixedbytes0 = val;
+ return 0;
+}
+uint32_t
+pwbox_encoded_get_fixedbytes1(pwbox_encoded_t *inp)
+{
+ return inp->fixedbytes1;
+}
+int
+pwbox_encoded_set_fixedbytes1(pwbox_encoded_t *inp, uint32_t val)
+{
+ if (! ((val == PWBOX0_CONST1))) {
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+ }
+ inp->fixedbytes1 = val;
+ return 0;
+}
+uint8_t
+pwbox_encoded_get_header_len(pwbox_encoded_t *inp)
+{
+ return inp->header_len;
+}
+int
+pwbox_encoded_set_header_len(pwbox_encoded_t *inp, uint8_t val)
+{
+ inp->header_len = val;
+ return 0;
+}
+size_t
+pwbox_encoded_getlen_skey_header(const pwbox_encoded_t *inp)
+{
+ return TRUNNEL_DYNARRAY_LEN(&inp->skey_header);
+}
+
+uint8_t
+pwbox_encoded_get_skey_header(pwbox_encoded_t *inp, size_t idx)
+{
+ return TRUNNEL_DYNARRAY_GET(&inp->skey_header, idx);
+}
+
+int
+pwbox_encoded_set_skey_header(pwbox_encoded_t *inp, size_t idx, uint8_t elt)
+{
+ TRUNNEL_DYNARRAY_SET(&inp->skey_header, idx, elt);
+ return 0;
+}
+int
+pwbox_encoded_add_skey_header(pwbox_encoded_t *inp, uint8_t elt)
+{
+#if SIZE_MAX >= UINT8_MAX
+ if (inp->skey_header.n_ == UINT8_MAX)
+ goto trunnel_alloc_failed;
+#endif
+ TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->skey_header, elt, {});
+ return 0;
+ trunnel_alloc_failed:
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+}
+
+uint8_t *
+pwbox_encoded_getarray_skey_header(pwbox_encoded_t *inp)
+{
+ return inp->skey_header.elts_;
+}
+int
+pwbox_encoded_setlen_skey_header(pwbox_encoded_t *inp, size_t newlen)
+{
+ uint8_t *newptr;
+#if UINT8_MAX < SIZE_MAX
+ if (newlen > UINT8_MAX)
+ goto trunnel_alloc_failed;
+#endif
+ newptr = trunnel_dynarray_setlen(&inp->skey_header.allocated_,
+ &inp->skey_header.n_, inp->skey_header.elts_, newlen,
+ sizeof(inp->skey_header.elts_[0]), (trunnel_free_fn_t) NULL,
+ &inp->trunnel_error_code_);
+ if (newptr == NULL)
+ goto trunnel_alloc_failed;
+ inp->skey_header.elts_ = newptr;
+ return 0;
+ trunnel_alloc_failed:
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+}
+size_t
+pwbox_encoded_getlen_iv(const pwbox_encoded_t *inp)
+{
+ (void)inp; return 16;
+}
+
+uint8_t
+pwbox_encoded_get_iv(const pwbox_encoded_t *inp, size_t idx)
+{
+ trunnel_assert(idx < 16);
+ return inp->iv[idx];
+}
+
+int
+pwbox_encoded_set_iv(pwbox_encoded_t *inp, size_t idx, uint8_t elt)
+{
+ trunnel_assert(idx < 16);
+ inp->iv[idx] = elt;
+ return 0;
+}
+
+uint8_t *
+pwbox_encoded_getarray_iv(pwbox_encoded_t *inp)
+{
+ return inp->iv;
+}
+size_t
+pwbox_encoded_getlen_data(const pwbox_encoded_t *inp)
+{
+ return TRUNNEL_DYNARRAY_LEN(&inp->data);
+}
+
+uint8_t
+pwbox_encoded_get_data(pwbox_encoded_t *inp, size_t idx)
+{
+ return TRUNNEL_DYNARRAY_GET(&inp->data, idx);
+}
+
+int
+pwbox_encoded_set_data(pwbox_encoded_t *inp, size_t idx, uint8_t elt)
+{
+ TRUNNEL_DYNARRAY_SET(&inp->data, idx, elt);
+ return 0;
+}
+int
+pwbox_encoded_add_data(pwbox_encoded_t *inp, uint8_t elt)
+{
+ TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->data, elt, {});
+ return 0;
+ trunnel_alloc_failed:
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+}
+
+uint8_t *
+pwbox_encoded_getarray_data(pwbox_encoded_t *inp)
+{
+ return inp->data.elts_;
+}
+int
+pwbox_encoded_setlen_data(pwbox_encoded_t *inp, size_t newlen)
+{
+ uint8_t *newptr;
+ newptr = trunnel_dynarray_setlen(&inp->data.allocated_,
+ &inp->data.n_, inp->data.elts_, newlen,
+ sizeof(inp->data.elts_[0]), (trunnel_free_fn_t) NULL,
+ &inp->trunnel_error_code_);
+ if (newptr == NULL)
+ goto trunnel_alloc_failed;
+ inp->data.elts_ = newptr;
+ return 0;
+ trunnel_alloc_failed:
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+}
+size_t
+pwbox_encoded_getlen_hmac(const pwbox_encoded_t *inp)
+{
+ (void)inp; return 32;
+}
+
+uint8_t
+pwbox_encoded_get_hmac(const pwbox_encoded_t *inp, size_t idx)
+{
+ trunnel_assert(idx < 32);
+ return inp->hmac[idx];
+}
+
+int
+pwbox_encoded_set_hmac(pwbox_encoded_t *inp, size_t idx, uint8_t elt)
+{
+ trunnel_assert(idx < 32);
+ inp->hmac[idx] = elt;
+ return 0;
+}
+
+uint8_t *
+pwbox_encoded_getarray_hmac(pwbox_encoded_t *inp)
+{
+ return inp->hmac;
+}
+const char *
+pwbox_encoded_check(const pwbox_encoded_t *obj)
+{
+ if (obj == NULL)
+ return "Object was NULL";
+ if (obj->trunnel_error_code_)
+ return "A set function failed on this object";
+ if (! (obj->fixedbytes0 == PWBOX0_CONST0))
+ return "Integer out of bounds";
+ if (! (obj->fixedbytes1 == PWBOX0_CONST1))
+ return "Integer out of bounds";
+ if (TRUNNEL_DYNARRAY_LEN(&obj->skey_header) != obj->header_len)
+ return "Length mismatch for skey_header";
+ return NULL;
+}
+
+ssize_t
+pwbox_encoded_encoded_len(const pwbox_encoded_t *obj)
+{
+ ssize_t result = 0;
+
+ if (NULL != pwbox_encoded_check(obj))
+ return -1;
+
+
+ /* Length of u32 fixedbytes0 IN [PWBOX0_CONST0] */
+ result += 4;
+
+ /* Length of u32 fixedbytes1 IN [PWBOX0_CONST1] */
+ result += 4;
+
+ /* Length of u8 header_len */
+ result += 1;
+
+ /* Length of u8 skey_header[header_len] */
+ result += TRUNNEL_DYNARRAY_LEN(&obj->skey_header);
+
+ /* Length of u8 iv[16] */
+ result += 16;
+
+ /* Length of u8 data[] */
+ result += TRUNNEL_DYNARRAY_LEN(&obj->data);
+
+ /* Length of u8 hmac[32] */
+ result += 32;
+ return result;
+}
+int
+pwbox_encoded_clear_errors(pwbox_encoded_t *obj)
+{
+ int r = obj->trunnel_error_code_;
+ obj->trunnel_error_code_ = 0;
+ return r;
+}
+ssize_t
+pwbox_encoded_encode(uint8_t *output, size_t avail, const pwbox_encoded_t *obj)
+{
+ ssize_t result = 0;
+ size_t written = 0;
+ uint8_t *ptr = output;
+ const char *msg;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ const ssize_t encoded_len = pwbox_encoded_encoded_len(obj);
+#endif
+ int enforce_avail = 0;
+ const size_t avail_orig = avail;
+
+ if (NULL != (msg = pwbox_encoded_check(obj)))
+ goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ trunnel_assert(encoded_len >= 0);
+#endif
+
+ /* Encode u32 fixedbytes0 IN [PWBOX0_CONST0] */
+ trunnel_assert(written <= avail);
+ if (avail - written < 4)
+ goto truncated;
+ trunnel_set_uint32(ptr, trunnel_htonl(obj->fixedbytes0));
+ written += 4; ptr += 4;
+
+ /* Encode u32 fixedbytes1 IN [PWBOX0_CONST1] */
+ trunnel_assert(written <= avail);
+ if (avail - written < 4)
+ goto truncated;
+ trunnel_set_uint32(ptr, trunnel_htonl(obj->fixedbytes1));
+ written += 4; ptr += 4;
+
+ /* Encode u8 header_len */
+ trunnel_assert(written <= avail);
+ if (avail - written < 1)
+ goto truncated;
+ trunnel_set_uint8(ptr, (obj->header_len));
+ written += 1; ptr += 1;
+
+ /* Encode u8 skey_header[header_len] */
+ {
+ size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->skey_header);
+ trunnel_assert(obj->header_len == elt_len);
+ trunnel_assert(written <= avail);
+ if (avail - written < elt_len)
+ goto truncated;
+ memcpy(ptr, obj->skey_header.elts_, elt_len);
+ written += elt_len; ptr += elt_len;
+ }
+
+ /* Encode u8 iv[16] */
+ trunnel_assert(written <= avail);
+ if (avail - written < 16)
+ goto truncated;
+ memcpy(ptr, obj->iv, 16);
+ written += 16; ptr += 16;
+ {
+
+ /* Encode u8 data[] */
+ {
+ size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->data);
+ trunnel_assert(written <= avail);
+ if (avail - written < elt_len)
+ goto truncated;
+ memcpy(ptr, obj->data.elts_, elt_len);
+ written += elt_len; ptr += elt_len;
+ }
+ trunnel_assert(written <= avail);
+ if (avail - written < 32)
+ goto truncated;
+ avail = written + 32;
+ enforce_avail = 1;
+ }
+
+ /* Encode u8 hmac[32] */
+ trunnel_assert(written <= avail);
+ if (avail - written < 32) {
+ if (avail_orig - written < 32)
+ goto truncated;
+ else
+ goto check_failed;
+ }
+ memcpy(ptr, obj->hmac, 32);
+ written += 32; ptr += 32;
+
+
+ trunnel_assert(ptr == output + written);
+ if (enforce_avail && avail != written)
+ goto check_failed;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+ {
+ trunnel_assert(encoded_len >= 0);
+ trunnel_assert((size_t)encoded_len == written);
+ }
+
+#endif
+
+ return written;
+
+ truncated:
+ result = -2;
+ goto fail;
+ check_failed:
+ (void)msg;
+ result = -1;
+ goto fail;
+ fail:
+ trunnel_assert(result < 0);
+ return result;
+}
+
+/** As pwbox_encoded_parse(), but do not allocate the output object.
+ */
+static ssize_t
+pwbox_encoded_parse_into(pwbox_encoded_t *obj, const uint8_t *input, const size_t len_in)
+{
+ const uint8_t *ptr = input;
+ size_t remaining = len_in;
+ ssize_t result = 0;
+ (void)result;
+
+ /* Parse u32 fixedbytes0 IN [PWBOX0_CONST0] */
+ CHECK_REMAINING(4, truncated);
+ obj->fixedbytes0 = trunnel_ntohl(trunnel_get_uint32(ptr));
+ remaining -= 4; ptr += 4;
+ if (! (obj->fixedbytes0 == PWBOX0_CONST0))
+ goto fail;
+
+ /* Parse u32 fixedbytes1 IN [PWBOX0_CONST1] */
+ CHECK_REMAINING(4, truncated);
+ obj->fixedbytes1 = trunnel_ntohl(trunnel_get_uint32(ptr));
+ remaining -= 4; ptr += 4;
+ if (! (obj->fixedbytes1 == PWBOX0_CONST1))
+ goto fail;
+
+ /* Parse u8 header_len */
+ CHECK_REMAINING(1, truncated);
+ obj->header_len = (trunnel_get_uint8(ptr));
+ remaining -= 1; ptr += 1;
+
+ /* Parse u8 skey_header[header_len] */
+ CHECK_REMAINING(obj->header_len, truncated);
+ TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->skey_header, obj->header_len, {});
+ obj->skey_header.n_ = obj->header_len;
+ memcpy(obj->skey_header.elts_, ptr, obj->header_len);
+ ptr += obj->header_len; remaining -= obj->header_len;
+
+ /* Parse u8 iv[16] */
+ CHECK_REMAINING(16, truncated);
+ memcpy(obj->iv, ptr, 16);
+ remaining -= 16; ptr += 16;
+ {
+ size_t remaining_after;
+ CHECK_REMAINING(32, truncated);
+ remaining_after = 32;
+ remaining = remaining - 32;
+
+ /* Parse u8 data[] */
+ TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->data, remaining, {});
+ obj->data.n_ = remaining;
+ memcpy(obj->data.elts_, ptr, remaining);
+ ptr += remaining; remaining -= remaining;
+ if (remaining != 0)
+ goto fail;
+ remaining = remaining_after;
+ }
+
+ /* Parse u8 hmac[32] */
+ CHECK_REMAINING(32, truncated);
+ memcpy(obj->hmac, ptr, 32);
+ remaining -= 32; ptr += 32;
+ trunnel_assert(ptr + remaining == input + len_in);
+ return len_in - remaining;
+
+ truncated:
+ return -2;
+ trunnel_alloc_failed:
+ return -1;
+ fail:
+ result = -1;
+ return result;
+}
+
+ssize_t
+pwbox_encoded_parse(pwbox_encoded_t **output, const uint8_t *input, const size_t len_in)
+{
+ ssize_t result;
+ *output = pwbox_encoded_new();
+ if (NULL == *output)
+ return -1;
+ result = pwbox_encoded_parse_into(*output, input, len_in);
+ if (result < 0) {
+ pwbox_encoded_free(*output);
+ *output = NULL;
+ }
+ return result;
+}
diff --git a/src/trunnel/pwbox.h b/src/trunnel/pwbox.h
new file mode 100644
index 0000000000..5b170eb45e
--- /dev/null
+++ b/src/trunnel/pwbox.h
@@ -0,0 +1,173 @@
+/* pwbox.h -- generated by by Trunnel v1.2.
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+#ifndef TRUNNEL_PWBOX_H
+#define TRUNNEL_PWBOX_H
+
+#include <stdint.h>
+#include "trunnel.h"
+
+#define PWBOX0_CONST0 1414484546
+#define PWBOX0_CONST1 1331179568
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_PWBOX_ENCODED)
+struct pwbox_encoded_st {
+ uint32_t fixedbytes0;
+ uint32_t fixedbytes1;
+ uint8_t header_len;
+ TRUNNEL_DYNARRAY_HEAD(, uint8_t) skey_header;
+ uint8_t iv[16];
+ TRUNNEL_DYNARRAY_HEAD(, uint8_t) data;
+ uint8_t hmac[32];
+ uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct pwbox_encoded_st pwbox_encoded_t;
+/** Return a newly allocated pwbox_encoded with all elements set to
+ * zero.
+ */
+pwbox_encoded_t *pwbox_encoded_new(void);
+/** Release all storage held by the pwbox_encoded in 'victim'. (Do
+ * nothing if 'victim' is NULL.)
+ */
+void pwbox_encoded_free(pwbox_encoded_t *victim);
+/** Try to parse a pwbox_encoded from the buffer in 'input', using up
+ * to 'len_in' bytes from the input buffer. On success, return the
+ * number of bytes consumed and set *output to the newly allocated
+ * pwbox_encoded_t. On failure, return -2 if the input appears
+ * truncated, and -1 if the input is otherwise invalid.
+ */
+ssize_t pwbox_encoded_parse(pwbox_encoded_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * pwbox_encoded in 'obj'. On failure, return a negative value. Note
+ * that this value may be an overestimate, and can even be an
+ * underestimate for certain unencodeable objects.
+ */
+ssize_t pwbox_encoded_encoded_len(const pwbox_encoded_t *obj);
+/** Try to encode the pwbox_encoded from 'input' into the buffer at
+ * 'output', using up to 'avail' bytes of the output buffer. On
+ * success, return the number of bytes used. On failure, return -2 if
+ * the buffer was not long enough, and -1 if the input was invalid.
+ */
+ssize_t pwbox_encoded_encode(uint8_t *output, const size_t avail, const pwbox_encoded_t *input);
+/** Check whether the internal state of the pwbox_encoded in 'obj' is
+ * consistent. Return NULL if it is, and a short message if it is not.
+ */
+const char *pwbox_encoded_check(const pwbox_encoded_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int pwbox_encoded_clear_errors(pwbox_encoded_t *obj);
+/** Return the value of the fixedbytes0 field of the pwbox_encoded_t
+ * in 'inp'
+ */
+uint32_t pwbox_encoded_get_fixedbytes0(pwbox_encoded_t *inp);
+/** Set the value of the fixedbytes0 field of the pwbox_encoded_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int pwbox_encoded_set_fixedbytes0(pwbox_encoded_t *inp, uint32_t val);
+/** Return the value of the fixedbytes1 field of the pwbox_encoded_t
+ * in 'inp'
+ */
+uint32_t pwbox_encoded_get_fixedbytes1(pwbox_encoded_t *inp);
+/** Set the value of the fixedbytes1 field of the pwbox_encoded_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int pwbox_encoded_set_fixedbytes1(pwbox_encoded_t *inp, uint32_t val);
+/** Return the value of the header_len field of the pwbox_encoded_t in
+ * 'inp'
+ */
+uint8_t pwbox_encoded_get_header_len(pwbox_encoded_t *inp);
+/** Set the value of the header_len field of the pwbox_encoded_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int pwbox_encoded_set_header_len(pwbox_encoded_t *inp, uint8_t val);
+/** Return the length of the dynamic array holding the skey_header
+ * field of the pwbox_encoded_t in 'inp'.
+ */
+size_t pwbox_encoded_getlen_skey_header(const pwbox_encoded_t *inp);
+/** Return the element at position 'idx' of the dynamic array field
+ * skey_header of the pwbox_encoded_t in 'inp'.
+ */
+uint8_t pwbox_encoded_get_skey_header(pwbox_encoded_t *inp, size_t idx);
+/** Change the element at position 'idx' of the dynamic array field
+ * skey_header of the pwbox_encoded_t in 'inp', so that it will hold
+ * the value 'elt'.
+ */
+int pwbox_encoded_set_skey_header(pwbox_encoded_t *inp, size_t idx, uint8_t elt);
+/** Append a new element 'elt' to the dynamic array field skey_header
+ * of the pwbox_encoded_t in 'inp'.
+ */
+int pwbox_encoded_add_skey_header(pwbox_encoded_t *inp, uint8_t elt);
+/** Return a pointer to the variable-length array field skey_header of
+ * 'inp'.
+ */
+uint8_t * pwbox_encoded_getarray_skey_header(pwbox_encoded_t *inp);
+/** Change the length of the variable-length array field skey_header
+ * of 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on
+ * success; return -1 and set the error code on 'inp' on failure.
+ */
+int pwbox_encoded_setlen_skey_header(pwbox_encoded_t *inp, size_t newlen);
+/** Return the (constant) length of the array holding the iv field of
+ * the pwbox_encoded_t in 'inp'.
+ */
+size_t pwbox_encoded_getlen_iv(const pwbox_encoded_t *inp);
+/** Return the element at position 'idx' of the fixed array field iv
+ * of the pwbox_encoded_t in 'inp'.
+ */
+uint8_t pwbox_encoded_get_iv(const pwbox_encoded_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field iv
+ * of the pwbox_encoded_t in 'inp', so that it will hold the value
+ * 'elt'.
+ */
+int pwbox_encoded_set_iv(pwbox_encoded_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 16-element array field iv of 'inp'.
+ */
+uint8_t * pwbox_encoded_getarray_iv(pwbox_encoded_t *inp);
+/** Return the length of the dynamic array holding the data field of
+ * the pwbox_encoded_t in 'inp'.
+ */
+size_t pwbox_encoded_getlen_data(const pwbox_encoded_t *inp);
+/** Return the element at position 'idx' of the dynamic array field
+ * data of the pwbox_encoded_t in 'inp'.
+ */
+uint8_t pwbox_encoded_get_data(pwbox_encoded_t *inp, size_t idx);
+/** Change the element at position 'idx' of the dynamic array field
+ * data of the pwbox_encoded_t in 'inp', so that it will hold the
+ * value 'elt'.
+ */
+int pwbox_encoded_set_data(pwbox_encoded_t *inp, size_t idx, uint8_t elt);
+/** Append a new element 'elt' to the dynamic array field data of the
+ * pwbox_encoded_t in 'inp'.
+ */
+int pwbox_encoded_add_data(pwbox_encoded_t *inp, uint8_t elt);
+/** Return a pointer to the variable-length array field data of 'inp'.
+ */
+uint8_t * pwbox_encoded_getarray_data(pwbox_encoded_t *inp);
+/** Change the length of the variable-length array field data of 'inp'
+ * to 'newlen'.Fill extra elements with 0. Return 0 on success; return
+ * -1 and set the error code on 'inp' on failure.
+ */
+int pwbox_encoded_setlen_data(pwbox_encoded_t *inp, size_t newlen);
+/** Return the (constant) length of the array holding the hmac field
+ * of the pwbox_encoded_t in 'inp'.
+ */
+size_t pwbox_encoded_getlen_hmac(const pwbox_encoded_t *inp);
+/** Return the element at position 'idx' of the fixed array field hmac
+ * of the pwbox_encoded_t in 'inp'.
+ */
+uint8_t pwbox_encoded_get_hmac(const pwbox_encoded_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field hmac
+ * of the pwbox_encoded_t in 'inp', so that it will hold the value
+ * 'elt'.
+ */
+int pwbox_encoded_set_hmac(pwbox_encoded_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field hmac of 'inp'.
+ */
+uint8_t * pwbox_encoded_getarray_hmac(pwbox_encoded_t *inp);
+
+
+#endif
diff --git a/src/trunnel/pwbox.trunnel b/src/trunnel/pwbox.trunnel
new file mode 100644
index 0000000000..10db74b4e5
--- /dev/null
+++ b/src/trunnel/pwbox.trunnel
@@ -0,0 +1,14 @@
+
+const PWBOX0_CONST0 = 0x544f5242; // TORB
+const PWBOX0_CONST1 = 0x4f583030; // OX00
+
+struct pwbox_encoded {
+ u32 fixedbytes0 IN [PWBOX0_CONST0];
+ u32 fixedbytes1 IN [PWBOX0_CONST1];
+ u8 header_len;
+ u8 skey_header[header_len];
+ u8 iv[16];
+ u8 data[..-32];
+ u8 hmac[32];
+};
+
diff --git a/src/trunnel/trunnel-local.h b/src/trunnel/trunnel-local.h
new file mode 100644
index 0000000000..b7c2ab98ef
--- /dev/null
+++ b/src/trunnel/trunnel-local.h
@@ -0,0 +1,18 @@
+
+#ifndef TRUNNEL_LOCAL_H_INCLUDED
+#define TRUNNEL_LOCAL_H_INCLUDED
+
+#include "util.h"
+#include "compat.h"
+#include "crypto.h"
+
+#define trunnel_malloc tor_malloc
+#define trunnel_calloc tor_calloc
+#define trunnel_strdup tor_strdup
+#define trunnel_free_ tor_free_
+#define trunnel_realloc tor_realloc
+#define trunnel_reallocarray tor_reallocarray
+#define trunnel_assert tor_assert
+#define trunnel_memwipe(mem, len) memwipe((mem), 0, (len))
+
+#endif
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index 5e670c35c1..4a9ad29c64 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -14,8 +14,6 @@
/* Define to 1 if you have the <ctype.h> header file. */
#define HAVE_CTYPE_H
-#define ENABLE_THREADS
-
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H
@@ -86,18 +84,11 @@
#define HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
-#if defined (WINCE)
-#define HAVE_STRLCAT
-#else
#undef HAVE_STRLCAT
-#endif
/* Define to 1 if you have the `strlcpy' function. */
-#if defined (WINCE)
-#define HAVE_STRLCPY
-#else
#undef HAVE_STRLCPY
-#endif
+
/* Define to 1 if you have the `strptime' function. */
#undef HAVE_STRPTIME
@@ -241,7 +232,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.2.5.14-dev"
+#define VERSION "0.2.6.12-dev"
@@ -253,7 +244,6 @@
#define SHARE_DATADIR ""
#define HAVE_EVENT2_DNS_H
#define HAVE_EVENT_BASE_LOOPEXIT
-#define CURVE25519_ENABLED
#define USE_CURVE25519_DONNA
#define ENUM_VALS_ARE_SIGNED 1