├── BUGS ├── LICENSE ├── Makefile ├── README ├── SConstruct ├── TODO ├── bin64.cpp ├── bin64.h ├── bingrep.cpp ├── bins.cpp ├── bins.h ├── channel.cpp ├── compat.cpp ├── compat.h ├── datagram.cpp ├── datagram.h ├── doc ├── apusapus.png ├── binmaps-alenex.pdf ├── cc-states.png ├── draft-ietf-ppsp-grishchenko-swift.nroff ├── draft-ietf-ppsp-grishchenko-swift.txt ├── index.html ├── p2tp-lancaster.pdf ├── p2tp-uml-er.pdf ├── sofi.jpg ├── state-diagram.pdf ├── style.css ├── swift.css └── wireshark-dissector │ ├── AUTHORS │ ├── CMakeLists.txt │ ├── COPYING │ ├── ChangeLog │ ├── Makefile │ ├── Makefile.am │ ├── Makefile.common │ ├── Makefile.in │ ├── Makefile.nmake │ ├── README │ ├── moduleinfo.h │ ├── moduleinfo.nmake │ ├── packet-swift.c │ ├── packet-swift.lo │ ├── plugin.c │ ├── plugin.lo │ ├── plugin.rc.in │ └── swift.la ├── ext ├── seq_picker.cpp └── simple_selector.cpp ├── getopt.c ├── getopt_long.c ├── getopt_win.h ├── hashtree.cpp ├── hashtree.h ├── httpgw.cpp ├── mfold ├── bash_profile ├── build.default.sh ├── clean.default.sh ├── compile.default.sh ├── doall ├── docmd ├── dohrv ├── dotop ├── env.1mbit.sh ├── env.default.sh ├── env.lossy.sh ├── env.messy.sh ├── install.default.sh ├── loggraphs ├── logparse ├── logreport ├── net.aussie.sh ├── net.lossy.sh ├── net.messy.sh ├── netem.default.sh ├── ps.default.sh ├── report.css ├── run.default.sh ├── run.seeder.sh └── status.default.sh ├── send_control.cpp ├── sendrecv.cpp ├── sha1.cpp ├── sha1.h ├── swift.cpp ├── swift.h ├── tests ├── SConscript ├── bin64test.cpp ├── binstest.cpp ├── binstest2.cpp ├── bintest.cpp ├── congctrltest.cpp ├── connecttest.cpp ├── dgramtest.cpp ├── freemap.cpp ├── hashtest.cpp ├── ledbattest.cpp ├── ledbattest2.cpp ├── pex_test.sh ├── rwtest.cpp ├── sbit2test.cpp ├── sbittest.cpp └── transfertest.cpp └── transfer.cpp /BUGS: -------------------------------------------------------------------------------- 1 | * min_owd TINT_NEVER is logged 2 | 3 | v hints, data for non-existing ranges 4 | v opens multiple channels to the same address 5 | v hints do not expire 6 | v RTT calculations need improvement (test) 7 | v google-log is unnecessary 8 | * reduce template use (peer queue) 9 | v hints do not expire 10 | v survive 10% loss 11 | v unlimited ping pong 12 | v git sha-1 13 | v check hints agains ack_out?_ 14 | v check data against ack_in 15 | v channel suspend/wake. 3 cong modes state machine - ??? 16 | * release hints for a dormant channel 17 | * minimize the number of template instantiations 18 | v Channel thinks how much it HINTs a second, 19 | picker thinks which HINTs are snubbed 20 | * files <1sec download : how HINTs are sent? 21 | v dead Channels are not killed => cannot open a new one 22 | (have a channel already) 23 | v peers don't cooperate 24 | * RecoverProgress fails sometime 25 | v leecher can't see file is done already 26 | v why leecher waits 1sec? 27 | * hint queue buildup 28 | * file operations are not 64-bit ready 29 | http://mail.python.org/pipermail/patches/2000-June/000848.html 30 | * recovery: last packet 31 | v no-HINT sending to a dead peer 32 | * what if rtt>1sec 33 | v unHINTed repeated sending 34 | v 1259859412.out#8,9 connection breaks, #8 rtt 1000, #9 hint - 35 | mudachestvo, cwnd => send int 0.5sec 36 | 0_11_10_075_698 #9 sendctrl may send 0 < 0.000000 & 1732919509_-49_-45_-200_-111 (rtt 59661) 37 | 0_11_10_075_698 #9 +data (0,194) 38 | 0_11_10_575_703 #9 sendctrl loss detected 39 | 0_11_10_575_703 #9 Tdata (0,194) 40 | 0_11_10_575_703 #9 sendctrl may send 0 < 0.000000 & 1732919509_-49_-44_-700_-110 (rtt 59661) 41 | v complete peer reconnects 1259967418.out.gz 42 | * underhinting causes repetition causes interarr underest causes underhinting 43 | * misterious initiating handshake bursts 44 | v whether sending is limited by cwnd or app 45 | * actually: whether packets are ACKed faster than sent 46 | * uproot DATA NONE: complicates and deceives 47 | v r735 goes to github; r741 48 | * receiver is swapping => strange behavior 49 | v on high losses cwnd goes to silly fractions => slows down recovery 50 | v code the pingpong<->keepalive<->slowstart transition 51 | v empty datagram hammering (see at linode) 52 | * make a testkit!!! 53 | * never back from keepalive syndrome (because of underhashing) 54 | * HTTP daemon, combined select() loop 55 | * range requests, priorities 56 | v LEDBAT 57 | * CUBIC 58 | v misterious mass packet losses (!data) 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CPPFLAGS=-O2 -I. 2 | 3 | all: swift 4 | 5 | swift: swift.o sha1.o compat.o sendrecv.o send_control.o hashtree.o bin64.o bins.o channel.o datagram.o transfer.o httpgw.o 6 | g++ -I. *.o -o swift 7 | 8 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | swift: the multiparty transport protocol 2 | (aka BitTorrent at the transport layer) 3 | Differently from TCP, the protocol does not use the ordered data stream 4 | abstraction. Effectively, it splits a file into 1KB packets and sends 5 | them around. The secret sauce is Merkle hash trees and binmaps. 6 | 7 | see doc/index.html for marketing stuff, ideas and rants 8 | doc/swift.txt for protocol draft spec 9 | *.cpp for the actual code 10 | swift.cpp is the main exec file; may run as e.g. 11 | 12 | ./swift -t node300.das2.ewi.tudelft.nl:20000 -h \ 13 | d1502706c46779d361a1d562a10da0a45c4c40e5 -f \ 14 | trailer.ogg 15 | 16 | ...to retrieve video and save it to a file. 17 | 18 | Alternatively, you might play with the HTTP gateway, the preliminary 19 | version. First, run the seeder-tracker: 20 | 21 | $ ./swift -f ~/Downloads/big_buck_bunny_480p_stereo.ogg -l 0.0.0.0:20000 22 | Root hash: 7c462ad1d980ba44ab4b819e29004eb0bf6e6d5f 23 | 24 | ...then you may try running the swift-HTTP gateway... 25 | 26 | ./swift -t localhost:20000 -g 0.0.0.0:8080 -w 27 | 28 | ...and finally you may point your browser at the gateway... 29 | 30 | http://localhost:8080/7c462ad1d980ba44ab4b819e29004eb0bf6e6d5f 31 | 32 | If you use an HTML5 browser (Chrome preferred), you are likely to see 33 | the bunny trailer at this point... 34 | -------------------------------------------------------------------------------- /SConstruct: -------------------------------------------------------------------------------- 1 | # Written by Victor Grishchenko, Arno Bakker 2 | # see LICENSE.txt for license information 3 | # 4 | # Requirements: 5 | # - scons: Cross-platform build system http://www.scons.org/ 6 | # - googletest: Google C++ Test Framework http://code.google.com/p/googletest/ 7 | # * Install in ..\gtest-1.4.0 8 | # 9 | 10 | import os 11 | import re 12 | import sys 13 | 14 | DEBUG = True 15 | 16 | TestDir='tests' 17 | 18 | target = 'swift' 19 | source = [ 'bin64.cpp','sha1.cpp','hashtree.cpp','datagram.cpp','bins.cpp', 20 | 'transfer.cpp', 'channel.cpp', 'sendrecv.cpp', 'send_control.cpp', 21 | 'compat.cpp'] 22 | 23 | env = Environment() 24 | if sys.platform == "win32": 25 | # "MSVC works out of the box". Sure. 26 | # Make sure scons finds cl.exe, etc. 27 | env.Append ( ENV = { 'PATH' : os.environ['PATH'] } ) 28 | 29 | # Make sure scons finds std MSVC include files 30 | if not 'INCLUDE' in os.environ: 31 | print "swift: Please run scons in a Visual Studio Command Prompt" 32 | sys.exit(-1) 33 | 34 | include = os.environ['INCLUDE'] 35 | include += '..\\gtest-1.4.0\\include;' 36 | include += '\\openssl\\include;' 37 | 38 | env.Append ( ENV = { 'INCLUDE' : include } ) 39 | 40 | # Other compiler flags 41 | env.Append(CPPPATH=".") 42 | if DEBUG: 43 | env.Append(CXXFLAGS="/Zi /Yd /MTd") 44 | env.Append(LINKFLAGS="/DEBUG") 45 | 46 | # Add simulated pread/write 47 | source += ['compat/unixio.cpp'] 48 | 49 | # Set libs to link to 50 | libs = ['ws2_32'] 51 | if DEBUG: 52 | libs += ['gtestd','libeay32MTd'] 53 | else: 54 | libs += ['gtest','libeay32'] 55 | 56 | # Update lib search path 57 | libpath = os.environ['LIBPATH'] 58 | if DEBUG: 59 | libpath += '\\build\\gtest-1.4.0\\msvc\\gtest\\Debug;' 60 | libpath += '\\openssl\\lib\\VC\\static;' 61 | else: 62 | libpath += '\\build\\gtest-1.4.0\\msvc\\gtest\\Release;' 63 | libpath += '\\openssl\\lib;' 64 | # Somehow linker can't find uuid.lib 65 | libpath += 'C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0A\\Lib;' 66 | 67 | else: 68 | # Enable the user defining external includes 69 | if 'CPPPATH' in os.environ: 70 | cpppath = os.environ['CPPPATH'] 71 | else: 72 | cpppath = "" 73 | print "To use external libs, set CPPPATH environment variable to list of colon-separated include dirs" 74 | env.Append(CPPPATH=".:"+cpppath) 75 | #env.Append(LINKFLAGS="--static") 76 | 77 | #if DEBUG: 78 | # env.Append(CXXFLAGS="-g") 79 | 80 | # Set libs to link to 81 | libs = ['stdc++','pthread'] 82 | if 'LIBPATH' in os.environ: 83 | libpath = os.environ['LIBPATH'] 84 | else: 85 | libpath = "" 86 | print "To use external libs, set LIBPATH environment variable to list of colon-separated lib dirs" 87 | 88 | if DEBUG: 89 | env.Append(CXXFLAGS="-DDEBUG") 90 | 91 | env.StaticLibrary ( 92 | target='libswift', 93 | source = source, 94 | LIBS=libs, 95 | LIBPATH=libpath ) 96 | 97 | env.Program( 98 | target='swift', 99 | source=['swift.cpp','httpgw.cpp'], 100 | CPPPATH=cpppath, 101 | LIBS=[libs,'libswift'], 102 | LIBPATH=libpath+':.' ) 103 | 104 | Export("env") 105 | Export("libs") 106 | Export("libpath") 107 | Export("DEBUG") 108 | SConscript('tests/SConscript') 109 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | TRIAL TODO 2 | 3 | STATE MACHINE 4 | * imposed HINTs are terribly broken, resent for the data in flight 5 | * check ACK/HAVE redundancy 6 | * HAVE overuses find_filtered 7 | * set priorities on ranges 8 | * small-progress update problem (aka peer nap) 9 | guarantee size of updates < x% of data, on both ends 10 | * pex is affected by peer nap 11 | * how will tracker aggregate pexes? 12 | * SWIFT_MSGTYPE_RCVD 13 | * HAVE ALL / HAVE NONE 14 | * aggregate ACKS (schedule for +x ms) 15 | * channel close msg (hs 0) 16 | * connection rotation / pex / pex_del 17 | * misterious bug: Rdata (NONE) 18 | * ?amend MAX_REORDER depending on rtt_dev 19 | * Tdata repetitions bug 20 | 21 | PERFORMANCE 22 | * move to the.zett's binmaps 23 | * optimize redundant HASH messages 24 | * move to rolling HAVE queue 25 | * 32 bit time field 26 | * ?empty/full binmaps 27 | * initiate RTT with prev RTT to host:port 28 | * fractional cwnd 29 | 30 | CACHING/FILES 31 | * connection rotation 32 | * file rotation 33 | * real LRU/LFU 34 | * file/hash-file re-open in read-only mode 35 | * no cache recheck, failure-resistant 36 | * completion mark 37 | * unified events/callbacks 38 | * move to 64-bit IO 39 | * Transfer(fd) constructor 40 | * think of sliding window(s) 41 | * the ability to sniff file without downloading 42 | 43 | MANIFOLD 44 | * all-swarm performance stats 45 | * run chained setups (cmd line protocol subsetting) 46 | * implement: multiple swift instances per server 47 | * run thousand-daemon caching tests (use httpgw) 48 | * use a dedicated tracker 49 | * add NATs to the setup 50 | * recover mfold.libswift.org 51 | * integrate Windowses 52 | 53 | API 54 | * pluggable storage 55 | 56 | NAT 57 | * NAT type detection => need peer identifiers (x100 amplification) 58 | 59 | MFOLD 60 | * integrate multi-peer changes by Jori 61 | * do global swarm stats 62 | 63 | OTHER 64 | * httpgw or nginx? 65 | * Sha1Hash constructor ambiguity 66 | * don't #include .cpp 67 | * think of using HTTP (?) as a fallback 68 | * add header/footer, better abstract to the draft 69 | * Gertjan: separate peer from channel? cng ctrl per peer ? 70 | * packing hashes into a single datagram (tracking 1000s) 71 | * partial channels / lightweight channels 72 | 73 | THOUGHTS 74 | * 6 degrees of sep = 3-hop TorrentSmell 75 | * 60% immediately not connectable 76 | * support traffic 77 | -------------------------------------------------------------------------------- /bin64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * bin64.cpp 3 | * swift 4 | * 5 | * Created by Victor Grishchenko on 10/10/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include "bin64.h" 10 | 11 | const uint64_t bin64_t::NONE = 0xffffffffffffffffULL; 12 | const uint64_t bin64_t::ALL = 0x7fffffffffffffffULL; 13 | const uint32_t bin64_t::NONE32 = 0xffffffffU; 14 | const uint32_t bin64_t::ALL32 = 0x7fffffffU; 15 | 16 | uint32_t bin64_t::to32() const { 17 | if (v<0xffffffff && v!=0x7fffffff) 18 | return (uint32_t)v; 19 | if (v==ALL) 20 | return ALL32; 21 | return NONE32; 22 | } 23 | 24 | bin64_t::bin64_t(const uint32_t val) { 25 | if (val==ALL32) 26 | v = ALL; 27 | else if (val==NONE32) 28 | v = NONE; 29 | else 30 | v = val; 31 | } 32 | 33 | bin64_t bin64_t::next_dfsio (uint8_t floor) { 34 | /*while (ret.is_right()) 35 | ret = ret.parent(); 36 | ret = ret.sibling(); 37 | while (ret.layer()>floor) 38 | ret = ret.left();*/ 39 | if (is_right()) { 40 | return parent(); 41 | } else { 42 | bin64_t ret = sibling(); 43 | while (ret.layer()>floor) 44 | ret = ret.left(); 45 | return ret; 46 | } 47 | } 48 | 49 | int bin64_t::peaks (uint64_t length, bin64_t* peaks) { 50 | int pp=0; 51 | uint8_t layer = 0; 52 | while (length) { 53 | if (length&1) 54 | peaks[pp++] = bin64_t(layer,length^1); 55 | length>>=1; 56 | layer++; 57 | } 58 | for(int i=0; i<(pp>>1); i++) { 59 | uint64_t memo = peaks[pp-1-i]; 60 | peaks[pp-1-i] = peaks[i]; 61 | peaks[i] = memo; 62 | } 63 | peaks[pp] = NONE; 64 | return pp; 65 | } 66 | 67 | #include 68 | 69 | const char* bin64_t::str () const { 70 | static char _b64sr[4][32]; 71 | static int _rsc; 72 | _rsc = (_rsc+1) & 3; 73 | if (v==ALL) 74 | return "(ALL)"; 75 | else if (v==NONE) 76 | return "(NONE)"; 77 | else 78 | sprintf(_b64sr[_rsc],"(%i,%lli)",(int)layer(),offset()); 79 | return _b64sr[_rsc]; 80 | } 81 | -------------------------------------------------------------------------------- /bin64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * bin64.h 3 | * bin numbers (binaty tree enumeration/navigation) 4 | * 5 | * Created by Victor Grishchenko on ??/09/09 in Karlovy Vary 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #ifndef BIN64_H 10 | #define BIN64_H 11 | #include 12 | #include "compat.h" 13 | 14 | 15 | /** Numbering for (aligned) logarithmical bins. 16 | Each number stands for an interval 17 | [o*2^l,(o+1)*2^l), where l is the layer and o 18 | is the offset. 19 | Bin numbers in the tail111 encoding: meaningless 20 | bits in the tail are set to 0111...11, while the 21 | head denotes the offset. Thus, 1101 is the bin 22 | at layer 1, offset 3 (i.e. fourth). 23 | Obviously, bins form a binary tree. All navigation 24 | is made in terms of binary trees: left, right, 25 | sibling, parent, etc. 26 | */ 27 | struct bin64_t { 28 | uint64_t v; 29 | static const uint64_t NONE; 30 | static const uint64_t ALL; 31 | static const uint32_t NONE32; 32 | static const uint32_t ALL32; 33 | 34 | bin64_t() : v(NONE) {} 35 | bin64_t(const bin64_t&b) : v(b.v) {} 36 | bin64_t(const uint32_t val) ; 37 | bin64_t(const uint64_t val) : v(val) {} 38 | bin64_t(uint8_t layer, uint64_t offset) : 39 | v( (offset<<(layer+1)) | ((1ULL<>1; 53 | } 54 | 55 | /** Get the sibling interval in the binary tree. */ 56 | bin64_t sibling () const { 57 | // if (v==ALL) return NONE; 58 | return bin64_t(v^(tail_bit()<<1)); 59 | } 60 | 61 | int layer () const { 62 | int r = 0; 63 | uint64_t tail = ((v^(v+1))+1)>>1; 64 | if (tail>0xffffffffULL) { 65 | r = 32; 66 | tail>>=32; 67 | } 68 | // courtesy of Sean Eron Anderson 69 | // http://graphics.stanford.edu/~seander/bithacks.html 70 | static const int DeBRUIJN[32] = { 71 | 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 72 | 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 73 | }; 74 | r += DeBRUIJN[((uint32_t)(tail*0x077CB531U))>>27]; 75 | return r; 76 | } 77 | 78 | /** Get the bin's offset in base units, i.e. 4 for (1,2). */ 79 | uint64_t base_offset () const { 80 | return (v&~(tail_bits()))>>1; 81 | } 82 | 83 | /** Get the bin's offset at its own layer, e.g. 2 for (1,2). */ 84 | uint64_t offset () const { 85 | return v >> (layer()+1); 86 | } 87 | 88 | /** Get a child bin; either right(true) or left(false). */ 89 | bin64_t to (bool right) const { 90 | if (!(v&1)) 91 | return NONE; 92 | uint64_t tb = ((tail_bits() >> 1) + 1) >> 1; 93 | if (right) 94 | return bin64_t(v + tb); 95 | return bin64_t(v ^ tb); 96 | } 97 | 98 | /** Get the left child bin. */ 99 | bin64_t left () const { 100 | return to(false); 101 | } 102 | 103 | /** Get the right child bin. */ 104 | bin64_t right () const { 105 | return to(true); 106 | } 107 | 108 | /** Check whether this bin is within the specified bin. */ 109 | bool within (bin64_t maybe_asc) { 110 | if (maybe_asc==bin64_t::NONE) 111 | return false; 112 | uint64_t short_tail = maybe_asc.tail_bits(); 113 | if (tail_bits()>short_tail) 114 | return false; 115 | return (v&~short_tail) == (maybe_asc.v&~short_tail) ; 116 | } 117 | 118 | /** Left or right, depending whether the destination is. */ 119 | bin64_t towards (bin64_t dest) const { 120 | if (!dest.within(*this)) 121 | return NONE; 122 | if (dest.within(left())) 123 | return left(); 124 | else 125 | return right(); 126 | } 127 | 128 | /** Twist/untwist a bin number according to the mask. */ 129 | bin64_t twisted (uint64_t mask) const { 130 | return bin64_t( v ^ ((mask<<1)&~tail_bits()) ); 131 | } 132 | 133 | /** Get the paretn bin. */ 134 | bin64_t parent () const { 135 | uint64_t tbs = tail_bits(), ntbs = (tbs+1)|tbs; 136 | return bin64_t( (v&~ntbs) | tbs ); 137 | } 138 | 139 | /** Check whether this bin is the left sibling. */ 140 | inline bool is_left () const { 141 | uint64_t tb = tail_bit(); 142 | return !(v&(tb<<1)); 143 | } 144 | 145 | /** Check whether this bin is the right sibling. */ 146 | inline bool is_right() const { return !is_left(); } 147 | 148 | /** Get the leftmost basic bin within this bin. */ 149 | bin64_t left_foot () const { 150 | if (v==NONE) 151 | return NONE; 152 | return bin64_t(0,base_offset()); 153 | } 154 | 155 | /** Whether layer is 0. */ 156 | bool is_base () const { 157 | return !(v & 1); 158 | } 159 | 160 | /** Depth-first in-order binary tree traversal. */ 161 | bin64_t next_dfsio (uint8_t floor); 162 | 163 | /** Return the number of basic bins within this bin. */ 164 | bin64_t width () const { 165 | return (tail_bits()+1)>>1; 166 | } 167 | 168 | /** Get the standard-form null-terminated string 169 | representation of this bin, e.g. "(2,1)". 170 | The string is statically allocated, must 171 | not be reused or released. */ 172 | const char* str () const; 173 | 174 | /** The array must have 64 cells, as it is the max 175 | number of peaks possible +1 (and there are no reason 176 | to assume there will be less in any given case. */ 177 | static int peaks (uint64_t length, bin64_t* peaks) ; 178 | 179 | }; 180 | 181 | 182 | #endif 183 | 184 | /** 185 | 00111 186 | 0011 1011 187 | 001 101 1001 1101 188 | 0 10 100 110 1000 1010 1100 1110 189 | 190 | 7 191 | 3 11 192 | 1 5 9 13 193 | 0 2 4 6 8 10 12 14 194 | 195 | once we have peak hashes, this struture is more natural than bin-v1 196 | 197 | */ 198 | -------------------------------------------------------------------------------- /bingrep.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "bin64.h" 4 | 5 | int main (int argn, char** args) { 6 | int lr; 7 | unsigned long long of; 8 | sscanf(args[1],"%i,%lli",&lr,&of); 9 | bin64_t target(lr,of); 10 | char line[1024]; 11 | while (gets(line)) { 12 | char* br = strchr(line,'('); 13 | if (br && 2==sscanf(br,"(%i,%lli)",&lr,&of)) { 14 | bin64_t found(lr,of); 15 | if ( found.within(target) || target.within(found)) 16 | printf("%s\n",line); 17 | } 18 | } 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /bins.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sbit.cpp 3 | * binmap, a hybrid of bitmap and binary tree 4 | * 5 | * Created by Victor Grishchenko on 3/28/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #ifndef BINS_H 10 | #define BINS_H 11 | #include "bin64.h" 12 | 13 | class iterator; // FIXME shame 14 | 15 | /** A binmap covering 2^64 range. Binmap is a hybrid of a bitmap (aka 16 | bit vector) and a binary tree. The key ability of a binmap is 17 | the aggregation of solid (all-0 or all-1) ranges. */ 18 | class binmap_t { 19 | 20 | public: 21 | /** Need a 3-valued logic as a range might be either all-0 or all-1 22 | or some mix. In fact, any value different from 0x0 or 0xffff 23 | must be interpreted as MIXED. 24 | All read/write operations on a binmap are made in terms of 25 | aligned binary intervals (bins). 26 | */ 27 | typedef enum { FILLED=0xffff, EMPTY=0x0000, MIXED=0x5555 } fill_t; 28 | static const int NOJOIN; 29 | 30 | binmap_t(); 31 | 32 | /** Copying constructor. */ 33 | binmap_t(const binmap_t& b); 34 | 35 | /** Destructor. */ 36 | ~binmap_t(); 37 | 38 | /** Get value for the bin. */ 39 | uint16_t get (bin64_t bin); 40 | 41 | /** Set value for the bin. */ 42 | void set (bin64_t bin, fill_t val=FILLED); 43 | 44 | typedef enum { 45 | OR_OP, 46 | AND_OP, 47 | REMOVE_OP, 48 | COPY_OP 49 | } bin_op_t; 50 | 51 | /** Copy a range from another binmap. */ 52 | void range_op (binmap_t& mask, bin64_t range, bin_op_t op); 53 | void range_copy (binmap_t& mask, bin64_t range) 54 | { range_op(mask, range, COPY_OP); } 55 | void range_remove (binmap_t& mask, bin64_t range) 56 | { range_op(mask, range, REMOVE_OP); } 57 | void range_or (binmap_t& mask, bin64_t range) 58 | { range_op(mask, range, OR_OP); } 59 | void range_and (binmap_t& mask, bin64_t range) 60 | { range_op(mask, range, AND_OP); } 61 | 62 | /** Find the leftmost bin within the specified range which is 63 | either filled or empty. */ 64 | bin64_t find (const bin64_t range, fill_t seek=EMPTY) ; 65 | 66 | /** Find the leftmost bin within the specified range which is 67 | either filled or empty. Bins set to 1 in the filter binmap cannot 68 | be returned. In fact, this is an incremental bitwise op. */ 69 | bin64_t find_filtered 70 | (binmap_t& filter, bin64_t range, fill_t seek=EMPTY) ; 71 | 72 | /** Bitwise SUB; any bins set to one in the filter binmap should 73 | be set to 0 in this binmap. */ 74 | void remove (binmap_t& filter); 75 | 76 | void dump(const char* note); 77 | 78 | /** Represent the binmap as a sequence of 0 and 1 stripes; for each 79 | new stripe only the starting offset is given. The first stripe 80 | is supposed to be empty (if the (0,0) bin is actually filled, 81 | the next stripe will also start at 0). */ 82 | uint64_t* get_stripes (int& count); 83 | 84 | /** Return the number of cells allocated in the binmap. */ 85 | uint32_t size() { return cells_allocated; } 86 | 87 | uint64_t seq_length (); 88 | 89 | /** Return the topmost solid bin which covers the specified bin. */ 90 | bin64_t cover(bin64_t val); 91 | 92 | uint64_t mass (); 93 | 94 | /** Return true if the range is solid (either all-0 or 1). If val is 95 | specified, the interval must be both solid and filled/empty, 96 | depending on the value. */ 97 | bool is_solid (bin64_t range=bin64_t::ALL, fill_t val=MIXED) ; 98 | /** Whether range/bin is empty. */ 99 | bool is_empty (bin64_t range=bin64_t::ALL) { return is_solid(range,EMPTY); } 100 | /** Whether range/bin is filled. */ 101 | bool is_filled (bin64_t range=bin64_t::ALL) { return is_solid(range,FILLED); } 102 | 103 | /** Clear everything, empty all bins. */ 104 | void clear (); 105 | 106 | /** Returns whether the int is mixed (not all-1 or all-0). */ 107 | static bool is_mixed (uint16_t val) { return val!=EMPTY && val!=FILLED; } 108 | /** Returns whether the int is solid (0x0 or 0xffff). */ 109 | static bool is_solid (uint16_t val) { return val==EMPTY || val==FILLED; } 110 | 111 | /** Twisting is some generalization of XOR. For every 1-bit in the mask, 112 | the respective layer of the binary tree is flipped, i.e. left and 113 | right change places. Twisting is mostly needed for randomization. */ 114 | void twist (uint64_t mask); 115 | 116 | /** Convert binmap to a conventional flat bitmap; only bits corresponding 117 | to solid filled bins are set to 1. 118 | @param range the bin (the range) to cover 119 | @param height aggregation level; use 2**height bins (2**height base 120 | layer bits per one bitmap bit). 121 | @param bits uint16_t array to put bitmap into; must have enough 122 | of space, i.e. 2**(range.layer()-height-4) cells. */ 123 | void to_coarse_bitmap (uint16_t* bits, bin64_t range, uint8_t height); 124 | 125 | private: 126 | 127 | /** Every 16th uint32 is a flag field denoting whether 128 | previous 30 halves (in 15 cells) are deep or not. 129 | The last bit is used as a fill-flag. 130 | Free cells have a value of 0; neither deep nor flat 131 | cell could have a value of 0 except for the root 132 | cell in case the binmap is all-0. */ 133 | union { 134 | uint32_t *cells; 135 | uint16_t *halves; 136 | }; 137 | uint32_t blocks_allocated; 138 | uint32_t cells_allocated; 139 | int height; 140 | uint64_t twist_mask; 141 | uint16_t free_top; 142 | 143 | void extend(); 144 | 145 | static const uint8_t SPLIT[16]; 146 | static const uint8_t JOIN[16]; 147 | 148 | bool deep(uint32_t half) const { 149 | return cells[(half>>1)|0xf] & (1<<(half&0x1f)); 150 | } 151 | void mark(uint32_t half) { 152 | cells[(half>>1)|0xf] |= (1<<(half&0x1f)); 153 | } 154 | void unmark(uint32_t half) { 155 | cells[(half>>1)|0xf] &= ~(1<<(half&0x1f)); 156 | } 157 | 158 | void extend_range(); 159 | 160 | uint16_t alloc_cell (); 161 | void free_cell (uint16_t cell); 162 | 163 | /** Join the cell this half is pointing to 164 | (in other words, flatten the half). */ 165 | bool join(uint32_t half) ; 166 | 167 | /** Make the half deep. */ 168 | void split(uint32_t half) ; 169 | 170 | static uint32_t split16to32(uint16_t half); 171 | static int join32to16(uint32_t cell); 172 | 173 | void map16 (uint16_t* target, bin64_t range); 174 | 175 | friend class iterator; 176 | #ifdef FRIEND_TEST 177 | FRIEND_TEST(BinsTest,Routines); 178 | #endif 179 | }; 180 | 181 | 182 | /** Iterates over bins; for deep halves, bin==half. 183 | For flat halves, bin is a range of bits in a half. 184 | Iterator may split cells if needed. 185 | Value is either undefined (deep cell, mixed cell) 186 | or FILLED/EMPTY. */ 187 | class iterator { 188 | public: // rm this 189 | binmap_t *host; 190 | uint32_t history[64]; 191 | uint32_t half; 192 | uint8_t layer_; 193 | bin64_t pos; // TODO: half[] layer bin 194 | public: 195 | iterator(binmap_t* host, bin64_t start=bin64_t(0,0), bool split=false); 196 | ~iterator(); 197 | bool deep () { return host->deep(half); } 198 | bool solid () { 199 | return !deep() && binmap_t::is_solid(host->halves[half]); 200 | } 201 | void sibling () { half^=1; pos=pos.sibling(); } 202 | bool end () { return half==1; } 203 | void to (bool right); 204 | void left() {to(0);} 205 | void right() {to(1);} 206 | /** Move to the next defined (non-deep, flat) cell. 207 | If solid==true, move to a solid (0xffff/0x0) cell. */ 208 | bin64_t next (bool stop_undeep=true, bool stop_solid=false, uint8_t stop_layer=0); 209 | bin64_t next_solid () { return next(false, true,0); } 210 | bin64_t bin() { return pos; } 211 | void towards(bin64_t bin) { 212 | bin64_t next = pos.towards(bin); 213 | assert(next!=bin64_t::NONE); 214 | to(next.is_right()); 215 | } 216 | void parent() ; 217 | bool defined() { return !host->deep(half); } 218 | uint16_t& operator* () { return host->halves[half]; } 219 | uint8_t layer() const { return layer_; } 220 | }; 221 | 222 | 223 | class binheap { 224 | bin64_t *heap_; 225 | uint32_t filled_; 226 | uint32_t size_; 227 | public: 228 | binheap(); 229 | bin64_t pop(); 230 | void push(bin64_t); 231 | bool empty() const { return !filled_; } 232 | void extend(); 233 | ~binheap(); 234 | }; 235 | 236 | 237 | #endif 238 | -------------------------------------------------------------------------------- /channel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * swift.cpp 3 | * serp++ 4 | * 5 | * Created by Victor Grishchenko on 3/6/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | #ifndef _WIN32 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #endif 19 | #include 20 | #include 21 | 22 | //#include 23 | #include "swift.h" 24 | #include "datagram.h" 25 | 26 | using namespace std; 27 | using namespace swift; 28 | 29 | swift::tint Channel::last_tick = 0; 30 | int Channel::MAX_REORDERING = 4; 31 | bool Channel::SELF_CONN_OK = false; 32 | swift::tint Channel::TIMEOUT = TINT_SEC*60; 33 | std::vector Channel::channels(1); 34 | Address Channel::tracker; 35 | tbheap Channel::send_queue; 36 | FILE* Channel::debug_file = NULL; 37 | #include "ext/simple_selector.cpp" 38 | PeerSelector* Channel::peer_selector = new SimpleSelector(); 39 | 40 | Channel::Channel (FileTransfer* transfer, int socket, Address peer_addr) : 41 | transfer_(transfer), peer_(peer_addr), peer_channel_id_(0), pex_out_(0), 42 | socket_(socket==INVALID_SOCKET?Datagram::default_socket():socket), // FIXME 43 | data_out_cap_(bin64_t::ALL), last_data_out_time_(0), last_data_in_time_(0), 44 | own_id_mentioned_(false), next_send_time_(0), last_send_time_(0), 45 | last_recv_time_(0), rtt_avg_(TINT_SEC), dev_avg_(0), dip_avg_(TINT_SEC), 46 | data_in_dbl_(bin64_t::NONE), hint_out_size_(0), 47 | cwnd_(1), send_interval_(TINT_SEC), send_control_(PING_PONG_CONTROL), 48 | sent_since_recv_(0), ack_rcvd_recent_(0), ack_not_rcvd_recent_(0), 49 | last_loss_time_(0), owd_min_bin_(0), owd_min_bin_start_(NOW), 50 | owd_cur_bin_(0), dgrams_sent_(0), dgrams_rcvd_(0), 51 | data_in_(TINT_NEVER,bin64_t::NONE) 52 | { 53 | if (peer_==Address()) 54 | peer_ = tracker; 55 | this->id_ = channels.size(); 56 | channels.push_back(this); 57 | transfer_->hs_in_.push_back(id_); 58 | for(int i=0; i<4; i++) { 59 | owd_min_bins_[i] = TINT_NEVER; 60 | owd_current_[i] = TINT_NEVER; 61 | } 62 | Reschedule(); 63 | dprintf("%s #%u init %s\n",tintstr(),id_,peer_.str()); 64 | } 65 | 66 | 67 | Channel::~Channel () { 68 | channels[id_] = NULL; 69 | } 70 | 71 | 72 | void swift::SetTracker(const Address& tracker) { 73 | Channel::tracker = tracker; 74 | } 75 | 76 | 77 | int Channel::DecodeID(int scrambled) { 78 | return scrambled ^ (int)Datagram::start; 79 | } 80 | int Channel::EncodeID(int unscrambled) { 81 | return unscrambled ^ (int)Datagram::start; 82 | } 83 | 84 | 85 | int swift::Listen (Address addr) { 86 | sckrwecb_t cb; 87 | cb.may_read = &Channel::RecvDatagram; 88 | cb.sock = Datagram::Bind(addr,cb); 89 | return cb.sock; 90 | } 91 | 92 | 93 | void swift::Shutdown (int sock_des) { 94 | Datagram::Shutdown(); 95 | } 96 | 97 | 98 | void swift::Loop (tint till) { 99 | Channel::Loop(till); 100 | } 101 | 102 | 103 | 104 | int swift::Open (const char* filename, const Sha1Hash& hash) { 105 | FileTransfer* ft = new FileTransfer(filename, hash); 106 | if (ft && ft->file().file_descriptor()) { 107 | 108 | /*if (FileTransfer::files.size()file().file_descriptor(); 117 | } else { 118 | if (ft) 119 | delete ft; 120 | return -1; 121 | } 122 | } 123 | 124 | 125 | void swift::Close (int fd) { 126 | if (fdAddPeer(address,root); 133 | } 134 | 135 | 136 | uint64_t swift::Size (int fdes) { 137 | if (FileTransfer::files.size()>fdes && FileTransfer::files[fdes]) 138 | return FileTransfer::files[fdes]->file().size(); 139 | else 140 | return 0; 141 | } 142 | 143 | 144 | bool swift::IsComplete (int fdes) { 145 | if (FileTransfer::files.size()>fdes && FileTransfer::files[fdes]) 146 | return FileTransfer::files[fdes]->file().is_complete(); 147 | else 148 | return 0; 149 | } 150 | 151 | 152 | uint64_t swift::Complete (int fdes) { 153 | if (FileTransfer::files.size()>fdes && FileTransfer::files[fdes]) 154 | return FileTransfer::files[fdes]->file().complete(); 155 | else 156 | return 0; 157 | } 158 | 159 | 160 | uint64_t swift::SeqComplete (int fdes) { 161 | if (FileTransfer::files.size()>fdes && FileTransfer::files[fdes]) 162 | return FileTransfer::files[fdes]->file().seq_complete(); 163 | else 164 | return 0; 165 | } 166 | 167 | 168 | const Sha1Hash& swift::RootMerkleHash (int file) { 169 | FileTransfer* trans = FileTransfer::file(file); 170 | if (!trans) 171 | return Sha1Hash::ZERO; 172 | return trans->file().root_hash(); 173 | } 174 | 175 | 176 | /**

