+# Written by Victor Grishchenko, Arno Bakker
+# see LICENSE.txt for license information
+#
+# Requirements:
+# - scons: Cross-platform build system http://www.scons.org/
+# - googletest: Google C++ Test Framework http://code.google.com/p/googletest/
+# * Install in ..\gtest-1.4.0
+# - google-glog: Google Logging Library for C++ http://code.google.com/p/google-glog/
+# * Install in ..\glog-0.3.0
+# * I get ..\glog-0.3.0\src\windows\glog/log_severity.h(51) : error C2059: syntax error :
+# 'constant' while running scons. Apparently the ERROR constant is already defined somewhere.
+# #undef ERROR before the def allows include.
+#
+# - OpenSSL: http://www.slproweb.com/products/Win32OpenSSL.html
+# * Install non-light Win32 binary in \openssl
+# * Using a openssl-0.9.8k tar-ball doesn't work as the includes there
+# are symbolic links which get turned into 0 length files by 7Zip.
+#
+
import os
import re
+import sys
+
+DEBUG = True
TestDir='tests'
-env = Environment(CPPPATH = ['.'])
+target = 'p2tp'
+source = [ 'bin64.cpp','hashtree.cpp','datagram.cpp','bins.cpp', 'transfer.cpp', 'compat/hirestimeofday.cpp', 'compat/util.cpp']
+
+env = Environment()
+if sys.platform == "win32":
+ # "MSVC works out of the box". Sure.
+ # Make sure scons finds cl.exe, etc.
+ env.Append ( ENV = { 'PATH' : os.environ['PATH'] } )
+
+ # Make sure scons finds std MSVC include files
+ if not 'INCLUDE' in os.environ:
+ print "p2tp: Please run scons in a Visual Studio Command Prompt"
+ sys.exit(-1)
+
+ include = os.environ['INCLUDE']
+ include += '..\\gtest-1.4.0\\include;'
+ include += '..\\glog-0.3.0\\src\\windows;' # Funky
+ include += '\\openssl\\include;'
+
+ env.Append ( ENV = { 'INCLUDE' : include } )
+
+ # Other compiler flags
+ env.Append(CPPPATH=".")
+ if DEBUG:
+ env.Append(CXXFLAGS="/Zi /Yd /MTd")
+ env.Append(LINKFLAGS="/DEBUG")
+
+ # Add simulated pread/write
+ source += ['compat/unixio.cpp']
+
+ # Set libs to link to
+ libs = ['libglog','ws2_32']
+ if DEBUG:
+ libs += ['gtestd','libeay32MTd']
+ else:
+ libs += ['gtest','libeay32']
+
+ # Update lib search path
+ libpath = os.environ['LIBPATH']
+ if DEBUG:
+ libpath += '\\build\\gtest-1.4.0\\msvc\\gtest\\Debug;'
+ libpath += '\\build\\glog-0.3.0\\vsprojects\\libglog\\Debug;'
+ libpath += '\\openssl\\lib\\VC\\static;'
+ else:
+ libpath += '\\build\\gtest-1.4.0\\msvc\\gtest\\Release;'
+ libpath += '\\build\\glog-0.3.0\\vsprojects\\libglog\\Release;'
+ libpath += '\\openssl\\lib;'
+ # Somehow linker can't find uuid.lib
+ libpath += 'C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0A\\Lib;'
+
+else:
+ # Enable the user defining external includes
+ if 'CPPPATH' in os.environ:
+ cpppath = os.environ['CPPPATH']
+ else:
+ cpppath = ""
+ print "To use external libs, set CPPPATH environment variable to list of colon-separated include dirs"
+ env.Append(CPPPATH=".:"+cpppath)
+ env.Append(LINKFLAGS="--static")
+
+ #if DEBUG:
+ # env.Append(CXXFLAGS="-g")
+
+ # Set libs to link to
+ libs = ['stdc++','gtest','glog','pthread','crypto']
+ if 'LIBPATH' in os.environ:
+ libpath = os.environ['LIBPATH']
+ else:
+ libpath = ""
+ print "To use external libs, set LIBPATH environment variable to list of colon-separated lib dirs"
-env.SharedLibrary (
- target='p2tp',
- source = [ 'bin64.cpp','hashtree.cpp','datagram.cpp',
- 'bins.cpp', 'transfer.cpp' ],
- LIBS=['stdc++','gtest','glog','crypto'] )
+env.StaticLibrary (
+ target= target,
+ source = source,
+ LIBS=libs,
+ LIBPATH=libpath )
+Export("env")
+Export("libs")
+Export("libpath")
+Export("DEBUG")
SConscript('tests/SConscript')
* serp++
*
* Created by Victor Grishchenko on 3/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
* serp++
*
* Created by Victor Grishchenko on 3/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#ifndef BIN_H
#define BIN_H
#include <assert.h>
-#include <stdint.h>
+#ifdef _MSC_VER
+ // To avoid complaints about std::max. Appears to work in VS2008
+ #undef min
+ #undef max
+ #include "compat/stdint.h"
+#else
+ #include <stdint.h>
+#endif
#include <deque>
struct bin {
uint32_t b;
-
+
static bin NONE;
static bin ALL;
static uint8_t BC[256];
static uint8_t T0[256];
-
+
bin() : b(0) {}
bin(const bin& b_) : b(b_.b) {}
bin(uint32_t b_) : b(b_) {}
-
+
bin(uint8_t layer_, uint32_t offset) {
b = lenpeak((offset+1)<<layer_);
b -= layer() - layer_;
}
-
+
static void init ();
-
+
static uint8_t tailzeros (uint32_t i) {
uint8_t ret = 0;
if ( (i&0xffff)==0 )
ret +=8, i>>=8;
return ret+T0[i&0xff];
}
-
+
static uint8_t bitcount (uint32_t i) {
//uint8_t* p = (uint8_t*) &i;
//return BC[p[0]] + BC[p[1]] + BC[p[2]] + BC[p[3]];
BC[(i>>16)&0xff] +
BC[i>>24];
}
-
+
static uint32_t blackout (uint32_t i) {
return i|=(i|=(i|=(i|=(i|=i>>1)>>2)>>4)>>8)>>16;
}
-
+
static uint32_t highbit (uint32_t i) {
return (blackout(i)+1)>>1;
}
-
+
static bool all1 (uint32_t a) {
return !(a&(a+1));
}
-
+
static bin lenpeak (uint32_t length) {
return (length<<1) - bitcount(length);
}
-
+
static uint8_t lenlayer (uint32_t len) {
return tailzeros(len);
}
-
+
static bin layermass (uint8_t layer) {
return (2<<layer)-1;
}
-
+
static uint32_t lastbiton (uint32_t i) {
return (~i+1)&i;
}
-
+
typedef std::deque<bin> vec;
static vec peaks (uint32_t len);
-
+
static void order (vec* v);
-
+
operator uint32_t() const { return b; }
-
+
bin operator ++ () { return b++; }
bin operator -- () { return b--; }
bin operator ++ (int) { return ++b; }
bin operator -- (int) { return --b; }
-
+
uint32_t mlat() const {
return 0;
}
-
+
bin left() const {
return bin(b-(mass()>>1)-1);
}
-
+
bin right() const {
return bin(b-1);
}
-
+
bin right_foot() const {
return bin(b-layer());
}
-
+
bin left_foot() const {
return bin(b-mass()+1);
}
-
+
uint32_t length() const {
//assert(*this<=ALL);
uint32_t apx = (b>>1) + 16; //if (b<=ALL-32) apx = ALL>>1;
next = apx = lenpeak(next)>=b ? next : apx;
return apx;
}
-
+
uint32_t mass() const {
return layermass(layer());
}
-
+
uint8_t layer() const {
uint32_t len = length();
uint8_t topeak = lenpeak(len) - b;
return lenlayer(len) - topeak;
}
-
+
uint32_t width () const {
return 1<<layer();
}
-
+
bin peak() const {
return lenpeak(length());
}
-
+
bin divide (uint8_t ls) const {
uint32_t newlen = ((length()-1)>>ls) +1;
uint8_t newlr = std::max(0,layer()-ls);
return lenpeak(newlen) - lenlayer(newlen) + newlr;
}
-
+
uint32_t offset () const {
return length() - width();
}
-
+
bin modulo (uint8_t ls) const {
if (layer()>=ls)
return layermass(ls);
bin blockleft = lenpeak(((length()-1) & ~((1<<ls)-1)) + 1);
return b - blockleft + 1;
}
-
+
bin multiply (uint8_t ls) const {
return b + length()*(layermass(ls)-1);
}
-
+
bool contains (bin c) const {
return c.b<=b && c.b>b-mass();
}
-
+
bin commonParent (bin other) const {
uint8_t maxlayer = std::max(layer(),other.layer());
uint32_t myoff = offset()>>maxlayer, othoff = other.offset()>>maxlayer;
uint8_t toshift = bitcount(diff);
return bin(maxlayer+toshift,myoff>>toshift);
}
-
+
bin child (bin dir) const {
return left().contains(dir) ? left() : right();
}
-
+
bin parent (uint8_t g=1) const {
uint32_t l = length();
uint8_t h2b = layer()+g;
return lenpeak(l2b) - lenlayer(l2b) + h2b;
//length()==bin(b+1).length() ? b+1 : b+mass()+1;
}
-
+
bool is_right () const {
return this->parent()==b+1;
}
-
+
bool is_left () const {
return !is_right();
}
-
+
bin sibling () const {
return is_left() ? bin(b+mass()) : bin(b-mass());
}
assert(layer()<=top.layer()); // TERRIBLE
assert(top.layer()>=height);
uint8_t rel_layer;
- if (layer()+height>=top.layer())
+ if (layer()+height>=top.layer())
rel_layer = layer()+height-top.layer();
else
rel_layer = 0;//top.layer() - height;
uint32_t rel_offset = (offset()-top.offset()) >> (top.layer()-height+rel_layer);
return bin(rel_layer,rel_offset);
}
-
+
bin unscoped (bin top, uint8_t height) const {
uint32_t undermass = layermass(top.layer()-height);
uint32_t pad = (1<<height) - length();
uint32_t peak = (1<<(height+1))-1;
return top - (peak-this->b) + pad - undermass*pad;
}
-
+
} ;
* p2tp
*
* Created by Victor Grishchenko on 10/10/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include "bin64.h"
#ifndef BIN64_H
#define BIN64_H
#include <assert.h>
-#include <stdint.h>
-
+#ifdef _MSC_VER
+ #include "compat/stdint.h"
+#else
+ #include <stdint.h>
+#endif
/** Numbering for (aligned) logarithmical bins.
bin64_t() : v(NONE) {}
bin64_t(const bin64_t&b) : v(b.v) {}
bin64_t(const uint64_t val) : v(val) {}
- bin64_t(uint8_t layer, uint64_t offset) :
+ bin64_t(uint8_t layer, uint64_t offset) :
v( (offset<<(layer+1)) | ((1ULL<<layer)-1) ) {}
operator uint64_t () const { return v; }
uint32_t to32() const ;
}
bin64_t sibling () const {
- // if (v==ALL) return NONE;
+ // if (v==ALL) return NONE;
return bin64_t(v^(tail_bit()<<1));
}
// courtesy of Sean Eron Anderson
// http://graphics.stanford.edu/~seander/bithacks.html
static const int DeBRUIJN[32] = {
- 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
r += DeBRUIJN[((uint32_t)(tail*0x077CB531U))>>27];
bin64_t left_foot () const {
return bin64_t(0,base_offset());
}
-
+
/** Whether layer is 0. */
bool is_base () const {
return !(v & 1);
}
-
+
/** Depth-first in-order binary tree traversal. */
bin64_t next_dfsio (uint8_t floor);
-
+
bin64_t width () const {
return (tail_bits()+1)>>1;
}
-
+
/** The array must have 64 cells, as it is the max
number of peaks possible +1 (and there are no reason
to assume there will be less in any given case. */
static int peaks (uint64_t length, bin64_t* peaks) ;
-
+
};
* serp++
*
* Created by Victor Grishchenko on 4/1/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include "bins.h"
* serp++
*
* Created by Victor Grishchenko on 3/28/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#ifndef BINS_H
--- /dev/null
+/*\r
+ * Inspired by\r
+ * - http://msdn.microsoft.com/en-us/library/ms644904%28VS.85%29.aspx\r
+ * - Python-2.6.3/Modules/timemodule.c\r
+ */\r
+\r
+#include <iostream>\r
+#include "compat/hirestimeofday.h"\r
+\r
+#ifndef _MSC_VER\r
+#include <sys/time.h>\r
+#endif\r
+\r
+namespace p2tp {\r
+\r
+HiResTimeOfDay* HiResTimeOfDay::_instance = 0;\r
+\r
+HiResTimeOfDay* HiResTimeOfDay::Instance()\r
+{\r
+ if (_instance == 0)\r
+ _instance = new HiResTimeOfDay();\r
+ return _instance;\r
+}\r
+\r
+\r
+#ifdef _MSC_VER\r
+#include <windows.h>\r
+#include <sys/timeb.h>\r
+\r
+\r
+HiResTimeOfDay::HiResTimeOfDay(void)\r
+{\r
+ frequency = getFrequency();\r
+ epochstart = getFTime();\r
+ epochcounter = getCounter();\r
+}\r
+\r
+\r
+tint HiResTimeOfDay::getTimeUSec(void)\r
+{\r
+ LARGE_INTEGER currentcounter;\r
+ tint currentstart;\r
+\r
+ currentstart = getFTime();\r
+ currentcounter = getCounter();\r
+\r
+ if (currentcounter.QuadPart < epochcounter.QuadPart)\r
+ {\r
+\r
+ // Wrap around detected, reestablish baseline\r
+ epochstart = currentstart;\r
+ epochcounter = currentcounter;\r
+ }\r
+ return epochstart + (1000000*(currentcounter.QuadPart-epochcounter.QuadPart))/frequency.QuadPart;\r
+}\r
+\r
+\r
+// Private\r
+tint HiResTimeOfDay::getFTime()\r
+{\r
+ struct timeb t;\r
+ ftime(&t);\r
+ tint usec;\r
+ usec = t.time * 1000000;\r
+ usec += t.millitm * 1000;\r
+ return usec;\r
+}\r
+\r
+\r
+\r
+LARGE_INTEGER HiResTimeOfDay::getFrequency(void)\r
+{\r
+ LARGE_INTEGER proc_freq;\r
+\r
+ if (!::QueryPerformanceFrequency(&proc_freq))\r
+ std::cerr << "HiResTimeOfDay: QueryPerformanceFrequency() failed";\r
+\r
+ return proc_freq;\r
+}\r
+\r
+LARGE_INTEGER HiResTimeOfDay::getCounter()\r
+{\r
+ LARGE_INTEGER counter;\r
+\r
+ DWORD_PTR oldmask = ::SetThreadAffinityMask(::GetCurrentThread(), 0);\r
+ if (!::QueryPerformanceCounter(&counter))\r
+ std::cerr << "HiResTimeOfDay: QueryPerformanceCounter() failed";\r
+ ::SetThreadAffinityMask(::GetCurrentThread(), oldmask);\r
+\r
+ return counter;\r
+}\r
+\r
+#else\r
+\r
+HiResTimeOfDay::HiResTimeOfDay(void)\r
+{\r
+}\r
+\r
+\r
+tint HiResTimeOfDay::getTimeUSec(void)\r
+{\r
+ struct timeval t;\r
+ gettimeofday(&t,NULL);\r
+ tint ret;\r
+ ret = t.tv_sec;\r
+ ret *= 1000000;\r
+ ret += t.tv_usec;\r
+ return ret;\r
+}\r
+#endif\r
+\r
+ \r
+ \r
+ \r
+// ARNOTODO: move to p2tp.cpp\r
+\r
+#ifdef _MSC_VER\r
+static WSADATA _WSAData;\r
+#endif\r
+ \r
+void LibraryInit(void)\r
+{\r
+#ifdef _MSC_VER\r
+ // win32 requires you to initialize the Winsock DLL with the desired\r
+ // specification version\r
+ WORD wVersionRequested;\r
+ wVersionRequested = MAKEWORD(2, 2);\r
+ WSAStartup(wVersionRequested, &_WSAData);\r
+#endif\r
+}\r
+ \r
+ \r
+} // end of namespace\r
+\r
+\r
+\r
+\r
+#ifdef TEST\r
+#include <iostream>\r
+\r
+using namespace p2tp;\r
+\r
+int main()\r
+{\r
+ HiResTimeOfDay *t = HiResTimeOfDay::Instance();\r
+ for (int i=0; i<100; i++)\r
+ {\r
+ tint st = t->getTimeUSec();\r
+ Sleep(1000);\r
+ tint et = t->getTimeUSec();\r
+ tint diff = et - st;\r
+ std::cout << "diffxTime is " << diff << "\n";\r
+ }\r
+ return 0;\r
+}\r
+#endif\r
+\r
--- /dev/null
+/*\r
+ * Written by Arno Bakker\r
+ * see LICENSE.txt for license information\r
+ *\r
+ * Singleton class to retrieve a time-of-day in UTC in usec in a platform-\r
+ * independent manner.\r
+ */\r
+#ifndef HIRESTIMEOFDAY_H\r
+#define HIRESTIMEOFDAY_H\r
+\r
+#ifdef _MSC_VER\r
+#include "compat/stdint.h"\r
+#include <windows.h>\r
+#else\r
+#include <stdint.h>\r
+#endif\r
+\r
+\r
+namespace p2tp {\r
+\r
+typedef int64_t tint;\r
+#define TINT_SEC ((tint)1000000)\r
+#define TINT_MSEC ((tint)1000)\r
+#define TINT_uSEC ((tint)1)\r
+#define TINT_NEVER ((tint)0x7fffffffffffffffLL)\r
+\r
+\r
+class HiResTimeOfDay\r
+{\r
+public:\r
+ HiResTimeOfDay(void);\r
+ tint getTimeUSec(void);\r
+ static HiResTimeOfDay* Instance();\r
+\r
+private:\r
+#ifdef _MSC_VER\r
+ tint epochstart; // in usec\r
+ LARGE_INTEGER epochcounter;\r
+ LARGE_INTEGER last;\r
+ LARGE_INTEGER frequency;\r
+\r
+ tint HiResTimeOfDay::getFTime();\r
+ LARGE_INTEGER getFrequency(void);\r
+ LARGE_INTEGER getCounter(void);\r
+#endif\r
+\r
+ static HiResTimeOfDay* _instance;\r
+};\r
+\r
+};\r
+#endif\r
--- /dev/null
+/*\r
+ * Written by Arno Bakker\r
+ * see LICENSE.txt for license information\r
+ */\r
+\r
+#ifndef STDINT_H_\r
+#define STDINT_H_\r
+\r
+typedef unsigned char uint8_t;\r
+typedef signed char int8_t;\r
+typedef unsigned short uint16_t;\r
+typedef short int16_t;\r
+typedef unsigned int uint32_t;\r
+typedef int int32_t;\r
+typedef __int64 int64_t;\r
+typedef unsigned __int64 uint64_t;\r
+\r
+#endif /* STDINT_H_ */\r
--- /dev/null
+/*\r
+ * Written by Arno Bakker\r
+ * see LICENSE.txt for license information\r
+ */\r
+\r
+#include "compat/unixio.h"\r
+#include <io.h>\r
+#include <stdio.h>\r
+#include <winsock2.h>\r
+\r
+size_t pread(int fildes, void *buf, size_t nbyte, long offset)\r
+{\r
+ _lseek(fildes,offset,SEEK_SET);\r
+ return read(fildes,buf,nbyte);\r
+}\r
+\r
+size_t pwrite(int fildes, const void *buf, size_t nbyte, long offset)\r
+{\r
+ _lseek(fildes,offset,SEEK_SET);\r
+ return write(fildes,buf,nbyte);\r
+}\r
+\r
+\r
+int inet_aton(const char *cp, struct in_addr *inp)\r
+{\r
+ inp->S_un.S_addr = inet_addr(cp);\r
+ return 1;\r
+}\r
--- /dev/null
+/*\r
+ * Written by Arno Bakker\r
+ * see LICENSE.txt for license information\r
+ *\r
+ * Defines UNIX like I/O calls and parameters for Win32\r
+ */\r
+\r
+#ifndef UNIXIO_H_\r
+#define UNIXIO_H_\r
+\r
+#define open(a,b,c) _open(a,b,c)\r
+#define S_IRUSR _S_IREAD\r
+#define S_IWUSR _S_IWRITE\r
+#define S_IRGRP _S_IREAD\r
+#define S_IROTH _S_IREAD\r
+#define ftruncate(a, b) _chsize(a,b)\r
+\r
+size_t pread(int fildes, void *buf, size_t nbyte, long offset);\r
+/** UNIX pread approximation. Does change file pointer. Is not thread-safe */\r
+size_t pwrite(int fildes, const void *buf, size_t nbyte, long offset);\r
+/** UNIX pwrite approximation. Does change file pointer. Is not thread-safe */\r
+\r
+int inet_aton(const char *cp, struct in_addr *inp);\r
+\r
+#endif /* UNIXIO_H_ */\r
--- /dev/null
+/*\r
+ * Written by Arno Bakker\r
+ * see LICENSE.txt for license information\r
+ */\r
+\r
+#include "util.h"\r
+#include <vector>\r
+\r
+#ifdef _MSC_VER\r
+#include <windows.h>\r
+#include <Tchar.h>\r
+#endif\r
+\r
+namespace p2tp\r
+{\r
+\r
+std::string gettmpdir(void)\r
+{\r
+#ifdef _MSC_VER\r
+ DWORD result = ::GetTempPath(0, _T(""));\r
+ if (result == 0)\r
+ throw std::runtime_error("Could not get system temp path");\r
+\r
+ std::vector<TCHAR> tempPath(result + 1);\r
+ result = ::GetTempPath(static_cast<DWORD>(tempPath.size()), &tempPath[0]);\r
+ if((result == 0) || (result >= tempPath.size()))\r
+ throw std::runtime_error("Could not get system temp path");\r
+\r
+ return std::string(tempPath.begin(), tempPath.begin() + static_cast<std::size_t>(result));\r
+#else\r
+ return std::string("/tmp/");\r
+#endif\r
+}\r
+\r
+\r
+}; // namespace\r
+\r
--- /dev/null
+/*\r
+ * util.h\r
+ *\r
+ * Created on: 20-Oct-2009\r
+ * Author: arno\r
+ */\r
+\r
+#ifndef UTIL_H_\r
+#define UTIL_H_\r
+\r
+#include <string>\r
+\r
+namespace p2tp\r
+{\r
+ std::string gettmpdir(void);\r
+ /**\r
+ * Return path of temporary directory.\r
+ *\r
+ * From http://msdn.microsoft.com/en-us/library/aa364992%28VS.85%29.aspx\r
+ *\r
+ * TODO: Unicode... (gets hairy with open() call on Linux. Win32 has _wopen)\r
+ */\r
+\r
+\r
+};\r
+\r
+#endif /* UTIL_H_ */\r
* serp++
*
* Created by Victor Grishchenko on 3/9/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
-#include <arpa/inet.h>
+#include <iostream>
+
+#ifdef _MSC_VER
+ #include <winsock2.h>
+ typedef int socklen_t;
+#else
+ #include <arpa/inet.h>
+#endif
#include <glog/logging.h>
#include "datagram.h"
uint32_t Datagram::Address::LOCALHOST = INADDR_LOOPBACK;
int Datagram::Send () {
- int r = sendto(sock,buf+offset,length-offset,0,
+ int r = sendto(sock,(const char *)buf+offset,length-offset,0,
(struct sockaddr*)&(addr.addr),sizeof(struct sockaddr_in));
offset=0;
length=0;
int Datagram::Recv () {
socklen_t addrlen = sizeof(struct sockaddr_in);
offset = 0;
- length = recvfrom (sock, buf, MAXDGRAMSZ, 0,
+ length = recvfrom (sock, (char *)buf, MAXDGRAMSZ, 0,
(struct sockaddr*)&(addr), &addrlen);
if (length<0)
+#ifdef _MSC_VER
+ PLOG(ERROR)<<"on recv" << WSAGetLastError() << "\n";
+#else
PLOG(ERROR)<<"on recv";
+#endif
now = Time();
return length;
}
-int Datagram::Wait (int sockcnt, int* sockets, tint usec) {
- LOG(INFO)<<"waiting for "<<sockcnt;
+SOCKET Datagram::Wait (int sockcnt, SOCKET* sockets, tint usec) {
+ // ARNOTODO: LOG commented out, it causes a crash on win32 (in a strlen()
+ // done as part of a std::local::name() ??
+ //
+ //LOG(INFO)<<"waiting for "<<sockcnt;
struct timeval timeout;
timeout.tv_sec = usec/TINT_SEC;
timeout.tv_usec = usec%TINT_SEC;
for (int i=0; i<=sockcnt; i++)
if (FD_ISSET(sockets[i],&bases))
return sockets[i];
- } else if (sel<0)
+ } else if (sel<0)
+#ifdef _MSC_VER
+ PLOG(ERROR)<<"select fails" << WSAGetLastError() << "\n";
+#else
PLOG(ERROR)<<"select fails";
- return -1;
+#endif
+
+ // Arno: may return 0 when timeout expired
+ return sel;
}
tint Datagram::Time () {
- struct timeval t;
- gettimeofday(&t,NULL);
- tint ret;
- ret = t.tv_sec;
- ret *= 1000000;
- ret += t.tv_usec;
+ HiResTimeOfDay* tod = HiResTimeOfDay::Instance();
+ tint ret = tod->getTimeUSec();
//DLOG(INFO)<<"now is "<<ret;
return now=ret;
}
-int Datagram::Bind (Address addr_) {
+SOCKET Datagram::Bind (Address addr_) {
struct sockaddr_in addr = addr_;
- int fd, len = sizeof(struct sockaddr_in),
- sndbuf=1<<20, rcvbuf=1<<20;
+ SOCKET fd;
+ int len = sizeof(struct sockaddr_in), sndbuf=1<<20, rcvbuf=1<<20;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
PLOG(ERROR)<<"socket fails";
return -1;
}
+#ifdef _MSC_VER
+ u_long enable = 1;
+ ioctlsocket(fd, FIONBIO, &enable);
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&sndbuf, sizeof(int)) != 0 ) {
+ PLOG(ERROR)<<"setsockopt fails";
+ return -3;
+ }
+ if ( setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&rcvbuf, sizeof(int)) != 0 ) {
+ PLOG(ERROR)<<"setsockopt2 fails";
+ return -3;
+ }
+#else
if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1)
return -2;
- if ( setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0 ) {
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0 ) {
PLOG(ERROR)<<"setsockopt fails";
return -3;
}
PLOG(ERROR)<<"setsockopt2 fails";
return -3;
}
+#endif
printf("BUFS: %i %i\n",sndbuf,rcvbuf);
/*memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
}
void Datagram::Close (int sock) { // remove from fd_set
+#ifdef _MSC_VER
+ if (closesocket(sock)!=0)
+#else
if (::close(sock)!=0)
+#endif
PLOG(ERROR)<<"on closing a socket";
}
std::string sock2str (struct sockaddr_in addr) {
char ipch[32];
+#ifdef _MSC_VER
+ //Vista only: InetNtop(AF_INET,&(addr.sin_addr),ipch,32);
+ // IPv4 only:
+ struct in_addr inaddr;
+ memcpy(&inaddr, &(addr.sin_addr), sizeof(inaddr));
+ strncpy(ipch, inet_ntoa(inaddr),32);
+#else
inet_ntop(AF_INET,&(addr.sin_addr),ipch,32);
+#endif
sprintf(ipch+strlen(ipch),":%i",ntohs(addr.sin_port));
return std::string(ipch);
}
std::string Datagram::to_string () const { // TODO: pretty-print P2TP
std::string addrs = sock2str(addr);
char hex[MAXDGRAMSZ*2];
- for(int i=offset; i<length; i++)
+ for(int i=offset; i<length; i++)
sprintf(hex+i*2,"%02x",buf[i]);
std::string hexs(hex+offset*2,(length-offset)*2);
return addrs + '\t' + hexs;
* serp++
*
* Created by Victor Grishchenko on 3/9/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#ifndef DATAGRAM_H
#define DATAGRAM_H
-#include <stdint.h>
+
+#ifdef _MSC_VER
+ #include "compat/stdint.h"
+ #include <winsock2.h>
+ #include "compat/unixio.h"
+#else
+ typedef int SOCKET;
+ #include <stdint.h>
+ #include <arpa/inet.h>
+ #include <sys/select.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <unistd.h>
+#endif
#include <stdlib.h>
#include <fcntl.h>
-#include <sys/select.h>
#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-//#include <sys/mman.h>
#include <string.h>
-#include <unistd.h>
#include <stdio.h>
#include <string>
#include "hashtree.h"
+#include "compat/hirestimeofday.h"
+
namespace p2tp {
-typedef int64_t tint;
-#define TINT_SEC ((tint)1000000)
-#define TINT_MSEC ((tint)1000)
-#define TINT_uSEC ((tint)1)
-#define TINT_NEVER ((tint)0x7fffffffffffffffLL)
#define MAXDGRAMSZ 1400
+#ifndef _MSC_VER
#define INVALID_SOCKET -1
-
-
+#endif
+
struct Datagram {
-
+
struct Address {
struct sockaddr_in addr;
static uint32_t LOCALHOST;
void init(uint32_t ipv4=0, uint16_t port=0) {
- memset(&addr,0,sizeof(struct sockaddr_in));
+ memset(&addr,0,sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(ipv4);
}
Address(const struct sockaddr_in& address) : addr(address) {}
operator sockaddr_in () const {return addr;}
- bool operator == (const Address& b) {
+ bool operator == (const Address& b) {
return addr.sin_family==b.addr.sin_family &&
- addr.sin_port==b.addr.sin_port &&
+ addr.sin_port==b.addr.sin_port &&
addr.sin_addr.s_addr==b.addr.sin_addr.s_addr;
}
bool operator != (const Address& b) { return !(*this==b); }
};
-
+
Address addr;
- int sock;
+ SOCKET sock;
int offset, length;
uint8_t buf[MAXDGRAMSZ*2];
-
- static int Bind(Address address);
+
+ static SOCKET Bind(Address address);
static void Close(int port);
static tint Time();
- static int Wait (int sockcnt, int* sockets, tint usec=0);
+ static SOCKET Wait (int sockcnt, SOCKET* sockets, tint usec=0);
static tint now;
-
- Datagram (int socket, const Address addr_) : addr(addr_), offset(0),
+
+ Datagram (SOCKET socket, const Address addr_) : addr(addr_), offset(0),
length(0), sock(socket) {}
- Datagram (int socket) : offset(0), length(0), sock(socket) {
+ Datagram (SOCKET socket) : offset(0), length(0), sock(socket) {
}
-
+
int space () const { return MAXDGRAMSZ-length; }
int size() const { return length-offset; }
std::string str() const { return std::string((char*)buf+offset,size()); }
const uint8_t* operator * () const { return buf+offset; }
-
+
int Push (const uint8_t* data, int l) { // scatter-gather one day
int toc = l<space() ? l : space();
memcpy(buf+length,data,toc);
offset += toc;
return toc;
}
-
+
int Send ();
int Recv ();
const Address& address() const { return addr; }
void PushHash (const Sha1Hash& hash) {
Push(hash.bits, Sha1Hash::SIZE);
}
-
+
uint8_t Pull8() {
if (size()<1) return 0;
return buf[offset++];
return Sha1Hash(false,(char*)buf+offset-Sha1Hash::SIZE);
}
//std::string to_string () const ;
-
+
};
std::string sock2str (struct sockaddr_in addr);
* p2tp
*
* Created by Victor Grishchenko on 10/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
* p2tp
*
* Created by Victor Grishchenko on 10/7/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include "p2tp.h"
* p2tp
*
* Created by Victor Grishchenko on 10/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
* p2tp
*
* Created by Victor Grishchenko on 10/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
* serp++
*
* Created by Victor Grishchenko on 3/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include "hashtree.h"
#include <openssl/sha.h>
#include <string.h>
+#ifndef _MSC_VER
#include <sys/mman.h>
+#endif
#include <sys/stat.h>
#include <stdlib.h>
#include <fcntl.h>
return ACCEPT;
} else
return REJECT;
-
+
}
*/
* serp++
*
* Created by Victor Grishchenko on 3/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#ifndef P2TP_SHA1_HASH_TREE_H
* serp++
*
* Created by Victor Grishchenko on 3/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
Channel::Channel (FileTransfer* file, int socket, struct sockaddr_in peer_addr) :
- file_(file), peer(peer_addr), peer_channel_id(0),
+ file_(file), peer(peer_addr), peer_channel_id(0),
socket_(socket) // FIXME
{
this->id = channels.size();
}
-void p2tp::Loop (tint till) {
- Channel::Loop(till);
+void p2tp::Loop (tint till) {
+ Channel::Loop(till);
}
is mostly zeroed; intialization happens as
conversation progresses
</ul>
- <b>Note:</b>
+ <b>Note:</b>
*/
-
* serp++
*
* Created by Victor Grishchenko on 3/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
- *
+ * Copyright 2009 Delft University of Technology. All rights reserved.
+ *
*/
-/*
+/*
The P2TP protocol
-
+
Messages
-
+
HANDSHAKE 00, channelid
Communicates the channel id of the sender. The
initial handshake packet also has the root hash
(a HASH message).
-
+
DATA 01, bin_32, buffer
1K of data.
-
+
ACK 02, bin_32
ACKTS 08, bin_32, timestamp_32
Confirms successfull delivery of data. Used for
congestion control, as well.
-
+
HINT 03, bin_32
Practical value of "hints" is to avoid overlap, mostly.
Hints might be lost in the network or ignored.
is considered to be ignored.
As peers cant pick randomly kilobyte here and there,
they send out "long hints" for non-base bins.
-
+
HASH 04, bin_32, sha1hash
SHA1 hash tree hashes for data verification. The
connection to a fresh peer starts with bootstrapping
him with peak hashes. Later, before sending out
any data, a peer sends the necessary uncle hashes.
-
+
PEX+/PEX- 05/06, ipv4 addr, port
Peer exchange messages; reports all connected and
disconected peers. Might has special meaning (as
in the case with swarm supervisors).
-
+
*/
#ifndef P2TP_H
#define P2TP_H
+
+#ifdef _MSC_VER
+#include "compat/stdint.h"
+#else
#include <stdint.h>
+#endif
#include <vector>
#include <deque>
+#include <string>
#include "bin64.h"
#include "bins.h"
#include "datagram.h"
tintbin() : time(0), bin(bin64_t::NONE) {}
tintbin(tint time_, bin64_t bin_) : time(time_), bin(bin_) {}
};
-
+
typedef std::deque<tintbin> tbqueue;
typedef std::deque<bin64_t> binqueue;
typedef Datagram::Address Address;
- typedef enum {
- P2TP_HANDSHAKE = 0,
- P2TP_DATA = 1,
- P2TP_ACK = 2,
- P2TP_ACK_TS = 8,
- P2TP_HINT = 3,
- P2TP_HASH = 4,
+ typedef enum {
+ P2TP_HANDSHAKE = 0,
+ P2TP_DATA = 1,
+ P2TP_ACK = 2,
+ P2TP_ACK_TS = 8,
+ P2TP_HINT = 3,
+ P2TP_HASH = 4,
P2TP_PEX_ADD = 5,
P2TP_PEX_RM = 6,
P2TP_MESSAGE_COUNT = 7
} messageid_t;
-
+
class PiecePicker;
class CongestionController;
class PeerSelector;
-
+
class FileTransfer {
-
+
public:
-
+
/** Open/submit/retrieve a file. */
FileTransfer(const char *file_name, const Sha1Hash& _root_hash=Sha1Hash::ZERO);
-
+
/** Close everything. */
~FileTransfer();
-
+
/** Offer a hash; returns true if it verified; false otherwise.
Once it cannot be verified (no sibling or parent), the hash
is remembered, while returning false. */
/** Offer data; the behavior is the same as with a hash:
accept or remember or drop. Returns true => ACK is sent. */
bool OfferData (bin64_t bin, const uint8_t* data, size_t length);
-
+
static FileTransfer* Find (const Sha1Hash& hash);
- static FileTransfer* file (int fd) {
- return fd<files.size() ? files[fd] : NULL;
+ static FileTransfer* file (int fd) {
+ return fd<files.size() ? files[fd] : NULL;
}
-
+
int peak_count () const { return peak_count_; }
bin64_t peak (int i) const { return peaks_[i]; }
const Sha1Hash& peak_hash (int i) const { return peak_hashes_[i]; }
bin64_t peak_for (bin64_t pos) const;
- const Sha1Hash& hash (bin64_t pos) const {
+ const Sha1Hash& hash (bin64_t pos) const {
assert(pos<sizek_*2);
return hashes_[pos];
}
uint64_t complete_kilo () const { return completek_; }
uint64_t seq_complete () const { return seq_complete_; }
bins& ack_out () { return ack_out_; }
- int file_descriptor () const { return fd_; }
+ int file_descriptor () const { return fd_; }
PiecePicker* picker () { return picker_; }
-
+
static int instance; // FIXME this smells
-
+
private:
static std::vector<FileTransfer*> files;
- static const char* HASH_FILE_TEMPLATE;
- static const char* PEAK_FILE_TEMPLATE;
-
+ static std::string GetTempFilename(Sha1Hash& root_hash, int instance, std::string postfix);
+
/** file descriptor. */
int fd_;
/** File size, as derived from the hashes. */
PiecePicker* picker_;
/** File for keeping the Merkle hash tree. */
int hashfd_;
+#ifdef _MSC_VER
+ HANDLE hashmaphandle_;
+#endif
/** Merkle hash tree: root */
Sha1Hash root_hash_;
/** Merkle hash tree: peak hashes */
bool dry_run_;
/** Error encountered */
char* error_;
-
+
protected:
void SetSize(size_t bytes);
void Submit();
friend int Open (const char* filename, const Sha1Hash& hash) ;
friend void Close (int fd) ;
};
-
class CongestionController {
public:
virtual void OnAckRcvd(const tintbin& tsack) = 0;
virtual ~CongestionController() = 0;
};
-
+
class PiecePicker {
public:
virtual bin64_t Pick (bins& from, uint8_t layer) = 0;
virtual void Received (bin64_t b) = 0;
virtual void Snubbed (bin64_t b) = 0;
};
-
+
class PeerSelector {
public:
virtual void AddPeer (const Datagram::Address& addr, const Sha1Hash& root) = 0;
virtual Datagram::Address GetPeer (const Sha1Hash& for_root) = 0;
};
-
+
class DataStorer {
public:
DataStorer (const Sha1Hash& id, size_t size);
virtual size_t ReadData (bin64_t pos,uint8_t** buf) = 0;
virtual size_t WriteData (bin64_t pos, uint8_t* buf, size_t len) = 0;
};
-
+
/** P2TP channel's "control block"; channels loosely correspond to TCP
connections or FTP sessions; one channel is created for one file
public:
Channel (FileTransfer* file, int socket, struct sockaddr_in peer);
~Channel();
-
+
static void Recv (int socket);
static void Loop (tint till);
-
+
void Recv (Datagram& dgram);
tint Send ();
void OnHash (Datagram& dgram);
void OnPex (Datagram& dgram);
void OnHandshake (Datagram& dgram);
-
void AddHandshake (Datagram& dgram);
bin64_t AddData (Datagram& dgram);
void AddAck (Datagram& dgram);
const std::string id_string () const;
/** A channel is "established" if had already sent and received packets. */
bool is_established () { return peer_channel_id && own_id_mentioned; }
-
+
static int DecodeID(int scrambled);
static int EncodeID(int unscrambled);
static Channel* channel(int i) {
return i<channels.size()?channels[i]:NULL;
}
-
+
FileTransfer& file() { return *file_; }
-
-
+
private:
-
+
/** Channel id: index in the channel array. */
uint32_t id;
/** Socket address of the peer. */
CongestionController *cc;
/** For repeats. */
tint last_send_time, last_recv_time;
-
+
/** Get a rewuest for one packet from the queue of peer's requests. */
bin64_t DequeueHint();
void CleanStaleHints();
-
+
static PeerSelector* peer_selector;
-
+
static int MAX_REORDERING;
static tint TIMEOUT;
static std::vector<Channel*> channels;
static int sockets[8];
static int socket_count;
static tint last_tick;
-
+
friend int Listen (Datagram::Address addr);
friend void Shutdown (int sock_des);
friend void AddPeer (Datagram::Address address, const Sha1Hash& root);
};
-
+
/*************** The top-level API ****************/
/** Start listening a port. Returns socket descriptor. */
/** Returns size of the file in bytes, 0 if unknown. Might be rounded up to a kilobyte
before the transmission is complete. */
size_t Size (int fdes);
- /** Returns the amount of retrieved and verified data, in bytes.
+ /** Returns the amount of retrieved and verified data, in bytes.
A 100% complete transmission has Size()==Complete(). */
size_t Complete (int fdes);
/** Returns the number of bytes that are complete sequentially, starting from the
beginning, till the first not-yet-retrieved packet. */
size_t SeqComplete (int fdes);
-
+
//uint32_t Width (const tbinvec& v);
-}
+
+ void LibraryInit(void);
+ /** Must be called by any client using the library */
+
+
+} // namespace end
#define RETLOG(str) { LOG(WARNING)<<str; return; }
* serp++
*
* Created by Victor Grishchenko on 3/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
* serp++
*
* Created by Victor Grishchenko on 4/1/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include "sbit.h"
* serp++
*
* Created by Victor Grishchenko on 3/28/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#ifndef SERP_SBIT_H
* serp++
*
* Created by Victor Grishchenko on 3/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include <algorithm>
-env = Environment(CPPPATH = '.',CXXFLAGS="-g")
+import sys
+
+Import("DEBUG")
+Import("env")
+Import("libs")
+Import("libpath")
+
+cpppath = env["CPPPATH"]
+libs = ['p2tp'] + libs # order is important, crypto needs to be last
+
+if sys.platform == "win32":
+ cpppath = ".."
+ libpath += '..;'
+ if DEBUG:
+ env.Append(CXXFLAGS="/Zi /Yd /MTd")
+else:
+ cpppath = cpppath + ':..'
+ libpath += ':..'
+ if DEBUG:
+ env.Append(CXXFLAGS="-g")
+
+print "tests: libpath is",libpath
env.Program(
target='binstest2',
source=['binstest2.cpp'],
- CPPPATH=['..'],
- LIBS=['p2tp','stdc++','gtest','glog'],
- LIBPATH='..' )
+ CPPPATH=cpppath,
+ LIBS=libs,
+ LIBPATH=libpath )
env.Program(
target='dgramtest',
source=['dgramtest.cpp'],
- CPPPATH=['..'],
- LIBS=['p2tp','stdc++','gtest','glog'],
- LIBPATH='..' )
+ CPPPATH=cpppath,
+ LIBS=libs,
+ LIBPATH=libpath )
env.Program(
target='hashtest',
source=['hashtest.cpp'],
- CPPPATH=['..'],
- LIBS=['p2tp','stdc++','gtest','glog','crypto'],
- LIBPATH='..' )
+ CPPPATH=cpppath,
+ LIBS=libs,
+ LIBPATH=libpath )
env.Program(
target='ledbattest',
source=['ledbattest.cpp'],
- CPPPATH=['..'],
- LIBS=['p2tp','stdc++','gtest','glog','crypto'],
- LIBPATH='..' )
+ CPPPATH=cpppath,
+ LIBS=libs,
+ LIBPATH=libpath )
-env.Program(
- target='ledbattest2',
- source=['ledbattest2.cpp'],
- CPPPATH=['..'],
- LIBS=['p2tp','stdc++','gtest','glog','crypto'],
- LIBPATH='..' )
+
+if sys.platform != "win32":
+ # Arno: Needs getopt
+ env.Program(
+ target='ledbattest2',
+ source=['ledbattest2.cpp'],
+ CPPPATH=cpppath,
+ LIBS=libs,
+ LIBPATH=libpath )
env.Program(
target='freemap',
source=['freemap.cpp'],
- CPPPATH=['..'],
- LIBS=['p2tp','stdc++','gtest','glog'],
- LIBPATH='..' )
+ CPPPATH=cpppath,
+ LIBS=libs,
+ LIBPATH=libpath )
env.Program(
target='bin64test',
source=['bin64test.cpp'],
- CPPPATH=['..'],
- LIBS=['p2tp','gtest'],
- LIBPATH='..' )
+ CPPPATH=cpppath,
+ LIBS=libs,
+ LIBPATH=libpath )
env.Program(
target='transfertest',
source=['transfertest.cpp'],
- CPPPATH=['..'],
- LIBS=['p2tp','gtest'],
- LIBPATH='..' )
-
+ CPPPATH=cpppath,
+ LIBS=libs,
+ LIBPATH=libpath )
* bin++
*
* Created by Victor Grishchenko on 3/9/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include "bin64.h"
}
TEST(Bin64Test,Overflows) {
-
+
/*EXPECT_EQ(bin64_t::NONE.parent(),bin64_t::NONE);
EXPECT_EQ(bin64_t::NONE.left(),bin64_t::NONE);
EXPECT_EQ(bin64_t::NONE.right(),bin64_t::NONE);
}
TEST(Bin64Test, Advanced) {
-
+
EXPECT_EQ(4,bin64_t(2,3).width());
EXPECT_FALSE(bin64_t(1,1234).is_base());
EXPECT_TRUE(bin64_t(0,12345).is_base());
EXPECT_EQ(bin64_t(2,0),peaks[0]);
EXPECT_EQ(bin64_t(1,2),peaks[1]);
EXPECT_EQ(bin64_t(0,6),peaks[2]);
-
+
}
TEST(Bin64Test, Iteration) {
}
int main (int argc, char** argv) {
-
+
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
-
+
}
* serp++
*
* Created by Victor Grishchenko on 3/22/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include <time.h>
* serp++
*
* Created by Victor Grishchenko on 3/22/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include <time.h>
* bin++
*
* Created by Victor Grishchenko on 3/9/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include "bin.h"
* p2tp
*
* Created by Victor Grishchenko on 7/13/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include <stdint.h>
* serp++
*
* Created by Victor Grishchenko on 3/19/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
* serp++
*
* Created by Victor Grishchenko on 3/13/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include <gtest/gtest.h>
#include <glog/logging.h>
#include "datagram.h"
+#include "p2tp.h" // Arno: for LibraryInit
using namespace p2tp;
-TEST(Datagram, BinaryTest) {
- int socket = Datagram::Bind(7001);
+TEST(Datagram, BinaryTest) {
+ SOCKET socket = Datagram::Bind(7001);
ASSERT_TRUE(socket>0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
EXPECT_STREQ("74657874ababcdabcdef01000abcdefabcdeff",buf);
int datalen = strlen(text)+1+2+4+8;
ASSERT_EQ(datalen,d.Send());
- int socks[1] = {socket};
- ASSERT_EQ (socket, Datagram::Wait(1,socks));
- Datagram rcv(socket);
+ SOCKET socks[1] = {socket};
+ // Arno: timeout 0 gives undeterministic behaviour on win32
+ SOCKET waitsocket = Datagram::Wait(1,socks,1000000);
+ ASSERT_EQ(socket,waitsocket);
+ Datagram rcv(waitsocket);
ASSERT_EQ(datalen,rcv.Recv());
char* rbuf;
int pl = rcv.Pull((uint8_t**)&rbuf,strlen(text));
addr2.sin_family = AF_INET;
addr2.sin_port = htons(10002);
addr2.sin_addr.s_addr = htonl(INADDR_LOOPBACK);*/
-
+
Datagram send(sock1,Datagram::Address(10002));
send.Push32(1234);
send.Send();
-
- int socks[2] = {sock1,sock2};
- EXPECT_EQ(sock2,Datagram::Wait(2,socks));
+
+ SOCKET socks[2] = {sock1,sock2};
+ // Arno: timeout 0 gives undeterministic behaviour on win32
+ EXPECT_EQ(sock2,Datagram::Wait(2,socks,1000000));
Datagram recv(sock2);
recv.Recv();
uint32_t test = recv.Pull32();
ASSERT_EQ(1234,test);
-
+
Datagram::Close(sock1);
Datagram::Close(sock2);
}
int main (int argc, char** argv) {
-
+
+ p2tp::LibraryInit();
+
testing::InitGoogleTest(&argc, argv);
google::InitGoogleLogging(argv[0]);
return RUN_ALL_TESTS();
-
+
}
* serp++
*
* Created by Victor Grishchenko on 3/22/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include <time.h>
#include <set>
#include "bins.h"
+#ifdef _MSC_VER
+ #define RANDOM rand
+#else
+ #define RANDOM random
+#endif
+
int bins_stripe_count (bins& b) {
int stripe_count;
uint64_t * stripes = b.get_stripes(stripe_count);
}
uint8_t rand_norm (uint8_t lim) {
- long rnd = random() & ((1<<lim)-1);
+ long rnd = RANDOM() & ((1<<lim)-1);
uint8_t bits = 0;
while (rnd) {
bits += rnd&1;
* serp++
*
* Created by Victor Grishchenko on 3/12/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include <fcntl.h>
tint last_sec = 0;
int sec_ackd = 0;
- int send_sock = Datagram::Bind(10001); // bind sending socket
- int ack_sock = Datagram::Bind(10002); // bind receiving socket
+ SOCKET send_sock = Datagram::Bind(10001); // bind sending socket
+ SOCKET ack_sock = Datagram::Bind(10002); // bind receiving socket
struct sockaddr_in send_to, ack_to;
send_to.sin_family = AF_INET;
send_to.sin_port = htons(10002);
ack_to.sin_port = htons(10001);
ack_to.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
uint8_t* garbage = (uint8_t*) malloc(1024);
- int socks[2] = {send_sock,ack_sock};
- int sock2read;
+ SOCKET socks[2] = {send_sock,ack_sock};
+ SOCKET sock2read;
tint wait_time = 100*TINT_MSEC;
while (sock2read = Datagram::Wait(2,socks,wait_time)) {
fprintf(stderr,"%lli rcvd%i\n",now/TINT_SEC,seq);
// TODO: peer cwnd !!!
continue;
- }
+ }
if (sock2read==send_sock) { // process an acknowledgement
Datagram ack(send_sock);
ack.Recv();
int main (int argc, char** argv) {
printf("Warning: use the script to set up dummynet!\n");
+
+ p2tp::LibraryInit();
+
testing::InitGoogleTest(&argc, argv);
google::InitGoogleLogging(argv[0]);
return RUN_ALL_TESTS();
#include <stdio.h>
#include <stdlib.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+#ifdef _MSC_VER
+ #include "compat/stdint.h"
+ #include <winsock2.h>
+#else
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+#endif
#include <vector>
#include <deque>
#include "datagram.h"
fprintf(stderr,"%lli rcvd%i\n",now/TINT_SEC,seq);
// TODO: peer cwnd !!!
continue;
- }
+ }
if (sock2read==send_sock) { // process an acknowledgement
Datagram ack(send_sock);
ack.Recv();
* serp++
*
* Created by Victor Grishchenko on 3/19/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
* serp++
*
* Created by Victor Grishchenko on 4/1/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
* serp++
*
* Created by Victor Grishchenko on 3/9/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include "bin.h"
* p2tp
*
* Created by Victor Grishchenko on 10/7/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
#include <gtest/gtest.h>
+#include <glog/logging.h>
#include "p2tp.h"
+#include "compat/util.h"
+#ifdef _MSC_VER
+#include "compat/unixio.h"
+#endif
using namespace p2tp;
ROOT = Sha1Hash(ROOT,Sha1Hash::ZERO);
//printf("m %lli %s\n",(uint64_t)pos.parent(),ROOT.hex().c_str());
}
-
+
// submit a new file
FileTransfer* seed = new FileTransfer(BTF);
EXPECT_TRUE(A==seed->hash(0));
EXPECT_EQ(5,seed->size_kilo());
EXPECT_EQ(4100,seed->complete());
EXPECT_EQ(4100,seed->seq_complete());
-
+
// retrieve it
unlink("copy");
FileTransfer::instance = 1;
EXPECT_EQ(5,leech->size_kilo());
EXPECT_EQ(4100,leech->complete());
EXPECT_EQ(4100,leech->seq_complete());
-
+
}
/*
FIXME
*/
int main (int argc, char** argv) {
-
- unlink("/tmp/.70196e6065a42835b1f08227ac3e2fb419cf78c8.0.hashes");
- unlink("/tmp/.70196e6065a42835b1f08227ac3e2fb419cf78c8.0.peaks");
- unlink("/tmp/.70196e6065a42835b1f08227ac3e2fb419cf78c8.1.hashes");
- unlink("/tmp/.70196e6065a42835b1f08227ac3e2fb419cf78c8.1.peaks");
- unlink("/tmp/.70196e6065a42835b1f08227ac3e2fb419cf78c8.2.hashes");
- unlink("/tmp/.70196e6065a42835b1f08227ac3e2fb419cf78c8.2.peaks");
-
+
+ google::InitGoogleLogging(argv[0]);
+
+ std::string tempdir = gettmpdir();
+ unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.0.hashes")).c_str());
+ unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.0.peaks")).c_str());
+ unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.1.hashes")).c_str());
+ unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.1.peaks")).c_str());
+ unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.2.hashes")).c_str());
+ unlink((tempdir + std::string(".70196e6065a42835b1f08227ac3e2fb419cf78c8.2.peaks")).c_str());
+
unlink(BTF);
unlink("copy");
-
+
int f = open(BTF,O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (f < 0)
+ {
+ PLOG(FATAL)<< "Error opening " << BTF << "\n";
+ return -1;
+ }
uint8_t buf[1024];
memset(buf,'A',1024);
A = Sha1Hash(buf,1024);
E = Sha1Hash(buf,4);
write(f,buf,4);
close(f);
-
+
testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
-
+
return ret;
}
* p2tp
*
* Created by Victor Grishchenko on 10/6/09.
- * Copyright 2009 Delft Technical University. All rights reserved.
+ * Copyright 2009 Delft University of Technology. All rights reserved.
*
*/
+#ifdef _MSC_VER
+#include "compat/unixio.h"
+#else
#include <sys/mman.h>
+#endif
#include <errno.h>
+#include <string>
+#include <sstream>
#include "p2tp.h"
+#include "compat/util.h"
using namespace p2tp;
std::vector<FileTransfer*> FileTransfer::files(20);
-const char* FileTransfer::HASH_FILE_TEMPLATE = "/tmp/.%s.%i.hashes";
-const char* FileTransfer::PEAK_FILE_TEMPLATE = "/tmp/.%s.%i.peaks";
+
int FileTransfer::instance = 0;
#define BINHASHSIZE (sizeof(bin64_t)+sizeof(Sha1Hash))
// FIXME: separate Bootstrap() and Download(), then Size(), Progress(), SeqProgress()
FileTransfer::FileTransfer (const char* filename, const Sha1Hash& _root_hash) :
- root_hash_(_root_hash), fd_(0), hashfd_(0), dry_run_(false),
+ root_hash_(_root_hash), fd_(0), hashfd_(0), dry_run_(false),
peak_count_(0), hashes_(NULL), error_(NULL), size_(0), sizek_(0),
complete_(0), completek_(0), seq_complete_(0)
{
void FileTransfer::LoadPeaks () {
- char file_name[1024];
- sprintf(file_name,PEAK_FILE_TEMPLATE,root_hash().hex().c_str(),instance);
- int peakfd = open(file_name,O_RDONLY);
+ std::string file_name = GetTempFilename(root_hash_,instance,std::string(".peaks"));
+ int peakfd = open(file_name.c_str(),O_RDONLY,0);
if (peakfd<0)
return;
bin64_t peak;
void FileTransfer::SavePeaks () {
- char file_name[1024];
- sprintf(file_name,PEAK_FILE_TEMPLATE,root_hash().hex().c_str(),instance);
- int peakfd = open(file_name,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ std::string file_name = GetTempFilename(root_hash_,instance,std::string(".peaks"));
+ int peakfd = open(file_name.c_str(),O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
for(int i=0; i<peak_count(); i++) {
write(peakfd,&(peaks_[i]),sizeof(bin64_t));
write(peakfd,*peak_hashes_[i],Sha1Hash::SIZE);
size_ = bytes;
completek_ = complete_ = seq_complete_ = 0;
sizek_ = (size_>>10) + ((size_&1023) ? 1 : 0);
-
- char file_name[1024];
+
struct stat st;
fstat(fd_, &st);
if (st.st_size!=bytes)
if (ftruncate(fd_, bytes))
return; // remain in the 0-state
// mmap the hash file into memory
- sprintf(file_name,HASH_FILE_TEMPLATE,root_hash().hex().c_str(),instance);
- hashfd_ = open(file_name,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
- size_t expected_size = Sha1Hash::SIZE * sizek_ * 2;
+ std::string file_name = GetTempFilename(root_hash_,instance,std::string(".hashes"));
+ hashfd_ = open(file_name.c_str(),O_RDWR|O_CREAT,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ size_t expected_size_ = Sha1Hash::SIZE * sizek_ * 2;
struct stat hash_file_st;
fstat(hashfd_, &hash_file_st);
- if ( hash_file_st.st_size != expected_size )
- ftruncate(hashfd_, expected_size);
- hashes_ = (Sha1Hash*) mmap (NULL, expected_size, PROT_READ|PROT_WRITE,
+ if ( hash_file_st.st_size != expected_size_ )
+ ftruncate(hashfd_, expected_size_);
+#ifdef _MSC_VER
+ HANDLE hashhandle = (HANDLE)_get_osfhandle(hashfd_);
+ hashmaphandle_ = CreateFileMapping(hashhandle,
+ NULL,
+ PAGE_READWRITE,
+ 0,
+ 0,
+ NULL);
+ if (hashmaphandle_ != NULL)
+ {
+ hashes_ = (Sha1Hash*)MapViewOfFile(hashmaphandle_,
+ FILE_MAP_WRITE,
+ 0,
+ 0,
+ 0);
+
+ }
+ if (hashmaphandle_ == NULL || hashes_ == NULL)
+#else
+ hashes_ = (Sha1Hash*) mmap (NULL, expected_size, PROT_READ|PROT_WRITE,
MAP_SHARED, hashfd_, 0);
- if (hashes_==MAP_FAILED) {
+ if (hashes_==MAP_FAILED)
+#endif
+ {
hashes_ = NULL;
size_ = sizek_ = complete_ = completek_ = seq_complete_ = 0;
error_ = strerror(errno); // FIXME dprintf()
}
for(int i=0; i<peak_count_; i++)
hashes_[peaks_[i]] = peak_hashes_[i];
-}
+}
void FileTransfer::Submit () {
hashes_ = (Sha1Hash*) malloc(Sha1Hash::SIZE*sizek_*2);
peak_count_ = bin64_t::peaks(sizek_,peaks_);
for (int p=0; p<peak_count_; p++) {
- for(bin64_t b=peaks_[p].left_foot(); b.within(peaks_[p]); b=b.next_dfsio(0))
+ for(bin64_t b=peaks_[p].left_foot(); b.within(peaks_[p]); b=b.next_dfsio(0))
if (b.is_base()) {
uint8_t kilo[1<<10];
size_t rd = pread(fd_,kilo,1<<10,b.base_offset()<<10);
}
-void FileTransfer::OfferHash (bin64_t pos, const Sha1Hash& hash) {
+void FileTransfer::OfferHash (bin64_t pos, const Sha1Hash& hash) {
if (!size_) // only peak hashes are accepted at this point
return OfferPeak(pos,hash);
int pi=0;
bin64_t peak = peak_for(pos);
if (peak==bin64_t::NONE)
return false;
-
- Sha1Hash hash(data,length);
+
+ Sha1Hash hash(data,length);
bin64_t p = pos;
while ( p!=peak && ack_out_.get(p)==bins::EMPTY ) {
hashes_[p] = hash;
}
if (hash!=hashes_[p])
return false;
-
+
//printf("g %lli %s\n",(uint64_t)pos,hash.hex().c_str());
// walk to the nearest proven hash FIXME 0-layer peak
ack_out_.set(pos,bins::FILLED);
assert(!size_);
if (peak_count_) {
bin64_t last_peak = peaks_[peak_count_-1];
- if ( pos.layer()>=last_peak.layer() ||
+ if ( pos.layer()>=last_peak.layer() ||
pos.base_offset()!=last_peak.base_offset()+last_peak.width() )
peak_count_ = 0;
}
}
-FileTransfer::~FileTransfer () {
+FileTransfer::~FileTransfer ()
+{
+#ifdef _MSC_VER
+ UnmapViewOfFile(hashes_);
+ CloseHandle(hashmaphandle_);
+#else
munmap(hashes_,sizek_*2*Sha1Hash::SIZE);
close(hashfd_);
close(fd_);
files[fd_] = NULL;
+#endif
}
-
+
FileTransfer* FileTransfer::Find (const Sha1Hash& root_hash) {
for(int i=0; i<files.size(); i++)
if (files[i] && files[i]->root_hash_==root_hash)
}
+
+std::string FileTransfer::GetTempFilename(Sha1Hash& root_hash, int instance, std::string postfix)
+{
+ std::string tempfile = gettmpdir();
+ std::stringstream ss;
+ ss << instance;
+ tempfile += std::string(".") + root_hash.hex() + std::string(".") + ss.str() + postfix;
+ return tempfile;
+}
+
+
+
int p2tp::Open (const char* filename, const Sha1Hash& hash) {
FileTransfer* ft = new FileTransfer(filename, hash);
int fdes = ft->file_descriptor();
break;
x = x.left();
}
-
+
if (x.layer()==10) {
if (recheck_data) {
uint8_t data[1024];
ack_out->set(x,bins::FILLED);
}
}
-
+
while (x.is_right() && x!=peaks[i])
x = x.parent();
x = x.sibling();
} while (x!=end);
}
-
-
-
-
+
+
+
+
// open file
if ( hash_file_st.st_size < (sizeof(bin64_t)+Sha1Hash::SIZE)*64 )
return;
}
if (!size)
return;
-
-
+
+
*/