swift handshake

177 | Basic rules: 178 |
    179 |
  • to send a datagram, a channel must be created 180 | (channels are cheap and easily recycled) 181 |
  • a datagram must contain either the receiving 182 | channel id (scrambled) or the root hash 183 |
184 | Note: 185 | */ 186 | -------------------------------------------------------------------------------- /compat.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * compat.cpp 3 | * swift 4 | * 5 | * Created by Arno Bakker, Victor Grishchenko 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | 10 | #include "compat.h" 11 | #include 12 | #include 13 | #include 14 | #ifdef _WIN32 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #else 21 | #include 22 | #include 23 | #endif 24 | 25 | namespace swift { 26 | 27 | #ifdef _WIN32 28 | static HANDLE map_handles[1024]; 29 | #endif 30 | 31 | size_t file_size (int fd) { 32 | struct stat st; 33 | fstat(fd, &st); 34 | return st.st_size; 35 | } 36 | 37 | int file_seek (int fd, size_t offset) { 38 | #ifndef _WIN32 39 | return lseek(fd,offset,SEEK_SET); 40 | #else 41 | return _lseek(fd,offset,SEEK_SET); 42 | #endif 43 | } 44 | 45 | int file_resize (int fd, size_t new_size) { 46 | #ifndef _WIN32 47 | return ftruncate(fd, new_size); 48 | #else 49 | return _chsize(fd,new_size); 50 | #endif 51 | } 52 | 53 | void print_error(const char* msg) { 54 | perror(msg); 55 | #ifdef _WIN32 56 | int e = WSAGetLastError(); 57 | if (e) 58 | fprintf(stderr,"network error #%u\n",e); 59 | #endif 60 | } 61 | 62 | void* memory_map (int fd, size_t size) { 63 | if (!size) 64 | size = file_size(fd); 65 | void *mapping; 66 | #ifndef _WIN32 67 | mapping = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 68 | if (mapping==MAP_FAILED) 69 | return NULL; 70 | return mapping; 71 | #else 72 | HANDLE fhandle = (HANDLE)_get_osfhandle(fd); 73 | assert(fd<1024); 74 | HANDLE maphandle = CreateFileMapping( fhandle, 75 | NULL, 76 | PAGE_READWRITE, 77 | 0, 78 | 0, 79 | NULL ); 80 | if (maphandle == NULL) 81 | return NULL; 82 | map_handles[fd] = maphandle; 83 | 84 | mapping = MapViewOfFile ( maphandle, 85 | FILE_MAP_WRITE, 86 | 0, 87 | 0, 88 | 0 ); 89 | 90 | return mapping; 91 | #endif 92 | } 93 | 94 | void memory_unmap (int fd, void* mapping, size_t size) { 95 | #ifndef _WIN32 96 | munmap(mapping,size); 97 | close(fd); 98 | #else 99 | UnmapViewOfFile(mapping); 100 | CloseHandle(map_handles[fd]); 101 | #endif 102 | } 103 | 104 | #ifdef _WIN32 105 | 106 | size_t pread(int fildes, void *buf, size_t nbyte, long offset) 107 | { 108 | _lseek(fildes,offset,SEEK_SET); 109 | return read(fildes,buf,nbyte); 110 | } 111 | 112 | size_t pwrite(int fildes, const void *buf, size_t nbyte, long offset) 113 | { 114 | _lseek(fildes,offset,SEEK_SET); 115 | return write(fildes,buf,nbyte); 116 | } 117 | 118 | 119 | int inet_aton(const char *cp, struct in_addr *inp) 120 | { 121 | inp->S_un.S_addr = inet_addr(cp); 122 | return 1; 123 | } 124 | 125 | #endif 126 | 127 | #ifdef _WIN32 128 | 129 | LARGE_INTEGER get_freq() { 130 | LARGE_INTEGER proc_freq; 131 | if (!::QueryPerformanceFrequency(&proc_freq)) 132 | print_error("HiResTimeOfDay: QueryPerformanceFrequency() failed"); 133 | return proc_freq; 134 | } 135 | 136 | tint usec_time(void) 137 | { 138 | static LARGE_INTEGER last_time; 139 | LARGE_INTEGER cur_time; 140 | QueryPerformanceCounter(&cur_time); 141 | if (cur_time.QuadPart tempPath(result + 1); 186 | result = ::GetTempPath(static_cast(tempPath.size()), &tempPath[0]); 187 | if((result == 0) || (result >= tempPath.size())) 188 | throw std::runtime_error("Could not get system temp path"); 189 | 190 | return std::string(tempPath.begin(), tempPath.begin() + static_cast(result)); 191 | #else 192 | return std::string("/tmp/"); 193 | #endif 194 | } 195 | 196 | bool make_socket_nonblocking(SOCKET fd) { 197 | #ifdef _WIN32 198 | u_long enable = 1; 199 | return 0==ioctlsocket(fd, FIONBIO, &enable); 200 | #else 201 | int enable=1; 202 | return 0==fcntl(fd, F_SETFL, O_NONBLOCK); 203 | #endif 204 | } 205 | 206 | bool close_socket (SOCKET sock) { 207 | #ifdef _WIN32 208 | return 0==closesocket(sock); 209 | #else 210 | return 0==::close(sock); 211 | #endif 212 | } 213 | 214 | 215 | } 216 | -------------------------------------------------------------------------------- /compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * compat.h 3 | * compatibility wrappers 4 | * 5 | * Created by Arno Bakker, Victor Grishchenko 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #ifndef SWIFT_COMPAT_H 10 | #define SWIFT_COMPAT_H 11 | 12 | #ifdef _MSC_VER 13 | typedef unsigned char uint8_t; 14 | typedef signed char int8_t; 15 | typedef unsigned short uint16_t; 16 | typedef short int16_t; 17 | typedef unsigned int uint32_t; 18 | typedef int int32_t; 19 | typedef __int64 int64_t; 20 | typedef unsigned __int64 uint64_t; 21 | #else 22 | #include 23 | #endif 24 | 25 | #ifdef _WIN32 26 | #include 27 | #include 28 | #include 29 | #else 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #endif 36 | 37 | #ifndef _WIN32 38 | typedef int SOCKET; 39 | #endif 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #ifdef _MSC_VER 48 | #include "getopt_win.h" 49 | #else 50 | #include 51 | #endif 52 | 53 | #ifdef _WIN32 54 | #define open(a,b,c) _open(a,b,c) 55 | #endif 56 | #ifndef S_IRUSR 57 | #define S_IRUSR _S_IREAD 58 | #endif 59 | #ifndef S_IWUSR 60 | #define S_IWUSR _S_IWRITE 61 | #endif 62 | #ifndef S_IRGRP 63 | #define S_IRGRP _S_IREAD 64 | #endif 65 | #ifndef S_IROTH 66 | #define S_IROTH _S_IREAD 67 | #endif 68 | 69 | #ifdef _WIN32 70 | #define setsockoptptr_t (char*) 71 | #else 72 | #define setsockoptptr_t void* 73 | #endif 74 | 75 | 76 | namespace swift { 77 | 78 | /** tint is the time integer type; microsecond-precise. */ 79 | typedef int64_t tint; 80 | #define TINT_HOUR ((tint)1000000*60*60) 81 | #define TINT_MIN ((tint)1000000*60) 82 | #define TINT_SEC ((tint)1000000) 83 | #define TINT_MSEC ((tint)1000) 84 | #define TINT_uSEC ((tint)1) 85 | #define TINT_NEVER ((tint)0x3fffffffffffffffLL) 86 | 87 | 88 | size_t file_size (int fd); 89 | 90 | int file_seek (int fd, size_t offset); 91 | 92 | int file_resize (int fd, size_t new_size); 93 | 94 | void* memory_map (int fd, size_t size=0); 95 | void memory_unmap (int fd, void*, size_t size); 96 | 97 | void print_error (const char* msg); 98 | 99 | #ifdef _WIN32 100 | 101 | /** UNIX pread approximation. Does change file pointer. Is not thread-safe */ 102 | size_t pread(int fildes, void *buf, size_t nbyte, long offset); 103 | 104 | /** UNIX pwrite approximation. Does change file pointer. Is not thread-safe */ 105 | size_t pwrite(int fildes, const void *buf, size_t nbyte, long offset); 106 | 107 | int inet_aton(const char *cp, struct in_addr *inp); 108 | 109 | #endif 110 | 111 | std::string gettmpdir(void); 112 | 113 | tint usec_time (); 114 | 115 | bool make_socket_nonblocking(SOCKET s); 116 | 117 | bool close_socket (SOCKET sock); 118 | 119 | 120 | }; 121 | 122 | #endif 123 | 124 | -------------------------------------------------------------------------------- /datagram.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * datagram.cpp 3 | * serp++ 4 | * 5 | * Created by Victor Grishchenko, Arno Bakker on 3/9/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include 10 | 11 | #ifdef _WIN32 12 | #include 13 | typedef int socklen_t; 14 | #else 15 | #include 16 | #include 17 | #endif 18 | 19 | #include "datagram.h" 20 | #include "compat.h" 21 | 22 | namespace swift { 23 | 24 | tint Datagram::now = Datagram::Time(); 25 | tint Datagram::start = now; 26 | tint Datagram::epoch = now/360000000LL*360000000LL; // make logs mergeable 27 | uint32_t Address::LOCALHOST = INADDR_LOOPBACK; 28 | uint64_t Datagram::dgrams_up=0, Datagram::dgrams_down=0, 29 | Datagram::bytes_up=0, Datagram::bytes_down=0; 30 | sckrwecb_t Datagram::sock_open[] = {}; 31 | int Datagram::sock_count = 0; 32 | 33 | const char* tintstr (tint time) { 34 | if (time==0) 35 | time = Datagram::now; 36 | static char ret_str[4][32]; // wow 37 | static int i; 38 | i = (i+1) & 3; 39 | if (time==TINT_NEVER) 40 | return "NEVER"; 41 | time -= Datagram::epoch; 42 | assert(time>=0); 43 | int hours = time/TINT_HOUR; 44 | time %= TINT_HOUR; 45 | int mins = time/TINT_MIN; 46 | time %= TINT_MIN; 47 | int secs = time/TINT_SEC; 48 | time %= TINT_SEC; 49 | int msecs = time/TINT_MSEC; 50 | time %= TINT_MSEC; 51 | int usecs = time/TINT_uSEC; 52 | sprintf(ret_str[i],"%i_%02i_%02i_%03i_%03i",hours,mins,secs,msecs,usecs); 53 | return ret_str[i]; 54 | } 55 | 56 | void Address::set_ipv4 (const char* ip_str) { 57 | struct hostent *h = gethostbyname(ip_str); 58 | if (h == NULL) { 59 | print_error("cannot lookup address"); 60 | return; 61 | } else { 62 | addr.sin_addr.s_addr = *(u_long *) h->h_addr_list[0]; 63 | } 64 | } 65 | 66 | 67 | Address::Address(const char* ip_port) { 68 | clear(); 69 | if (strlen(ip_port)>=1024) 70 | return; 71 | char ipp[1024]; 72 | strncpy(ipp,ip_port,1024); 73 | char* semi = strchr(ipp,':'); 74 | if (semi) { 75 | *semi = 0; 76 | set_ipv4(ipp); 77 | set_port(semi+1); 78 | } else { 79 | if (strchr(ipp, '.')) { 80 | set_ipv4(ipp); 81 | set_port((uint16_t)0); 82 | } else { 83 | set_ipv4(INADDR_LOOPBACK); 84 | set_port(ipp); 85 | } 86 | } 87 | } 88 | 89 | 90 | bool Datagram::Listen3rdPartySocket (sckrwecb_t cb) { 91 | int i=0; 92 | while (imax_sock_fd) 157 | max_sock_fd = sock_open[i].sock; 158 | } 159 | SOCKET sel = select(max_sock_fd+1, &rdfd, &wrfd, &errfd, &timeout); 160 | Time(); 161 | if (sel>0) { 162 | for (int i=0; i<=sock_count; i++) { 163 | sckrwecb_t& sct = sock_open[i]; 164 | if (sct.may_read && FD_ISSET(sct.sock,&rdfd)) 165 | (*(sct.may_read))(sct.sock); 166 | if (sct.may_write && FD_ISSET(sct.sock,&wrfd)) 167 | (*(sct.may_write))(sct.sock); 168 | if (sct.on_error && FD_ISSET(sct.sock,&errfd)) 169 | (*(sct.on_error))(sct.sock); 170 | } 171 | } else if (sel<0) { 172 | print_error("select fails"); 173 | } 174 | return sel; 175 | } 176 | 177 | tint Datagram::Time () { 178 | //HiResTimeOfDay* tod = HiResTimeOfDay::Instance(); 179 | //tint ret = tod->getTimeUSec(); 180 | //DLOG(INFO)<<"now is "<= 0 ); 191 | dbnd_ensure( make_socket_nonblocking(fd) ); // FIXME may remove this 192 | int enable = true; 193 | dbnd_ensure ( setsockopt(fd, SOL_SOCKET, SO_SNDBUF, 194 | (setsockoptptr_t)&sndbuf, sizeof(int)) == 0 ); 195 | dbnd_ensure ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, 196 | (setsockoptptr_t)&rcvbuf, sizeof(int)) == 0 ); 197 | //setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (setsockoptptr_t)&enable, sizeof(int)); 198 | dbnd_ensure ( ::bind(fd, (sockaddr*)&addr, len) == 0 ); 199 | callbacks.sock = fd; 200 | Datagram::sock_open[Datagram::sock_count++] = callbacks; 201 | return fd; 202 | } 203 | 204 | void Datagram::Close (SOCKET sock) { 205 | for(int i=0; i 13 | #include 14 | #include "hashtree.h" 15 | #include "compat.h" 16 | 17 | 18 | namespace swift { 19 | 20 | #define MAXDGRAMSZ 2800 21 | #ifndef _WIN32 22 | #define INVALID_SOCKET -1 23 | #endif 24 | 25 | 26 | /** IPv4 address, just a nice wrapping around struct sockaddr_in. */ 27 | struct Address { 28 | struct sockaddr_in addr; 29 | static uint32_t LOCALHOST; 30 | void set_port (uint16_t port) { 31 | addr.sin_port = htons(port); 32 | } 33 | void set_port (const char* port_str) { 34 | int p; 35 | if (sscanf(port_str,"%i",&p)) 36 | set_port(p); 37 | } 38 | void set_ipv4 (uint32_t ipv4) { 39 | addr.sin_addr.s_addr = htonl(ipv4); 40 | } 41 | void set_ipv4 (const char* ipv4_str) ; 42 | //{ inet_aton(ipv4_str,&(addr.sin_addr)); } 43 | void clear () { 44 | memset(&addr,0,sizeof(struct sockaddr_in)); 45 | addr.sin_family = AF_INET; 46 | } 47 | Address() { 48 | clear(); 49 | } 50 | Address(const char* ip, uint16_t port) { 51 | clear(); 52 | set_ipv4(ip); 53 | set_port(port); 54 | } 55 | Address(const char* ip_port); 56 | Address(uint16_t port) { 57 | clear(); 58 | set_ipv4((uint32_t)INADDR_ANY); 59 | set_port(port); 60 | } 61 | Address(uint32_t ipv4addr, uint16_t port) { 62 | clear(); 63 | set_ipv4(ipv4addr); 64 | set_port(port); 65 | } 66 | Address(const struct sockaddr_in& address) : addr(address) {} 67 | uint32_t ipv4 () const { return ntohl(addr.sin_addr.s_addr); } 68 | uint16_t port () const { return ntohs(addr.sin_port); } 69 | operator sockaddr_in () const {return addr;} 70 | bool operator == (const Address& b) const { 71 | return addr.sin_family==b.addr.sin_family && 72 | addr.sin_port==b.addr.sin_port && 73 | addr.sin_addr.s_addr==b.addr.sin_addr.s_addr; 74 | } 75 | const char* str () const { 76 | static char rs[4][32]; 77 | static int i; 78 | i = (i+1) & 3; 79 | sprintf(rs[i],"%i.%i.%i.%i:%i",ipv4()>>24,(ipv4()>>16)&0xff, 80 | (ipv4()>>8)&0xff,ipv4()&0xff,port()); 81 | return rs[i]; 82 | } 83 | bool operator != (const Address& b) const { return !(*this==b); } 84 | }; 85 | 86 | 87 | typedef void (*sockcb_t) (SOCKET); 88 | struct sckrwecb_t { 89 | sckrwecb_t (SOCKET s=0, sockcb_t mr=NULL, sockcb_t mw=NULL, sockcb_t oe=NULL) : 90 | sock(s), may_read(mr), may_write(mw), on_error(oe) {} 91 | SOCKET sock; 92 | sockcb_t may_read; 93 | sockcb_t may_write; 94 | sockcb_t on_error; 95 | }; 96 | 97 | 98 | /** UDP datagram class, a nice wrapping around sendto/recvfrom/select. 99 | Reading/writing from/to a datagram is done in a FIFO (deque) fashion: 100 | written data is appended to the tail (push) while read data is 101 | taken from the "head" of the buffer. */ 102 | class Datagram { 103 | 104 | Address addr; 105 | SOCKET sock; 106 | int offset, length; 107 | uint8_t buf[MAXDGRAMSZ*2]; 108 | 109 | #define DGRAM_MAX_SOCK_OPEN 128 110 | static int sock_count; 111 | static sckrwecb_t sock_open[DGRAM_MAX_SOCK_OPEN]; 112 | 113 | public: 114 | 115 | /** bind to the address */ 116 | static SOCKET Bind(Address address, sckrwecb_t callbacks=sckrwecb_t()); 117 | 118 | /** close the port */ 119 | static void Close(SOCKET sock); 120 | 121 | /** the current time */ 122 | static tint Time(); 123 | 124 | /** wait till one of the sockets has some io to do; usec is the timeout */ 125 | static SOCKET Wait (tint usec); 126 | 127 | static bool Listen3rdPartySocket (sckrwecb_t cb) ; 128 | 129 | static void Shutdown (); 130 | 131 | static SOCKET default_socket() 132 | { return sock_count ? sock_open[0].sock : INVALID_SOCKET; } 133 | 134 | static tint now, epoch, start; 135 | static uint64_t dgrams_up, dgrams_down, bytes_up, bytes_down; 136 | 137 | /** This constructor is normally used to SEND something to the address. */ 138 | Datagram (SOCKET socket, const Address addr_) : addr(addr_), offset(0), 139 | length(0), sock(socket) {} 140 | /** This constructor is normally used to RECEIVE something at the socket. */ 141 | Datagram (SOCKET socket) : offset(0), length(0), sock(socket) { 142 | } 143 | 144 | /** space remaining */ 145 | int space () const { return MAXDGRAMSZ-length; } 146 | /** size of the data (not counting UDP etc headers) */ 147 | int size() const { return length-offset; } 148 | std::string str() const { return std::string((char*)buf+offset,size()); } 149 | const uint8_t* operator * () const { return buf+offset; } 150 | const Address& address () const { return addr; } 151 | /** Append some data at the back */ 152 | int Push (const uint8_t* data, int l) { // scatter-gather one day 153 | int toc = l>32)); 188 | *(uint32_t*)(buf+length+4) = htonl((uint32_t)(l&0xffffffff)); 189 | length+=8; 190 | } 191 | void PushHash (const Sha1Hash& hash) { 192 | Push((uint8_t*)hash.bits, Sha1Hash::SIZE); 193 | } 194 | 195 | uint8_t Pull8() { 196 | if (size()<1) return 0; 197 | return buf[offset++]; 198 | } 199 | uint16_t Pull16() { 200 | if (size()<2) return 0; 201 | offset+=2; 202 | return ntohs(*(uint16_t*)(buf+offset-2)); 203 | } 204 | uint32_t Pull32() { 205 | if (size()<4) return 0; 206 | uint32_t i = ntohl(*(uint32_t*)(buf+offset)); 207 | offset+=4; 208 | return i; 209 | } 210 | uint64_t Pull64() { 211 | if (size()<8) return 0; 212 | uint64_t l = ntohl(*(uint32_t*)(buf+offset)); 213 | l<<=32; 214 | l |= ntohl(*(uint32_t*)(buf+offset+4)); 215 | offset+=8; 216 | return l; 217 | } 218 | Sha1Hash PullHash() { 219 | if (size() div { 15 | width: 60em; 16 | margin: auto; 17 | margin-top: 64px; 18 | margin-bottom: 64px; 19 | /*background: #d0e0ff;*/ 20 | background: rgba(208,224,255,0.9); 21 | padding-top: 16px; 22 | padding-bottom: 16px; 23 | } 24 | 25 | img#logo { 26 | /*display: block; 27 | margin-left: auto; 28 | margin-right: auto; 29 | position: relative; 30 | top: -40px;*/ 31 | position:absolute; 32 | top: 4px; 33 | } 34 | 35 | body > div > h1 { 36 | text-align:center; 37 | } 38 | 39 | body > div > div { 40 | width: 90%; 41 | margin: auto; 42 | } 43 | 44 | div#motto { 45 | text-align: right; 46 | font-style: italic; 47 | font-size: larger; 48 | margin-bottom: 28pt; 49 | } 50 | 51 | div#abstract { 52 | letter-spacing: 0.06em; 53 | /*font-size: larger;*/ 54 | font-style: italic; 55 | font-family: Georgia; 56 | } 57 | 58 | div.fold>h2, div.fold>h3, div.fold>h4 { 59 | cursor: pointer; 60 | } 61 | 62 | [bullet='open']:before { 63 | content: "⊟ "; 64 | } 65 | 66 | [bullet='closed']:before { 67 | content: "⊞ "; 68 | } 69 | -------------------------------------------------------------------------------- /doc/swift.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: Georgia, serif; 3 | } 4 | 5 | a { 6 | text-decoration: none; 7 | } 8 | 9 | img#logo { 10 | position:absolute; 11 | top: 40px; 12 | } 13 | 14 | a:hover { 15 | text-decoration: underline; 16 | } 17 | 18 | body { 19 | background: #A3CDEA; 20 | margin: 0; 21 | padding: 0px; 22 | } 23 | 24 | h1, h2, h3, h4 { 25 | font-family: Trebuchet MS, Arial, sans-serif; 26 | padding: 0; 27 | } 28 | 29 | h1 { 30 | color: #000; 31 | font-size: 200%; 32 | font-weight: bold; 33 | margin: 0; 34 | } 35 | 36 | h2 { 37 | border-top: 1px dotted #aaa; 38 | font-size: 150%; 39 | margin: 30px 0 10px 0; 40 | padding: 20px 0 0 0; 41 | } 42 | 43 | div > h2:first-child { 44 | border-top: none; 45 | margin: 0 0 10px 0; 46 | padding: 0; 47 | } 48 | 49 | h3 { 50 | font-weight: normal; 51 | margin: 30px 0 10px 0; 52 | } 53 | 54 | h4 { 55 | font-size: 90%; 56 | font-weight: bold; 57 | margin: 20px 0 10px 0; 58 | } 59 | 60 | 61 | li { 62 | font-size: 12px; 63 | line-height: 1.5em; 64 | } 65 | 66 | p { 67 | font-size: 12px; 68 | line-height: 1.5em; 69 | } 70 | 71 | ul { 72 | list-style: square; 73 | margin: 0; 74 | padding: 0 0 0 15px; 75 | } 76 | 77 | 78 | 79 | div#container { 80 | margin: 0 auto 0 auto; 81 | width: 700px; 82 | } 83 | 84 | div#header { 85 | font: 32pt Verdana bold; 86 | color: white; 87 | background: #44a; 88 | padding: 5px 30px 15px 0; 89 | text-align: center; 90 | } 91 | 92 | div#header img { 93 | vertical-align: middle; 94 | } 95 | 96 | div#intro { 97 | background: #fff; 98 | border-bottom: 1px dotted #aaa; 99 | padding: 25px 20px 10px 20px; 100 | } 101 | 102 | div#intro p { 103 | font-size: 16px; 104 | } 105 | 106 | div#content { 107 | background: #f6f6f6; 108 | border-bottom: 1px solid black; 109 | padding: 20px 20px 20px 20px; 110 | } 111 | 112 | div#contact { 113 | background: #fff; 114 | padding: 20px 20px 20px 20px; 115 | } 116 | 117 | div#footer { 118 | background: #444; 119 | color: #aaa; 120 | padding: 20px 20px 20px 20px; 121 | } 122 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/AUTHORS: -------------------------------------------------------------------------------- 1 | Author : 2 | Andrew Keating 3 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | # 3 | # $Id: CMakeLists.txt 31995 2010-02-24 22:32:10Z jmayer $ 4 | # 5 | # Wireshark - Network traffic analyzer 6 | # By Gerald Combs 7 | # Copyright 1998 Gerald Combs 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the GNU General Public License 11 | # as published by the Free Software Foundation; either version 2 12 | # of the License, or (at your option) any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program; if not, write to the Free Software 21 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 22 | # 23 | 24 | set(DISSECTOR_SRC 25 | packet-swift.c 26 | ) 27 | 28 | set(PLUGIN_FILES 29 | plugin.c 30 | ${DISSECTOR_SRC} 31 | ) 32 | 33 | set(CLEAN_FILES 34 | ${PLUGIN_FILES} 35 | ) 36 | 37 | if (WERROR) 38 | set_source_files_properties( 39 | ${CLEAN_FILES} 40 | PROPERTIES 41 | COMPILE_FLAGS -Werror 42 | ) 43 | endif() 44 | 45 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 46 | 47 | register_dissector_files(plugin.c 48 | plugin 49 | ${DISSECTOR_SRC} 50 | ) 51 | 52 | add_library(swift ${LINK_MODE_MODULE} 53 | ${PLUGIN_FILES} 54 | ) 55 | set_target_properties(swift PROPERTIES PREFIX "") 56 | set_target_properties(swift PROPERTIES SOVERSION ${CPACK_PACKAGE_VERSION}) 57 | set_target_properties(swift PROPERTIES LINK_FLAGS ${WS_LINK_FLAGS}) 58 | 59 | target_link_libraries(swift epan) 60 | 61 | install(TARGETS swift 62 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/@CPACK_PACKAGE_NAME@/plugins/${CPACK_PACKAGE_VERSION} NAMELINK_SKIP 63 | RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/@CPACK_PACKAGE_NAME@/plugins/${CPACK_PACKAGE_VERSION} 64 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/@CPACK_PACKAGE_NAME@/plugins/${CPACK_PACKAGE_VERSION} 65 | ) 66 | 67 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gritzko/swift/da6809ab9fb95117c973f914fe01c6bacf153eb0/doc/wireshark-dissector/ChangeLog -------------------------------------------------------------------------------- /doc/wireshark-dissector/Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile.am 2 | # Automake file for swift plugin 3 | # By Andrew Keating 4 | # Copyright 2011 Andrew Keating 5 | # 6 | # $Id$ 7 | # 8 | # Wireshark - Network traffic analyzer 9 | # By Gerald Combs 10 | # Copyright 1998 Gerald Combs 11 | # 12 | # This program is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU General Public License 14 | # as published by the Free Software Foundation; either version 2 15 | # of the License, or (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program; if not, write to the Free Software 24 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 25 | # 26 | 27 | INCLUDES = -I$(top_srcdir) -I$(includedir) 28 | 29 | include Makefile.common 30 | 31 | if HAVE_WARNINGS_AS_ERRORS 32 | AM_CFLAGS = -Werror 33 | endif 34 | 35 | plugindir = @plugindir@ 36 | 37 | plugin_LTLIBRARIES = swift.la 38 | swift_la_SOURCES = \ 39 | plugin.c \ 40 | moduleinfo.h \ 41 | $(DISSECTOR_SRC) \ 42 | $(DISSECTOR_SUPPORT_SRC) \ 43 | $(DISSECTOR_INCLUDES) 44 | swift_la_LDFLAGS = -module -avoid-version 45 | swift_la_LIBADD = @PLUGIN_LIBS@ 46 | 47 | # Libs must be cleared, or else libtool won't create a shared module. 48 | # If your module needs to be linked against any particular libraries, 49 | # add them here. 50 | LIBS = 51 | 52 | # 53 | # Build plugin.c, which contains the plugin version[] string, a 54 | # function plugin_register() that calls the register routines for all 55 | # protocols, and a function plugin_reg_handoff() that calls the handoff 56 | # registration routines for all protocols. 57 | # 58 | # We do this by scanning sources. If that turns out to be too slow, 59 | # maybe we could just require every .o file to have an register routine 60 | # of a given name (packet-aarp.o -> proto_register_aarp, etc.). 61 | # 62 | # Formatting conventions: The name of the proto_register_* routines an 63 | # proto_reg_handoff_* routines must start in column zero, or must be 64 | # preceded only by "void " starting in column zero, and must not be 65 | # inside #if. 66 | # 67 | # DISSECTOR_SRC is assumed to have all the files that need to be scanned. 68 | # 69 | # For some unknown reason, having a big "for" loop in the Makefile 70 | # to scan all the files doesn't work with some "make"s; they seem to 71 | # pass only the first few names in the list to the shell, for some 72 | # reason. 73 | # 74 | # Therefore, we have a script to generate the plugin.c file. 75 | # The shell script runs slowly, as multiple greps and seds are run 76 | # for each input file; this is especially slow on Windows. Therefore, 77 | # if Python is present (as indicated by PYTHON being defined), we run 78 | # a faster Python script to do that work instead. 79 | # 80 | # The first argument is the directory in which the source files live. 81 | # The second argument is "plugin", to indicate that we should build 82 | # a plugin.c file for a plugin. 83 | # All subsequent arguments are the files to scan. 84 | # 85 | plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \ 86 | $(top_srcdir)/tools/make-dissector-reg.py 87 | @if test -n "$(PYTHON)"; then \ 88 | echo Making plugin.c with python ; \ 89 | $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ 90 | plugin $(DISSECTOR_SRC) ; \ 91 | else \ 92 | echo Making plugin.c with shell script ; \ 93 | $(top_srcdir)/tools/make-dissector-reg $(srcdir) \ 94 | $(plugin_src) plugin $(DISSECTOR_SRC) ; \ 95 | fi 96 | 97 | # 98 | # Currently plugin.c can be included in the distribution because 99 | # we always build all protocol dissectors. We used to have to check 100 | # whether or not to build the snmp dissector. If we again need to 101 | # variably build something, making plugin.c non-portable, uncomment 102 | # the dist-hook line below. 103 | # 104 | # Oh, yuk. We don't want to include "plugin.c" in the distribution, as 105 | # its contents depend on the configuration, and therefore we want it 106 | # to be built when the first "make" is done; however, Automake insists 107 | # on putting *all* source into the distribution. 108 | # 109 | # We work around this by having a "dist-hook" rule that deletes 110 | # "plugin.c", so that "dist" won't pick it up. 111 | # 112 | #dist-hook: 113 | # @rm -f $(distdir)/plugin.c 114 | 115 | CLEANFILES = \ 116 | swift \ 117 | *~ 118 | 119 | MAINTAINERCLEANFILES = \ 120 | Makefile.in \ 121 | plugin.c 122 | 123 | EXTRA_DIST = \ 124 | Makefile.common \ 125 | Makefile.nmake \ 126 | moduleinfo.nmake \ 127 | plugin.rc.in \ 128 | CMakeLists.txt 129 | 130 | checkapi: 131 | $(PERL) $(top_srcdir)/tools/checkAPIs.pl -g abort -g termoutput $(DISSECTOR_SRC) $(DISSECTOR_INCLUDES) 132 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/Makefile.common: -------------------------------------------------------------------------------- 1 | # Makefile.common for Interlink plugin 2 | # Contains the stuff from Makefile.am and Makefile.nmake that is 3 | # a) common to both files and 4 | # b) portable between both files 5 | # 6 | # $Id$ 7 | # 8 | # Wireshark - Network traffic analyzer 9 | # By Gerald Combs 10 | # Copyright 1998 Gerald Combs 11 | # 12 | # This program is free software; you can redistribute it and/or 13 | # modify it under the terms of the GNU General Public License 14 | # as published by the Free Software Foundation; either version 2 15 | # of the License, or (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program; if not, write to the Free Software 24 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 25 | 26 | # the name of the plugin 27 | PLUGIN_NAME = swift 28 | 29 | # the dissector sources (without any helpers) 30 | DISSECTOR_SRC = \ 31 | packet-swift.c 32 | 33 | # Dissector helpers. They're included in the source files in this 34 | # directory, but they're not dissectors themselves, i.e. they're not 35 | # used to generate "plugin.c". 36 | DISSECTOR_SUPPORT_SRC = 37 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/Makefile.nmake: -------------------------------------------------------------------------------- 1 | # Makefile.nmake 2 | # nmake file for Wireshark plugin 3 | # 4 | # $Id: Makefile.nmake 29883 2009-09-13 19:48:22Z morriss $ 5 | # 6 | 7 | include ..\..\config.nmake 8 | include moduleinfo.nmake 9 | 10 | include Makefile.common 11 | 12 | CFLAGS=/WX /DHAVE_CONFIG_H /I../.. $(GLIB_CFLAGS) \ 13 | /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS) 14 | 15 | .c.obj:: 16 | $(CC) $(CFLAGS) -Fd.\ -c $< 17 | 18 | LDFLAGS = $(PLUGIN_LDFLAGS) 19 | 20 | !IFDEF ENABLE_LIBWIRESHARK 21 | LINK_PLUGIN_WITH=..\..\epan\libwireshark.lib 22 | CFLAGS=/D_NEED_VAR_IMPORT_ $(CFLAGS) 23 | 24 | DISSECTOR_OBJECTS = $(DISSECTOR_SRC:.c=.obj) 25 | 26 | DISSECTOR_SUPPORT_OBJECTS = $(DISSECTOR_SUPPORT_SRC:.c=.obj) 27 | 28 | OBJECTS = $(DISSECTOR_OBJECTS) $(DISSECTOR_SUPPORT_OBJECTS) plugin.obj 29 | 30 | RESOURCE=$(PLUGIN_NAME).res 31 | 32 | all: $(PLUGIN_NAME).dll 33 | 34 | $(PLUGIN_NAME).rc : moduleinfo.nmake 35 | sed -e s/@PLUGIN_NAME@/$(PLUGIN_NAME)/ \ 36 | -e s/@RC_MODULE_VERSION@/$(RC_MODULE_VERSION)/ \ 37 | -e s/@RC_VERSION@/$(RC_VERSION)/ \ 38 | -e s/@MODULE_VERSION@/$(MODULE_VERSION)/ \ 39 | -e s/@PACKAGE@/$(PACKAGE)/ \ 40 | -e s/@VERSION@/$(VERSION)/ \ 41 | -e s/@MSVC_VARIANT@/$(MSVC_VARIANT)/ \ 42 | < plugin.rc.in > $@ 43 | 44 | $(PLUGIN_NAME).dll $(PLUGIN_NAME).exp $(PLUGIN_NAME).lib : $(OBJECTS) $(LINK_PLUGIN_WITH) $(RESOURCE) 45 | link -dll /out:$(PLUGIN_NAME).dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \ 46 | $(GLIB_LIBS) $(RESOURCE) 47 | 48 | # 49 | # Build plugin.c, which contains the plugin version[] string, a 50 | # function plugin_register() that calls the register routines for all 51 | # protocols, and a function plugin_reg_handoff() that calls the handoff 52 | # registration routines for all protocols. 53 | # 54 | # We do this by scanning sources. If that turns out to be too slow, 55 | # maybe we could just require every .o file to have an register routine 56 | # of a given name (packet-aarp.o -> proto_register_aarp, etc.). 57 | # 58 | # Formatting conventions: The name of the proto_register_* routines an 59 | # proto_reg_handoff_* routines must start in column zero, or must be 60 | # preceded only by "void " starting in column zero, and must not be 61 | # inside #if. 62 | # 63 | # DISSECTOR_SRC is assumed to have all the files that need to be scanned. 64 | # 65 | # For some unknown reason, having a big "for" loop in the Makefile 66 | # to scan all the files doesn't work with some "make"s; they seem to 67 | # pass only the first few names in the list to the shell, for some 68 | # reason. 69 | # 70 | # Therefore, we have a script to generate the plugin.c file. 71 | # The shell script runs slowly, as multiple greps and seds are run 72 | # for each input file; this is especially slow on Windows. Therefore, 73 | # if Python is present (as indicated by PYTHON being defined), we run 74 | # a faster Python script to do that work instead. 75 | # 76 | # The first argument is the directory in which the source files live. 77 | # The second argument is "plugin", to indicate that we should build 78 | # a plugin.c file for a plugin. 79 | # All subsequent arguments are the files to scan. 80 | # 81 | !IFDEF PYTHON 82 | plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg.py 83 | @echo Making plugin.c (using python) 84 | @$(PYTHON) "../../tools/make-dissector-reg.py" . plugin $(DISSECTOR_SRC) 85 | !ELSE 86 | plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg 87 | @echo Making plugin.c (using sh) 88 | @$(SH) ../../tools/make-dissector-reg . plugin $(DISSECTOR_SRC) 89 | !ENDIF 90 | 91 | !ENDIF 92 | 93 | clean: 94 | rm -f $(OBJECTS) $(RESOURCE) plugin.c *.pdb \ 95 | $(PLUGIN_NAME).dll $(PLUGIN_NAME).dll.manifest $(PLUGIN_NAME).lib \ 96 | $(PLUGIN_NAME).exp $(PLUGIN_NAME).rc 97 | 98 | distclean: clean 99 | 100 | maintainer-clean: distclean 101 | 102 | checkapi: 103 | $(PERL) ../../tools/checkAPIs.pl -g abort -g termoutput $(DISSECTOR_SRC) $(DISSECTOR_INCLUDES) 104 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/README: -------------------------------------------------------------------------------- 1 | This is a protocol dissector for swift: the multiparty transport protocol 2 | (http://libswift.org) 3 | 4 | For instructions on how to include this plugin in a Wireshark build, see 5 | Wireshark's /doc/README.developer 6 | 7 | If you are new to Wireshark protocol dissectors, take a look at 8 | http://www.wireshark.org/docs/wsdg_html_chunked/ChDissectAdd.html 9 | 10 | Author: Andrew Keating 11 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/moduleinfo.h: -------------------------------------------------------------------------------- 1 | /* Included *after* config.h, in order to re-define these macros */ 2 | 3 | #ifdef PACKAGE 4 | #undef PACKAGE 5 | #endif 6 | 7 | /* Name of package */ 8 | #define PACKAGE "swift" 9 | 10 | 11 | #ifdef VERSION 12 | #undef VERSION 13 | #endif 14 | 15 | /* Version number of package */ 16 | #define VERSION "0.0.1" 17 | 18 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/moduleinfo.nmake: -------------------------------------------------------------------------------- 1 | # 2 | # $Id$ 3 | # 4 | 5 | # The name 6 | PACKAGE=swift 7 | 8 | # The version 9 | MODULE_VERSION_MAJOR=0 10 | MODULE_VERSION_MINOR=0 11 | MODULE_VERSION_MICRO=1 12 | MODULE_VERSION_EXTRA=0 13 | 14 | # 15 | # The RC_VERSION should be comma-separated, not dot-separated, 16 | # as per Graham Bloice's message in 17 | # 18 | # http://www.ethereal.com/lists/ethereal-dev/200303/msg00283.html 19 | # 20 | # "The RC_VERSION variable in config.nmake should be comma separated. 21 | # This allows the resources to be built correctly and the version 22 | # number to be correctly displayed in the explorer properties dialog 23 | # for the executables, and XP's tooltip, rather than 0.0.0.0." 24 | # 25 | 26 | MODULE_VERSION=$(MODULE_VERSION_MAJOR).$(MODULE_VERSION_MINOR).$(MODULE_VERSION_MICRO).$(MODULE_VERSION_EXTRA) 27 | RC_MODULE_VERSION=$(MODULE_VERSION_MAJOR),$(MODULE_VERSION_MINOR),$(MODULE_VERSION_MICRO),$(MODULE_VERSION_EXTRA) 28 | 29 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/packet-swift.lo: -------------------------------------------------------------------------------- 1 | # packet-swift.lo - a libtool object file 2 | # Generated by ltmain.sh (GNU libtool) 2.2.6b Debian-2.2.6b-2ubuntu1 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # Name of the PIC object. 8 | pic_object='.libs/packet-swift.o' 9 | 10 | # Name of the non-PIC object 11 | non_pic_object=none 12 | 13 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/plugin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Do not modify this file. 3 | * 4 | * It is created automatically by Makefile or Makefile.nmake. 5 | */ 6 | 7 | #ifdef HAVE_CONFIG_H 8 | # include "config.h" 9 | #endif 10 | 11 | #include 12 | 13 | #include "moduleinfo.h" 14 | 15 | #ifndef ENABLE_STATIC 16 | G_MODULE_EXPORT const gchar version[] = VERSION; 17 | 18 | /* Start the functions we need for the plugin stuff */ 19 | 20 | G_MODULE_EXPORT void 21 | plugin_register (void) 22 | { 23 | {extern void proto_register_swift (void); proto_register_swift ();} 24 | } 25 | 26 | G_MODULE_EXPORT void 27 | plugin_reg_handoff(void) 28 | { 29 | {extern void proto_reg_handoff_swift (void); proto_reg_handoff_swift ();} 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/plugin.lo: -------------------------------------------------------------------------------- 1 | # plugin.lo - a libtool object file 2 | # Generated by ltmain.sh (GNU libtool) 2.2.6b Debian-2.2.6b-2ubuntu1 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # Name of the PIC object. 8 | pic_object='.libs/plugin.o' 9 | 10 | # Name of the non-PIC object 11 | non_pic_object=none 12 | 13 | -------------------------------------------------------------------------------- /doc/wireshark-dissector/plugin.rc.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gritzko/swift/da6809ab9fb95117c973f914fe01c6bacf153eb0/doc/wireshark-dissector/plugin.rc.in -------------------------------------------------------------------------------- /doc/wireshark-dissector/swift.la: -------------------------------------------------------------------------------- 1 | # swift.la - a libtool library file 2 | # Generated by ltmain.sh (GNU libtool) 2.2.6b Debian-2.2.6b-2ubuntu1 3 | # 4 | # Please DO NOT delete this file! 5 | # It is necessary for linking the library. 6 | 7 | # The name that we can dlopen(3). 8 | dlname='swift.so' 9 | 10 | # Names of this library. 11 | library_names='swift.so swift.so swift.so' 12 | 13 | # The name of the static archive. 14 | old_library='' 15 | 16 | # Linker flags that can not go in dependency_libs. 17 | inherited_linker_flags=' -pthread' 18 | 19 | # Libraries that this one depends upon. 20 | dependency_libs=' -L/usr/local/lib' 21 | 22 | # Names of additional weak libraries provided by this library 23 | weak_library_names='' 24 | 25 | # Version information for swift. 26 | current=0 27 | age=0 28 | revision=0 29 | 30 | # Is this an already installed library? 31 | installed=no 32 | 33 | # Should we warn about portability when linking against -modules? 34 | shouldnotlink=yes 35 | 36 | # Files to dlopen/dlpreopen 37 | dlopen='' 38 | dlpreopen='' 39 | 40 | # Directory that this library needs to be installed in: 41 | libdir='/root/build/root/lib/wireshark/plugins/1.4.7' 42 | -------------------------------------------------------------------------------- /ext/seq_picker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * seq_picker.cpp 3 | * swift 4 | * 5 | * Created by Victor Grishchenko on 10/6/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | 10 | #include "swift.h" 11 | 12 | using namespace swift; 13 | 14 | 15 | /** Picks pieces nearly sequentialy; some local randomization (twisting) 16 | is introduced to prevent synchronization among multiple channels. */ 17 | class SeqPiecePicker : public PiecePicker { 18 | 19 | binmap_t ack_hint_out_; 20 | tbqueue hint_out_; 21 | FileTransfer* transfer_; 22 | uint64_t twist_; 23 | bin64_t range_; 24 | 25 | public: 26 | 27 | SeqPiecePicker (FileTransfer* file_to_pick_from) : range_(bin64_t::ALL), 28 | transfer_(file_to_pick_from), ack_hint_out_(), twist_(0) { 29 | ack_hint_out_.range_copy(file().ack_out(),bin64_t::ALL); 30 | } 31 | virtual ~SeqPiecePicker() {} 32 | 33 | HashTree& file() { 34 | return transfer_->file(); 35 | } 36 | 37 | virtual void Randomize (uint64_t twist) { 38 | twist_ = twist; 39 | } 40 | 41 | virtual void LimitRange (bin64_t range) { 42 | range_ = range; 43 | } 44 | 45 | virtual bin64_t Pick (binmap_t& offer, uint64_t max_width, tint expires) { 46 | while (hint_out_.size() && hint_out_.front().timemax_width) 77 | hint = hint.left(); 78 | assert(ack_hint_out_.get(hint)==binmap_t::EMPTY); 79 | ack_hint_out_.set(hint); 80 | hint_out_.push_back(tintbin(NOW,hint)); 81 | return hint; 82 | } 83 | 84 | }; 85 | -------------------------------------------------------------------------------- /ext/simple_selector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * simple_selector.cpp 3 | * swift 4 | * 5 | * Created by Victor Grishchenko on 10/6/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | 10 | #include 11 | #include "swift.h" 12 | 13 | using namespace swift; 14 | 15 | class SimpleSelector : public PeerSelector { 16 | typedef std::pair memo_t; 17 | typedef std::deque peer_queue_t; 18 | peer_queue_t peers; 19 | public: 20 | SimpleSelector () { 21 | } 22 | void AddPeer (const Address& addr, const Sha1Hash& root) { 23 | peers.push_front(memo_t(addr,root)); //,root.fingerprint() !!! 24 | } 25 | Address GetPeer (const Sha1Hash& for_root) { 26 | //uint32_t fp = for_root.fingerprint(); 27 | for(peer_queue_t::iterator i=peers.begin(); i!=peers.end(); i++) 28 | if (i->second==for_root) { 29 | i->second = Sha1Hash::ZERO; // horror TODO rewrite 30 | sockaddr_in ret = i->first; 31 | while (peers.begin()->second==Sha1Hash::ZERO) 32 | peers.pop_front(); 33 | return ret; 34 | } 35 | return Address(); 36 | } 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /getopt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1987, 1993, 1994 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by the University of 16 | * California, Berkeley and its contributors. 17 | * 4. Neither the name of the University nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | */ 33 | 34 | /*#if defined(LIBC_SCCS) && !defined(lint) 35 | static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95"; 36 | #endif /* LIBC_SCCS and not lint 37 | #include 38 | //__FBSDID("$FreeBSD: src/lib/libc/stdlib/getopt.c,v 1.6 2002/03/29 22:43:42 markm Exp $"); 39 | 40 | #include "namespace.h"*/ 41 | #include 42 | #include 43 | #include 44 | /*#include "un-namespace.h"*/ 45 | 46 | /*#include "libc_private.h"*/ 47 | 48 | int opterr = 1, /* if error message should be printed */ 49 | optind = 1, /* index into parent argv vector */ 50 | optopt, /* character checked for validity */ 51 | optreset; /* reset getopt */ 52 | char *optarg; /* argument associated with option */ 53 | 54 | #define BADCH (int)'?' 55 | #define BADARG (int)':' 56 | #define EMSG "" 57 | 58 | /* 59 | * getopt -- 60 | * Parse argc/argv argument vector. 61 | */ 62 | int 63 | getopt(nargc, nargv, ostr) 64 | int nargc; 65 | char * const *nargv; 66 | const char *ostr; 67 | { 68 | static char *place = EMSG; /* option letter processing */ 69 | char *oli; /* option letter list index */ 70 | 71 | if (optreset || !*place) { /* update scanning pointer */ 72 | optreset = 0; 73 | if (optind >= nargc || *(place = nargv[optind]) != '-') { 74 | place = EMSG; 75 | return (-1); 76 | } 77 | if (place[1] && *++place == '-') { /* found "--" */ 78 | ++optind; 79 | place = EMSG; 80 | return (-1); 81 | } 82 | } /* option letter okay? */ 83 | if ((optopt = (int)*place++) == (int)':' || 84 | !(oli = strchr(ostr, optopt))) { 85 | /* 86 | * if the user didn't specify '-' as an option, 87 | * assume it means -1. 88 | */ 89 | if (optopt == (int)'-') 90 | return (-1); 91 | if (!*place) 92 | ++optind; 93 | if (opterr && *ostr != ':' && optopt != BADCH) 94 | (void)fprintf(stderr, "%s: illegal option -- %c\n", 95 | "progname", optopt); 96 | return (BADCH); 97 | } 98 | if (*++oli != ':') { /* don't need argument */ 99 | optarg = NULL; 100 | if (!*place) 101 | ++optind; 102 | } 103 | else { /* need an argument */ 104 | if (*place) /* no white space */ 105 | optarg = place; 106 | else if (nargc <= ++optind) { /* no arg */ 107 | place = EMSG; 108 | if (*ostr == ':') 109 | return (BADARG); 110 | if (opterr) 111 | (void)fprintf(stderr, 112 | "%s: option requires an argument -- %c\n", 113 | "progname", optopt); 114 | return (BADCH); 115 | } 116 | else /* white space */ 117 | optarg = nargv[optind]; 118 | place = EMSG; 119 | ++optind; 120 | } 121 | return (optopt); /* dump back option letter */ 122 | } 123 | -------------------------------------------------------------------------------- /getopt_win.h: -------------------------------------------------------------------------------- 1 | /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ 2 | /* $FreeBSD: src/include/getopt.h,v 1.1 2002/09/29 04:14:30 eric Exp $ */ 3 | 4 | /*- 5 | * Copyright (c) 2000 The NetBSD Foundation, Inc. 6 | * All rights reserved. 7 | * 8 | * This code is derived from software contributed to The NetBSD Foundation 9 | * by Dieter Baron and Thomas Klausner. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions 13 | * are met: 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notice, this list of conditions and the following disclaimer. 16 | * 2. Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 3. All advertising materials mentioning features or use of this software 20 | * must display the following acknowledgement: 21 | * This product includes software developed by the NetBSD 22 | * Foundation, Inc. and its contributors. 23 | * 4. Neither the name of The NetBSD Foundation nor the names of its 24 | * contributors may be used to endorse or promote products derived 25 | * from this software without specific prior written permission. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 | * POSSIBILITY OF SUCH DAMAGE. 38 | */ 39 | 40 | #ifndef _GETOPT_H_ 41 | #define _GETOPT_H_ 42 | 43 | #ifdef _WIN32 44 | /* from */ 45 | # ifdef __cplusplus 46 | # define __BEGIN_DECLS extern "C" { 47 | # define __END_DECLS } 48 | # else 49 | # define __BEGIN_DECLS 50 | # define __END_DECLS 51 | # endif 52 | # define __P(args) args 53 | #endif 54 | 55 | /*#ifndef _WIN32 56 | #include 57 | #include 58 | #endif*/ 59 | 60 | #ifdef _WIN32 61 | # if !defined(GETOPT_API) 62 | # define GETOPT_API __declspec(dllimport) 63 | # endif 64 | #endif 65 | 66 | /* 67 | * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions 68 | */ 69 | #if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE) 70 | #define no_argument 0 71 | #define required_argument 1 72 | #define optional_argument 2 73 | 74 | struct option { 75 | /* name of long option */ 76 | const char *name; 77 | /* 78 | * one of no_argument, required_argument, and optional_argument: 79 | * whether option takes an argument 80 | */ 81 | int has_arg; 82 | /* if not NULL, set *flag to val when option found */ 83 | int *flag; 84 | /* if flag not NULL, value to set *flag to; else return value */ 85 | int val; 86 | }; 87 | 88 | __BEGIN_DECLS 89 | GETOPT_API int getopt_long __P((int, char * const *, const char *, 90 | const struct option *, int *)); 91 | __END_DECLS 92 | #endif 93 | 94 | #ifdef _WIN32 95 | /* These are global getopt variables */ 96 | __BEGIN_DECLS 97 | 98 | GETOPT_API extern int opterr, /* if error message should be printed */ 99 | optind, /* index into parent argv vector */ 100 | optopt, /* character checked for validity */ 101 | optreset; /* reset getopt */ 102 | GETOPT_API extern char* optarg; /* argument associated with option */ 103 | 104 | /* Original getopt */ 105 | GETOPT_API int getopt __P((int, char * const *, const char *)); 106 | 107 | __END_DECLS 108 | #endif 109 | 110 | #endif /* !_GETOPT_H_ */ 111 | -------------------------------------------------------------------------------- /hashtree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * hashtree.h 3 | * hashing, Merkle hash trees and data integrity 4 | * 5 | * Created by Victor Grishchenko on 3/6/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #ifndef SWIFT_SHA1_HASH_TREE_H 10 | #define SWIFT_SHA1_HASH_TREE_H 11 | #include "bin64.h" 12 | #include "bins.h" 13 | #include 14 | #include 15 | 16 | namespace swift { 17 | 18 | 19 | /** SHA-1 hash, 20 bytes of data */ 20 | struct Sha1Hash { 21 | uint8_t bits[20]; 22 | 23 | Sha1Hash() { memset(bits,0,20); } 24 | /** Make a hash of two hashes (for building Merkle hash trees). */ 25 | Sha1Hash(const Sha1Hash& left, const Sha1Hash& right); 26 | /** Hash an old plain string. */ 27 | Sha1Hash(const char* str, size_t length=-1); 28 | Sha1Hash(const uint8_t* data, size_t length); 29 | /** Either parse hash from hex representation of read in raw format. */ 30 | Sha1Hash(bool hex, const char* hash); 31 | 32 | std::string hex() const; 33 | bool operator == (const Sha1Hash& b) const 34 | { return 0==memcmp(bits,b.bits,SIZE); } 35 | bool operator != (const Sha1Hash& b) const { return !(*this==b); } 36 | const char* operator * () const { return (char*) bits; } 37 | 38 | const static Sha1Hash ZERO; 39 | const static size_t SIZE; 40 | }; 41 | 42 | 43 | /** This class controls data integrity of some file; hash tree is put to 44 | an auxilliary file next to it. The hash tree file is mmap'd for 45 | performance reasons. Actually, I'd like the data file itself to be 46 | mmap'd, but 32-bit platforms do not allow that for bigger files. 47 | 48 | There are two variants of the general workflow: either a HashTree 49 | is initialized with a root hash and the rest of hashes and data is 50 | spoon-fed later, OR a HashTree is initialized with a data file, so 51 | the hash tree is derived, including the root hash. 52 | */ 53 | class HashTree { 54 | 55 | /** Merkle hash tree: root */ 56 | Sha1Hash root_hash_; 57 | Sha1Hash *hashes_; 58 | /** Merkle hash tree: peak hashes */ 59 | Sha1Hash peak_hashes_[64]; 60 | bin64_t peaks_[64]; 61 | int peak_count_; 62 | /** File descriptor to put hashes to */ 63 | int fd_; 64 | int hash_fd_; 65 | /** Whether to re-hash files. */ 66 | bool data_recheck_; 67 | /** Base size, as derived from the hashes. */ 68 | size_t size_; 69 | size_t sizek_; 70 | /** Part of the tree currently checked. */ 71 | size_t complete_; 72 | size_t completek_; 73 | binmap_t ack_out_; 74 | 75 | protected: 76 | 77 | void Submit(); 78 | void RecoverProgress(); 79 | Sha1Hash DeriveRoot(); 80 | bool OfferPeakHash (bin64_t pos, const Sha1Hash& hash); 81 | 82 | public: 83 | 84 | HashTree (const char* file_name, const Sha1Hash& root=Sha1Hash::ZERO, 85 | const char* hash_filename=NULL); 86 | 87 | /** Offer a hash; returns true if it verified; false otherwise. 88 | Once it cannot be verified (no sibling or parent), the hash 89 | is remembered, while returning false. */ 90 | bool OfferHash (bin64_t pos, const Sha1Hash& hash); 91 | /** Offer data; the behavior is the same as with a hash: 92 | accept or remember or drop. Returns true => ACK is sent. */ 93 | bool OfferData (bin64_t bin, const char* data, size_t length); 94 | /** For live streaming. Not implemented yet. */ 95 | int AppendData (char* data, int length) ; 96 | 97 | int file_descriptor () const { return fd_; } 98 | /** Returns the number of peaks (read on peak hashes). */ 99 | int peak_count () const { return peak_count_; } 100 | /** Returns the i-th peak's bin number. */ 101 | bin64_t peak (int i) const { return peaks_[i]; } 102 | /** Returns peak hash #i. */ 103 | const Sha1Hash& peak_hash (int i) const { return peak_hashes_[i]; } 104 | /** Return the peak bin the given bin belongs to. */ 105 | bin64_t peak_for (bin64_t pos) const; 106 | /** Return a (Merkle) hash for the given bin. */ 107 | const Sha1Hash& hash (bin64_t pos) const {return hashes_[pos];} 108 | /** Give the root hash, which is effectively an identifier of this file. */ 109 | const Sha1Hash& root_hash () const { return root_hash_; } 110 | /** Get file size, in bytes. */ 111 | uint64_t size () const { return size_; } 112 | /** Get file size in packets (in kilobytes, rounded up). */ 113 | uint64_t packet_size () const { return sizek_; } 114 | /** Number of bytes retrieved and checked. */ 115 | uint64_t complete () const { return complete_; } 116 | /** Number of packets retrieved and checked. */ 117 | uint64_t packets_complete () const { return completek_; } 118 | /** The number of bytes completed sequentially, i.e. from the beginning of 119 | the file, uninterrupted. */ 120 | uint64_t seq_complete () ; 121 | /** Whether the file is complete. */ 122 | bool is_complete () 123 | { return size_ && complete_==size_; } 124 | /** The binmap of complete packets. */ 125 | binmap_t& ack_out () { return ack_out_; } 126 | 127 | ~HashTree (); 128 | 129 | 130 | }; 131 | 132 | } 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /httpgw.cpp: -------------------------------------------------------------------------------- 1 | #include "swift.h" 2 | 3 | using namespace swift; 4 | 5 | #define HTTPGW_MAX_CLIENT 128 6 | 7 | enum { 8 | HTTPGW_RANGE=0, 9 | HTTPGW_MAX_HEADER=1 10 | }; 11 | const char * HTTPGW_HEADERS[HTTPGW_MAX_HEADER] = { 12 | "Content-Range" 13 | }; 14 | 15 | 16 | struct http_gw_t { 17 | int id; 18 | uint64_t offset; 19 | uint64_t tosend; 20 | int transfer; 21 | SOCKET sink; 22 | char* headers[HTTPGW_MAX_HEADER]; 23 | } http_requests[HTTPGW_MAX_CLIENT]; 24 | 25 | 26 | int http_gw_reqs_open = 0; 27 | int http_gw_reqs_count = 0; 28 | 29 | void HttpGwNewRequestCallback (SOCKET http_conn); 30 | void HttpGwNewRequestCallback (SOCKET http_conn); 31 | 32 | http_gw_t* HttpGwFindRequest (SOCKET sock) { 33 | for(int i=0; iid,sock); 44 | for(int i=0; iheaders[i]) { 46 | free(req->headers[i]); 47 | req->headers[i] = NULL; 48 | } 49 | *req = http_requests[--http_gw_reqs_open]; 50 | } 51 | swift::close_socket(sock); 52 | swift::Datagram::Listen3rdPartySocket(sckrwecb_t(sock)); 53 | } 54 | 55 | 56 | void HttpGwMayWriteCallback (SOCKET sink) { 57 | http_gw_t* req = HttpGwFindRequest(sink); 58 | uint64_t complete = swift::SeqComplete(req->transfer); 59 | if (complete>req->offset) { // send data 60 | char buf[1<<12]; 61 | uint64_t tosend = std::min((uint64_t)1<<12,complete-req->offset); 62 | size_t rd = pread(req->transfer,buf,tosend,req->offset); // hope it is cached 63 | if (rd<0) { 64 | HttpGwCloseConnection(sink); 65 | return; 66 | } 67 | int wn = send(sink, buf, rd, 0); 68 | if (wn<0) { 69 | print_error("send fails"); 70 | HttpGwCloseConnection(sink); 71 | return; 72 | } 73 | dprintf("%s @%i sent %ib\n",tintstr(),req->id,(int)wn); 74 | req->offset += wn; 75 | req->tosend -= wn; 76 | } else { 77 | if (req->tosend==0) { // done; wait for new request 78 | dprintf("%s @%i done\n",tintstr(),req->id); 79 | sckrwecb_t wait_new_req 80 | // (req->sink,HttpGwNewRequestCallback,NULL,HttpGwCloseConnection); 81 | (req->sink,NULL,NULL,NULL); 82 | HttpGwCloseConnection(sink); 83 | swift::Datagram::Listen3rdPartySocket (wait_new_req); 84 | } else { // wait for data 85 | dprintf("%s @%i waiting for data\n",tintstr(),req->id); 86 | sckrwecb_t wait_swift_data(req->sink,NULL,NULL,HttpGwCloseConnection); 87 | swift::Datagram::Listen3rdPartySocket(wait_swift_data); 88 | } 89 | } 90 | } 91 | 92 | 93 | void HttpGwSwiftProgressCallback (int transfer, bin64_t bin) { 94 | dprintf("%s @A pcb: %s\n",tintstr(),bin.str()); 95 | for (int httpc=0; httpc http_requests[httpc].offset ) { 99 | dprintf("%s @%i progress: %s\n",tintstr(),http_requests[httpc].id,bin.str()); 100 | sckrwecb_t maywrite_callbacks 101 | (http_requests[httpc].sink,NULL, 102 | HttpGwMayWriteCallback,HttpGwCloseConnection); 103 | Datagram::Listen3rdPartySocket (maywrite_callbacks); 104 | } 105 | } 106 | 107 | 108 | void HttpGwFirstProgressCallback (int transfer, bin64_t bin) { 109 | if (bin!=bin64_t(0,0)) // need the first packet 110 | return; 111 | swift::RemoveProgressCallback(transfer,&HttpGwFirstProgressCallback); 112 | swift::AddProgressCallback(transfer,&HttpGwSwiftProgressCallback,0); 113 | for (int httpc=0; httpctransfer==transfer && req->tosend==0) { // FIXME states 116 | uint64_t file_size = swift::Size(transfer); 117 | char response[1024]; 118 | sprintf(response, 119 | "HTTP/1.1 200 OK\r\n"\ 120 | "Connection: keep-alive\r\n"\ 121 | "Content-Type: video/ogg\r\n"\ 122 | /*"X-Content-Duration: 32\r\n"*/\ 123 | "Content-Length: %lli\r\n"\ 124 | "Accept-Ranges: none\r\n"\ 125 | "\r\n", 126 | file_size); 127 | send(req->sink,response,strlen(response),0); 128 | req->tosend = file_size; 129 | dprintf("%s @%i headers_sent size %lli\n",tintstr(),req->id,file_size); 130 | } 131 | } 132 | HttpGwSwiftProgressCallback(transfer,bin); 133 | } 134 | 135 | 136 | void HttpGwNewRequestCallback (SOCKET http_conn){ 137 | http_gw_t* req = http_requests + http_gw_reqs_open++; 138 | req->id = ++http_gw_reqs_count; 139 | req->sink = http_conn; 140 | req->offset = 0; 141 | req->tosend = 0; 142 | dprintf("%s @%i new http request\n",tintstr(),req->id); 143 | // read headers - the thrilling part 144 | // we surely do not support pipelining => one request at a time 145 | #define HTTPGW_MAX_REQ_SIZE 1024 146 | char buf[HTTPGW_MAX_REQ_SIZE+1]; 147 | int rd = recv(http_conn,buf,HTTPGW_MAX_REQ_SIZE,0); 148 | if (rd<=0) { // if conn is closed by the peer, rd==0 149 | HttpGwCloseConnection(http_conn); 150 | return; 151 | } 152 | buf[rd] = 0; 153 | // HTTP request line 154 | char* reqline = strtok(buf,"\r\n"); 155 | char method[16], url[512], version[16], crlf[5]; 156 | if (3!=sscanf(reqline,"%16s %512s %16s",method,url,version)) { 157 | HttpGwCloseConnection(http_conn); 158 | return; 159 | } 160 | // HTTP header fields 161 | char* headerline; 162 | while (headerline=strtok(NULL,"\n\r")) { 163 | char header[128], value[256]; 164 | if (2!=sscanf(headerline,"%120[^: ]: %250[^\r\n]",header,value)) { 165 | HttpGwCloseConnection(http_conn); 166 | return; 167 | } 168 | for(int i=0; iheaders[i]) 170 | req->headers[i] = strdup(value); 171 | } 172 | // parse URL 173 | char * hashch=strtok(url,"/"), hash[41]; 174 | while (hashch && (1!=sscanf(hashch,"%40[0123456789abcdefABCDEF]",hash) || strlen(hash)!=40)) 175 | hashch = strtok(NULL,"/"); 176 | if (strlen(hash)!=40) { 177 | HttpGwCloseConnection(http_conn); 178 | return; 179 | } 180 | dprintf("%s @%i demands %s\n",tintstr(),req->id,hash); 181 | // initiate transmission 182 | Sha1Hash root_hash = Sha1Hash(true,hash); 183 | int file = swift::Find(root_hash); 184 | if (file==-1) 185 | file = swift::Open(hash,root_hash); 186 | req->transfer = file; 187 | if (swift::Size(file)) { 188 | HttpGwFirstProgressCallback(file,bin64_t(0,0)); 189 | } else { 190 | swift::AddProgressCallback(file,&HttpGwFirstProgressCallback,0); 191 | sckrwecb_t install (http_conn,NULL,NULL,HttpGwCloseConnection); 192 | swift::Datagram::Listen3rdPartySocket(install); 193 | } 194 | } 195 | 196 | 197 | // be liberal in what you do, be conservative in what you accept 198 | void HttpGwNewConnectionCallback (SOCKET serv) { 199 | Address client_address; 200 | socklen_t len; 201 | SOCKET conn = accept (serv, (sockaddr*) & (client_address.addr), &len); 202 | if (conn==INVALID_SOCKET) { 203 | print_error("client conn fails"); 204 | return; 205 | } 206 | make_socket_nonblocking(conn); 207 | // submit 3rd party socket to the swift loop 208 | sckrwecb_t install 209 | (conn,HttpGwNewRequestCallback,NULL,HttpGwCloseConnection); 210 | swift::Datagram::Listen3rdPartySocket(install); 211 | } 212 | 213 | 214 | void HttpGwError (SOCKET s) { 215 | print_error("httpgw is dead"); 216 | dprintf("%s @0 closed http gateway\n",tintstr()); 217 | close_socket(s); 218 | swift::Datagram::Listen3rdPartySocket(sckrwecb_t(s)); 219 | } 220 | 221 | 222 | #include 223 | SOCKET InstallHTTPGateway (Address bind_to) { 224 | SOCKET fd; 225 | #define gw_ensure(x) { if (!(x)) { \ 226 | print_error("http binding fails"); close_socket(fd); \ 227 | return INVALID_SOCKET; } } 228 | gw_ensure ( (fd=socket(AF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET ); 229 | int enable = true; 230 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (setsockoptptr_t)&enable, sizeof(int)); 231 | //setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (setsockoptptr_t)&enable, sizeof(int)); 232 | //struct sigaction act; 233 | //memset(&act,0,sizeof(struct sigaction)); 234 | //act.sa_handler = SIG_IGN; 235 | //sigaction (SIGPIPE, &act, NULL); // FIXME 236 | signal( SIGPIPE, SIG_IGN ); 237 | gw_ensure ( 0==bind(fd, (sockaddr*)&(bind_to.addr), sizeof(struct sockaddr_in)) ); 238 | gw_ensure (make_socket_nonblocking(fd)); 239 | gw_ensure ( 0==listen(fd,8) ); 240 | sckrwecb_t install_http(fd,HttpGwNewConnectionCallback,NULL,HttpGwError); 241 | gw_ensure (swift::Datagram::Listen3rdPartySocket(install_http)); 242 | dprintf("%s @0 installed http gateway on %s\n",tintstr(),bind_to.str()); 243 | return fd; 244 | } 245 | -------------------------------------------------------------------------------- /mfold/bash_profile: -------------------------------------------------------------------------------- 1 | export PATH=$HOME/bin:$PATH 2 | export CPPPATH=$CPPPATH:$HOME/include 3 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/lib 4 | export LIBPATH=$LD_LIBRARY_PATH 5 | -------------------------------------------------------------------------------- /mfold/build.default.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if ! which git || ! which g++ || ! which scons || ! which make ; then 4 | sudo apt-get -y install make g++ scons git-core || exit -4 5 | fi 6 | 7 | if [ ! -e ~/include/gtest/gtest.h ]; then 8 | echo installing gtest 9 | mkdir tmp 10 | cd tmp || exit -3 11 | wget -c http://googletest.googlecode.com/files/gtest-1.4.0.tar.bz2 || exit -2 12 | rm -rf gtest-1.4.0 13 | tar -xjf gtest-1.4.0.tar.bz2 || exit -1 14 | cd gtest-1.4.0 || exit 1 15 | ./configure --prefix=$HOME || exit 2 16 | make || exit 3 17 | make install || exit 4 18 | echo done gtest 19 | fi 20 | 21 | #if ! which pcregrep ; then 22 | # echo installing pcregrep 23 | # mkdir tmp 24 | # cd tmp 25 | # wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.01.tar.gz || exit 5 26 | # tar -xzf pcre-8.01.tar.gz 27 | # cd pcre-8.01 28 | # ./configure --prefix=$HOME || exit 6 29 | # make -j4 || exit 7 30 | # make install || exit 8 31 | # echo done pcregrep 32 | #fi 33 | 34 | if [ ! -e swift ]; then 35 | echo clone the repo 36 | git clone $ORIGIN || exit 6 37 | fi 38 | cd swift 39 | echo pulling updates 40 | git pull origin $BRANCH:$BRANCH || exit 5 41 | echo switching the branch 42 | git checkout $BRANCH || exit 5 43 | 44 | echo building 45 | CPPPATH=~/include LIBPATH=~/lib scons -j4 || exit 7 46 | echo testing 47 | tests/connecttest || exit 8 48 | 49 | # TODO: one method 50 | if [ ! -e bin ]; then mkdir bin; fi 51 | g++ -I. *.cpp ext/seq_picker.cpp -pg -o bin/swift-pg & 52 | g++ -I. *.cpp ext/seq_picker.cpp -g -o bin/swift-dbg & 53 | g++ -I. *.cpp ext/seq_picker.cpp -O2 -o bin/swift-o2 & 54 | wait 55 | 56 | echo done 57 | -------------------------------------------------------------------------------- /mfold/clean.default.sh: -------------------------------------------------------------------------------- 1 | if [ $EMIF ]; then 2 | sudo tc qdisc del dev $EMIF ingress 3 | sudo tc qdisc del dev ifb0 root 4 | fi 5 | sudo iptables -F & 6 | cd swift 7 | rm -f chunk core 8 | killall swift-o2 9 | killall swift-dbg 10 | echo DONE 11 | -------------------------------------------------------------------------------- /mfold/compile.default.sh: -------------------------------------------------------------------------------- 1 | cd swift || exit 1 2 | if [ ! -d bin ]; then mkdir bin; fi 3 | git pull || exit 2 4 | rm bin/swift-pg bin/swift-o3 bin/swift-dbg 5 | 6 | g++ -I. *.cpp compat/*.cpp ext/seq_picker.cpp -pg -o bin/swift-pg & 7 | g++ -I. *.cpp compat/*.cpp ext/seq_picker.cpp -g -o bin/swift-dbg & 8 | g++ -I. *.cpp compat/*.cpp ext/seq_picker.cpp -O3 -o bin/swift-o3 & 9 | wait 10 | if [ ! -e bin/swift-pg ]; then exit 4; fi 11 | if [ ! -e bin/swift-dbg ]; then exit 5; fi 12 | if [ ! -e bin/swift-o3 ]; then exit 6; fi 13 | -------------------------------------------------------------------------------- /mfold/doall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script executes a chain of commands 3 | # on all the member servers, in parallel. 4 | # Commands are defined in .sh files (see 5 | # docmd.sh); all failed executions are 6 | # put to the FAILURES file 7 | rm -f FAILURES 8 | if [ ! -d logs ]; then 9 | mkdir logs 10 | fi 11 | 12 | if [ -z "$SERVERS" ]; then 13 | SERVERS="servers.txt" 14 | fi 15 | 16 | for srv in `grep -v '^#' $SERVERS`; do 17 | ( 18 | if ! ./docmd $srv $1; then 19 | echo $srv >> FAILURES 20 | echo $srv FAILED 21 | break 22 | fi 23 | ) & 24 | done 25 | 26 | wait 27 | echo DONE 28 | -------------------------------------------------------------------------------- /mfold/docmd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HOST=$1 4 | CMD=$2 5 | ENV=env.default.sh 6 | 7 | if [ -e env.$HOST.sh ]; then 8 | ENV="$ENV env.$HOST.sh" 9 | fi 10 | 11 | if [ -e $CMD.$HOST.sh ] ; then 12 | SHSC=$CMD.$HOST.sh ; 13 | else 14 | SHSC=$CMD.default.sh ; 15 | fi 16 | 17 | if [ ! -d logs ]; then mkdir logs; fi 18 | if [ ! -e $SHSC ]; then 19 | echo $HOST $CMD EMPTY 20 | exit 0 21 | fi 22 | 23 | if ( (echo "HOST=$HOST"; cat $ENV $SHSC) | ssh $HOST ) > \ 24 | logs/$HOST.$CMD.out 2> logs/$HOST.$CMD.err; then 25 | echo $HOST $CMD OK 26 | exit 0 27 | else 28 | echo $HOST $CMD FAIL 29 | cat $SHSC 30 | cat logs/$HOST.$CMD.out logs/$HOST.$CMD.err 31 | exit 1 32 | fi 33 | -------------------------------------------------------------------------------- /mfold/dohrv: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # The script downloads logs in parallel, 3 | # feeds them into fifos; sort takes logs 4 | # from fifos, merges and gzips them; 5 | # the result is put into harvest/ 6 | # 7 | if [ ! $SERVERS ]; then 8 | export SERVERS="servers.txt" 9 | fi 10 | 11 | mv harvest .hrv-old 12 | rm -rf .hrv-old & 13 | mkdir harvest 14 | 15 | for s in `grep -v '#' $SERVERS`; do 16 | mkfifo harvest/$s.fifo 17 | # yas, yes, yes 18 | ( scp ~/.ssh/config $s:.ssh/config > /dev/null ) & 19 | done 20 | wait 21 | 22 | for s in `grep -v '#' $SERVERS`; do 23 | (if ssh $s \ 24 | "cd swift/ && \ 25 | rm -rf harvest && mkdir harvest && \ 26 | ( zcat lout.gz | ./mfold/logparse $s | gzip )" \ 27 | | gunzip > harvest/$s.fifo ; then 28 | 29 | ssh $s "cd swift/; tar cz harvest" | tar xz 30 | echo $s harvest OK 31 | 32 | else 33 | echo $s harvest FAIL 34 | fi) & 35 | done 36 | 37 | # Ensure your version of sort is recent enough 38 | # batch-size is critical for performance 39 | LC_ALL=C sort -m -s --batch-size=64 harvest/*.fifo | gzip > harvest/swarm.log.gz & 40 | wait 41 | ./loggraphs 42 | ./logreport > harvest/index.html 43 | 44 | rm harvest/*.fifo 45 | cp report.css harvest 46 | scp -rq harvest mfold.libswift.org:/storage/mfold-granary/`date +%d%b_%H:%M`_`whoami` & 47 | 48 | echo DONE 49 | -------------------------------------------------------------------------------- /mfold/dotop: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while true; do 4 | rm logs/*status.out 5 | ( ./doall status > /dev/null ) & 6 | wait 7 | clear 8 | cat logs/*status.out | sort 9 | done 10 | -------------------------------------------------------------------------------- /mfold/env.1mbit.sh: -------------------------------------------------------------------------------- 1 | EMIF=eth0 2 | EMBW=1mbit 3 | EMDELAY=50ms 4 | 5 | -------------------------------------------------------------------------------- /mfold/env.default.sh: -------------------------------------------------------------------------------- 1 | # This script sets up shared environment variables 2 | # at the servers 3 | export SEEDER=130.161.211.198 4 | export SWFTPORT=10004 5 | export HASH=66b9644bb01eaad09269354df00172c8a924773b 6 | export BRANCH=ack-have 7 | export ORIGIN=git://github.com/gritzko/swift.git 8 | -------------------------------------------------------------------------------- /mfold/env.lossy.sh: -------------------------------------------------------------------------------- 1 | EMIF=eth0 2 | EMBW=1mbit 3 | 4 | -------------------------------------------------------------------------------- /mfold/env.messy.sh: -------------------------------------------------------------------------------- 1 | EMIF=eth0 2 | EMBW=1mbit 3 | EMDELAY=100ms 4 | EMJTTR=20ms 5 | 6 | -------------------------------------------------------------------------------- /mfold/install.default.sh: -------------------------------------------------------------------------------- 1 | echo TODO 2 | -------------------------------------------------------------------------------- /mfold/loggraphs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$SERVERS" ]; then 4 | SERVERS="servers.txt" 5 | fi 6 | 7 | VERSION=`date`,`git log --summary | head -1` 8 | 9 | cd harvest 10 | 11 | HEAD=`head -1 *.log | grep -v '^$' | cut -f1 | sort | head -1` 12 | TAIL=`tail -n1 -q *.log | grep -v '^$' | cut -f1 | sort | tail -n1 -q` 13 | 14 | for from in `grep -v '^#' ../$SERVERS`; do 15 | for to in `grep -v '^#' ../$SERVERS`; do 16 | CWNDLOG="$from-$to-cwnd.log" 17 | if [ ! -e $CWNDLOG ]; then 18 | continue 19 | fi 20 | GP="$from-$to.gnuplot" 21 | 22 | echo "set term png large size 2048,768" > $GP 23 | PNG="$from-$to.big.png" 24 | if [ -e $PNG ]; then rm $PNG; fi 25 | echo "set out '$PNG'" >> $GP 26 | 27 | echo "set y2tics" >> $GP 28 | echo "set y2label 'packets'" >> $GP 29 | echo "set ylabel 'microseconds'" >> $GP 30 | echo "set xlabel 'run time millis'" >> $GP 31 | echo "set title '$VERSION'" >> $GP 32 | #echo "set xrange [$HEAD:$TAIL]" >> $GP 33 | CWNDLOG="$from-$to-cwnd.log" 34 | echo -ne "plot '$CWNDLOG' using 1:2 with lines lt rgb '#00aa00' title 'cwnd'"\ 35 | " axis x1y2, "\ 36 | " '$CWNDLOG' using 1:3 with lines lt rgb '#99ff99' title 'data out'"\ 37 | " axis x1y2 "\ 38 | >> $GP 39 | RTTLOG="$from-$to-rtt.log" 40 | if [ -e $RTTLOG ]; then 41 | echo -ne ", '$RTTLOG' using 1:2 with lines lt rgb '#2833ff' title 'rtt' "\ 42 | "axis x1y1, "\ 43 | "'$RTTLOG' using 1:3 with lines lt rgb '#8844ff' title 'dev' "\ 44 | "axis x1y1"\ 45 | >> $GP 46 | fi 47 | OWDLOG="$from-$to-owd.log" 48 | if [ -e $OWDLOG ]; then 49 | echo -ne ", '$OWDLOG' using 1:2 with lines lt rgb '#ff00ee' title 'owd' "\ 50 | "axis x1y1, "\ 51 | "'$OWDLOG' using 1:3 with lines lw 2 lt rgb '#0044cc' title 'min owd'"\ 52 | "axis x1y1, "\ 53 | "'$OWDLOG' using 1:(\$3+25000) with lines lw 2 lt rgb '#0000ff' title 'target'"\ 54 | "axis x1y1 "\ 55 | >> $GP 56 | fi 57 | RDATALOG="$from-$to-rdata.log" 58 | if [ -e $RDATALOG ]; then 59 | echo -ne ", '$RDATALOG' using 1:(1) with points "\ 60 | "lt rgb '#0f0000' title 'r-losses'"\ 61 | >> $GP 62 | fi 63 | TDATALOG="$from-$to-tdata.log" 64 | if [ -e $TDATALOG ]; then 65 | echo -ne ", '$TDATALOG' using 1:(1) with points "\ 66 | "lt rgb '#ff0000' title 't-losses'"\ 67 | >> $GP 68 | fi 69 | echo >> $GP 70 | 71 | echo "set term png size 512,192" >> $GP 72 | PNG="$from-$to.thumb.png" 73 | if [ -e $PNG ]; then rm $PNG; fi 74 | echo "set out '$PNG'" >> $GP 75 | echo "unset title" >> $GP 76 | echo "unset xlabel" >> $GP 77 | echo "unset ylabel" >> $GP 78 | echo "replot" >> $GP 79 | 80 | ( cat $GP | gnuplot ) & 81 | done 82 | done 83 | 84 | wait 85 | cd .. 86 | -------------------------------------------------------------------------------- /mfold/logparse: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | $SERVER=shift; 4 | %HOSTS = (); 5 | %CHANN = ( "#0" => "none" ); 6 | %EVENTS = ( "#0" => {"+hs"=>0} ); 7 | %SENT = (); 8 | %RCVD = (); 9 | %DSENT = (); 10 | %DRCVD = (); 11 | %CWNDLOG = (); 12 | %RTTLOG = (); 13 | %OWDLOG = (); 14 | %TDATALOG = (); 15 | %RDATALOG = (); 16 | $SENTB = 0; 17 | $RCVDB = 0; 18 | 19 | open(SRV,$ENV{"HOME"}."/.ssh/config") or die; 20 | while () { 21 | $srvname=$1 if /Host (\S+)/; 22 | $HOSTS{$1}=$srvname if /HostName (\S+)/; 23 | } 24 | close SRV; 25 | 26 | while (<>) { 27 | /(\d+_\d+_\d+_\d+_\d+) (#\d+) (\S+) (.*)/ or next; 28 | my $time = $1; 29 | my $channel = $2; 30 | my $event = $3; 31 | my $rest = $4; 32 | my $host = $CHANN{"$channel"}; 33 | $host = "unknown" if not $host; 34 | $time =~ /^(\d+)_(\d+)_(\d+)_(\d+)/; 35 | my $ms=$1*60; $ms=($ms+$2)*60; $ms=($ms+$3)*1000; $ms+=$4; 36 | if ($event eq "sent") { 37 | $rest =~ /(\d+)b ([\d\.]+):/; 38 | $ip = $2; 39 | $host = $HOSTS{$ip}; 40 | #$SENT{$h} = 0 if not exists $SENT{$h}; 41 | $SENT{$host} += $1; 42 | $SENTB += $1; 43 | $DSENT{$host}++; 44 | $CHANN{"$channel"} = $host; 45 | } elsif ($event eq "recvd") { 46 | $rest =~ /(\d+)/; 47 | #$RCVD{$h} = 0 if not exists $RCVD{$h}; 48 | $DRCVD{$host}++; 49 | $RCVD{$host} += $1; 50 | $RCVDB += $1; 51 | } elsif ($event eq "sendctrl") { 52 | if ($rest =~ /cwnd (\d+\.\d+).*data_out (\d+)/) { 53 | if (not exists $CWNDLOG{$host}) { 54 | open(my $handle, '>', "harvest/$SERVER-$host-cwnd.log") or die; 55 | $CWNDLOG{$host} = $handle; 56 | } 57 | print {$CWNDLOG{$host}} "$ms\t$1\t$2\n"; 58 | } elsif ($rest =~ /ledbat (\-?\d+)\-(\-?\d+)/) { 59 | if (not exists $OWDLOG{$host}) { 60 | open(my $handle, '>', "harvest/$SERVER-$host-owd.log") or die; 61 | $OWDLOG{$host} = $handle; 62 | } 63 | print {$OWDLOG{$host}} "$ms\t$1\t$2\n"; 64 | } elsif ($rest =~ /rtt (\d+) dev (\d+)/) { 65 | if (not exists $RTTLOG{$host}) { 66 | open(my $handle, '>', "harvest/$SERVER-$host-rtt.log") or die; 67 | $RTTLOG{$host} = $handle; 68 | } 69 | print {$RTTLOG{$host}} "$ms\t$1\t$2\n"; 70 | } 71 | } elsif ($event eq "Tdata") { 72 | if (not exists $TDATALOG{$host}) { 73 | open(my $handle, '>', "harvest/$SERVER-$host-tdata.log") or die; 74 | $TDATALOG{$host} = $handle; 75 | } 76 | print {$TDATALOG{$host}} "$ms\n"; 77 | } elsif ($event eq "Rdata") { 78 | if (not exists $RDATALOG{$host}) { 79 | open(my $handle, '>', "harvest/$SERVER-$host-rdata.log") or die; 80 | $RDATALOG{$host} = $handle; 81 | } 82 | print {$RDATALOG{$host}} "$ms\n"; 83 | } 84 | $EVENTS{"$host"} = { "+hs"=>0 } if not exists $EVENTS{"$host"}; 85 | 86 | print "$time $SERVER $host$channel $event $rest\n"; 87 | 88 | # DO STATS 89 | $EVENTS{"$host"}{"$event"} = 0 if not exists $EVENTS{"$host"}{"$event"}; 90 | $EVENTS{"$host"}{"$event"}++; 91 | 92 | } 93 | 94 | for $host (keys %CWNDLOG) { 95 | close($CWNDLOG{$host}); 96 | } 97 | for $host (keys %OWDLOG) { 98 | close ($OWDLOG{$host}); 99 | } 100 | for $host (keys %RTTLOG) { 101 | close ($RTTLOG{$host}); 102 | } 103 | for $host (keys %TDATALOG) { 104 | close ($TDATALOG{$host}); 105 | } 106 | for $host (keys %RDATALOG) { 107 | close ($RDATALOG{$host}); 108 | } 109 | 110 | open(LEGEND,"> harvest/$SERVER-legend.txt") or die; 111 | 112 | for $channel (keys %CHANN) { 113 | my $host = $CHANN{"$channel"}; 114 | print LEGEND "$channel\t$host\n"; 115 | open(STATS,"> harvest/$SERVER-$host.stat") or die; 116 | my %events = %{ $EVENTS{"$host"} }; 117 | for $event ( keys %events ) { 118 | print STATS "$event\t".($events{"$event"})."\n"; 119 | } 120 | close STATS; 121 | open(HTML,"> harvest/$SERVER-$host.html") or die; 122 | print HTML "\n"; 123 | my $rcvd = $RCVD{$host}; 124 | my $sent = $SENT{$host}; 125 | $rcvd=0.001 if not $rcvd; 126 | $sent=0.001 if not $sent; 127 | printf HTML 128 | "". 129 | "\n", 130 | $sent, $SENTB?$sent/$SENTB*100:0, $rcvd, $RCVDB?$rcvd/$RCVDB*100:0; 131 | print HTML 132 | "\n"; 133 | printf HTML 134 | "\n", 135 | $events{"+data"}, ($events{"+data"}*1029)/$sent*100, 136 | $events{"-data"}, ($events{"-data"}*1029)/$rcvd*100; 137 | printf HTML 138 | "\n", 139 | $events{"+hash"}, ($events{"+hash"}*25)/$sent*100, 140 | $events{"-hash"}, ($events{"-hash"}*25)/$rcvd*100; 141 | printf HTML 142 | "\n", 143 | $events{"+ack"}, ($events{"+ack"}*5)/$sent*100, 144 | $events{"-ack"}, ($events{"-ack"}*5)/$rcvd*100; 145 | printf HTML 146 | "\n", 147 | $events{"+hint"}, ($events{"+hint"}*5)/$sent*100, 148 | $events{"-hint"}, ($events{"-hint"}*5)/$rcvd*100; 149 | printf HTML 150 | "\n", 151 | $events{"+hs"}, $events{"-hs"}; 152 | my $losses = $events{"+data"}>0 ? 153 | ($events{"Rdata"}+$events{"Tdata"})/$events{"+data"}*100 : 0; 154 | printf HTML 155 | "\n", 156 | $events{"Rdata"}, $events{"Tdata"}, 157 | $events{"Rdata"}+$events{"Tdata"}, $losses; 158 | 159 | print HTML "
sentrcvd
bytes%i/%.1f%%%i/%.1f%%
dgrams".$DSENT{$host}."".$DRCVD{$host}."
data%i/%.1f%%%i/%.1f%%
hash%i/%.1f%%%i/%.1f%%
ack%i/%.1f%%%i/%.1f%%
hint%i/%.1f%%%i/%.1f%%
hs%i%i
lossesR:%i+T:%i=%i/%.1f%%
\n"; 160 | close HTML; 161 | } 162 | close LEGEND; 163 | -------------------------------------------------------------------------------- /mfold/logreport: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! $SERVERS ]; then 4 | export SERVERS="servers.txt" 5 | fi 6 | 7 | cd harvest 8 | 9 | echo '' 10 | echo '' 11 | echo 'Manifold: swarm tomography' `date` `git log --summary | head -1` '' 12 | echo '' 13 | echo '' 16 | done 17 | echo '' 18 | for from in `grep -v '#' ../$SERVERS`; do 19 | echo '' 20 | for to in `grep -v '#' ../$SERVERS`; do 21 | echo '' 29 | done 30 | echo '' 31 | done 32 | echo '' 33 | -------------------------------------------------------------------------------- /mfold/net.aussie.sh: -------------------------------------------------------------------------------- 1 | echo eth0 > .netem-on 2 | 3 | sudo tc qdisc add dev eth0 root netem delay 400ms 4 | -------------------------------------------------------------------------------- /mfold/net.lossy.sh: -------------------------------------------------------------------------------- 1 | echo eth0 > .netem-on 2 | 3 | sudo tc qdisc add dev eth0 root netem delay 100ms loss 5.0% 4 | -------------------------------------------------------------------------------- /mfold/net.messy.sh: -------------------------------------------------------------------------------- 1 | echo eth0 > .netem-on 2 | 3 | sudo tc qdisc add dev eth0 root netem delay 100ms 20ms 25% 4 | -------------------------------------------------------------------------------- /mfold/netem.default.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ ! $EMIF ] ; then 4 | exit 5 | fi 6 | 7 | if [ ! $EMLOSS ]; then 8 | EMLOSS=0% 9 | fi 10 | 11 | if [ ! $EMDELAY ]; then 12 | EMDELAY=10ms 13 | fi 14 | 15 | if [ ! $EMBW ]; then 16 | EMBW=10mbit 17 | fi 18 | 19 | if [ ! $EMJTTR ]; then 20 | EMJTTR=0ms 21 | fi 22 | 23 | TC="sudo tc " 24 | 25 | echo ifb0 up 26 | sudo modprobe ifb 27 | sudo ip link set dev ifb0 up 28 | 29 | echo cleanup 30 | $TC qdisc del dev $EMIF ingress 31 | $TC qdisc del dev ifb0 root 32 | 33 | echo adding ingress 34 | $TC qdisc add dev $EMIF ingress || exit 1 35 | 36 | echo redirecting to ifb 37 | $TC filter add dev $EMIF parent ffff: protocol ip prio 1 u32 \ 38 | match ip sport $SWFTPORT 0xffff flowid 1:1 action mirred egress redirect dev ifb0 || exit 2 39 | echo adding netem for $EMDELAY - $EMLOSS 40 | $TC qdisc add dev ifb0 root handle 1:0 netem delay $EMDELAY $EMJTTR 25% loss $EMLOSS || exit 3 41 | echo adding tfb for $EMBW 42 | $TC qdisc add dev ifb0 parent 1:1 handle 10: tbf rate $EMBW buffer 102400 latency 40ms || exit 4 43 | 44 | -------------------------------------------------------------------------------- /mfold/ps.default.sh: -------------------------------------------------------------------------------- 1 | if ps -ef | grep l[e]echer > /dev/null; then 2 | echo `hostname` has a running leecher 3 | return 1 4 | fi 5 | -------------------------------------------------------------------------------- /mfold/report.css: -------------------------------------------------------------------------------- 1 | table#main table { 2 | background: #ffe; 3 | } 4 | 5 | td.host { 6 | text-align: center; 7 | font: 24pt "Courier"; 8 | } 9 | 10 | table.channel { 11 | /* border: 1 dotted #aa5; */ 12 | font-size: smaller; 13 | } 14 | 15 | td { 16 | border-top: 1 dotted #aa5; 17 | border-spacing: 0; 18 | } 19 | 20 | pp { 21 | color: #a00; 22 | } 23 | 24 | tr.bytes { 25 | background: #fed; 26 | } 27 | 28 | img.thumb { 29 | width: 160pt; 30 | border-style: none; 31 | } 32 | 33 | table#main tr td { 34 | vertical-align: top; 35 | } 36 | -------------------------------------------------------------------------------- /mfold/run.default.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script runs a leecher at some server; 3 | # env variables are set in env.default.sh 4 | 5 | ulimit -c 1024000 6 | cd swift || exit 1 7 | rm -f core 8 | rm -f chunk 9 | sleep $(( $RANDOM % 5 )) 10 | bin/swift-o2 -w -h $HASH -f chunk -t $SEEDER:$SWFTPORT \ 11 | -l 0.0.0.0:$RUNPORT -p -D 2>lerr | gzip > lout.gz || exit 2 12 | -------------------------------------------------------------------------------- /mfold/run.seeder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ulimit -c 1024000 4 | cd swift || exit 2 5 | if [ ! -e ScottKim_2008P.mp4 ]; then 6 | wget -c http://video.ted.com/talks/podcast/ScottKim_2008P.mp4 || exit 1 7 | fi 8 | 9 | bin/swift-o2 -w -f ScottKim_2008P.mp4 -p -D \ 10 | -l 0.0.0.0:$SWFTPORT 2>lerr | gzip > lout.gz || exit 2 11 | exit 12 | -------------------------------------------------------------------------------- /mfold/status.default.sh: -------------------------------------------------------------------------------- 1 | echo -e $HOST"\t"`tail -1 swift/lerr` 2 | -------------------------------------------------------------------------------- /send_control.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * send_control.cpp 3 | * congestion control logic for the swift protocol 4 | * 5 | * Created by Victor Grishchenko on 12/10/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | 10 | #include "swift.h" 11 | 12 | using namespace swift; 13 | using namespace std; 14 | 15 | tint Channel::MIN_DEV = 50*TINT_MSEC; 16 | tint Channel::MAX_SEND_INTERVAL = TINT_SEC*58; 17 | tint Channel::LEDBAT_TARGET = TINT_MSEC*25; 18 | float Channel::LEDBAT_GAIN = 1.0/LEDBAT_TARGET; 19 | tint Channel::LEDBAT_DELAY_BIN = TINT_SEC*30; 20 | tint Channel::MAX_POSSIBLE_RTT = TINT_SEC*10; 21 | const char* Channel::SEND_CONTROL_MODES[] = {"keepalive", "pingpong", 22 | "slowstart", "standard_aimd", "ledbat", "closing"}; 23 | 24 | 25 | tint Channel::NextSendTime () { 26 | TimeoutDataOut(); // precaution to know free cwnd 27 | switch (send_control_) { 28 | case KEEP_ALIVE_CONTROL: return KeepAliveNextSendTime(); 29 | case PING_PONG_CONTROL: return PingPongNextSendTime(); 30 | case SLOW_START_CONTROL: return SlowStartNextSendTime(); 31 | case AIMD_CONTROL: return AimdNextSendTime(); 32 | case LEDBAT_CONTROL: return LedbatNextSendTime(); 33 | case CLOSE_CONTROL: return TINT_NEVER; 34 | default: assert(false); 35 | } 36 | } 37 | 38 | tint Channel::SwitchSendControl (int control_mode) { 39 | dprintf("%s #%u sendctrl switch %s->%s\n",tintstr(),id(), 40 | SEND_CONTROL_MODES[send_control_],SEND_CONTROL_MODES[control_mode]); 41 | switch (control_mode) { 42 | case KEEP_ALIVE_CONTROL: 43 | send_interval_ = rtt_avg_; //max(TINT_SEC/10,rtt_avg_); 44 | dev_avg_ = max(TINT_SEC,rtt_avg_); 45 | data_out_cap_ = bin64_t::ALL; 46 | cwnd_ = 1; 47 | break; 48 | case PING_PONG_CONTROL: 49 | dev_avg_ = max(TINT_SEC,rtt_avg_); 50 | data_out_cap_ = bin64_t::ALL; 51 | cwnd_ = 1; 52 | break; 53 | case SLOW_START_CONTROL: 54 | cwnd_ = 1; 55 | break; 56 | case AIMD_CONTROL: 57 | break; 58 | case LEDBAT_CONTROL: 59 | break; 60 | case CLOSE_CONTROL: 61 | break; 62 | default: 63 | assert(false); 64 | } 65 | send_control_ = control_mode; 66 | return NextSendTime(); 67 | } 68 | 69 | tint Channel::KeepAliveNextSendTime () { 70 | if (sent_since_recv_>=3 && last_recv_time_MAX_SEND_INTERVAL) 79 | send_interval_ = MAX_SEND_INTERVAL; 80 | return last_send_time_ + send_interval_; 81 | } 82 | 83 | tint Channel::PingPongNextSendTime () { // FIXME INFINITE LOOP 84 | if (dgrams_sent_>=10) 85 | return SwitchSendControl(KEEP_ALIVE_CONTROL); 86 | if (ack_rcvd_recent_) 87 | return SwitchSendControl(SLOW_START_CONTROL); 88 | if (data_in_.time!=TINT_NEVER) 89 | return NOW; 90 | if (last_recv_time_>last_send_time_) 91 | return NOW; 92 | if (!last_send_time_) 93 | return NOW; 94 | return last_send_time_ + ack_timeout(); // timeout 95 | } 96 | 97 | tint Channel::CwndRateNextSendTime () { 98 | if (data_in_.time!=TINT_NEVER) 99 | return NOW; // TODO: delayed ACKs 100 | //if (last_recv_time_max(rtt_avg_,TINT_SEC)*4) 104 | return SwitchSendControl(KEEP_ALIVE_CONTROL); 105 | if (data_out_.size()1) 142 | cwnd_ += ack_rcvd_recent_/cwnd_; 143 | else 144 | cwnd_ *= 2; 145 | } 146 | ack_rcvd_recent_=0; 147 | return CwndRateNextSendTime(); 148 | } 149 | 150 | tint Channel::LedbatNextSendTime () { 151 | tint owd_cur(TINT_NEVER), owd_min(TINT_NEVER); 152 | for(int i=0; i<4; i++) { 153 | if (owd_min>owd_min_bins_[i]) 154 | owd_min = owd_min_bins_[i]; 155 | if (owd_cur>owd_current_[i]) 156 | owd_cur = owd_current_[i]; 157 | } 158 | if (ack_not_rcvd_recent_) 159 | BackOffOnLosses(0.8); 160 | ack_rcvd_recent_ = 0; 161 | tint queueing_delay = owd_cur - owd_min; 162 | tint off_target = LEDBAT_TARGET - queueing_delay; 163 | cwnd_ += LEDBAT_GAIN * off_target / cwnd_; 164 | if (cwnd_<1) 165 | cwnd_ = 1; 166 | if (owd_cur==TINT_NEVER || owd_min==TINT_NEVER) 167 | cwnd_ = 1; 168 | dprintf("%s #%u sendctrl ledbat %lli-%lli => %3.2f\n", 169 | tintstr(),id_,owd_cur,owd_min,cwnd_); 170 | return CwndRateNextSendTime(); 171 | } 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /sha1.cpp: -------------------------------------------------------------------------------- 1 | // licensed under the GPL v2 as part of the git project http://git-scm.com/ 2 | /* 3 | * SHA1 routine optimized to do word accesses rather than byte accesses, 4 | * and to avoid unnecessary copies into the context array. 5 | * 6 | * This was initially based on the Mozilla SHA1 implementation, although 7 | * none of the original Mozilla code remains. 8 | */ 9 | 10 | /* this is only to get definitions for memcpy(), ntohl() and htonl() */ 11 | //#include "../git-compat-util.h" 12 | #ifdef _WIN32 13 | #include 14 | #else 15 | #include 16 | #endif 17 | #include 18 | 19 | #include "sha1.h" 20 | 21 | #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 22 | 23 | /* 24 | * Force usage of rol or ror by selecting the one with the smaller constant. 25 | * It _can_ generate slightly smaller code (a constant of 1 is special), but 26 | * perhaps more importantly it's possibly faster on any uarch that does a 27 | * rotate with a loop. 28 | */ 29 | 30 | #define SHA_ASM(op, x, n) ({ unsigned int __res; __asm__(op " %1,%0":"=r" (__res):"i" (n), "0" (x)); __res; }) 31 | #define SHA_ROL(x,n) SHA_ASM("rol", x, n) 32 | #define SHA_ROR(x,n) SHA_ASM("ror", x, n) 33 | 34 | #else 35 | 36 | #define SHA_ROT(X,l,r) (((X) << (l)) | ((X) >> (r))) 37 | #define SHA_ROL(X,n) SHA_ROT(X,n,32-(n)) 38 | #define SHA_ROR(X,n) SHA_ROT(X,32-(n),n) 39 | 40 | #endif 41 | 42 | /* 43 | * If you have 32 registers or more, the compiler can (and should) 44 | * try to change the array[] accesses into registers. However, on 45 | * machines with less than ~25 registers, that won't really work, 46 | * and at least gcc will make an unholy mess of it. 47 | * 48 | * So to avoid that mess which just slows things down, we force 49 | * the stores to memory to actually happen (we might be better off 50 | * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as 51 | * suggested by Artur Skawina - that will also make gcc unable to 52 | * try to do the silly "optimize away loads" part because it won't 53 | * see what the value will be). 54 | * 55 | * Ben Herrenschmidt reports that on PPC, the C version comes close 56 | * to the optimized asm with this (ie on PPC you don't want that 57 | * 'volatile', since there are lots of registers). 58 | * 59 | * On ARM we get the best code generation by forcing a full memory barrier 60 | * between each SHA_ROUND, otherwise gcc happily get wild with spilling and 61 | * the stack frame size simply explode and performance goes down the drain. 62 | */ 63 | 64 | #if defined(__i386__) || defined(__x86_64__) 65 | #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val)) 66 | #elif defined(__GNUC__) && defined(__arm__) 67 | #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0) 68 | #else 69 | #define setW(x, val) (W(x) = (val)) 70 | #endif 71 | 72 | /* 73 | * Performance might be improved if the CPU architecture is OK with 74 | * unaligned 32-bit loads and a fast ntohl() is available. 75 | * Otherwise fall back to byte loads and shifts which is portable, 76 | * and is faster on architectures with memory alignment issues. 77 | */ 78 | 79 | #if defined(__i386__) || defined(__x86_64__) || \ 80 | defined(__ppc__) || defined(__ppc64__) || \ 81 | defined(__powerpc__) || defined(__powerpc64__) || \ 82 | defined(__s390__) || defined(__s390x__) 83 | 84 | #define get_be32(p) ntohl(*(unsigned int *)(p)) 85 | #define put_be32(p, v) do { *(unsigned int *)(p) = htonl(v); } while (0) 86 | 87 | #else 88 | 89 | #define get_be32(p) ( \ 90 | (*((unsigned char *)(p) + 0) << 24) | \ 91 | (*((unsigned char *)(p) + 1) << 16) | \ 92 | (*((unsigned char *)(p) + 2) << 8) | \ 93 | (*((unsigned char *)(p) + 3) << 0) ) 94 | #define put_be32(p, v) do { \ 95 | unsigned int __v = (v); \ 96 | *((unsigned char *)(p) + 0) = __v >> 24; \ 97 | *((unsigned char *)(p) + 1) = __v >> 16; \ 98 | *((unsigned char *)(p) + 2) = __v >> 8; \ 99 | *((unsigned char *)(p) + 3) = __v >> 0; } while (0) 100 | 101 | #endif 102 | 103 | /* This "rolls" over the 512-bit array */ 104 | #define W(x) (array[(x)&15]) 105 | 106 | /* 107 | * Where do we get the source from? The first 16 iterations get it from 108 | * the input data, the next mix it from the 512-bit array. 109 | */ 110 | #define SHA_SRC(t) get_be32(data + t) 111 | #define SHA_MIX(t) SHA_ROL(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1) 112 | 113 | #define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ 114 | unsigned int TEMP = input(t); setW(t, TEMP); \ 115 | E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \ 116 | B = SHA_ROR(B, 2); } while (0) 117 | 118 | #define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) 119 | #define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) 120 | #define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E ) 121 | #define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E ) 122 | #define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E ) 123 | 124 | static void blk_SHA1_Block(blk_SHA_CTX *ctx, const unsigned int *data) 125 | { 126 | unsigned int A,B,C,D,E; 127 | unsigned int array[16]; 128 | 129 | A = ctx->H[0]; 130 | B = ctx->H[1]; 131 | C = ctx->H[2]; 132 | D = ctx->H[3]; 133 | E = ctx->H[4]; 134 | 135 | /* Round 1 - iterations 0-16 take their input from 'data' */ 136 | T_0_15( 0, A, B, C, D, E); 137 | T_0_15( 1, E, A, B, C, D); 138 | T_0_15( 2, D, E, A, B, C); 139 | T_0_15( 3, C, D, E, A, B); 140 | T_0_15( 4, B, C, D, E, A); 141 | T_0_15( 5, A, B, C, D, E); 142 | T_0_15( 6, E, A, B, C, D); 143 | T_0_15( 7, D, E, A, B, C); 144 | T_0_15( 8, C, D, E, A, B); 145 | T_0_15( 9, B, C, D, E, A); 146 | T_0_15(10, A, B, C, D, E); 147 | T_0_15(11, E, A, B, C, D); 148 | T_0_15(12, D, E, A, B, C); 149 | T_0_15(13, C, D, E, A, B); 150 | T_0_15(14, B, C, D, E, A); 151 | T_0_15(15, A, B, C, D, E); 152 | 153 | /* Round 1 - tail. Input from 512-bit mixing array */ 154 | T_16_19(16, E, A, B, C, D); 155 | T_16_19(17, D, E, A, B, C); 156 | T_16_19(18, C, D, E, A, B); 157 | T_16_19(19, B, C, D, E, A); 158 | 159 | /* Round 2 */ 160 | T_20_39(20, A, B, C, D, E); 161 | T_20_39(21, E, A, B, C, D); 162 | T_20_39(22, D, E, A, B, C); 163 | T_20_39(23, C, D, E, A, B); 164 | T_20_39(24, B, C, D, E, A); 165 | T_20_39(25, A, B, C, D, E); 166 | T_20_39(26, E, A, B, C, D); 167 | T_20_39(27, D, E, A, B, C); 168 | T_20_39(28, C, D, E, A, B); 169 | T_20_39(29, B, C, D, E, A); 170 | T_20_39(30, A, B, C, D, E); 171 | T_20_39(31, E, A, B, C, D); 172 | T_20_39(32, D, E, A, B, C); 173 | T_20_39(33, C, D, E, A, B); 174 | T_20_39(34, B, C, D, E, A); 175 | T_20_39(35, A, B, C, D, E); 176 | T_20_39(36, E, A, B, C, D); 177 | T_20_39(37, D, E, A, B, C); 178 | T_20_39(38, C, D, E, A, B); 179 | T_20_39(39, B, C, D, E, A); 180 | 181 | /* Round 3 */ 182 | T_40_59(40, A, B, C, D, E); 183 | T_40_59(41, E, A, B, C, D); 184 | T_40_59(42, D, E, A, B, C); 185 | T_40_59(43, C, D, E, A, B); 186 | T_40_59(44, B, C, D, E, A); 187 | T_40_59(45, A, B, C, D, E); 188 | T_40_59(46, E, A, B, C, D); 189 | T_40_59(47, D, E, A, B, C); 190 | T_40_59(48, C, D, E, A, B); 191 | T_40_59(49, B, C, D, E, A); 192 | T_40_59(50, A, B, C, D, E); 193 | T_40_59(51, E, A, B, C, D); 194 | T_40_59(52, D, E, A, B, C); 195 | T_40_59(53, C, D, E, A, B); 196 | T_40_59(54, B, C, D, E, A); 197 | T_40_59(55, A, B, C, D, E); 198 | T_40_59(56, E, A, B, C, D); 199 | T_40_59(57, D, E, A, B, C); 200 | T_40_59(58, C, D, E, A, B); 201 | T_40_59(59, B, C, D, E, A); 202 | 203 | /* Round 4 */ 204 | T_60_79(60, A, B, C, D, E); 205 | T_60_79(61, E, A, B, C, D); 206 | T_60_79(62, D, E, A, B, C); 207 | T_60_79(63, C, D, E, A, B); 208 | T_60_79(64, B, C, D, E, A); 209 | T_60_79(65, A, B, C, D, E); 210 | T_60_79(66, E, A, B, C, D); 211 | T_60_79(67, D, E, A, B, C); 212 | T_60_79(68, C, D, E, A, B); 213 | T_60_79(69, B, C, D, E, A); 214 | T_60_79(70, A, B, C, D, E); 215 | T_60_79(71, E, A, B, C, D); 216 | T_60_79(72, D, E, A, B, C); 217 | T_60_79(73, C, D, E, A, B); 218 | T_60_79(74, B, C, D, E, A); 219 | T_60_79(75, A, B, C, D, E); 220 | T_60_79(76, E, A, B, C, D); 221 | T_60_79(77, D, E, A, B, C); 222 | T_60_79(78, C, D, E, A, B); 223 | T_60_79(79, B, C, D, E, A); 224 | 225 | ctx->H[0] += A; 226 | ctx->H[1] += B; 227 | ctx->H[2] += C; 228 | ctx->H[3] += D; 229 | ctx->H[4] += E; 230 | } 231 | 232 | void blk_SHA1_Init(blk_SHA_CTX *ctx) 233 | { 234 | ctx->size = 0; 235 | 236 | /* Initialize H with the magic constants (see FIPS180 for constants) */ 237 | ctx->H[0] = 0x67452301; 238 | ctx->H[1] = 0xefcdab89; 239 | ctx->H[2] = 0x98badcfe; 240 | ctx->H[3] = 0x10325476; 241 | ctx->H[4] = 0xc3d2e1f0; 242 | } 243 | 244 | void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, unsigned long len) 245 | { 246 | int lenW = ctx->size & 63; 247 | 248 | ctx->size += len; 249 | 250 | /* Read the data into W and process blocks as they get full */ 251 | if (lenW) { 252 | int left = 64 - lenW; 253 | if (len < left) 254 | left = len; 255 | memcpy(lenW + (char *)ctx->W, data, left); 256 | lenW = (lenW + left) & 63; 257 | len -= left; 258 | data = ((const char *)data + left); 259 | if (lenW) 260 | return; 261 | blk_SHA1_Block(ctx, ctx->W); 262 | } 263 | while (len >= 64) { 264 | blk_SHA1_Block(ctx, (const unsigned int*)data); 265 | data = ((const char *)data + 64); 266 | len -= 64; 267 | } 268 | if (len) 269 | memcpy(ctx->W, data, len); 270 | } 271 | 272 | void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx) 273 | { 274 | static const unsigned char pad[64] = { 0x80 }; 275 | unsigned int padlen[2]; 276 | int i; 277 | 278 | /* Pad with a binary 1 (ie 0x80), then zeroes, then length */ 279 | padlen[0] = htonl(ctx->size >> 29); 280 | padlen[1] = htonl(ctx->size << 3); 281 | 282 | i = ctx->size & 63; 283 | blk_SHA1_Update(ctx, pad, 1+ (63 & (55 - i))); 284 | blk_SHA1_Update(ctx, padlen, 8); 285 | 286 | /* Output hash */ 287 | for (i = 0; i < 5; i++) 288 | put_be32(hashout + i*4, ctx->H[i]); 289 | } 290 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | // licensed under the GPL v2 as part of the git project http://git-scm.com/ 2 | /* 3 | * SHA1 routine optimized to do word accesses rather than byte accesses, 4 | * and to avoid unnecessary copies into the context array. 5 | * 6 | * This was initially based on the Mozilla SHA1 implementation, although 7 | * none of the original Mozilla code remains. 8 | */ 9 | #ifndef GIT_SHA1 10 | #define GIT_SHA1 11 | 12 | typedef struct { 13 | unsigned long long size; 14 | unsigned int H[5]; 15 | unsigned int W[16]; 16 | } blk_SHA_CTX; 17 | 18 | void blk_SHA1_Init(blk_SHA_CTX *ctx); 19 | void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, unsigned long len); 20 | void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx); 21 | 22 | #endif 23 | 24 | -------------------------------------------------------------------------------- /swift.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * swift.cpp 3 | * swift the multiparty transport protocol 4 | * 5 | * Created by Victor Grishchenko on 2/15/10. 6 | * Copyright 2010 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include "compat.h" 12 | #include "swift.h" 13 | 14 | using namespace swift; 15 | 16 | #define quit(...) {fprintf(stderr,__VA_ARGS__); exit(1); } 17 | SOCKET InstallHTTPGateway (Address addr); 18 | 19 | 20 | int main (int argc, char** argv) { 21 | 22 | static struct option long_options[] = 23 | { 24 | {"hash", required_argument, 0, 'h'}, 25 | {"file", required_argument, 0, 'f'}, 26 | {"daemon", no_argument, 0, 'd'}, 27 | {"listen", required_argument, 0, 'l'}, 28 | {"tracker", required_argument, 0, 't'}, 29 | {"debug", no_argument, 0, 'D'}, 30 | {"progress",no_argument, 0, 'p'}, 31 | {"http", optional_argument, 0, 'g'}, 32 | {"wait", optional_argument, 0, 'w'}, 33 | {0, 0, 0, 0} 34 | }; 35 | 36 | Sha1Hash root_hash; 37 | char* filename = 0; 38 | bool daemonize = false, report_progress = false; 39 | Address bindaddr; 40 | Address tracker; 41 | Address http_gw; 42 | tint wait_time = 0; 43 | 44 | LibraryInit(); 45 | 46 | int c; 47 | while ( -1 != (c = getopt_long (argc, argv, ":h:f:dl:t:Dpg::w::", long_options, 0)) ) { 48 | 49 | switch (c) { 50 | case 'h': 51 | if (strlen(optarg)!=40) 52 | quit("SHA1 hash must be 40 hex symbols\n"); 53 | root_hash = Sha1Hash(true,optarg); // FIXME ambiguity 54 | if (root_hash==Sha1Hash::ZERO) 55 | quit("SHA1 hash must be 40 hex symbols\n"); 56 | break; 57 | case 'f': 58 | filename = strdup(optarg); 59 | break; 60 | case 'd': 61 | daemonize = true; 62 | break; 63 | case 'l': 64 | bindaddr = Address(optarg); 65 | if (bindaddr==Address()) 66 | quit("address must be hostname:port, ip:port or just port\n"); 67 | wait_time = TINT_NEVER; 68 | break; 69 | case 't': 70 | tracker = Address(optarg); 71 | if (tracker==Address()) 72 | quit("address must be hostname:port, ip:port or just port\n"); 73 | SetTracker(tracker); 74 | break; 75 | case 'D': 76 | Channel::debug_file = optarg ? fopen(optarg,"a") : stdout; 77 | break; 78 | case 'p': 79 | report_progress = true; 80 | break; 81 | case 'g': 82 | http_gw = optarg ? Address(optarg) : Address(Address::LOCALHOST,8080); 83 | if (wait_time==-1) 84 | wait_time = TINT_NEVER; // seed 85 | break; 86 | case 'w': 87 | if (optarg) { 88 | char unit = 'u'; 89 | if (sscanf(optarg,"%lli%c",&wait_time,&unit)!=2) 90 | quit("time format: 1234[umsMHD], e.g. 1M = one minute\n"); 91 | switch (unit) { 92 | case 'D': wait_time *= 24; 93 | case 'H': wait_time *= 60; 94 | case 'M': wait_time *= 60; 95 | case 's': wait_time *= 1000; 96 | case 'm': wait_time *= 1000; 97 | case 'u': break; 98 | default: quit("time format: 1234[umsMHD], e.g. 1D = one day\n"); 99 | } 100 | } else 101 | wait_time = TINT_NEVER; 102 | break; 103 | } 104 | 105 | } // arguments parsed 106 | 107 | 108 | if (bindaddr!=Address()) { // seeding 109 | if (Listen(bindaddr)<=0) 110 | quit("cant listen to %s\n",bindaddr.str()) 111 | } else if (tracker!=Address() || http_gw!=Address()) { // leeching 112 | for (int i=0; i<=10; i++) { 113 | bindaddr = Address((uint32_t)INADDR_ANY,0); 114 | if (Listen(bindaddr)>0) 115 | break; 116 | if (i==10) 117 | quit("cant listen on %s\n",bindaddr.str()); 118 | } 119 | } 120 | 121 | if (tracker!=Address()) 122 | SetTracker(tracker); 123 | 124 | if (http_gw!=Address()) 125 | InstallHTTPGateway(http_gw); 126 | 127 | if (root_hash!=Sha1Hash::ZERO && !filename) 128 | filename = strdup(root_hash.hex().c_str()); 129 | 130 | int file = -1; 131 | if (filename) { 132 | file = Open(filename,root_hash); 133 | if (file<=0) 134 | quit("cannot open file %s",filename); 135 | printf("Root hash: %s\n", RootMerkleHash(file).hex().c_str()); 136 | } 137 | 138 | if (bindaddr==Address() && file==-1 && http_gw==Address()) { 139 | fprintf(stderr,"Usage:\n"); 140 | fprintf(stderr," -h, --hash\troot Merkle hash for the transmission\n"); 141 | fprintf(stderr," -f, --file\tname of file to use (root hash by default)\n"); 142 | fprintf(stderr," -l, --listen\t[ip:|host:]port to listen to (default: random)\n"); 143 | fprintf(stderr," -t, --tracker\t[ip:|host:]port of the tracker (default: none)\n"); 144 | fprintf(stderr," -D, --debug\tfile name for debugging logs (default: stdout)\n"); 145 | fprintf(stderr," -p, --progress\treport transfer progress\n"); 146 | fprintf(stderr," -g, --http\t[ip:|host:]port to bind HTTP gateway to (default localhost:8080)\n"); 147 | fprintf(stderr," -w, --wait\tlimit running time, e.g. 1[DHMs] (default: infinite with -l, -g)\n"); 148 | return 1; 149 | } 150 | 151 | tint start_time = NOW; 152 | 153 | while ( (file>=0 && !IsComplete(file)) || 154 | (start_time+wait_time>NOW) ) { 155 | swift::Loop(TINT_SEC); 156 | if (report_progress && file>=0) { 157 | fprintf(stderr, 158 | "%s %lli of %lli (seq %lli) %lli dgram %lli bytes up, "\ 159 | "%lli dgram %lli bytes down\n", 160 | IsComplete(file) ? "DONE" : "done", 161 | Complete(file), Size(file), SeqComplete(file), 162 | Datagram::dgrams_up, Datagram::bytes_up, 163 | Datagram::dgrams_down, Datagram::bytes_down ); 164 | } 165 | } 166 | 167 | if (file!=-1) 168 | Close(file); 169 | 170 | if (Channel::debug_file) 171 | fclose(Channel::debug_file); 172 | 173 | swift::Shutdown(); 174 | 175 | return 0; 176 | 177 | } 178 | 179 | -------------------------------------------------------------------------------- /tests/SConscript: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | Import("DEBUG") 4 | Import("env") 5 | Import("libs") 6 | Import("libpath") 7 | 8 | cpppath = env["CPPPATH"] 9 | if DEBUG and sys.platform == "win32": 10 | libs = ['swift','gtestd'] + libs # order is important, crypto needs to be last 11 | else: 12 | libs = ['swift','gtest'] + libs # order is important, crypto needs to be last 13 | 14 | if sys.platform == "win32": 15 | cpppath = ".." 16 | libpath += '..;' 17 | if DEBUG: 18 | env.Append(CXXFLAGS="/Zi /Yd /MTd") 19 | else: 20 | cpppath = cpppath + ':..' 21 | libpath += ':..' 22 | if DEBUG: 23 | env.Append(CXXFLAGS="-g") 24 | 25 | print "tests: libpath is",libpath 26 | 27 | env.Program( 28 | target='binstest2', 29 | source=['binstest2.cpp'], 30 | CPPPATH=cpppath, 31 | LIBS=libs, 32 | LIBPATH=libpath ) 33 | 34 | env.Program( 35 | target='dgramtest', 36 | source=['dgramtest.cpp'], 37 | CPPPATH=cpppath, 38 | LIBS=libs, 39 | LIBPATH=libpath ) 40 | 41 | env.Program( 42 | target='hashtest', 43 | source=['hashtest.cpp'], 44 | CPPPATH=cpppath, 45 | LIBS=libs, 46 | LIBPATH=libpath ) 47 | 48 | #env.Program( 49 | # target='ledbattest', 50 | # source=['ledbattest.cpp'], 51 | # CPPPATH=cpppath, 52 | # LIBS=libs, 53 | # LIBPATH=libpath ) 54 | 55 | 56 | #if sys.platform != "win32": 57 | # # Arno: Needs getopt 58 | # env.Program( 59 | # target='ledbattest2', 60 | # source=['ledbattest2.cpp'], 61 | # CPPPATH=cpppath, 62 | # LIBS=libs, 63 | # LIBPATH=libpath ) 64 | 65 | env.Program( 66 | target='freemap', 67 | source=['freemap.cpp'], 68 | CPPPATH=cpppath, 69 | LIBS=libs, 70 | LIBPATH=libpath ) 71 | 72 | env.Program( 73 | target='bin64test', 74 | source=['bin64test.cpp'], 75 | CPPPATH=cpppath, 76 | LIBS=libs, 77 | LIBPATH=libpath ) 78 | 79 | env.Program( 80 | target='transfertest', 81 | source=['transfertest.cpp'], 82 | CPPPATH=cpppath, 83 | LIBS=libs, 84 | LIBPATH=libpath ) 85 | 86 | env.Program( 87 | target='connecttest', 88 | source=['connecttest.cpp'], 89 | CPPPATH=cpppath, 90 | LIBS=libs, 91 | LIBPATH=libpath ) 92 | 93 | -------------------------------------------------------------------------------- /tests/bin64test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * bintest.cpp 3 | * bin++ 4 | * 5 | * Created by Victor Grishchenko on 3/9/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include "bin64.h" 10 | #include 11 | 12 | TEST(Bin64Test,InitGet) { 13 | 14 | EXPECT_EQ(0x1,bin64_t(1,0)); 15 | EXPECT_EQ(0xB,bin64_t(2,1)); 16 | EXPECT_EQ(0x2,bin64_t(2,1).layer()); 17 | EXPECT_EQ(34,bin64_t(34,2345).layer()); 18 | EXPECT_EQ(0x7ffffffffULL,bin64_t(34,2345).tail_bits()); 19 | EXPECT_EQ(1,bin64_t(2,1).offset()); 20 | EXPECT_EQ(2345,bin64_t(34,2345).offset()); 21 | EXPECT_EQ(1,bin64_t(0,123).tail_bit()); 22 | EXPECT_EQ(1<<16,bin64_t(16,123).tail_bit()); 23 | 24 | } 25 | 26 | TEST(Bin64Test,Navigation) { 27 | 28 | bin64_t mid(4,18); 29 | EXPECT_EQ(bin64_t(5,9),mid.parent()); 30 | EXPECT_EQ(bin64_t(3,36),mid.left()); 31 | EXPECT_EQ(bin64_t(3,37),mid.right()); 32 | EXPECT_EQ(bin64_t(5,9),bin64_t(4,19).parent()); 33 | bin64_t up32(30,1); 34 | EXPECT_EQ(bin64_t(31,0),up32.parent()); 35 | 36 | } 37 | 38 | TEST(Bin64Test,Overflows) { 39 | 40 | EXPECT_FALSE(bin64_t(0,1).within(bin64_t::NONE)); 41 | EXPECT_TRUE(bin64_t(0,1).within(bin64_t::ALL)); 42 | EXPECT_EQ(0,bin64_t::none().width()); 43 | EXPECT_EQ(bin64_t::none(),bin64_t::none().twisted(123)); 44 | /*EXPECT_EQ(bin64_t::NONE.parent(),bin64_t::NONE); 45 | EXPECT_EQ(bin64_t::NONE.left(),bin64_t::NONE); 46 | EXPECT_EQ(bin64_t::NONE.right(),bin64_t::NONE); 47 | EXPECT_EQ(bin64_t::NONE,bin64_t(0,2345).left()); 48 | EXPECT_EQ(bin64_t::NONE,bin64_t::ALL.parent()); 49 | */ 50 | } 51 | 52 | TEST(Bin64Test, Advanced) { 53 | 54 | EXPECT_EQ(4,bin64_t(2,3).width()); 55 | EXPECT_FALSE(bin64_t(1,1234).is_base()); 56 | EXPECT_TRUE(bin64_t(0,12345).is_base()); 57 | EXPECT_EQ(bin64_t(0,2),bin64_t(1,1).left_foot()); 58 | bin64_t peaks[64]; 59 | int peak_count = bin64_t::peaks(7,peaks); 60 | EXPECT_EQ(3,peak_count); 61 | EXPECT_EQ(bin64_t(2,0),peaks[0]); 62 | EXPECT_EQ(bin64_t(1,2),peaks[1]); 63 | EXPECT_EQ(bin64_t(0,6),peaks[2]); 64 | 65 | } 66 | 67 | TEST(Bin64Test, Iteration) { 68 | bin64_t i(1,0); 69 | i = i.next_dfsio(1); 70 | EXPECT_EQ(bin64_t(1,1),i); 71 | i = i.next_dfsio(1); 72 | EXPECT_EQ(bin64_t(2,0),i); 73 | i = i.next_dfsio(1); 74 | EXPECT_EQ(bin64_t(1,2),i); 75 | i = i.next_dfsio(1); 76 | EXPECT_EQ(bin64_t(1,3),i); 77 | i = i.next_dfsio(1); 78 | EXPECT_EQ(bin64_t(2,1),i); 79 | i = i.next_dfsio(1); 80 | EXPECT_EQ(bin64_t(3,0),i); 81 | } 82 | 83 | TEST(Bin64Test, Bits) { 84 | bin64_t all = bin64_t::ALL, none = bin64_t::NONE, big = bin64_t(40,18); 85 | uint32_t a32 = all.to32(), n32 = none.to32(), b32 = big.to32(); 86 | EXPECT_EQ(0x7fffffff,a32); 87 | EXPECT_EQ(0xffffffff,n32); 88 | EXPECT_EQ(bin64_t::NONE32,b32); 89 | } 90 | 91 | int main (int argc, char** argv) { 92 | 93 | testing::InitGoogleTest(&argc, argv); 94 | return RUN_ALL_TESTS(); 95 | 96 | } 97 | -------------------------------------------------------------------------------- /tests/binstest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * binstest.cpp 3 | * serp++ 4 | * 5 | * Created by Victor Grishchenko on 3/22/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include "bin.h" 13 | #include "sbit.h" 14 | 15 | TEST(BinsTest,AddSub) { 16 | bins b; 17 | b|=15; 18 | b-=1; 19 | ASSERT_TRUE(b.contains(2)); 20 | ASSERT_TRUE(b.contains(14)); 21 | ASSERT_FALSE(b.contains(3)); 22 | ASSERT_FALSE(b.contains(22)); 23 | ASSERT_TRUE(b.contains(12)); 24 | b-=13; 25 | ASSERT_FALSE(b.contains(12)); 26 | ASSERT_FALSE(b.contains(14)); 27 | ASSERT_FALSE(b.contains(11)); 28 | ASSERT_TRUE(b.contains(10)); 29 | } 30 | 31 | 32 | TEST(BinsTest,Peaks) { 33 | bin::vec peaks = bin::peaks(11); 34 | ASSERT_EQ(3,peaks.size()); 35 | ASSERT_EQ(15,peaks[0]); 36 | ASSERT_EQ(18,peaks[1]); 37 | ASSERT_EQ(19,peaks[2]); 38 | } 39 | 40 | TEST(BinsTest,Performance) { 41 | bins b; 42 | std::set s; 43 | clock_t start, end; 44 | double b_time, s_time; 45 | int b_size, s_size; 46 | 47 | start = clock(); 48 | for(int i=1; i<(1<<20); i++) 49 | b |= bin(i); 50 | //b_size = b.bits.size(); 51 | end = clock(); 52 | b_time = ((double) (end - start)) / CLOCKS_PER_SEC; 53 | //ASSERT_EQ(1,b.bits.size()); 54 | 55 | start = clock(); 56 | for(int i=1; i<(1<<20); i++) 57 | s.insert(i); 58 | s_size = s.size(); 59 | end = clock(); 60 | s_time = ((double) (end - start)) / CLOCKS_PER_SEC; 61 | 62 | printf("bins: %f (%i), set: %f (%i)\n",b_time,b_size,s_time,s_size); 63 | } 64 | 65 | int main (int argc, char** argv) { 66 | bin::init(); 67 | testing::InitGoogleTest(&argc, argv); 68 | return RUN_ALL_TESTS(); 69 | } 70 | -------------------------------------------------------------------------------- /tests/bintest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * bintest.cpp 3 | * bin++ 4 | * 5 | * Created by Victor Grishchenko on 3/9/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include "bin.h" 10 | #include 11 | 12 | TEST(BinTest,Mass) { 13 | EXPECT_EQ(bin(4).length(),3); 14 | EXPECT_EQ(bin(9).length(),6); 15 | EXPECT_EQ(bin(3).mass(),3); 16 | EXPECT_EQ(bin(5).mass(),1); 17 | EXPECT_EQ(bin(6).mass(),3); 18 | EXPECT_EQ(bin(10).mass(),3); 19 | EXPECT_TRUE(bin::all1(1)); 20 | EXPECT_TRUE(bin::all1(7)); 21 | } 22 | 23 | TEST(BinTest,Instantiation) { 24 | EXPECT_EQ(bin(0,1),2)<<"bin_new @0"; 25 | EXPECT_EQ(bin(2,0),7)<<"bin_new @2"; 26 | EXPECT_EQ(bin(1,2),10)<<"bin_new @1"; 27 | EXPECT_EQ(12,bin(0,7))<<"bin(0,7)"; 28 | EXPECT_EQ(9,bin::tailzeros(512)); 29 | EXPECT_EQ(0,bin::tailzeros(1)); 30 | EXPECT_EQ(5,bin::tailzeros(32+128)); 31 | } 32 | 33 | TEST(BinTest,Traversing) { 34 | EXPECT_EQ(6,bin(4).parent()); 35 | EXPECT_EQ(bin(30).parent(),31); 36 | EXPECT_EQ(bin(7).parent(),15); 37 | EXPECT_EQ(bin(18).parent(),22); 38 | EXPECT_EQ(bin(30).left(),22); 39 | EXPECT_EQ(bin(14).left(),10); 40 | EXPECT_EQ(bin(22).left(),18); 41 | EXPECT_EQ(bin(30).right(),29); 42 | EXPECT_EQ(bin(14).right(),13); 43 | EXPECT_EQ(bin(22).right(),21); 44 | EXPECT_EQ(bin(15).left_foot(),1)<<"15 left foot"; 45 | EXPECT_EQ(bin(15).right_foot(),12)<<"15 right foot"; 46 | EXPECT_EQ(bin(22).left_foot(),16)<<"22 left foot"; 47 | EXPECT_EQ(bin(22).right_foot(),20)<<"22 right foot"; 48 | } 49 | 50 | TEST(BinTest,Advanced) { 51 | EXPECT_EQ(0,bin(1).layer()); 52 | 53 | EXPECT_TRUE(bin(31).contains(14)); 54 | EXPECT_FALSE(bin(22).contains(14)); 55 | EXPECT_TRUE(bin(7).contains(7)); 56 | EXPECT_TRUE(bin(11).contains(11)); 57 | EXPECT_TRUE(bin(22).contains(20)); 58 | 59 | EXPECT_EQ(6,bin(5).commonParent(4)) << "common parent trivial"; 60 | EXPECT_EQ(7,bin(2).commonParent(4)) << "common parent trivial"; 61 | EXPECT_EQ(14,bin(8).commonParent(11)) << "common parent trick"; 62 | EXPECT_EQ(31,bin(14).commonParent(16)) << "common parent complex"; 63 | EXPECT_EQ(31,bin(8).commonParent(16)) << "common parent trick 2"; 64 | EXPECT_EQ(31,bin(31).commonParent(1)) << "common parent trick 2"; 65 | EXPECT_EQ(22,bin(22).commonParent(19)) << "common parent nested"; 66 | EXPECT_EQ(22,bin(19).commonParent(22)) << "common parent nested rev"; 67 | EXPECT_EQ(63,bin(32).commonParent(12)) << "common parent nested rev"; 68 | EXPECT_EQ(31,bin(14).commonParent(18)) << "common parent nested rev"; 69 | EXPECT_EQ(12,bin(12).commonParent(12)) << "common parent nested rev"; 70 | for(bin i=1; i<=127; i++) 71 | for(bin j=1; j<=127; j++) if (i!=j) { 72 | bin c = i.commonParent(j); 73 | EXPECT_TRUE(c.contains(i)); 74 | EXPECT_TRUE(c.contains(j)); 75 | bin l=c.left(), r=c.right(); 76 | //printf("%i %i => %i (%i,%i)\n",(int)i,(int)j,(int)c,(int)l,(int)r); 77 | EXPECT_FALSE(l.contains(i)&&l.contains(j)); 78 | EXPECT_FALSE(r.contains(i)&&r.contains(j)); 79 | } 80 | EXPECT_EQ(22,bin(16).parent(2)) << "parent 2"; 81 | EXPECT_EQ(31,bin(9).parent(4)) << "parent-snake"; 82 | } 83 | 84 | TEST(BinTest,Overflows) { 85 | // TODO 86 | //EXPECT_EQ( 1<<31, bin::ALL.length() ); 87 | } 88 | 89 | TEST(BinTest,Division) { 90 | EXPECT_EQ(bin(14).modulo(3),14); 91 | EXPECT_EQ(bin(22).modulo(3),7); 92 | EXPECT_EQ(bin(21).modulo(1),3); 93 | EXPECT_EQ(bin(31).modulo(3),15); 94 | EXPECT_EQ(bin(31).modulo(4),31); 95 | EXPECT_EQ(bin(22).divide(2),4); 96 | EXPECT_EQ(bin(30).divide(2),6); 97 | EXPECT_EQ(bin(31).divide(3),3); 98 | EXPECT_EQ(bin(14).multiply(1),30); 99 | EXPECT_EQ(bin(6).multiply(2),30); 100 | } 101 | 102 | TEST(BinTest, Scope) { 103 | EXPECT_EQ(1,bin(32).scoped(bin(62),4)); 104 | EXPECT_EQ(14,bin(29).scoped(bin(30),3)); 105 | EXPECT_EQ(15,bin(30).scoped(bin(30),3)); 106 | EXPECT_EQ(5,bin(11).scoped(bin(31),3)); 107 | EXPECT_EQ(4,bin(22).scoped(bin(31),2)); 108 | 109 | EXPECT_EQ(14,bin(2).unscoped(bin(15),1)); 110 | EXPECT_EQ(22,bin(4).unscoped(bin(31),2)); 111 | } 112 | 113 | TEST(BinTest, Order) { 114 | bin::vec v; 115 | v.push_back(22); 116 | v.push_back(17); 117 | v.push_back(19); 118 | v.push_back(6); 119 | v.push_back(3); 120 | v.push_back(14); 121 | bin::order(&v); 122 | ASSERT_EQ(2,v.size()); 123 | EXPECT_EQ(v[1],15); 124 | EXPECT_EQ(v[0],22); 125 | } 126 | 127 | int main (int argc, char** argv) { 128 | bin::init(); 129 | 130 | bin p(12234); 131 | printf("%i %i %i %i\n",(int)p,p.layer(),p.offset(),p.offset()< 10 | #include 11 | #include 12 | #include 13 | #include "p2tp.h" 14 | 15 | using namespace std; 16 | using namespace p2tp; 17 | 18 | class SimPeer; 19 | 20 | struct SimPacket { 21 | SimPacket(int from, int to, const SimPacket* toack, bool data) ; 22 | int peerfrom, peerto; 23 | tint datatime; 24 | tint acktime; 25 | tint arrivaltime; 26 | }; 27 | 28 | tint now = 0; 29 | 30 | /** very simplified; uplink is the bottleneck */ 31 | class SimPeer { 32 | public: 33 | SimPeer (tint tt, tint lt, int qlen) : travtime(tt), latency(lt), queue_length(qlen) {} 34 | int queue_length; 35 | int travtime; 36 | tint freetime; 37 | tint latency; 38 | int unackd; 39 | int rcvd, sent; 40 | queue packet_queue; 41 | queue dropped_queue; 42 | CongestionControl congc; 43 | 44 | void send(SimPacket pck) { 45 | if (packet_queue.size()==queue_length) { 46 | dropped_queue.push(pck); 47 | return; 48 | } 49 | tint start = max(now,freetime); 50 | tint done = pck.datatime ? start+travtime : start; 51 | freetime = done; 52 | pck.arrivaltime = done + latency; 53 | packet_queue.push(pck); 54 | } 55 | 56 | SimPacket recv () { 57 | assert(!packet_queue.empty()); 58 | SimPacket ret = packet_queue.front(); 59 | packet_queue.pop(); 60 | return ret; 61 | } 62 | 63 | tint next_recv_time () const { 64 | return packet_queue.empty() ? NEVER : packet_queue.front().arrivaltime; 65 | } 66 | 67 | void turn () { 68 | SimPacket rp = recv(); 69 | SimPacket reply; 70 | now = rp.arrivaltime; 71 | if (rp.acktime) { 72 | congc.RttSample(rp.arrivaltime-rp.acktime); 73 | congc.OnCongestionEvent(CongestionControl::ACK_EV); 74 | unackd--; 75 | rcvd++; 76 | } 77 | if (rp.datatime) { 78 | congc.OnCongestionEvent(CongestionControl::DATA_EV); 79 | reply.acktime = reply.datatime; 80 | } 81 | if (!dropped_queue.empty() && dropped_queue.top().datatimeunackd) { 84 | unackd++; 85 | reply.datatime = now; 86 | sent++; 87 | } 88 | rp.from->send(reply); 89 | } 90 | }; 91 | 92 | TEST(P2TP, TailDropTest) { 93 | // two peers exchange packets over 100ms link with tail-drop discipline 94 | // bw 1Mbits => travel time of 1KB is ~10ms 95 | SimPeer a(10*MSEC,100*MSEC,20), b(10*MSEC,100*MSEC,20); 96 | a.send(SimPacket(&b,now,0,0)); 97 | while (now<60*60*SEC) 98 | if (a.next_recv_time() 11 | //#include 12 | #include "swift.h" 13 | #include 14 | 15 | 16 | using namespace swift; 17 | 18 | 19 | TEST(Connection,CwndTest) { 20 | 21 | srand ( time(NULL) ); 22 | 23 | unlink("doc/sofi-copy.jpg"); 24 | struct stat st; 25 | ASSERT_EQ(0,stat("doc/sofi.jpg", &st)); 26 | int size = st.st_size;//, sizek = (st.st_size>>10) + (st.st_size%1024?1:0) ; 27 | Channel::SELF_CONN_OK = true; 28 | 29 | int sock1 = swift::Listen(7001); 30 | ASSERT_TRUE(sock1>=0); 31 | 32 | int file = swift::Open("doc/sofi.jpg"); 33 | FileTransfer* fileobj = FileTransfer::file(file); 34 | //FileTransfer::instance++; 35 | 36 | swift::SetTracker(Address("127.0.0.1",7001)); 37 | 38 | int copy = swift::Open("doc/sofi-copy.jpg",fileobj->root_hash()); 39 | 40 | swift::Loop(TINT_SEC); 41 | 42 | int count = 0; 43 | while (swift::SeqComplete(copy)!=size && count++<600) 44 | swift::Loop(TINT_SEC); 45 | ASSERT_EQ(size,swift::SeqComplete(copy)); 46 | 47 | swift::Close(file); 48 | swift::Close(copy); 49 | 50 | swift::Shutdown(sock1); 51 | 52 | } 53 | 54 | 55 | int main (int argc, char** argv) { 56 | 57 | swift::LibraryInit(); 58 | testing::InitGoogleTest(&argc, argv); 59 | Channel::debug_file = stdout; 60 | int ret = RUN_ALL_TESTS(); 61 | return ret; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /tests/dgramtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * dgramtest.cpp 3 | * serp++ 4 | * 5 | * Created by Victor Grishchenko on 3/13/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include 10 | //#include 11 | #include "datagram.h" 12 | #include "swift.h" // Arno: for LibraryInit 13 | 14 | using namespace swift; 15 | 16 | TEST(Datagram, AddressTest) { 17 | Address addr("127.0.0.1:1000"); 18 | EXPECT_EQ(INADDR_LOOPBACK,addr.ipv4()); 19 | EXPECT_EQ(1000,addr.port()); 20 | Address das2("node300.das2.ewi.tudelft.nl:20000"); 21 | Address das2b("130.161.211.200:20000"); 22 | EXPECT_EQ(das2.ipv4(),das2b.ipv4()); 23 | EXPECT_EQ(20000,das2.port()); 24 | } 25 | 26 | 27 | TEST(Datagram, BinaryTest) { 28 | SOCKET socket = Datagram::Bind(7001); 29 | ASSERT_TRUE(socket>0); 30 | struct sockaddr_in addr; 31 | addr.sin_family = AF_INET; 32 | addr.sin_port = htons(7001); 33 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 34 | Datagram d(socket,addr); //Address(7001)); 35 | const char * text = "text"; 36 | const uint8_t num8 = 0xab; 37 | const uint16_t num16 = 0xabcd; 38 | const uint32_t num32 = 0xabcdef01; 39 | const uint64_t num64 = 0xabcdefabcdeffULL; 40 | d.PushString(text); 41 | d.Push8(num8); 42 | d.Push16(num16); 43 | d.Push32(num32); 44 | d.Push64(num64); 45 | char buf[1024]; 46 | int i; 47 | for(i=0; i0); 79 | ASSERT_TRUE(sock2>0); 80 | /*struct sockaddr_in addr1, addr2; 81 | addr1.sin_family = AF_INET; 82 | addr1.sin_port = htons(10001); 83 | addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 84 | addr2.sin_family = AF_INET; 85 | addr2.sin_port = htons(10002); 86 | addr2.sin_addr.s_addr = htonl(INADDR_LOOPBACK);*/ 87 | 88 | Datagram send(sock1,Address("127.0.0.1:10002")); 89 | send.Push32(1234); 90 | send.Send(); 91 | 92 | SOCKET socks[2] = {sock1,sock2}; 93 | // Arno: timeout 0 gives undeterministic behaviour on win32 94 | //EXPECT_EQ(sock2, 95 | Datagram::Wait(1000000); 96 | //); 97 | Datagram recv(sock2); 98 | recv.Recv(); 99 | uint32_t test = recv.Pull32(); 100 | ASSERT_EQ(1234,test); 101 | 102 | Datagram::Close(sock1); 103 | Datagram::Close(sock2); 104 | } 105 | 106 | int main (int argc, char** argv) { 107 | 108 | swift::LibraryInit(); 109 | 110 | testing::InitGoogleTest(&argc, argv); 111 | return RUN_ALL_TESTS(); 112 | 113 | } 114 | -------------------------------------------------------------------------------- /tests/freemap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * binstest.cpp 3 | * serp++ 4 | * 5 | * Created by Victor Grishchenko on 3/22/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include "bins.h" 13 | 14 | #ifdef _MSC_VER 15 | #define RANDOM rand 16 | #else 17 | #define RANDOM random 18 | #endif 19 | 20 | int bins_stripe_count (binmap_t& b) { 21 | int stripe_count; 22 | uint64_t * stripes = b.get_stripes(stripe_count); 23 | free(stripes); 24 | return stripe_count; 25 | } 26 | 27 | uint8_t rand_norm (uint8_t lim) { 28 | long rnd = RANDOM() & ((1<>= 1; 33 | } 34 | return bits; 35 | } 36 | 37 | TEST(FreemapTest,Freemap) { 38 | binmap_t space; 39 | const bin64_t top(30,0); 40 | space.set(top,binmap_t::EMPTY); 41 | typedef std::pair timebin_t; 42 | typedef std::set ts_t; 43 | ts_t to_free; 44 | for (int t=0; t<1000000; t++) { 45 | if (t<500000 || t>504000) { 46 | uint8_t lr = rand_norm(28); 47 | bin64_t alloc = space.find(top); 48 | while (alloc.layer()>lr) 49 | alloc = alloc.left(); 50 | ASSERT_NE(0ULL,~alloc); 51 | EXPECT_EQ(binmap_t::EMPTY, space.get(alloc)); 52 | space.set(alloc,binmap_t::FILLED); 53 | long dealloc_time = 1<first<=t) { 61 | bin64_t freebin = to_free.begin()->second; 62 | to_free.erase(to_free.begin()); 63 | space.set(freebin,binmap_t::EMPTY); 64 | printf("freed at %lli\n", 65 | (uint64_t)freebin); 66 | } 67 | // log: space taken, gaps, binmap cells, tree cells 68 | int cells = space.size(); 69 | int intervals = bins_stripe_count(space); 70 | printf("time %i cells used %i intervals %i blocks %i\n", 71 | t,cells,intervals,(int)to_free.size()); 72 | //space.dump("space"); 73 | } 74 | for(ts_t::iterator i=to_free.begin(); i!=to_free.end(); i++) 75 | space.set(i->second,binmap_t::EMPTY); 76 | EXPECT_EQ(binmap_t::EMPTY,space.get(top)); 77 | } 78 | 79 | int main (int argc, char** argv) { 80 | testing::InitGoogleTest(&argc, argv); 81 | return RUN_ALL_TESTS(); 82 | } 83 | -------------------------------------------------------------------------------- /tests/hashtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * hashtest.cpp 3 | * serp++ 4 | * 5 | * Created by Victor Grishchenko on 3/12/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include 10 | #include "bin64.h" 11 | #include 12 | #include "hashtree.h" 13 | 14 | using namespace swift; 15 | 16 | char hash123[] = "a8fdc205a9f19cc1c7507a60c4f01b13d11d7fd0"; 17 | char rooth123[] = "d0bdb8ba28076d84d2b3a0e62521b998e42349a1"; 18 | 19 | TEST(Sha1HashTest,Trivial) { 20 | Sha1Hash hash("123\n"); 21 | EXPECT_STREQ(hash123,hash.hex().c_str()); 22 | } 23 | 24 | 25 | TEST(Sha1HashTest,OfferDataTest) { 26 | Sha1Hash roothash123(true,hash123); 27 | for(bin64_t pos(0,0); pos!=bin64_t::ALL; pos=pos.parent()) 28 | roothash123 = Sha1Hash(roothash123,Sha1Hash::ZERO); 29 | unlink("123"); 30 | EXPECT_STREQ(rooth123,roothash123.hex().c_str()); 31 | HashTree tree("123",roothash123); 32 | tree.OfferHash(bin64_t(0,0),Sha1Hash(true,hash123)); 33 | ASSERT_EQ(1,tree.packet_size()); 34 | ASSERT_TRUE(tree.OfferData(bin64_t(0,0), "123\n", 4)); 35 | unlink("123"); 36 | ASSERT_EQ(4,tree.size()); 37 | } 38 | 39 | 40 | TEST(Sha1HashTest,SubmitTest) { 41 | FILE* f123 = fopen("123","wb+"); 42 | fprintf(f123, "123\n"); 43 | fclose(f123); 44 | HashTree ht123("123"); 45 | EXPECT_STREQ(hash123,ht123.hash(bin64_t(0,0)).hex().c_str()); 46 | EXPECT_STREQ(rooth123,ht123.root_hash().hex().c_str()); 47 | EXPECT_EQ(4,ht123.size()); 48 | } 49 | 50 | 51 | /*TEST(Sha1HashTest,HashFileTest) { 52 | uint8_t a [1024], b[1024], c[1024]; 53 | memset(a,'a',1024); 54 | memset(b,'b',1024); 55 | memset(c,'c',1024); 56 | Sha1Hash aaahash(a,1024), bbbhash(b,1024), ccchash(c,1024); 57 | Sha1Hash abhash(aaahash,bbbhash), c0hash(ccchash,Sha1Hash::ZERO); 58 | Sha1Hash aabbccroot(abhash,c0hash); 59 | for(bin pos=bin(7); pos 2 | #include 3 | #include 4 | #include 5 | #include "datagram.h" 6 | #include "swift.h" 7 | #include 8 | 9 | using namespace swift; 10 | using namespace std; 11 | 12 | /** 13 | TODO 14 | * losses 15 | * smooth rate 16 | * seq 12345 stop 17 | * busy pipe => negative cwnd 18 | */ 19 | 20 | TEST(Datagram,LedbatTest) { 21 | 22 | int MAX_REORDERING = 3; 23 | tint TARGET = 25*TINT_MSEC; 24 | float GAIN = 1.0/TARGET; 25 | int seq_off = 0; 26 | float cwnd = 1; 27 | tint DELAY_BIN = TINT_SEC*30; 28 | tint min_delay = TINT_NEVER; 29 | tint rtt_avg = TINT_NEVER>>4, dev_avg = TINT_NEVER>>4; 30 | tint last_bin_time = 0; 31 | tint last_drop_time = 0; 32 | int delay_bin = 0; 33 | deque history, delay_history; 34 | tint min_delay_bins[4] = {TINT_NEVER,TINT_NEVER, 35 | TINT_NEVER,TINT_NEVER}; 36 | tint cur_delays[4] = {TINT_NEVER,TINT_NEVER, 37 | TINT_NEVER,TINT_NEVER}; 38 | tint last_sec = 0; 39 | int sec_ackd = 0; 40 | 41 | SOCKET send_sock = Datagram::Bind(10001); // bind sending socket 42 | SOCKET ack_sock = Datagram::Bind(10002); // bind receiving socket 43 | struct sockaddr_in send_to, ack_to; 44 | send_to.sin_family = AF_INET; 45 | send_to.sin_port = htons(10002); 46 | send_to.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 47 | ack_to.sin_family = AF_INET; 48 | ack_to.sin_port = htons(10001); 49 | ack_to.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 50 | uint8_t* garbage = (uint8_t*) malloc(1024); 51 | SOCKET socks[2] = {send_sock,ack_sock}; 52 | SOCKET sock2read; 53 | tint wait_time = 100*TINT_MSEC; 54 | 55 | while (sock2read = Datagram::Wait(2,socks,wait_time)) { 56 | tint now = Datagram::Time(); 57 | if (sock2read==ack_sock) { 58 | Datagram data(ack_sock); // send an acknowledgement 59 | data.Recv(); 60 | int seq = data.Pull32(); 61 | Datagram ack(ack_sock,ack_to); 62 | ack.Push32(seq); 63 | ack.Push64(now); 64 | if (4+8!=ack.Send()) 65 | fprintf(stderr,"short write\n"); 66 | fprintf(stderr,"%lli rcvd%i\n",now/TINT_SEC,seq); 67 | //cc->OnDataRecv(bin64_t(0,seq)); 68 | // TODO: peer cwnd !!! 69 | continue; 70 | } 71 | if (sock2read==send_sock) { // process an acknowledgement 72 | Datagram ack(send_sock); 73 | ack.Recv(); 74 | int seq = ack.Pull32(); 75 | tint arrival_time = ack.Pull64(); 76 | seq -= seq_off; 77 | if (seq<0) 78 | continue; 79 | if (seq>=history.size()) 80 | continue; 81 | if (history[seq]==0) 82 | continue; 83 | tint send_time = history[seq]; 84 | history[seq] = 0; 85 | if (seq>MAX_REORDERING*2) { //loss 86 | if (last_drop_time delay) 112 | min_delay_bins[delay_bin] = delay; 113 | if (delay < min_delay) 114 | min_delay = delay; 115 | cur_delays[(seq_off+seq)%4] = delay; 116 | tint current_delay = TINT_NEVER; 117 | for(int i=0; i<4; i++) 118 | if (current_delay > cur_delays[i]) 119 | current_delay = cur_delays[i]; // FIXME avg 120 | tint queueing_delay = current_delay - min_delay; 121 | // adjust cwnd 122 | tint off_target = TARGET - queueing_delay; 123 | //cerr<<"\t"< 2 | #include 3 | #ifdef _MSC_VER 4 | #include "compat/stdint.h" 5 | #include 6 | #else 7 | #include 8 | #include 9 | #include 10 | #endif 11 | #include 12 | #include 13 | #include "datagram.h" 14 | #include "swift.h" 15 | #include 16 | 17 | using namespace swift; 18 | using namespace std; 19 | 20 | /** 21 | TODO 22 | * losses 23 | * smooth rate 24 | * seq 12345 stop 25 | * busy pipe => negative cwnd 26 | */ 27 | 28 | unsigned long dest_addr; 29 | int send_port = 10001; 30 | int ack_port = 10002; 31 | 32 | TEST(Datagram,LedbatTest) { 33 | 34 | int MAX_REORDERING = 3; 35 | tint TARGET = 25*TINT_MSEC; 36 | float GAIN = 1.0/TARGET; 37 | int seq_off = 0; 38 | float cwnd = 1; 39 | tint DELAY_BIN = TINT_SEC*30; 40 | tint min_delay = TINT_NEVER; 41 | tint rtt_avg = TINT_NEVER>>4, dev_avg = TINT_NEVER>>4; 42 | tint last_bin_time = 0; 43 | tint last_drop_time = 0; 44 | int delay_bin = 0; 45 | deque history, delay_history; 46 | tint min_delay_bins[4] = {TINT_NEVER,TINT_NEVER, 47 | TINT_NEVER,TINT_NEVER}; 48 | tint cur_delays[4] = {TINT_NEVER,TINT_NEVER, 49 | TINT_NEVER,TINT_NEVER}; 50 | tint last_sec = 0; 51 | int sec_ackd = 0; 52 | 53 | // bind sending socket 54 | SOCKET send_sock = Datagram::Bind(Address(INADDR_ANY,send_port)); 55 | // bind receiving socket 56 | SOCKET ack_sock = Datagram::Bind(Address(INADDR_ANY,ack_port)); 57 | struct sockaddr_in send_to, ack_to; 58 | memset(&send_to, 0, sizeof(struct sockaddr_in)); 59 | memset(&ack_to, 0, sizeof(struct sockaddr_in)); 60 | send_to.sin_family = AF_INET; 61 | send_to.sin_port = htons(ack_port); 62 | send_to.sin_addr.s_addr = dest_addr; 63 | ack_to.sin_family = AF_INET; 64 | ack_to.sin_port = htons(send_port); 65 | ack_to.sin_addr.s_addr = dest_addr; 66 | uint8_t* garbage = (uint8_t*) malloc(1024); 67 | SOCKET socks[2] = {send_sock,ack_sock}; 68 | SOCKET sock2read; 69 | tint wait_time = 100*TINT_MSEC; 70 | 71 | while (sock2read = Datagram::Wait(2,socks,wait_time)) { 72 | tint now = Datagram::Time(); 73 | if (sock2read==ack_sock) { 74 | Datagram data(ack_sock); // send an acknowledgement 75 | data.Recv(); 76 | int seq = data.Pull32(); 77 | Datagram ack(ack_sock,ack_to); 78 | ack.Push32(seq); 79 | ack.Push64(now); 80 | if (4+8!=ack.Send()) 81 | fprintf(stderr,"short write\n"); 82 | fprintf(stderr,"%lli rcvd%i\n",now/TINT_SEC,seq); 83 | // TODO: peer cwnd !!! 84 | continue; 85 | } 86 | if (sock2read==send_sock) { // process an acknowledgement 87 | Datagram ack(send_sock); 88 | ack.Recv(); 89 | int seq = ack.Pull32(); 90 | tint arrival_time = ack.Pull64(); 91 | seq -= seq_off; 92 | if (seq<0) 93 | continue; 94 | if (seq>=history.size()) 95 | continue; 96 | if (history[seq]==0) 97 | continue; 98 | tint send_time = history[seq]; 99 | history[seq] = 0; 100 | if (seq>MAX_REORDERING*2) { //loss 101 | if (last_drop_time delay) 127 | min_delay_bins[delay_bin] = delay; 128 | if (delay < min_delay) 129 | min_delay = delay; 130 | cur_delays[(seq_off+seq)%4] = delay; 131 | tint current_delay = TINT_NEVER; 132 | for(int i=0; i<4; i++) 133 | if (current_delay > cur_delays[i]) 134 | current_delay = cur_delays[i]; // FIXME avg 135 | tint queueing_delay = current_delay - min_delay; 136 | // adjust cwnd 137 | tint off_target = TARGET - queueing_delay; 138 | //cerr<<"\t"< $STORE/leecher$i.log ) & 15 | TOKILL="$TOKILL $!" 16 | sleep 4; 17 | done 18 | 19 | sleep 10 20 | 21 | for p in $TOKILL; do 22 | kill -9 $p 23 | done 24 | 25 | for i in `seq 1 $PEERCOUNT`; do 26 | cat $STORE/leecher$i.log | grep sent | awk '{print $5}' | \ 27 | sort | uniq -c > $STORE/peers$i.txt 28 | peers=`wc -l < $STORE/peers$i.txt` 29 | if [ $peers -ne $PEERCOUNT ]; then 30 | echo Peer $i has $peers peers 31 | fi 32 | done 33 | -------------------------------------------------------------------------------- /tests/rwtest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * readwrite.cpp 3 | * serp++ 4 | * 5 | * Created by Victor Grishchenko on 3/19/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | 10 | #include 11 | #include "p2tp.h" 12 | 13 | TEST(P2TP, ConnectTest) { 14 | P2File(""); 15 | p2tp_init(7001); 16 | 17 | int tf = p2tp_open("test_file",NULL); 18 | int tb = p2tp_open("test_file_copy",p2tp_file_info(tf)->hash_data); 19 | struct sockaddr_in addr; 20 | addr.sin_family = AF_INET; 21 | addr.sin_port = htons(7001); 22 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 23 | p2tp_add_peer(tb,addr,0); // TRICK: will open a channel to the first file 24 | p2tp_loop(P2TP::now()+TINT1SEC/10); 25 | 26 | while (count=copy.read(bytes)) { 27 | read(orig,bytes2,count); 28 | ASSERT_EQ ( 0, memcmp(bytes,bytes2,count) ); 29 | } 30 | 31 | p2tp_close(tb); 32 | p2tp_close(tf); 33 | 34 | } 35 | 36 | int main (int argc, char** argv) { 37 | P2TP::init(); 38 | 39 | testing::InitGoogleTest(&argc, argv); 40 | return RUN_ALL_TESTS(); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /tests/sbit2test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * sbit2test.cpp 3 | * serp++ 4 | * 5 | * Created by Victor Grishchenko on 4/1/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | 10 | #include "bin.h" 11 | #include "sbit.h" 12 | #include 13 | 14 | TEST(SbitTest,Init) { 15 | bins s; 16 | s.set(1); 17 | EXPECT_TRUE(s.get(1)); 18 | EXPECT_FALSE(s.get(2)); 19 | EXPECT_FALSE(s.get(3)); 20 | s.set(3); 21 | EXPECT_TRUE(s.get(1)); 22 | EXPECT_TRUE(s.get(2)); 23 | EXPECT_TRUE(s.get(3)); 24 | } 25 | 26 | 27 | TEST(SbitTest,Expand) { 28 | bins s; 29 | s.set(1); 30 | s.set(34); 31 | EXPECT_TRUE(s.get(1)); 32 | EXPECT_FALSE(s.get(2)); 33 | EXPECT_TRUE(s.get(32)); 34 | EXPECT_TRUE(s.get(33)); 35 | EXPECT_FALSE(s.get(35)); 36 | s.set(31); 37 | s.set(62); 38 | EXPECT_TRUE(s.get(3)); 39 | EXPECT_TRUE(s.get(63)); 40 | } 41 | 42 | 43 | TEST(SbitTest,Chess) { 44 | bins s; 45 | s.set(7); 46 | s.set(22); 47 | EXPECT_FALSE(s.get(14)); 48 | EXPECT_FALSE(s.get(30)); 49 | EXPECT_FALSE(s.get(29)); 50 | s.set(29); 51 | EXPECT_FALSE(s.get(31)); 52 | s.set(10); 53 | EXPECT_FALSE(s.get(31)); 54 | s.set(11); 55 | EXPECT_FALSE(s.get(31)); 56 | s.set(12); 57 | EXPECT_TRUE(s.get(31)); 58 | } 59 | 60 | 61 | TEST(SbitTest,Hole) { 62 | bins b; 63 | int h=14; 64 | for(int i=0; i "); 121 | bin::order(&v); 122 | ///for(int i=0; i 12 | 13 | TEST(SierpinskyBitmapTest,Init) { 14 | uint64_t one32 = (1ULL<<32)-1; 15 | uint64_t mask = one32; 16 | uint64_t mask_history[5]; 17 | for(int i=0; i<5; i++) { 18 | mask_history[i] = mask; 19 | mask = sbit::join(bin(i+1,0),mask,0); 20 | } 21 | EXPECT_EQ(1,mask)<<"joined OK"; 22 | for(int i=5; i; i--) { 23 | uint64pair p = sbit::split(bin(i,0),mask); 24 | mask = p.first; 25 | EXPECT_EQ(mask_history[i-1],mask)<<"mask history check"; 26 | } 27 | EXPECT_EQ(one32,mask)<<"join/split cycle"; 28 | 29 | EXPECT_EQ(3, sbit::MASKS[0][3])<<"the first two-bit interval, layer 0"; 30 | EXPECT_EQ(5, sbit::MASKS[1][3])<<"the first two-bit interval, layer 1"; 31 | EXPECT_EQ(0x000000000000000FLLU, sbit::MASKS[0][bin(2,0)])<<"the first four-bit interval @0"; 32 | EXPECT_EQ(0xFF00000000000000LLU, sbit::MASKS[0][bin(3,7)])<<"the last eight-bit interval @0"; 33 | EXPECT_EQ(0xAAAA000000000000LLU, sbit::MASKS[1][bin(3,7)])<<"the last eight-bit interval @1"; 34 | EXPECT_EQ(0x8080808080808080LLU, sbit::MASKS[3][bin(3,7)])<<"the last eight-bit interval @3"; 35 | EXPECT_EQ(1<<16, sbit::MASKS[0][bin(0,16)])<< "trivial: bit 16"; 36 | EXPECT_EQ(0x100000000LLU, sbit::MASKS[1][bin(0,16)])<< "trivial: bit 16 layer 1"; 37 | EXPECT_EQ(2, sbit::MASKS[2][bin(0,16)])<< "layout: bit wrap, 16 @layer 2"; 38 | } 39 | 40 | TEST(SierpinskyBitmapTest,GetSetAggregation) { 41 | sbit s; 42 | s.set(3); 43 | EXPECT_EQ(true,s.get(1)) << "trivial set/retr"; 44 | EXPECT_EQ(false,s.get(31)) << "trivial 0"; 45 | s.set(14); 46 | s.set(30); 47 | EXPECT_EQ(false,s.get(31)) << "trivial 0"; 48 | s.set(6); 49 | EXPECT_EQ(true,s.get(31)) << "aggregated set/retr"; 50 | s.set(127); 51 | EXPECT_EQ(true,s.get(127)) << "just extension"; 52 | EXPECT_EQ(false,s.get(255)) << "just extension"; 53 | s.set(254); 54 | EXPECT_EQ(true,s.get(255)) << "aggregated with extension"; 55 | } 56 | 57 | TEST(SierpinskyBitmapTest,FishEyeBitmaps) { 58 | sbit s; // 2^8 = 256 bits 59 | s.set(bin(7,0)); 60 | s.set(bin(5,4)); 61 | s.set(bin(1,128)); 62 | s.set(bin(2,80)); 63 | feye eye(s, bin(6,2)); 64 | // water-ground-air-mountain set/get 65 | EXPECT_EQ( eye.bits[2], sbit::MASK1 ) << "all-1 chunk"; 66 | EXPECT_EQ( sbit::MASKS[2][bin(0,16)], eye.bits[3] ) << "all-1 chunk"; 67 | EXPECT_EQ( true, eye.get(bin(5,4)) ) << "MOUNTAIN 1-half"; 68 | EXPECT_EQ( false, eye.get(bin(5,5)) ) << "MOUNTAIN 0-half"; 69 | EXPECT_EQ( true, eye.get(bin(6,1)) ) << "MOUNTAIN all-ones"; 70 | EXPECT_EQ( true, eye.get(bin(7,0)) ) << "top-MOUNTAIN 7 layer ones"; 71 | EXPECT_EQ( false, eye.get(bin(7,1)) ) << "AIR just a quarter is 1, must be 0"; 72 | EXPECT_EQ( true, eye.get(bin(2,80)) ) << "GROUND 4-bit fragment is saved"; 73 | EXPECT_EQ( true, eye.get(bin(1,160)) ) 74 | << "WATER 2-bit fragment is saved (farther from the focus)"; 75 | EXPECT_EQ( false, eye.get(bin(1,128)) ) 76 | << "sunk-WATER 2-bit fragment is lost (far from the focus)"; 77 | // refocus 78 | feye triv(eye, bin(0,64*3)); 79 | EXPECT_EQ(triv.bits[0],eye.bits[1])<<"trivial refocus 1"; 80 | EXPECT_EQ(triv.bits[1],eye.bits[0])<<"trivial refocus 2"; 81 | EXPECT_EQ(triv.bits[2],eye.bits[2])<<"trivial refocus 3"; 82 | feye ref(eye, bin(0,64*8)); 83 | EXPECT_EQ (false, ref.get(bin(2,80)) ) << "after refocusing, the 4-bit fragment is lost"; 84 | EXPECT_EQ (true, ref.get(bin(7,0)) ) << "but 7l (128bits) fragment is still there"; 85 | EXPECT_EQ (sbit::MASKS[3][bin(4,0)]|sbit::MASKS[3][bin(2,4)],ref.bits[4]) << "gather OK"; 86 | 87 | } 88 | 89 | 90 | TEST(SierpinskyBitmapTest,BitwiseOps) { 91 | feye l(bin(6,2)); 92 | feye r(bin(6,2)); 93 | l.set(bin(1,0)); 94 | r.set(bin(1,1)); 95 | feye orf(l); 96 | orf |= r; 97 | EXPECT_EQ (true, orf.get(bin(2,0))) << "OR adds up correctly"; 98 | EXPECT_EQ (false, orf.get(bin(2,1))) << "OR adds up correctly"; 99 | feye andf = l&r; 100 | EXPECT_EQ (false, andf.get(bin(2,0)) ) << "AND adds up correctly"; 101 | feye eye(bin(18,1)); 102 | eye.set(bin::ALL); 103 | EXPECT_EQ(true,eye.get(bin::ALL)) << "bin_ALL"; 104 | EXPECT_EQ(true,eye.get(bin(12,34))) << "any in bin_ALL"; 105 | EXPECT_EQ(sbit::MASK1,eye.bits[24]) << "bin_ALL: all 1"; 106 | } 107 | 108 | 109 | bin bin_random () { 110 | return rand()%bin::ALL; 111 | } 112 | 113 | 114 | TEST (SierpinskyBitmapTest,CryBabyCry) { 115 | for (int i=0; i<10000; i++) { 116 | bin point = bin_random(); 117 | bin focus = bin(0,rand()%(1<<30)); 118 | feye f(focus); 119 | f.set(point); 120 | bin cp = point.commonParent(focus); 121 | uint8_t cpheight = cp.layer(); 122 | uint8_t pointheight = point.layer(); 123 | uint8_t topheight = cp==focus? 6 : cpheight-1 ; 124 | bool visible = topheight-6 <= pointheight; 125 | EXPECT_EQ (visible, f.get(point)) << 126 | "FAIL: another random test: point "<0 && !ref.get(point.left())) 142 | << "FAIL: mystically, left child is 0\n"; 143 | /*EXPECT_FALSE (pointheight>0 && !ref.get(bin_rightn(point,pointheight))) 144 | << "FAIL: mystically, the rightmost bit is 0\n";*/ 145 | } 146 | 147 | } 148 | 149 | } 150 | 151 | 152 | TEST(FishEyeBitmap, OrTest) { 153 | feye a(bin(0,0)), b(bin(0,256)); 154 | a.set(bin(2,64)); // 256-259 155 | feye ach(a,bin(0,256)); 156 | EXPECT_TRUE(ach.get(bin(2,64))); 157 | b.set(bin(0,260)); 158 | b.set(bin(0,261)); 159 | b.set(bin(0,262)); 160 | b.set(bin(0,263)); 161 | EXPECT_TRUE(b.get(bin(2,65))); 162 | b.refocus(bin(0,257)); 163 | EXPECT_TRUE(b.get(bin(2,65))); 164 | b |= a; 165 | EXPECT_TRUE(b.get(bin(2,65).parent())); 166 | } 167 | 168 | 169 | int main (int argc, char** argv) { 170 | bin::init(); 171 | sbit::init(); 172 | 173 | testing::InitGoogleTest(&argc, argv); 174 | return RUN_ALL_TESTS(); 175 | 176 | } 177 | -------------------------------------------------------------------------------- /tests/transfertest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * transfertest.cpp 3 | * swift 4 | * 5 | * Created by Victor Grishchenko on 10/7/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | //#include 10 | //#include 11 | #include "swift.h" 12 | #include "compat.h" 13 | #include 14 | 15 | using namespace swift; 16 | 17 | const char* BTF = "test_file"; 18 | 19 | Sha1Hash A,B,C,D,E,AB,CD,ABCD,E0,E000,ABCDE000,ROOT; 20 | 21 | 22 | TEST(TransferTest,TBHeap) { 23 | tbheap tbh; 24 | ASSERT_TRUE(tbh.is_empty()); 25 | tbh.push(tintbin(3,bin64_t::NONE)); 26 | tbh.push(tintbin(1,bin64_t::NONE)); 27 | ASSERT_EQ(2,tbh.size()); 28 | tbh.push(tintbin(2,bin64_t::ALL)); 29 | ASSERT_EQ(1,tbh.pop().time); 30 | ASSERT_EQ(bin64_t::ALL,tbh.peek().bin); 31 | ASSERT_EQ(2,tbh.pop().time); 32 | ASSERT_EQ(3,tbh.pop().time); 33 | } 34 | 35 | 36 | TEST(TransferTest,TransferFile) { 37 | 38 | AB = Sha1Hash(A,B); 39 | CD = Sha1Hash(C,D); 40 | ABCD = Sha1Hash(AB,CD); 41 | E0 = Sha1Hash(E,Sha1Hash::ZERO); 42 | E000 = Sha1Hash(E0,Sha1Hash::ZERO); 43 | ABCDE000 = Sha1Hash(ABCD,E000); 44 | ROOT = ABCDE000; 45 | for (bin64_t pos(3,0); pos!=bin64_t::ALL; pos=pos.parent()) { 46 | ROOT = Sha1Hash(ROOT,Sha1Hash::ZERO); 47 | //printf("m %lli %s\n",(uint64_t)pos.parent(),ROOT.hex().c_str()); 48 | } 49 | 50 | // now, submit a new file 51 | 52 | FileTransfer* seed_transfer = new FileTransfer(BTF); 53 | HashTree* seed = & seed_transfer->file(); 54 | EXPECT_TRUE(A==seed->hash(bin64_t(0,0))); 55 | EXPECT_TRUE(E==seed->hash(bin64_t(0,4))); 56 | EXPECT_TRUE(ABCD==seed->hash(bin64_t(2,0))); 57 | EXPECT_TRUE(ROOT==seed->root_hash()); 58 | EXPECT_TRUE(ABCD==seed->peak_hash(0)); 59 | EXPECT_TRUE(E==seed->peak_hash(1)); 60 | EXPECT_TRUE(ROOT==seed->root_hash()); 61 | EXPECT_EQ(4100,seed->size()); 62 | EXPECT_EQ(5,seed->packet_size()); 63 | EXPECT_EQ(4100,seed->complete()); 64 | EXPECT_EQ(4100,seed->seq_complete()); 65 | EXPECT_EQ(bin64_t(2,0),seed->peak(0)); 66 | 67 | // retrieve it 68 | unlink("copy"); 69 | FileTransfer* leech_transfer = new FileTransfer("copy",seed->root_hash()); 70 | HashTree* leech = & leech_transfer->file(); 71 | leech_transfer->picker().Randomize(0); 72 | // transfer peak hashes 73 | for(int i=0; ipeak_count(); i++) 74 | leech->OfferHash(seed->peak(i),seed->peak_hash(i)); 75 | ASSERT_EQ(5<<10,leech->size()); 76 | ASSERT_EQ(5,leech->packet_size()); 77 | ASSERT_EQ(0,leech->complete()); 78 | EXPECT_EQ(bin64_t(2,0),leech->peak(0)); 79 | // transfer data and hashes 80 | // ABCD E000 81 | // AB CD E0 0 82 | // AAAA BBBB CCCC DDDD E 0 0 0 83 | // calculated leech->OfferHash(bin64_t(1,0), seed->hashes[bin64_t(1,0)]); 84 | leech->OfferHash(bin64_t(1,1), seed->hash(bin64_t(1,1))); 85 | for (int i=0; i<5; i++) { 86 | if (i==2) { // now: stop, save, start 87 | delete leech_transfer; 88 | leech_transfer = new FileTransfer("copy",seed->root_hash()); 89 | leech = & leech_transfer->file(); 90 | leech_transfer->picker().Randomize(0); 91 | EXPECT_EQ(2,leech->packets_complete()); 92 | EXPECT_EQ(bin64_t(2,0),leech->peak(0)); 93 | } 94 | bin64_t next = leech_transfer->picker().Pick(seed->ack_out(),1,TINT_NEVER); 95 | ASSERT_NE(bin64_t::NONE,next); 96 | ASSERT_TRUE(next.base_offset()<5); 97 | uint8_t buf[1024]; //size_t len = seed->storer->ReadData(next,&buf); 98 | size_t len = pread(seed->file_descriptor(),buf,1024,next.base_offset()<<10); 99 | bin64_t sibling = next.sibling(); 100 | if (sibling.base_offset()packet_size()) 101 | leech->OfferHash(sibling, seed->hash(sibling)); 102 | uint8_t memo = *buf; 103 | *buf = 'z'; 104 | EXPECT_FALSE(leech->OfferData(next, (char*)buf, len)); 105 | fprintf(stderr,"kidding\n"); 106 | *buf = memo; 107 | EXPECT_TRUE(leech->OfferData(next, (char*)buf, len)); 108 | } 109 | EXPECT_EQ(4100,leech->size()); 110 | EXPECT_EQ(5,leech->packet_size()); 111 | EXPECT_EQ(4100,leech->complete()); 112 | EXPECT_EQ(4100,leech->seq_complete()); 113 | 114 | } 115 | /* 116 | FIXME 117 | - always rehashes (even fresh files) 118 | */ 119 | 120 | int main (int argc, char** argv) { 121 | 122 | unlink("test_file"); 123 | unlink("copy"); 124 | unlink("test_file.mhash"); 125 | unlink("copy.mhash"); 126 | 127 | int f = open(BTF,O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); 128 | if (f < 0) 129 | { 130 | eprintf("Error opening %s\n",BTF); 131 | return -1; 132 | } 133 | uint8_t buf[1024]; 134 | memset(buf,'A',1024); 135 | A = Sha1Hash(buf,1024); 136 | write(f,buf,1024); 137 | memset(buf,'B',1024); 138 | B = Sha1Hash(buf,1024); 139 | write(f,buf,1024); 140 | memset(buf,'C',1024); 141 | C = Sha1Hash(buf,1024); 142 | write(f,buf,1024); 143 | memset(buf,'D',1024); 144 | D = Sha1Hash(buf,1024); 145 | write(f,buf,1024); 146 | memset(buf,'E',4); 147 | E = Sha1Hash(buf,4); 148 | write(f,buf,4); 149 | close(f); 150 | 151 | testing::InitGoogleTest(&argc, argv); 152 | int ret = RUN_ALL_TESTS(); 153 | 154 | return ret; 155 | } 156 | -------------------------------------------------------------------------------- /transfer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * transfer.cpp 3 | * some transfer-scope code 4 | * 5 | * Created by Victor Grishchenko on 10/6/09. 6 | * Copyright 2009 Delft University of Technology. All rights reserved. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include "swift.h" 13 | 14 | #include "ext/seq_picker.cpp" // FIXME FIXME FIXME FIXME 15 | 16 | using namespace swift; 17 | 18 | std::vector FileTransfer::files(20); 19 | 20 | #define BINHASHSIZE (sizeof(bin64_t)+sizeof(Sha1Hash)) 21 | 22 | // FIXME: separate Bootstrap() and Download(), then Size(), Progress(), SeqProgress() 23 | 24 | FileTransfer::FileTransfer (const char* filename, const Sha1Hash& _root_hash) : 25 | file_(filename,_root_hash), hs_in_offset_(0), cb_installed(0) 26 | { 27 | if (files.size()Randomize(rand()&63); 32 | init_time_ = Datagram::Time(); 33 | } 34 | 35 | 36 | void Channel::CloseTransfer (FileTransfer* trans) { 37 | for(int i=0; itransfer_==trans) 39 | delete Channel::channels[i]; 40 | } 41 | 42 | 43 | void swift::AddProgressCallback (int transfer,ProgressCallback cb,uint8_t agg) { 44 | FileTransfer* trans = FileTransfer::file(transfer); 45 | if (!trans) 46 | return; 47 | trans->cb_agg[trans->cb_installed] = agg; 48 | trans->callbacks[trans->cb_installed] = cb; 49 | trans->cb_installed++; 50 | } 51 | 52 | 53 | void swift::ExternallyRetrieved (int transfer,bin64_t piece) { 54 | FileTransfer* trans = FileTransfer::file(transfer); 55 | if (!trans) 56 | return; 57 | trans->ack_out().set(piece); // that easy 58 | } 59 | 60 | 61 | void swift::RemoveProgressCallback (int transfer, ProgressCallback cb) { 62 | FileTransfer* trans = FileTransfer::file(transfer); 63 | if (!trans) 64 | return; 65 | for(int i=0; icb_installed; i++) 66 | if (trans->callbacks[i]==cb) 67 | trans->callbacks[i]=trans->callbacks[--trans->cb_installed]; 68 | } 69 | 70 | 71 | FileTransfer::~FileTransfer () 72 | { 73 | Channel::CloseTransfer(this); 74 | files[fd()] = NULL; 75 | delete picker_; 76 | } 77 | 78 | 79 | FileTransfer* FileTransfer::Find (const Sha1Hash& root_hash) { 80 | for(int i=0; iroot_hash()==root_hash) 82 | return files[i]; 83 | return NULL; 84 | } 85 | 86 | 87 | int swift:: Find (Sha1Hash hash) { 88 | FileTransfer* t = FileTransfer::Find(hash); 89 | if (t) 90 | return t->fd(); 91 | return -1; 92 | } 93 | 94 | 95 | 96 | void FileTransfer::OnPexIn (const Address& addr) { 97 | for(int i=0; itransfer().fd()==this->fd() && c->peer()==addr) 100 | return; // already connected 101 | } 102 | if (hs_in_.size()<20) { 103 | new Channel(this,Datagram::default_socket(),addr); 104 | } else { 105 | pex_in_.push_back(addr); 106 | if (pex_in_.size()>1000) 107 | pex_in_.pop_front(); 108 | } 109 | } 110 | 111 | 112 | int FileTransfer::RevealChannel (int& pex_out_) { // FIXME brainfuck 113 | pex_out_ -= hs_in_offset_; 114 | if (pex_out_<0) 115 | pex_out_ = 0; 116 | while (pex_out_transfer().fd()==this->fd()) { 119 | if (c->is_established()) { 120 | pex_out_ += hs_in_offset_ + 1; 121 | return c->id(); 122 | } else 123 | pex_out_++; 124 | } else { 125 | hs_in_[pex_out_] = hs_in_[0]; 126 | hs_in_.pop_front(); 127 | hs_in_offset_++; 128 | } 129 | } 130 | pex_out_ += hs_in_offset_; 131 | return -1; 132 | } 133 | 134 | --------------------------------------------------------------------------------
' 14 | for to in `grep -v '#' ../$SERVERS`; do 15 | echo '>'$to'
'$from'>' 22 | cat $from-$to.html 23 | if [ -e "$from-$to.big.png" ]; then 24 | echo "" 25 | echo "" 26 | echo "" 27 | fi 28 | echo '