├── .gitignore ├── BitWave.sln ├── BitWave.vcxproj ├── BitWave.vcxproj.filters ├── LICENSE ├── README ├── base ├── BaseTypes.h ├── Console.h ├── ObjectPool.h ├── RefCount.h ├── ScopePtr.h └── StringConv.h ├── buffer └── Buffer.h ├── core ├── BitCache.cpp ├── BitCache.h ├── BitController.cpp ├── BitController.h ├── BitCreator.cpp ├── BitCreator.h ├── BitData.cpp ├── BitData.h ├── BitDownloadDispatcher.cpp ├── BitDownloadDispatcher.h ├── BitDownloadingInfo.cpp ├── BitDownloadingInfo.h ├── BitException.h ├── BitFile.cpp ├── BitFile.h ├── BitNetProcessor.h ├── BitPeerConnection.cpp ├── BitPeerConnection.h ├── BitPeerCreateStrategy.cpp ├── BitPeerCreateStrategy.h ├── BitPeerData.cpp ├── BitPeerData.h ├── BitPeerListener.cpp ├── BitPeerListener.h ├── BitPiece.cpp ├── BitPiece.h ├── BitPieceMap.cpp ├── BitPieceMap.h ├── BitPieceSha1Calc.cpp ├── BitPieceSha1Calc.h ├── BitRepository.cpp ├── BitRepository.h ├── BitRequestList.cpp ├── BitRequestList.h ├── BitService.cpp ├── BitService.h ├── BitTask.cpp ├── BitTask.h ├── BitTrackerConnection.cpp ├── BitTrackerConnection.h ├── BitUploadDispatcher.cpp ├── BitUploadDispatcher.h ├── BitWave.cpp ├── BitWave.h ├── Main.cpp └── bencode │ ├── BenTypes.cpp │ ├── BenTypes.h │ ├── MetainfoFile.cpp │ ├── MetainfoFile.h │ ├── TrackerResponse.cpp │ └── TrackerResponse.h ├── log ├── Log.h ├── LogFactory.h ├── LogImpl.h └── Manipulator.h ├── net ├── Address.h ├── AddressResolver.h ├── BaseSocket.h ├── IoService.h ├── Iocp.h ├── NetException.h ├── NetHelper.h ├── Overlapped.h ├── ResolveService.h ├── ServiceBase.h ├── Socket.h ├── StreamUnpacker.h ├── TimerService.h └── WinSockIniter.h ├── protocol ├── HttpException.h ├── Request.cpp ├── Request.h ├── Response.cpp ├── Response.h ├── URI.cpp └── URI.h ├── sha1 ├── NetSha1Value.cpp ├── NetSha1Value.h ├── Sha1Value.cpp ├── Sha1Value.h ├── license.txt ├── sha1.cpp └── sha1.h ├── test ├── TestAddressResolver.cpp ├── TestBenType.cpp ├── TestLog.cpp ├── TestNetClient.cpp ├── TestNetServer.cpp ├── TestObjectPool.cpp ├── TestRefCount.cpp ├── TestResolveService.cpp ├── TestScopePtr.cpp ├── TestSha1.cpp ├── TestThread.cpp ├── TestTimer.cpp ├── TestTorrentFile.cpp ├── TestTracker.cpp ├── TestURI.cpp └── TestUnitTest.cpp ├── thread ├── Atomic.h ├── Event.h ├── Mutex.h ├── ReadWriteLock.h └── Thread.h ├── timer ├── TimeTraits.h ├── Timer.h └── TimerQueue.h └── unittest └── UnitTest.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.sdf 3 | *.suo 4 | *.swp 5 | *.opensdf 6 | /ipch/ 7 | /Debug/ 8 | /Release/ 9 | -------------------------------------------------------------------------------- /BitWave.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BitWave", "BitWave.vcxproj", "{9BDB4258-E02F-4FA8-A482-2AEE7C0A6A0A}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {9BDB4258-E02F-4FA8-A482-2AEE7C0A6A0A}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {9BDB4258-E02F-4FA8-A482-2AEE7C0A6A0A}.Debug|Win32.Build.0 = Debug|Win32 14 | {9BDB4258-E02F-4FA8-A482-2AEE7C0A6A0A}.Release|Win32.ActiveCfg = Release|Win32 15 | {9BDB4258-E02F-4FA8-A482-2AEE7C0A6A0A}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, airtrack 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this list 8 | of conditions and the following disclaimer. 9 | Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or other 11 | materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 17 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 20 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 21 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 22 | POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | BitWave is a BitTorrent client written in C++, aim to be a cross-platform 2 | BitTorrent client. Now just support Windows, plan on support Linux. 3 | 4 | BitWave now only support core BitTorrent protocol, download and upload 5 | algorithms are improving. 6 | 7 | Build: 8 | Build program using Visual Studio 2010. 9 | -------------------------------------------------------------------------------- /base/BaseTypes.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_TYPES_H 2 | #define BASE_TYPES_H 3 | 4 | #include 5 | #include 6 | 7 | class NotCopyable 8 | { 9 | public: 10 | NotCopyable() { } 11 | private: 12 | NotCopyable(const NotCopyable&); 13 | NotCopyable& operator = (const NotCopyable&); 14 | }; 15 | 16 | class StaticClass 17 | { 18 | private: 19 | StaticClass(); 20 | StaticClass(const StaticClass&); 21 | StaticClass& operator = (const StaticClass&); 22 | }; 23 | 24 | class BaseException 25 | { 26 | public: 27 | explicit BaseException(int ecode) 28 | : exception_code_(ecode) 29 | { 30 | } 31 | 32 | explicit BaseException(const std::string& w) 33 | : exception_code_(0), 34 | what_(w) 35 | { 36 | } 37 | 38 | BaseException(int ecode, const std::string& w) 39 | : exception_code_(ecode), 40 | what_(w) 41 | { 42 | } 43 | 44 | int get_exception_code() const 45 | { 46 | return exception_code_; 47 | } 48 | 49 | const char * what() const 50 | { 51 | return what_.c_str(); 52 | } 53 | 54 | private: 55 | int exception_code_; 56 | std::string what_; 57 | }; 58 | 59 | template 60 | inline void CheckedDelete(T *t) 61 | { 62 | typedef char TypeMustBeComplete[sizeof(T) ? 1 : -1]; 63 | (void)sizeof(TypeMustBeComplete); 64 | delete t; 65 | } 66 | 67 | template 68 | inline void CheckedArrayDelete(T *t) 69 | { 70 | typedef char TypeMustBeComplete[sizeof(T) ? 1 : -1]; 71 | (void)sizeof(TypeMustBeComplete); 72 | delete [] t; 73 | } 74 | 75 | template 76 | struct DelObject : public std::unary_function 77 | { 78 | void operator () (T *obj) const 79 | { 80 | CheckedDelete(obj); 81 | } 82 | }; 83 | 84 | template 85 | struct DelArray : public std::unary_function 86 | { 87 | void operator () (T *array) const 88 | { 89 | CheckedArrayDelete(array); 90 | } 91 | }; 92 | 93 | struct DeleteSecondOfPair 94 | { 95 | template 96 | void operator () (PairType& pair) const 97 | { 98 | CheckedDelete(pair.second); 99 | } 100 | }; 101 | 102 | #endif // BASE_TYPES_H 103 | -------------------------------------------------------------------------------- /base/Console.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSOLE_H 2 | #define CONSOLE_H 3 | 4 | #include "BaseTypes.h" 5 | #include 6 | 7 | class Console : private NotCopyable 8 | { 9 | public: 10 | Console() 11 | { 12 | console_ = ::GetStdHandle(STD_OUTPUT_HANDLE); 13 | } 14 | 15 | void SetCursorPos(int x, int y) 16 | { 17 | COORD cursor; 18 | cursor.X = x; 19 | cursor.Y = y; 20 | ::SetConsoleCursorPosition(console_, cursor); 21 | } 22 | 23 | void GetCursorPos(int& x, int& y) 24 | { 25 | CONSOLE_SCREEN_BUFFER_INFO info; 26 | ::GetConsoleScreenBufferInfo(console_, &info); 27 | x = info.dwCursorPosition.X; 28 | y = info.dwCursorPosition.Y; 29 | } 30 | 31 | void SetCursorVisible(bool visible) 32 | { 33 | CONSOLE_CURSOR_INFO info; 34 | info.dwSize = 1; 35 | info.bVisible = visible; 36 | ::SetConsoleCursorInfo(console_, &info); 37 | } 38 | 39 | void Write(const wchar_t *str, std::size_t size) 40 | { 41 | DWORD writed = 0; 42 | ::WriteConsole(console_, str, size, &writed, 0); 43 | } 44 | 45 | private: 46 | HANDLE console_; 47 | }; 48 | 49 | #endif // CONSOLE_H 50 | -------------------------------------------------------------------------------- /base/ObjectPool.h: -------------------------------------------------------------------------------- 1 | #ifndef _OBJECT_POOL_H_ 2 | #define _OBJECT_POOL_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "BaseTypes.h" 9 | 10 | template 11 | struct PODIniter 12 | { 13 | static void Init(T *obj, std::size_t count = 1) 14 | { 15 | memset(obj, 0, sizeof(T) * count); 16 | } 17 | }; 18 | 19 | template > 20 | class ObjectPool : private NotCopyable 21 | { 22 | public: 23 | static const std::size_t basecount = 100; 24 | static const std::size_t increase = 50; 25 | 26 | ObjectPool() 27 | : pools_(), 28 | notusedpool_(), 29 | basecount_(basecount), 30 | increase_(increase) 31 | { 32 | AllocObjects(basecount_); 33 | } 34 | 35 | ObjectPool(std::size_t count, std::size_t inccount) 36 | : pools_(), 37 | notusedpool_(), 38 | basecount_(count), 39 | increase_(inccount) 40 | { 41 | AllocObjects(basecount_); 42 | } 43 | 44 | ~ObjectPool() 45 | { 46 | std::for_each(pools_.begin(), pools_.end(), DelArray()); 47 | } 48 | 49 | T * ObtainObject() 50 | { 51 | if (notusedpool_.empty()) 52 | AllocObjects(increase_); 53 | 54 | T *ret = notusedpool_.front(); 55 | notusedpool_.pop_front(); 56 | return ret; 57 | } 58 | 59 | void ReturnObject(T *obj) 60 | { 61 | ObjIniter::Init(obj); 62 | notusedpool_.push_back(obj); 63 | } 64 | 65 | private: 66 | void AllocObjects(std::size_t size) 67 | { 68 | T *newobjs = new T[size]; 69 | ObjIniter::Init(newobjs, size); 70 | 71 | pools_.push_back(newobjs); 72 | T *endnewobjs = newobjs + size; 73 | for (; newobjs < endnewobjs; ++newobjs) 74 | notusedpool_.push_back(newobjs); 75 | } 76 | 77 | std::vector pools_; 78 | std::deque notusedpool_; 79 | const std::size_t basecount_; 80 | const std::size_t increase_; 81 | }; 82 | 83 | #endif // _OBJECT_POOL_H_ 84 | -------------------------------------------------------------------------------- /base/RefCount.h: -------------------------------------------------------------------------------- 1 | #ifndef _REF_COUNT_H_ 2 | #define _REF_COUNT_H_ 3 | 4 | #include 5 | 6 | class RefCount 7 | { 8 | public: 9 | RefCount() 10 | : usecount_(0) 11 | { 12 | } 13 | 14 | RefCount(bool) 15 | : usecount_(new int(1)) 16 | { 17 | } 18 | 19 | ~RefCount() 20 | { 21 | if (usecount_ && --*usecount_ == 0) 22 | delete usecount_; 23 | } 24 | 25 | RefCount(const RefCount& rc) 26 | : usecount_(0) 27 | { 28 | if (rc.UseCount() > 0) 29 | { 30 | usecount_ = rc.usecount_; 31 | ++*usecount_; 32 | } 33 | } 34 | 35 | RefCount& operator = (const RefCount& rc) 36 | { 37 | RefCount(rc).Swap(*this); 38 | return *this; 39 | } 40 | 41 | void Swap(RefCount& rc) 42 | { 43 | std::swap(rc.usecount_, usecount_); 44 | } 45 | 46 | int UseCount() const 47 | { 48 | return usecount_ ? *usecount_ : 0; 49 | } 50 | 51 | bool Only() const 52 | { 53 | return UseCount() == 1; 54 | } 55 | 56 | private: 57 | int *usecount_; 58 | }; 59 | 60 | #endif // _REF_COUNT_H_ 61 | -------------------------------------------------------------------------------- /base/ScopePtr.h: -------------------------------------------------------------------------------- 1 | #ifndef SCOPE_PTR_H 2 | #define SCOPE_PTR_H 3 | 4 | #include "BaseTypes.h" 5 | 6 | template 7 | class ScopePtr : private NotCopyable 8 | { 9 | public: 10 | explicit ScopePtr(T *pt = 0) 11 | : pt_(pt) 12 | { 13 | } 14 | 15 | ~ScopePtr() 16 | { 17 | CheckedDelete(pt_); 18 | } 19 | 20 | T * operator -> () const 21 | { 22 | return pt_; 23 | } 24 | 25 | T& operator * () const 26 | { 27 | return *pt_; 28 | } 29 | 30 | operator bool () const 31 | { 32 | return pt_ != 0; 33 | } 34 | 35 | void Reset(T *pt = 0) 36 | { 37 | delete pt_; 38 | pt_ = pt; 39 | } 40 | 41 | T * Get() const 42 | { 43 | return pt_; 44 | } 45 | 46 | private: 47 | T *pt_; 48 | }; 49 | 50 | #endif // SCOPE_PTR_H 51 | -------------------------------------------------------------------------------- /base/StringConv.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_CONV_H 2 | #define STRING_CONV_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | inline std::wstring MultiByteToUnicode(const std::string& str, unsigned code_page) 10 | { 11 | int count = ::MultiByteToWideChar(code_page, 0, str.c_str(), str.size(), 0, 0); 12 | assert(count > 0); 13 | std::vector buffer(count); 14 | ::MultiByteToWideChar(code_page, 0, str.c_str(), str.size(), &buffer[0], count); 15 | return std::wstring(&buffer[0], count); 16 | } 17 | 18 | inline std::string UnicodeToMultiByte(const std::wstring& wstr, unsigned code_page) 19 | { 20 | int count = ::WideCharToMultiByte(code_page, 0, wstr.c_str(), wstr.size(), 0, 0, 0, 0); 21 | assert(count > 0); 22 | std::vector buffer(count); 23 | ::WideCharToMultiByte(code_page, 0, wstr.c_str(), wstr.size(), &buffer[0], count, 0, 0); 24 | return std::string(&buffer[0], count); 25 | } 26 | 27 | inline std::wstring UTF8ToUnicode(const std::string& str) 28 | { 29 | return MultiByteToUnicode(str, CP_UTF8); 30 | } 31 | 32 | inline std::string UnicodeToUTF8(const std::wstring& wstr) 33 | { 34 | return UnicodeToMultiByte(wstr, CP_UTF8); 35 | } 36 | 37 | inline std::wstring ANSIToUnicode(const std::string str) 38 | { 39 | return MultiByteToUnicode(str, CP_ACP); 40 | } 41 | 42 | inline std::string UnicodeToANSI(const std::wstring& wstr) 43 | { 44 | return UnicodeToMultiByte(wstr, CP_ACP); 45 | } 46 | 47 | inline std::string ANSIToUTF8(const std::string& ansi) 48 | { 49 | return UnicodeToUTF8(ANSIToUnicode(ansi)); 50 | } 51 | 52 | inline std::string UTF8ToANSI(const std::string& utf8) 53 | { 54 | return UnicodeToANSI(UTF8ToUnicode(utf8)); 55 | } 56 | 57 | #endif // STRING_CONV_H 58 | -------------------------------------------------------------------------------- /core/BitCache.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_CACHE_H 2 | #define BIT_CACHE_H 3 | 4 | #include "BitFile.h" 5 | #include "BitPieceSha1Calc.h" 6 | #include "../base/BaseTypes.h" 7 | #include "../sha1/Sha1Value.h" 8 | #include 9 | #include 10 | #include 11 | 12 | namespace bitwave { 13 | namespace core { 14 | 15 | namespace bentypes { 16 | class MetainfoFile; 17 | } // namespace bentypes 18 | 19 | class BitData; 20 | class BitPiece; 21 | class BitPieceMap; 22 | class BitDownloadingInfo; 23 | 24 | class BitCache : private NotCopyable 25 | { 26 | public: 27 | // bool param is a flag of read success or not, const char * param 28 | // is the read data, the value is invalid when read success, otherwise 29 | // the value is 0 30 | typedef std::tr1::function ReadCallback; 31 | 32 | BitCache(const std::tr1::shared_ptr& bitdata, 33 | BitDownloadingInfo *downloading_info); 34 | 35 | bool IsInfoHashEqual(const Sha1Value& info_hash) const 36 | { 37 | return info_hash_ == info_hash; 38 | } 39 | 40 | void Read(std::size_t piece_index, 41 | std::size_t begin_of_piece, 42 | std::size_t length, 43 | const ReadCallback& callback); 44 | 45 | void Write(std::size_t piece_index, 46 | std::size_t begin_of_piece, 47 | std::size_t length, 48 | const char *block); 49 | 50 | void ProcessCache(); 51 | 52 | void FlushToFile(); 53 | 54 | private: 55 | struct AsyncReadData 56 | { 57 | ReadCallback callback; 58 | std::size_t begin_of_piece; 59 | std::size_t length; 60 | 61 | AsyncReadData(const ReadCallback& cb, 62 | std::size_t bop, 63 | std::size_t len) 64 | : callback(cb), 65 | begin_of_piece(bop), 66 | length(len) 67 | { 68 | } 69 | }; 70 | 71 | typedef std::tr1::shared_ptr PiecePtr; 72 | typedef std::map CachePiece; 73 | typedef std::multimap AsyncReadOps; 74 | 75 | PiecePtr FetchNewPiece(); 76 | 77 | CachePiece::iterator GetOldestPiece(); 78 | 79 | CachePiece::iterator InsertNewPiece(std::size_t piece_index); 80 | 81 | void ReadBlock(std::size_t piece_index, 82 | std::size_t begin_of_piece, 83 | std::size_t length, 84 | const ReadCallback& callback); 85 | 86 | void AsyncReadBlock(std::size_t piece_index, 87 | std::size_t begin_of_piece, 88 | std::size_t length, 89 | const ReadCallback& callback); 90 | 91 | void ReadCacheBlock(CachePiece::iterator it, 92 | std::size_t begin_of_piece, 93 | std::size_t length, 94 | const ReadCallback& callback); 95 | 96 | void ProcessAsyncReadOps(); 97 | 98 | void CompleteAsyncReadOps(CachePiece::iterator it); 99 | 100 | void WriteBlock(std::size_t piece_index, 101 | std::size_t begin_of_piece, 102 | std::size_t length, 103 | const char *block); 104 | 105 | void AsyncCheckPiece(CachePiece::iterator it); 106 | 107 | void ProcessAsyncCheckPiece(); 108 | 109 | void CompleteAsyncCheckPiece(std::size_t piece_index, 110 | const Sha1Value& sha1); 111 | 112 | void AsyncWritePiece(CachePiece::iterator it); 113 | 114 | void ProcessAsyncWritePiece(); 115 | 116 | void CompleteAsyncWritePiece(std::size_t piece_index); 117 | 118 | void FreeCachePiece(); 119 | 120 | const std::size_t piece_length_; 121 | const BitPieceMap& piece_map_; 122 | const Sha1Value info_hash_; 123 | const bentypes::MetainfoFile *metainfo_file_; 124 | BitDownloadingInfo *downloading_info_; 125 | CachePiece cache_piece_; 126 | std::size_t max_cache_pieces_; 127 | 128 | BitFile file_; 129 | AsyncReadOps async_read_ops_; 130 | BitPieceSha1Calc piece_sha1_calc_; 131 | }; 132 | 133 | } // namespace core 134 | } // namespace bitwave 135 | 136 | #endif // BIT_CACHE_H 137 | -------------------------------------------------------------------------------- /core/BitController.cpp: -------------------------------------------------------------------------------- 1 | #include "BitController.h" 2 | #include "BitTask.h" 3 | #include 4 | 5 | namespace bitwave { 6 | namespace core { 7 | 8 | void BitController::AddTask(const std::tr1::shared_ptr& task_ptr) 9 | { 10 | tasks_.push_back(task_ptr); 11 | } 12 | 13 | std::tr1::shared_ptr BitController::GetTask(const Sha1Value& info_hash) const 14 | { 15 | Tasks::const_iterator it = std::find_if(tasks_.begin(), tasks_.end(), 16 | std::tr1::bind(&BitTask::IsSameInfoHash, 17 | std::tr1::placeholders::_1, info_hash)); 18 | 19 | if (it == tasks_.end()) 20 | return std::tr1::shared_ptr(); 21 | 22 | return *it; 23 | } 24 | 25 | std::size_t BitController::GetTaskCount() const 26 | { 27 | return tasks_.size(); 28 | } 29 | 30 | void BitController::Process() 31 | { 32 | std::for_each(tasks_.begin(), tasks_.end(), 33 | std::tr1::bind(&BitTask::ProcessTask, std::tr1::placeholders::_1)); 34 | } 35 | 36 | } // namespace core 37 | } // namespace bitwave 38 | -------------------------------------------------------------------------------- /core/BitController.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_CONTROLLER_H 2 | #define BIT_CONTROLLER_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include "../sha1/Sha1Value.h" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace bitwave { 11 | namespace core { 12 | 13 | class BitTask; 14 | 15 | // this class manage and control all created BitTasks 16 | class BitController : private NotCopyable 17 | { 18 | public: 19 | void AddTask(const std::tr1::shared_ptr& task_ptr); 20 | std::tr1::shared_ptr GetTask(const Sha1Value& info_hash) const; 21 | std::size_t GetTaskCount() const; 22 | void Process(); 23 | 24 | private: 25 | typedef std::vector> Tasks; 26 | Tasks tasks_; 27 | }; 28 | 29 | } // namespace core 30 | } // namespace bitwave 31 | 32 | #endif // BIT_CONTROLLER_H 33 | -------------------------------------------------------------------------------- /core/BitCreator.cpp: -------------------------------------------------------------------------------- 1 | #include "BitCreator.h" 2 | #include "BitController.h" 3 | #include "BitData.h" 4 | #include "BitTask.h" 5 | #include "BitRepository.h" 6 | #include "BitService.h" 7 | 8 | namespace bitwave { 9 | namespace core{ 10 | 11 | BitNewTaskCreator::BitNewTaskCreator(BitController& controller, 12 | net::IoService& io_service) 13 | : controller_(controller), 14 | io_service_(io_service) 15 | { 16 | } 17 | 18 | void BitNewTaskCreator::CreateTask(const std::string& torrent_file, 19 | const std::string& download_path) 20 | { 21 | BitRepository::BitDataPtr bitdata = 22 | BitService::repository->CreateBitData(torrent_file); 23 | bitdata->SelectAllFile(true); 24 | 25 | std::string path = download_path; 26 | if (path.back() == '\\') 27 | path.pop_back(); 28 | bitdata->SetBasePath(path); 29 | 30 | BitTask *task = new BitTask(bitdata, io_service_); 31 | controller_.AddTask(std::tr1::shared_ptr(task)); 32 | } 33 | 34 | } // namespace core 35 | } // namespace bitwave 36 | -------------------------------------------------------------------------------- /core/BitCreator.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_CREATOR_H 2 | #define BIT_CREATOR_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include "../net/IoService.h" 6 | #include 7 | 8 | namespace bitwave { 9 | namespace core { 10 | 11 | class BitController; 12 | 13 | // this class to create a task and add created task to BitController 14 | class BitNewTaskCreator : private NotCopyable 15 | { 16 | public: 17 | // construct a creator, all created tasks will add to controller 18 | BitNewTaskCreator(BitController& controller, 19 | net::IoService& io_service); 20 | 21 | // create a new task from a torrent_file 22 | void CreateTask(const std::string& torrent_file, 23 | const std::string& download_path); 24 | 25 | private: 26 | BitController& controller_; 27 | net::IoService& io_service_; 28 | }; 29 | 30 | } // namespace core 31 | } // namespace bitwave 32 | 33 | #endif // BIT_CREATOR_H 34 | -------------------------------------------------------------------------------- /core/BitData.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_DATA_H 2 | #define BIT_DATA_H 3 | 4 | #include "BitPieceMap.h" 5 | #include "BitPeerData.h" 6 | #include "bencode/MetainfoFile.h" 7 | #include "../base/BaseTypes.h" 8 | #include "../base/ScopePtr.h" 9 | #include "../sha1/Sha1Value.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace bitwave { 16 | namespace core { 17 | 18 | // a class store bitwave task data info 19 | class BitData : private NotCopyable 20 | { 21 | public: 22 | struct PeerListenInfo 23 | { 24 | PeerListenInfo(unsigned long i, unsigned short p) 25 | : ip(i), port(p) 26 | { 27 | } 28 | 29 | friend bool operator < (const PeerListenInfo& left, 30 | const PeerListenInfo& right) 31 | { 32 | if (left.ip == right.ip) 33 | return left.port < right.port; 34 | return left.ip < right.ip; 35 | } 36 | 37 | unsigned long ip; 38 | unsigned short port; 39 | }; 40 | 41 | struct DownloadFileInfo 42 | { 43 | DownloadFileInfo(bool download, long long len) 44 | : is_download(download), 45 | length(len) 46 | { 47 | } 48 | 49 | bool is_download; // file is download or not 50 | long long length; // file total length in bytes 51 | std::string file_path; // file relative path 52 | }; 53 | 54 | typedef std::set ListenInfoSet; 55 | typedef std::set> PeerDataSet; 56 | typedef std::vector DownloadFiles; 57 | 58 | // construct a new BitTask's BitData 59 | explicit BitData(const std::string& torrent_file); 60 | 61 | // get MetainfoFile ptr 62 | const bentypes::MetainfoFile * GetMetainfoFile() const; 63 | 64 | // get the bitwave task torrent file path 65 | std::string GetTorrentFile() const; 66 | 67 | // get the BitData info hash of torrent file 68 | Sha1Value GetInfoHash() const; 69 | 70 | // get the bitwave task peer_id, the return value is string, store 71 | // the peer_id, 20 length 72 | std::string GetPeerId() const; 73 | 74 | // get piece count of the data 75 | std::size_t GetPieceCount() const; 76 | 77 | // get length bytes of one piece 78 | std::size_t GetPieceLength() const; 79 | 80 | // get total uploaded bytes 81 | long long GetUploaded() const; 82 | 83 | void IncreaseUploaded(long long inc); 84 | 85 | // get total downloaded bytes 86 | long long GetDownloaded() const; 87 | 88 | void IncreaseDownloaded(long long inc); 89 | 90 | // get total size bytes of need download 91 | long long GetTotalSize() const; 92 | 93 | long long GetCurrentDownload() const; 94 | 95 | void IncreaseCurrentDownload(long long inc); 96 | 97 | // download is complete or not 98 | bool IsDownloadComplete() const; 99 | 100 | // get downloaded piece map 101 | BitPieceMap& GetPieceMap() const; 102 | 103 | // get files info 104 | const DownloadFiles& GetFilesInfo() const; 105 | 106 | // set all downloaded files base path 107 | void SetBasePath(const std::string& path); 108 | 109 | // get all downloaded files base path 110 | std::string GetBasePath() const; 111 | 112 | // select file download or not 113 | void SelectFile(std::size_t file_index, bool download); 114 | 115 | // select all files download or not 116 | void SelectAllFile(bool download); 117 | 118 | // manage PeerListenInfo 119 | void AddPeerListenInfo(unsigned long ip, unsigned short port); 120 | ListenInfoSet& GetUnusedListenInfo(); 121 | ListenInfoSet& GetUsedListenInfo(); 122 | void MergeToUnusedListenInfo(const ListenInfoSet& info_set); 123 | void MergeToUsedListenInfo(const ListenInfoSet& info_set); 124 | void ClearUnusedListenInfo(); 125 | void ClearUsedListenInfo(); 126 | 127 | // manage PeerDataSet 128 | void AddPeerData(const std::tr1::shared_ptr& peer_data); 129 | void DelPeerData(const std::tr1::shared_ptr& peer_data); 130 | PeerDataSet& GetPeerDataSet(); 131 | 132 | private: 133 | void PrepareDownloadFiles(); 134 | void DoSelectFile(DownloadFiles::iterator it, bool download); 135 | 136 | typedef ScopePtr MetaInfoPtr; 137 | typedef ScopePtr PieceMapPtr; 138 | 139 | // base data 140 | Sha1Value info_hash_; 141 | std::string torrent_file_; 142 | std::string peer_id_; 143 | std::size_t piece_length_; 144 | std::size_t piece_count_; 145 | long long uploaded_; 146 | long long downloaded_; 147 | long long total_size_; 148 | long long current_download_; 149 | 150 | MetaInfoPtr metainfo_file_; 151 | PieceMapPtr downloaded_map_; 152 | ListenInfoSet unused_peers_; 153 | ListenInfoSet used_peers_; 154 | PeerDataSet peer_data_set_; 155 | DownloadFiles download_files_; 156 | std::string base_path_; 157 | }; 158 | 159 | } // namespace core 160 | } // namespace bitwave 161 | 162 | #endif // BIT_DATA_H 163 | -------------------------------------------------------------------------------- /core/BitDownloadDispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_DOWNLOAD_DISPATCHER_H 2 | #define BIT_DOWNLOAD_DISPATCHER_H 3 | 4 | #include "BitPieceMap.h" 5 | #include "BitRequestList.h" 6 | #include "BitDownloadingInfo.h" 7 | #include "../base/BaseTypes.h" 8 | #include "../base/ScopePtr.h" 9 | #include 10 | 11 | namespace bitwave { 12 | namespace core { 13 | 14 | class BitData; 15 | class BitPeerData; 16 | 17 | class BitDownloadDispatcher : 18 | public BitDownloadingInfo::Observer, private NotCopyable 19 | { 20 | public: 21 | class PieceIndexSearcher 22 | { 23 | public: 24 | virtual bool Search(const BitPieceMap& downloaded, 25 | const BitPieceMap& downloading, 26 | const BitPieceMap& need_download, 27 | const BitPieceMap& candidate, 28 | std::size_t *piece_index) = 0; 29 | virtual ~PieceIndexSearcher() { } 30 | }; 31 | 32 | BitDownloadDispatcher( 33 | const std::tr1::shared_ptr& bitdata, 34 | BitDownloadingInfo *downloading_info); 35 | 36 | ~BitDownloadDispatcher(); 37 | 38 | void DispatchRequestList( 39 | const std::tr1::shared_ptr& peer_data, 40 | BitRequestList& request_list); 41 | 42 | void ReturnRequest(BitRequestList& request_list, 43 | BitRequestList::Iterator it); 44 | 45 | bool IsEndDownloadingMode() const 46 | { return end_downloading_mode_; } 47 | 48 | private: 49 | virtual void DownloadingNewPiece(std::size_t piece_index) { } 50 | virtual void CompleteNewPiece(std::size_t piece_index); 51 | virtual void DownloadingFailed(std::size_t piece_index) { } 52 | 53 | void DispatchScatteredRequest( 54 | const std::tr1::shared_ptr& peer_data, 55 | BitRequestList& request_list); 56 | void DispatchNewRequest( 57 | const std::tr1::shared_ptr& peer_data, 58 | BitRequestList& request_list); 59 | void ScatterRequestPiece( 60 | std::size_t piece_index, 61 | BitRequestList& list); 62 | void DeleteScatteredRequest(std::size_t piece_index); 63 | bool EnterEndDownloadMode(); 64 | 65 | // bittask's bitdata 66 | std::tr1::shared_ptr bitdata_; 67 | // task downloading information 68 | BitDownloadingInfo *downloading_info_; 69 | // scattered block requests 70 | BitRequestList scattered_request_; 71 | // PieceIndexSearcher ptr 72 | ScopePtr piece_index_searcher_; 73 | // pieces count of total task 74 | std::size_t pieces_count_; 75 | // block count of one piece 76 | std::size_t block_count_; 77 | // end downloading mode, every peer will request every left piece 78 | bool end_downloading_mode_; 79 | }; 80 | 81 | } // namespace core 82 | } // namespace bitwave 83 | 84 | #endif // BIT_DOWNLOAD_DISPATCHER_H 85 | -------------------------------------------------------------------------------- /core/BitDownloadingInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "BitDownloadingInfo.h" 2 | #include "BitData.h" 3 | #include 4 | 5 | namespace bitwave { 6 | namespace core { 7 | 8 | BitDownloadingInfo::BitDownloadingInfo( 9 | const std::tr1::shared_ptr& bitdata) 10 | : downloaded_(bitdata->GetPieceMap()), 11 | need_download_(bitdata->GetPieceCount()), 12 | downloading_(bitdata->GetPieceCount()) 13 | { 14 | UpdateNeedDownload(bitdata); 15 | } 16 | 17 | void BitDownloadingInfo::MarkDownloading(std::size_t piece_index) 18 | { 19 | downloading_.MarkPiece(piece_index); 20 | std::for_each(observers_.begin(), observers_.end(), 21 | std::tr1::bind(&Observer::DownloadingNewPiece, 22 | std::tr1::placeholders::_1, piece_index)); 23 | } 24 | 25 | void BitDownloadingInfo::MarkDownloadComplete(std::size_t piece_index) 26 | { 27 | downloading_.UnMarkPiece(piece_index); 28 | downloaded_.MarkPiece(piece_index); 29 | std::for_each(observers_.begin(), observers_.end(), 30 | std::tr1::bind(&Observer::CompleteNewPiece, 31 | std::tr1::placeholders::_1, piece_index)); 32 | } 33 | 34 | void BitDownloadingInfo::DownloadingFailed(std::size_t piece_index) 35 | { 36 | downloading_.UnMarkPiece(piece_index); 37 | std::for_each(observers_.begin(), observers_.end(), 38 | std::tr1::bind(&Observer::DownloadingFailed, 39 | std::tr1::placeholders::_1, piece_index)); 40 | } 41 | 42 | void BitDownloadingInfo::UpdateNeedDownload( 43 | const std::tr1::shared_ptr& bitdata) 44 | { 45 | const BitData::DownloadFiles& files = bitdata->GetFilesInfo(); 46 | BitData::DownloadFiles::const_iterator it = files.begin(); 47 | BitData::DownloadFiles::const_iterator end = files.end(); 48 | 49 | long long file_begin = 0; 50 | std::size_t piece_length = bitdata->GetPieceLength(); 51 | for (; it != end; ++it) 52 | { 53 | long long file_end = file_begin + it->length; 54 | if (it->is_download) 55 | { 56 | std::size_t piece_index = static_cast( 57 | file_begin / piece_length); 58 | std::size_t end_piece_index = static_cast( 59 | ceil(file_end / static_cast(piece_length))); 60 | 61 | for (; piece_index < end_piece_index; ++piece_index) 62 | need_download_.MarkPiece(piece_index); 63 | } 64 | file_begin = file_end; 65 | } 66 | } 67 | 68 | } // namespace core 69 | } // namespace bitwave 70 | -------------------------------------------------------------------------------- /core/BitDownloadingInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_DOWNLOADING_INFO_H 2 | #define BIT_DOWNLOADING_INFO_H 3 | 4 | #include "BitPieceMap.h" 5 | #include "../base/BaseTypes.h" 6 | #include 7 | #include 8 | 9 | namespace bitwave { 10 | namespace core { 11 | 12 | class BitData; 13 | 14 | class BitDownloadingInfo : private NotCopyable 15 | { 16 | public: 17 | class Observer 18 | { 19 | public: 20 | virtual void DownloadingNewPiece(std::size_t piece_index) = 0; 21 | virtual void CompleteNewPiece(std::size_t piece_index) = 0; 22 | virtual void DownloadingFailed(std::size_t piece_index) = 0; 23 | virtual ~Observer() { } 24 | }; 25 | 26 | explicit BitDownloadingInfo( 27 | const std::tr1::shared_ptr& bitdata); 28 | 29 | void AddInfoObserver(Observer *observer) 30 | { observers_.insert(observer); } 31 | void RemoveInfoObserver(Observer *observer) 32 | { observers_.erase(observer); } 33 | 34 | const BitPieceMap& GetDownloaded() const 35 | { return downloaded_; } 36 | const BitPieceMap& GetNeedDownload() const 37 | { return need_download_; } 38 | const BitPieceMap& GetDownloading() const 39 | { return downloading_; } 40 | 41 | void MarkDownloading(std::size_t piece_index); 42 | void MarkDownloadComplete(std::size_t piece_index); 43 | void DownloadingFailed(std::size_t piece_index); 44 | 45 | private: 46 | void UpdateNeedDownload( 47 | const std::tr1::shared_ptr& bitdata); 48 | 49 | BitPieceMap& downloaded_; 50 | BitPieceMap need_download_; 51 | BitPieceMap downloading_; 52 | 53 | std::set observers_; 54 | }; 55 | 56 | } // namespace core 57 | } // namespace bitwave 58 | 59 | #endif // BIT_DOWNLOADING_INFO_H 60 | -------------------------------------------------------------------------------- /core/BitException.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_EXCEPTION_H 2 | #define BIT_EXCEPTION_H 3 | 4 | #include "../base/BaseTypes.h" 5 | 6 | namespace bitwave { 7 | namespace core { 8 | 9 | // bentypes exception enum code 10 | enum BenTypeExceptionCode 11 | { 12 | INVALIDATE_NOBENTYPE, 13 | INVALIDATE_INTERGER, 14 | INVALIDATE_STRING, 15 | INVALIDATE_LIST, 16 | INVALIDATE_DICTIONARY, 17 | }; 18 | 19 | // bentypes exception 20 | class BenTypeException : public BaseException 21 | { 22 | public: 23 | explicit BenTypeException(int code) 24 | : BaseException(code) 25 | { 26 | } 27 | }; 28 | 29 | class MetainfoFileExeception : public BaseException 30 | { 31 | public: 32 | explicit MetainfoFileExeception(const std::string& w) 33 | : BaseException(w) 34 | { 35 | } 36 | }; 37 | 38 | enum FileExceptionCode 39 | { 40 | PATH_ERROR, 41 | SPACE_NOT_ENOUGH, 42 | }; 43 | 44 | class CreateFileException : public BaseException 45 | { 46 | public: 47 | CreateFileException(int code, const std::string& file_path) 48 | : BaseException(code), 49 | file_path_(file_path) 50 | { 51 | } 52 | 53 | std::string GetFilePath() const 54 | { 55 | return file_path_; 56 | } 57 | 58 | private: 59 | std::string file_path_; 60 | }; 61 | 62 | // an exception class for BitPeerListener 63 | class ListenPortException : public BaseException 64 | { 65 | public: 66 | explicit ListenPortException(const std::string& w) 67 | : BaseException(w) 68 | { 69 | } 70 | }; 71 | 72 | } // namespace core 73 | } // namespace bitwave 74 | 75 | #endif // BIT_EXCEPTION_H 76 | -------------------------------------------------------------------------------- /core/BitFile.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_FILE_H 2 | #define BIT_FILE_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace bitwave { 10 | namespace core { 11 | 12 | class BitData; 13 | class BitPiece; 14 | 15 | class BitFile : private NotCopyable 16 | { 17 | public: 18 | typedef std::tr1::shared_ptr PiecePtr; 19 | 20 | explicit BitFile(const std::tr1::shared_ptr& bitdata); 21 | 22 | void ReadPiece(std::size_t piece_index, const PiecePtr& piece); 23 | 24 | void GetReadPieces(std::map& read_pieces); 25 | 26 | void WritePiece(std::size_t piece_index, const PiecePtr& piece); 27 | 28 | void GetWritedPieces(std::vector& writed_pieces); 29 | 30 | void FlushFileBuffer(); 31 | 32 | private: 33 | class FileService; 34 | 35 | std::tr1::shared_ptr bitdata_; 36 | std::tr1::shared_ptr file_service_; 37 | }; 38 | 39 | } // namespace core 40 | } // namespace bitwave 41 | 42 | #endif // BIT_FILE_H 43 | -------------------------------------------------------------------------------- /core/BitPeerCreateStrategy.cpp: -------------------------------------------------------------------------------- 1 | #include "BitPeerCreateStrategy.h" 2 | 3 | namespace bitwave { 4 | namespace core { 5 | 6 | namespace interval { 7 | 8 | class NormalPeerCreateStrategy : public BitPeerCreateStrategy 9 | { 10 | public: 11 | explicit NormalPeerCreateStrategy(std::size_t min_peer_count) 12 | : min_peer_count_(min_peer_count) 13 | { 14 | } 15 | 16 | virtual std::size_t CreatePeerInterval(std::size_t current_peer_count) 17 | { 18 | if (current_peer_count < min_peer_count_ / 2) 19 | return 1000; 20 | else if(current_peer_count < min_peer_count_) 21 | return 5000; 22 | else 23 | return 30000; 24 | } 25 | 26 | virtual std::size_t CreatePeerCount(std::size_t current_peer_count, 27 | std::size_t unused_listen_info) 28 | { 29 | // total peers must greater then min_peer_count_ at least 30 | if (current_peer_count < min_peer_count_) 31 | return unused_listen_info; 32 | 33 | // we create new peers appropriately 34 | if (unused_listen_info <= min_peer_count_ / 10) 35 | return unused_listen_info; 36 | else if (unused_listen_info <= min_peer_count_ / 5) 37 | return unused_listen_info / 2; 38 | else if (unused_listen_info <= min_peer_count_ / 2) 39 | return unused_listen_info / 5; 40 | else 41 | return unused_listen_info / 10; 42 | } 43 | 44 | private: 45 | std::size_t min_peer_count_; 46 | }; 47 | 48 | } // namespace interval 49 | 50 | BitPeerCreateStrategy * CreateDefaultPeerCreateStartegy() 51 | { 52 | return new interval::NormalPeerCreateStrategy(200); 53 | } 54 | 55 | } // namespace core 56 | } // namespace bitwave 57 | -------------------------------------------------------------------------------- /core/BitPeerCreateStrategy.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_PEER_CREATE_STRATEGY 2 | #define BIT_PEER_CREATE_STRATEGY 3 | 4 | #include 5 | 6 | namespace bitwave { 7 | namespace core { 8 | 9 | // base class of create peer strategy for BitTask 10 | class BitPeerCreateStrategy 11 | { 12 | public: 13 | // return next create peer interval, in millisecond 14 | virtual std::size_t CreatePeerInterval(std::size_t current_peer_count) = 0; 15 | // return need create new peers count 16 | virtual std::size_t CreatePeerCount(std::size_t current_peer_count, 17 | std::size_t unused_listen_info) = 0; 18 | virtual ~BitPeerCreateStrategy() {} 19 | }; 20 | 21 | BitPeerCreateStrategy * CreateDefaultPeerCreateStartegy(); 22 | 23 | } // namespace core 24 | } // namespace bitwave 25 | 26 | #endif // BIT_PEER_CREATE_STRATEGY 27 | -------------------------------------------------------------------------------- /core/BitPeerData.cpp: -------------------------------------------------------------------------------- 1 | #include "BitPeerData.h" 2 | 3 | namespace bitwave { 4 | namespace core { 5 | 6 | BitPeerData::BitPeerData(const std::string& peer_id, 7 | std::size_t piece_count) 8 | : peer_id_(peer_id), 9 | piece_map_(piece_count) 10 | { 11 | } 12 | 13 | void BitPeerData::PeerHavePiece(int piece_index) 14 | { 15 | piece_map_.MarkPiece(piece_index); 16 | } 17 | 18 | bool BitPeerData::SetPeerBitfield(const char *bit_field, std::size_t size) 19 | { 20 | return piece_map_.MarkPieceFromBitfield(bit_field, size); 21 | } 22 | 23 | const BitPieceMap& BitPeerData::GetPieceMap() const 24 | { 25 | return piece_map_; 26 | } 27 | 28 | } // namespace core 29 | } // namespace bitwave 30 | -------------------------------------------------------------------------------- /core/BitPeerData.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_PEER_DATA_H 2 | #define BIT_PEER_DATA_H 3 | 4 | #include "BitPieceMap.h" 5 | #include "../base/BaseTypes.h" 6 | #include 7 | 8 | namespace bitwave { 9 | namespace core { 10 | 11 | class BitPeerData : private NotCopyable 12 | { 13 | public: 14 | explicit BitPeerData(const std::string& peer_id, 15 | std::size_t piece_count); 16 | 17 | void PeerHavePiece(int piece_index); 18 | bool SetPeerBitfield(const char *bit_field, std::size_t size); 19 | const BitPieceMap& GetPieceMap() const; 20 | 21 | private: 22 | std::string peer_id_; 23 | BitPieceMap piece_map_; 24 | }; 25 | 26 | } // namespace core 27 | } // namespace bitwave 28 | 29 | #endif // BIT_PEER_DATA_H 30 | -------------------------------------------------------------------------------- /core/BitPeerListener.cpp: -------------------------------------------------------------------------------- 1 | #include "BitPeerListener.h" 2 | #include "BitService.h" 3 | #include "BitException.h" 4 | #include "BitRepository.h" 5 | #include 6 | #include 7 | 8 | namespace bitwave { 9 | namespace core { 10 | 11 | BitPeerListener::BitPeerListener(net::IoService& io_service) 12 | : io_service_(io_service) 13 | { 14 | if (!CreateListener()) 15 | throw ListenPortException("Listen port failure!"); 16 | 17 | WaitingForPeer(); 18 | } 19 | 20 | bool BitPeerListener::CreateListener() 21 | { 22 | short hsport = 6881; 23 | 24 | // we try 100 ports to listen 25 | for (int i = 0; i < 100; ++i) 26 | { 27 | net::Address any; 28 | net::Port port(hsport); 29 | 30 | try 31 | { 32 | listener_.Reset(new net::AsyncListener(any, port, io_service_)); 33 | 34 | assert(BitService::repository); 35 | BitService::repository->SetListenPort(hsport); 36 | 37 | // successful, we return 38 | return true; 39 | } 40 | catch (const net::NetException&) 41 | { 42 | // log NetException here 43 | } 44 | 45 | ++hsport; 46 | } 47 | return false; 48 | } 49 | 50 | void BitPeerListener::WaitingForPeer() 51 | { 52 | listener_->AsyncAccept( 53 | std::tr1::bind(&BitPeerListener::AcceptHandler, this, 54 | std::tr1::placeholders::_1, std::tr1::placeholders::_2)); 55 | } 56 | 57 | void BitPeerListener::AcceptHandler(bool success, net::BaseSocket peer_sock) 58 | { 59 | if (success) 60 | { 61 | net::AsyncSocket peer = net::MakeAsyncSocket(io_service_, peer_sock); 62 | NewPeersHost::PeerPtr peer_ptr(new BitPeerConnection(peer, &new_peers_host_)); 63 | new_peers_host_.HostingNewPeer(peer_ptr); 64 | peer_ptr->Receive(); 65 | } 66 | 67 | // waiting next peer 68 | WaitingForPeer(); 69 | } 70 | 71 | } // namespace core 72 | } // namespace bitwave 73 | -------------------------------------------------------------------------------- /core/BitPeerListener.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_PEER_LISTENER_H 2 | #define BIT_PEER_LISTENER_H 3 | 4 | #include "BitData.h" 5 | #include "BitTask.h" 6 | #include "BitService.h" 7 | #include "BitController.h" 8 | #include "../base/BaseTypes.h" 9 | #include "../base/ScopePtr.h" 10 | #include "../net/IoService.h" 11 | #include 12 | #include 13 | 14 | namespace bitwave { 15 | namespace core { 16 | 17 | class BitPeerConnection; 18 | 19 | // a class listen all peers connecting 20 | class BitPeerListener : private NotCopyable 21 | { 22 | public: 23 | explicit BitPeerListener(net::IoService& io_service); 24 | 25 | private: 26 | class NewPeersHost : public PeerConnectionOwner, private NotCopyable 27 | { 28 | public: 29 | typedef std::tr1::shared_ptr PeerPtr; 30 | typedef std::set NewPeers; 31 | 32 | void HostingNewPeer(const PeerPtr& peer) 33 | { 34 | new_peers_.insert(peer); 35 | } 36 | 37 | private: 38 | virtual bool NotifyInfoHash(const std::tr1::shared_ptr& child, const Sha1Value& info_hash) 39 | { 40 | std::tr1::shared_ptr task = BitService::controller->GetTask(info_hash); 41 | if (!task) 42 | return false; 43 | 44 | task->AttachPeer(child); 45 | new_peers_.erase(child); 46 | return true; 47 | } 48 | 49 | virtual void NotifyHandshakeOk(const std::tr1::shared_ptr& child) 50 | { 51 | } 52 | 53 | virtual void NotifyConnectionDrop(const std::tr1::shared_ptr& child) 54 | { 55 | new_peers_.erase(child); 56 | } 57 | 58 | NewPeers new_peers_; 59 | }; 60 | 61 | bool CreateListener(); 62 | void WaitingForPeer(); 63 | void AcceptHandler(bool success, net::BaseSocket peer_sock); 64 | 65 | net::IoService& io_service_; 66 | ScopePtr listener_; 67 | NewPeersHost new_peers_host_; 68 | }; 69 | 70 | } // namespace core 71 | } // namespace bitwave 72 | 73 | #endif // BIT_PEER_LISTENER_H 74 | -------------------------------------------------------------------------------- /core/BitPiece.cpp: -------------------------------------------------------------------------------- 1 | #include "BitPiece.h" 2 | #include 3 | #include 4 | 5 | namespace bitwave { 6 | namespace core { 7 | 8 | void BitPiece::WriteBlock(std::size_t begin, 9 | std::size_t length, 10 | const char *block) 11 | { 12 | if (state_ != NOT_CHECKED) 13 | return ; 14 | 15 | if (begin >= data_.size() || begin + length > data_.size()) 16 | return ; 17 | 18 | memcpy(&data_[begin], block, length); 19 | MarkWriteBlock(begin, begin + length); 20 | } 21 | 22 | bool BitPiece::IsComplete() const 23 | { 24 | if (writed_.empty()) 25 | return false; 26 | 27 | if (writed_[0].first == 0 && writed_[0].second == data_.size()) 28 | return true; 29 | 30 | return false; 31 | } 32 | 33 | void BitPiece::MarkWriteBlock(std::size_t begin, 34 | std::size_t end) 35 | { 36 | std::size_t i = 0; 37 | for (; i < writed_.size(); ++i) 38 | { 39 | if (writed_[i].first <= begin && writed_[i].second >= end) 40 | { 41 | // do nothing 42 | return ; 43 | } 44 | else if (writed_[i].first == end) 45 | { 46 | writed_[i].first = begin; 47 | return ; 48 | } 49 | else if (writed_[i].second == begin) 50 | { 51 | writed_[i].second = end; 52 | MergeNextWriteBlock(i); 53 | return ; 54 | } 55 | else 56 | { 57 | if (end < writed_[i].first) 58 | break; 59 | } 60 | } 61 | 62 | std::vector>::iterator it = 63 | writed_.begin(); 64 | std::advance(it, i); 65 | writed_.insert(it, std::make_pair(begin, end)); 66 | } 67 | 68 | void BitPiece::MergeNextWriteBlock(std::size_t cur) 69 | { 70 | std::size_t next = cur + 1; 71 | if (next >= writed_.size()) 72 | return ; 73 | 74 | if (writed_[cur].second == writed_[next].first) 75 | { 76 | writed_[cur].second = writed_[next].second; 77 | std::vector>::iterator it = 78 | writed_.begin(); 79 | std::advance(it, next); 80 | writed_.erase(it); 81 | } 82 | } 83 | 84 | } // namespace core 85 | } // namespace bitwave 86 | -------------------------------------------------------------------------------- /core/BitPiece.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_PIECE_H 2 | #define BIT_PIECE_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include "../timer/TimeTraits.h" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace bitwave { 11 | namespace core { 12 | 13 | class BitPiece : private NotCopyable 14 | { 15 | public: 16 | enum State 17 | { 18 | NOT_CHECKED, 19 | CHECKING_SHA1, 20 | CHECK_SHA1_OK, 21 | WRITED, 22 | }; 23 | 24 | explicit BitPiece(std::size_t size) 25 | : data_(size), 26 | state_(NOT_CHECKED), 27 | last_read_time_(time_traits::invalid()), 28 | read_times_(0) 29 | { 30 | } 31 | 32 | const char * GetRawDataPtr() const 33 | { 34 | return &data_[0]; 35 | } 36 | 37 | char * GetRawDataPtr() 38 | { 39 | return &data_[0]; 40 | } 41 | 42 | std::size_t GetSize() const 43 | { 44 | return data_.size(); 45 | } 46 | 47 | void SetState(State state) 48 | { 49 | state_ = state; 50 | } 51 | 52 | State GetState() const 53 | { 54 | return state_; 55 | } 56 | 57 | void TouchRead() 58 | { 59 | ++read_times_; 60 | last_read_time_ = time_traits::now(); 61 | } 62 | 63 | void Clear() 64 | { 65 | memset(&data_[0], 0, data_.size()); 66 | writed_.clear(); 67 | state_ = NOT_CHECKED; 68 | read_times_ = 0; 69 | last_read_time_ = time_traits::invalid(); 70 | } 71 | 72 | void WriteBlock(std::size_t begin, 73 | std::size_t length, 74 | const char *block); 75 | 76 | bool IsComplete() const; 77 | 78 | static bool IsReadTimeOld(const BitPiece& left, 79 | const BitPiece& right) 80 | { 81 | return time_traits::less( 82 | left.last_read_time_, right.last_read_time_); 83 | } 84 | 85 | static bool IsReadTimeEqual(const BitPiece& left, 86 | const BitPiece& right) 87 | { 88 | return time_traits::equal( 89 | left.last_read_time_, right.last_read_time_); 90 | } 91 | 92 | static bool IsReadTimesLess(const BitPiece& left, 93 | const BitPiece& right) 94 | { 95 | return left.read_times_ < right.read_times_; 96 | } 97 | 98 | private: 99 | void MarkWriteBlock(std::size_t begin, 100 | std::size_t end); 101 | void MergeNextWriteBlock(std::size_t cur); 102 | 103 | std::vector data_; 104 | std::vector> writed_; 105 | State state_; 106 | NormalTimeType last_read_time_; 107 | std::size_t read_times_; 108 | }; 109 | 110 | } // namespace core 111 | } // namespace bitwave 112 | 113 | #endif // BIT_PIECE_H 114 | -------------------------------------------------------------------------------- /core/BitPieceMap.cpp: -------------------------------------------------------------------------------- 1 | #include "BitPieceMap.h" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace bitwave { 7 | namespace core { 8 | 9 | BitPieceMap::BitPieceMap(std::size_t piece_count) 10 | : RefCount(true), 11 | piece_map_(0), 12 | map_size_(0) 13 | { 14 | assert(piece_count > 0); 15 | map_size_ = static_cast( 16 | ceil(static_cast(piece_count) / 8)); 17 | InitMap(); 18 | } 19 | 20 | BitPieceMap::BitPieceMap(const BitPieceMap& piece_map) 21 | : RefCount(piece_map), 22 | piece_map_(piece_map.piece_map_), 23 | map_size_(piece_map.map_size_) 24 | { 25 | } 26 | 27 | BitPieceMap::~BitPieceMap() 28 | { 29 | if (Only()) 30 | delete [] piece_map_; 31 | } 32 | 33 | BitPieceMap& BitPieceMap::operator = (const BitPieceMap& piece_map) 34 | { 35 | BitPieceMap(piece_map).Swap(*this); 36 | return *this; 37 | } 38 | 39 | void BitPieceMap::Clear() 40 | { 41 | memset(piece_map_, 0, map_size_); 42 | } 43 | 44 | void BitPieceMap::Swap(BitPieceMap& piece_map) 45 | { 46 | RefCount::Swap(piece_map); 47 | std::swap(piece_map_, piece_map.piece_map_); 48 | std::swap(map_size_, piece_map.map_size_); 49 | } 50 | 51 | void BitPieceMap::MarkPiece(std::size_t piece_index) 52 | { 53 | std::size_t index = piece_index / 8; 54 | std::size_t bit_index = piece_index - 8 * index; 55 | if (index < map_size_) 56 | piece_map_[index] |= 0x01 << (7 - bit_index); 57 | } 58 | 59 | void BitPieceMap::UnMarkPiece(std::size_t piece_index) 60 | { 61 | std::size_t index = piece_index / 8; 62 | std::size_t bit_index = piece_index - 8 * index; 63 | if (index < map_size_) 64 | piece_map_[index] &= ~(0x01 << (7 - bit_index)); 65 | } 66 | 67 | bool BitPieceMap::MarkPieceFromBitfield(const char *bit_field, std::size_t size) 68 | { 69 | if (map_size_ != size) 70 | return false; 71 | memcpy(piece_map_, bit_field, map_size_); 72 | return true; 73 | } 74 | 75 | std::size_t BitPieceMap::GetMapSize() const 76 | { 77 | return map_size_; 78 | } 79 | 80 | bool BitPieceMap::IsPieceMark(std::size_t piece_index) const 81 | { 82 | std::size_t index = piece_index / 8; 83 | std::size_t bit_index = piece_index - 8 * index; 84 | if (index < map_size_) 85 | return (piece_map_[index] & (0x01 << (7 - bit_index))) != 0; 86 | return false; 87 | } 88 | 89 | void BitPieceMap::ToBitfield(char *bit_field) const 90 | { 91 | assert(bit_field); 92 | memcpy(bit_field, piece_map_, map_size_); 93 | } 94 | 95 | void BitPieceMap::InitMap() 96 | { 97 | assert(!piece_map_); 98 | piece_map_ = new char[map_size_]; 99 | Clear(); 100 | } 101 | 102 | // static 103 | void BitPieceMap::Difference(const BitPieceMap& piece_map1, 104 | const BitPieceMap& piece_map2, 105 | std::size_t begin, std::size_t end, 106 | BitPieceMap& result) 107 | { 108 | assert(piece_map1.piece_map_); 109 | assert(piece_map2.piece_map_); 110 | assert(result.piece_map_); 111 | assert(result.map_size_ == piece_map1.map_size_); 112 | assert(result.map_size_ == piece_map2.map_size_); 113 | assert(begin <= result.map_size_ && end <= result.map_size_); 114 | 115 | for (; begin < end; ++begin) 116 | { 117 | result.piece_map_[begin] = 118 | piece_map1.piece_map_[begin] & (~piece_map2.piece_map_[begin]); 119 | } 120 | } 121 | 122 | // static 123 | void BitPieceMap::Intersection(const BitPieceMap& piece_map1, 124 | const BitPieceMap& piece_map2, 125 | std::size_t begin, std::size_t end, 126 | BitPieceMap& result) 127 | { 128 | assert(piece_map1.piece_map_); 129 | assert(piece_map2.piece_map_); 130 | assert(result.piece_map_); 131 | assert(result.map_size_ == piece_map1.map_size_); 132 | assert(result.map_size_ == piece_map2.map_size_); 133 | assert(begin <= result.map_size_ && end <= result.map_size_); 134 | 135 | for (; begin < end; ++begin) 136 | { 137 | result.piece_map_[begin] = 138 | piece_map1.piece_map_[begin] & piece_map2.piece_map_[begin]; 139 | } 140 | } 141 | 142 | // static 143 | void BitPieceMap::Union(const BitPieceMap& piece_map1, 144 | const BitPieceMap& piece_map2, 145 | std::size_t begin, std::size_t end, 146 | BitPieceMap& result) 147 | { 148 | assert(piece_map1.piece_map_); 149 | assert(piece_map2.piece_map_); 150 | assert(result.piece_map_); 151 | assert(result.map_size_ == piece_map1.map_size_); 152 | assert(result.map_size_ == piece_map2.map_size_); 153 | assert(begin <= result.map_size_ && end <= result.map_size_); 154 | 155 | for (; begin < end; ++begin) 156 | { 157 | result.piece_map_[begin] = 158 | piece_map1.piece_map_[begin] | piece_map2.piece_map_[begin]; 159 | } 160 | } 161 | 162 | bool BitPieceMap::IsEqual(const BitPieceMap& piece_map1, 163 | const BitPieceMap& piece_map2, 164 | std::size_t begin, std::size_t end) 165 | { 166 | assert(piece_map1.piece_map_); 167 | assert(piece_map2.piece_map_); 168 | assert(piece_map1.map_size_ == piece_map2.map_size_); 169 | assert(begin <= piece_map1.map_size_&& end <= piece_map1.map_size_); 170 | assert(begin <= end); 171 | 172 | std::size_t size = end - begin; 173 | if (size == 0) 174 | return false; 175 | 176 | return memcmp(piece_map1.piece_map_ + begin, 177 | piece_map2.piece_map_ + begin, size) == 0; 178 | } 179 | 180 | } // namespace core 181 | } // namespace bitwave 182 | -------------------------------------------------------------------------------- /core/BitPieceMap.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_PIECE_MAP_H 2 | #define BIT_PIECE_MAP_H 3 | 4 | #include "../base/RefCount.h" 5 | 6 | namespace bitwave { 7 | namespace core { 8 | 9 | class BitPieceMap : public RefCount 10 | { 11 | public: 12 | explicit BitPieceMap(std::size_t piece_count); 13 | 14 | BitPieceMap(const BitPieceMap& piece_map); 15 | 16 | ~BitPieceMap(); 17 | 18 | BitPieceMap& operator = (const BitPieceMap& piece_map); 19 | 20 | void Clear(); 21 | 22 | void Swap(BitPieceMap& piece_map); 23 | 24 | void MarkPiece(std::size_t piece_index); 25 | 26 | void UnMarkPiece(std::size_t piece_index); 27 | 28 | bool MarkPieceFromBitfield(const char *bit_field, std::size_t size); 29 | 30 | std::size_t GetMapSize() const; 31 | 32 | bool IsPieceMark(std::size_t piece_index) const; 33 | 34 | // store to bit_field, size must bigger than result of GetMapSize() 35 | void ToBitfield(char *bit_field) const; 36 | 37 | static void Difference(const BitPieceMap& piece_map1, 38 | const BitPieceMap& piece_map2, 39 | std::size_t begin, std::size_t end, 40 | BitPieceMap& result); 41 | 42 | static void Intersection(const BitPieceMap& piece_map1, 43 | const BitPieceMap& piece_map2, 44 | std::size_t begin, std::size_t end, 45 | BitPieceMap& result); 46 | 47 | static void Union(const BitPieceMap& piece_map1, 48 | const BitPieceMap& piece_map2, 49 | std::size_t begin, std::size_t end, 50 | BitPieceMap& result); 51 | 52 | static bool IsEqual(const BitPieceMap& piece_map1, 53 | const BitPieceMap& piece_map2, 54 | std::size_t begin, std::size_t end); 55 | 56 | private: 57 | void InitMap(); 58 | 59 | char *piece_map_; 60 | std::size_t map_size_; 61 | }; 62 | 63 | } // namespace core 64 | } // namespace bitwave 65 | 66 | #endif // BIT_PIECE_MAP_H 67 | -------------------------------------------------------------------------------- /core/BitPieceSha1Calc.cpp: -------------------------------------------------------------------------------- 1 | #include "BitPieceSha1Calc.h" 2 | #include "BitPiece.h" 3 | #include "../thread/Atomic.h" 4 | 5 | namespace bitwave { 6 | namespace core { 7 | 8 | BitPieceSha1Calc::BitPieceSha1Calc() 9 | : thread_exit_flag_(0) 10 | { 11 | sha1_thread_.Reset( 12 | new Thread(std::tr1::bind( 13 | &BitPieceSha1Calc::CalcSha1Thread, this))); 14 | } 15 | 16 | BitPieceSha1Calc::~BitPieceSha1Calc() 17 | { 18 | AtomicAdd(&thread_exit_flag_, 1); 19 | piece_list_event_.SetEvent(); 20 | sha1_thread_->Join(); 21 | } 22 | 23 | void BitPieceSha1Calc::GetResult(PieceSha1List& sha1_list) 24 | { 25 | SpinlocksMutexLocker locker(piece_sha1_list_mutex_); 26 | sha1_list.swap(piece_sha1_list_); 27 | } 28 | 29 | void BitPieceSha1Calc::AddPiece(std::size_t piece_index, 30 | const std::tr1::shared_ptr& piece) 31 | { 32 | SpinlocksMutexLocker locker(piece_list_mutex_); 33 | piece_list_.push_back(std::make_pair(piece_index, piece)); 34 | piece_list_event_.SetEvent(); 35 | } 36 | 37 | unsigned BitPieceSha1Calc::CalcSha1Thread() 38 | { 39 | while (true) 40 | { 41 | if (piece_list_event_.WaitForever()) 42 | { 43 | if (AtomicAdd(&thread_exit_flag_, 0)) 44 | break; 45 | 46 | PieceList piece_list; 47 | { 48 | SpinlocksMutexLocker locker(piece_list_mutex_); 49 | piece_list.swap(piece_list_); 50 | } 51 | 52 | PieceSha1List piece_sha1_list; 53 | CalculateSha1(piece_list, piece_sha1_list); 54 | { 55 | SpinlocksMutexLocker locker(piece_sha1_list_mutex_); 56 | piece_sha1_list_.insert(piece_sha1_list_.end(), 57 | piece_sha1_list.begin(), piece_sha1_list.end()); 58 | } 59 | } 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | void BitPieceSha1Calc::CalculateSha1(PieceList& piece_list, 66 | PieceSha1List& piece_sha1_list) 67 | { 68 | for (PieceList::iterator it = piece_list.begin(); 69 | it != piece_list.end(); ++it) 70 | { 71 | const char *data = it->second->GetRawDataPtr(); 72 | std::size_t size = it->second->GetSize(); 73 | piece_sha1_list.push_back( 74 | std::make_pair(it->first, 75 | Sha1Value(data, size))); 76 | } 77 | } 78 | 79 | } // namespace core 80 | } // namespace bitwave 81 | -------------------------------------------------------------------------------- /core/BitPieceSha1Calc.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_PIECE_SHA1_CALC_H 2 | #define BIT_PIECE_SHA1_CALC_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include "../base/ScopePtr.h" 6 | #include "../sha1/Sha1Value.h" 7 | #include "../thread/Thread.h" 8 | #include "../thread/Event.h" 9 | #include "../thread/Mutex.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace bitwave { 16 | namespace core { 17 | 18 | class BitPiece; 19 | 20 | class BitPieceSha1Calc : private NotCopyable 21 | { 22 | public: 23 | typedef std::vector< 24 | std::pair>> PieceList; 25 | typedef std::vector< 26 | std::pair> PieceSha1List; 27 | 28 | BitPieceSha1Calc(); 29 | ~BitPieceSha1Calc(); 30 | 31 | void GetResult(PieceSha1List& sha1_list); 32 | 33 | void AddPiece(std::size_t piece_index, 34 | const std::tr1::shared_ptr& piece); 35 | 36 | private: 37 | unsigned CalcSha1Thread(); 38 | void CalculateSha1(PieceList& piece_list, 39 | PieceSha1List& piece_sha1_list); 40 | 41 | volatile long thread_exit_flag_; 42 | ScopePtr sha1_thread_; 43 | AutoResetEvent piece_list_event_; 44 | SpinlocksMutex piece_list_mutex_; 45 | SpinlocksMutex piece_sha1_list_mutex_; 46 | PieceList piece_list_; 47 | PieceSha1List piece_sha1_list_; 48 | }; 49 | 50 | } // namespace core 51 | } // namespace bitwave 52 | 53 | #endif // BIT_PIECE_SHA1_CALC_H 54 | -------------------------------------------------------------------------------- /core/BitRepository.cpp: -------------------------------------------------------------------------------- 1 | #include "BitRepository.h" 2 | #include "BitData.h" 3 | 4 | namespace bitwave { 5 | namespace core { 6 | 7 | BitRepository::BitRepository() 8 | : listen_port_(0), 9 | bitdata_map_() 10 | { 11 | } 12 | 13 | BitRepository::~BitRepository() 14 | { 15 | } 16 | 17 | short BitRepository::GetListenPort() const 18 | { 19 | return listen_port_; 20 | } 21 | 22 | void BitRepository::SetListenPort(short port) 23 | { 24 | listen_port_ = port; 25 | } 26 | 27 | BitRepository::BitDataPtr BitRepository::CreateBitData(const std::string& torrent_file) 28 | { 29 | BitDataPtr ptr(new BitData(torrent_file)); 30 | Sha1Value key = ptr->GetInfoHash(); 31 | std::pair result = 32 | bitdata_map_.insert(std::make_pair(key, ptr)); 33 | return result.first->second; 34 | } 35 | 36 | BitRepository::BitDataPtr BitRepository::GetBitData(const Sha1Value& info_hash) const 37 | { 38 | BitDataMap::const_iterator it = bitdata_map_.find(info_hash); 39 | if (it == bitdata_map_.end()) 40 | return BitDataPtr(); 41 | 42 | return it->second; 43 | } 44 | 45 | void BitRepository::GetAllBitData(std::vector& data) const 46 | { 47 | data.reserve(bitdata_map_.size()); 48 | for (BitDataMap::const_iterator it = bitdata_map_.begin(); 49 | it != bitdata_map_.end(); ++it) 50 | { 51 | data.push_back(it->second); 52 | } 53 | } 54 | 55 | } // namespace core 56 | } // namespace bitwave 57 | -------------------------------------------------------------------------------- /core/BitRepository.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_REPOSITORY_H 2 | #define BIT_REPOSITORY_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include "../sha1/Sha1Value.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace bitwave { 12 | namespace core { 13 | 14 | class BitData; 15 | 16 | // a repository store all BitData 17 | class BitRepository : private NotCopyable 18 | { 19 | public: 20 | typedef std::tr1::shared_ptr BitDataPtr; 21 | 22 | BitRepository(); 23 | ~BitRepository(); 24 | 25 | // get current listen port(host) 26 | short GetListenPort() const; 27 | 28 | // set the bitwave listen port(host) 29 | void SetListenPort(short port); 30 | 31 | // create a BitData from torrent_file 32 | BitDataPtr CreateBitData(const std::string& torrent_file); 33 | 34 | // get a BitData by Sha1Value, if not existed return a empty ptr 35 | BitDataPtr GetBitData(const Sha1Value& info_hash) const; 36 | 37 | // get all BitDataPtrs 38 | void GetAllBitData(std::vector& data) const; 39 | 40 | private: 41 | typedef std::map BitDataMap; 42 | 43 | short listen_port_; 44 | BitDataMap bitdata_map_; 45 | }; 46 | 47 | } // namespace core 48 | } // namespace bitwave 49 | 50 | #endif // BIT_REPOSITORY_H 51 | -------------------------------------------------------------------------------- /core/BitRequestList.cpp: -------------------------------------------------------------------------------- 1 | #include "BitRequestList.h" 2 | #include 3 | 4 | namespace bitwave { 5 | namespace core { 6 | 7 | void BitRequestList::AddRequest(int index, int begin, int length) 8 | { 9 | request_list_.push_back(RequestData(index, begin, length)); 10 | } 11 | 12 | void BitRequestList::AddRequest(Iterator first, Iterator last) 13 | { 14 | for (; first != last; ++first) 15 | AddRequest(first->index, first->begin, first->length); 16 | } 17 | 18 | void BitRequestList::DelRequest(int index, int begin, int length) 19 | { 20 | request_list_.remove(RequestData(index, begin, length)); 21 | } 22 | 23 | BitRequestList::Iterator BitRequestList::FindRequest(int index, int begin, int length) 24 | { 25 | return std::find(Begin(), End(), RequestData(index, begin, length)); 26 | } 27 | 28 | BitRequestList::Iterator BitRequestList::Splice(BitRequestList& brl, Iterator it) 29 | { 30 | request_list_.splice(End(), brl.request_list_, it); 31 | return --End(); 32 | } 33 | 34 | void BitRequestList::Splice(BitRequestList& brl, Iterator first, Iterator last) 35 | { 36 | request_list_.splice(End(), brl.request_list_, first, last); 37 | } 38 | 39 | bool BitRequestList::IsExistRequest(int index, int begin, int length) const 40 | { 41 | return std::find(Begin(), End(), RequestData(index, begin, length)) != End(); 42 | } 43 | 44 | } // namespace core 45 | } // namespace bitwave 46 | -------------------------------------------------------------------------------- /core/BitRequestList.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_REQUEST_LIST_H 2 | #define BIT_REQUEST_LIST_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include 6 | #include 7 | 8 | namespace bitwave { 9 | namespace core { 10 | 11 | class BitRequestList : private NotCopyable 12 | { 13 | public: 14 | struct RequestData 15 | { 16 | RequestData(int i, int b, int l) 17 | : index(i), 18 | begin(b), 19 | length(l) 20 | { 21 | } 22 | 23 | int index; // zero-base piece index 24 | int begin; // zero-base byte offset within the piece 25 | int length; // request length 26 | 27 | friend bool operator == (const RequestData& left, 28 | const RequestData& right) 29 | { 30 | return left.index == right.index && 31 | left.begin == right.begin && 32 | left.length == right.length; 33 | } 34 | }; 35 | 36 | typedef std::list RequestList; 37 | typedef RequestList::iterator Iterator; 38 | typedef RequestList::const_iterator Const_Iterator; 39 | 40 | // add new request to tail 41 | void AddRequest(int index, int begin, int length); 42 | void AddRequest(Iterator first, Iterator last); 43 | 44 | // delete request if exists 45 | void DelRequest(int index, int begin, int length); 46 | 47 | // find request data, if exists return the Iterator, otherwise return End() 48 | Iterator FindRequest(int index, int begin, int length); 49 | 50 | // splice the element of it from argument brl BitRequestList to 51 | // target BitRequestList's tail, return the element Iterator in 52 | // target BitRequestList 53 | Iterator Splice(BitRequestList& brl, Iterator it); 54 | void Splice(BitRequestList& brl, Iterator first, Iterator last); 55 | 56 | // return the request is exist or not 57 | bool IsExistRequest(int index, int begin, int length) const; 58 | 59 | void Clear() { request_list_.clear(); } 60 | std::size_t Size() const { return request_list_.size(); } 61 | bool Empty() const { return request_list_.empty(); } 62 | void Erase(Iterator it) { request_list_.erase(it); } 63 | Iterator Begin() { return request_list_.begin(); } 64 | Iterator End() { return request_list_.end(); } 65 | Const_Iterator Begin() const { return request_list_.begin(); } 66 | Const_Iterator End() const { return request_list_.end(); } 67 | 68 | private: 69 | RequestList request_list_; 70 | }; 71 | 72 | } // namespace core 73 | } // namespace bitwave 74 | 75 | #endif // BIT_REQUEST_LIST_H 76 | -------------------------------------------------------------------------------- /core/BitService.cpp: -------------------------------------------------------------------------------- 1 | #include "BitService.h" 2 | 3 | namespace bitwave { 4 | namespace core { 5 | 6 | bool BitService::continue_run = false; 7 | net::IoService * BitService::io_service = 0; 8 | BitController * BitService::controller = 0; 9 | BitRepository * BitService::repository = 0; 10 | BitNewTaskCreator * BitService::new_task_creator = 0; 11 | 12 | } // namespace core 13 | } // namespace bitwave 14 | -------------------------------------------------------------------------------- /core/BitService.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_SERVICE_H 2 | #define BIT_SERVICE_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include "../net/IoService.h" 6 | 7 | namespace bitwave { 8 | namespace core { 9 | 10 | class BitRepository; 11 | class BitController; 12 | class BitNewTaskCreator; 13 | 14 | class BitService : private StaticClass 15 | { 16 | public: 17 | static bool continue_run; 18 | static net::IoService *io_service; 19 | static BitController *controller; 20 | static BitRepository *repository; 21 | static BitNewTaskCreator *new_task_creator; 22 | }; 23 | 24 | } // namespace core 25 | } // namespace bitwave 26 | 27 | #endif // BIT_SERVICE_H 28 | -------------------------------------------------------------------------------- /core/BitTask.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_TASK_H 2 | #define BIT_TASK_H 3 | 4 | #include "BitPeerConnection.h" 5 | #include "BitPeerCreateStrategy.h" 6 | #include "BitDownloadingInfo.h" 7 | #include "../base/BaseTypes.h" 8 | #include "../base/ScopePtr.h" 9 | #include "../net/IoService.h" 10 | #include "../timer/Timer.h" 11 | #include "../sha1/Sha1Value.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace bitwave { 19 | namespace core { 20 | 21 | class BitData; 22 | class BitCache; 23 | class BitPeerConnection; 24 | class BitTrackerConnection; 25 | class BitUploadDispatcher; 26 | class BitDownloadDispatcher; 27 | 28 | // task class to control a bitwave download task 29 | class BitTask : private NotCopyable 30 | { 31 | public: 32 | // create a BitTask associate with the bitdata 33 | BitTask(const std::tr1::shared_ptr& bitdata, 34 | net::IoService& io_service); 35 | 36 | ~BitTask(); 37 | 38 | // attach peer to this task 39 | void AttachPeer(const std::tr1::shared_ptr& peer); 40 | 41 | // the task info_hash is equal to param info_hash 42 | bool IsSameInfoHash(const Sha1Value& info_hash) const; 43 | 44 | void ProcessTask(); 45 | 46 | private: 47 | friend class TaskPeers; 48 | friend class DownloadedUpdater; 49 | typedef std::tr1::shared_ptr TrackerConnPtr; 50 | typedef std::vector TaskTrackers; 51 | 52 | class TaskPeers : public PeerConnectionOwner, private NotCopyable 53 | { 54 | public: 55 | TaskPeers() 56 | : task_(0) 57 | { 58 | } 59 | 60 | void SetTask(BitTask *task) 61 | { 62 | assert(task); 63 | task_ = task; 64 | } 65 | 66 | void AddPeer(const std::tr1::shared_ptr& peer) 67 | { 68 | peers_.insert(peer); 69 | } 70 | 71 | std::size_t GetPeerCount() const 72 | { 73 | return peers_.size(); 74 | } 75 | 76 | template 77 | void ForEach(const Operator& op) 78 | { 79 | std::for_each(peers_.begin(), peers_.end(), op); 80 | } 81 | 82 | private: 83 | virtual bool NotifyInfoHash(const std::tr1::shared_ptr& child, const Sha1Value& info_hash) 84 | { 85 | return true; 86 | } 87 | 88 | virtual void NotifyHandshakeOk(const std::tr1::shared_ptr& child) 89 | { 90 | assert(task_); 91 | task_->AddDownloadingInfoObserver(child.get()); 92 | task_->SetPeerConnectionBaseData(child.get()); 93 | } 94 | 95 | virtual void NotifyConnectionDrop(const std::tr1::shared_ptr& child) 96 | { 97 | assert(task_); 98 | task_->RemoveDownloadingInfoObserver(child.get()); 99 | peers_.erase(child); 100 | } 101 | 102 | BitTask *task_; 103 | std::set> peers_; 104 | }; 105 | 106 | class DownloadedUpdater : public BitDownloadingInfo::Observer 107 | { 108 | public: 109 | explicit DownloadedUpdater(const std::tr1::shared_ptr& bitdata); 110 | 111 | void SetTask(BitTask *task) 112 | { 113 | assert(task); 114 | task_ = task; 115 | } 116 | 117 | virtual void DownloadingNewPiece(std::size_t piece_index) { } 118 | virtual void CompleteNewPiece(std::size_t piece_index); 119 | virtual void DownloadingFailed(std::size_t piece_index) { } 120 | 121 | private: 122 | BitTask *task_; 123 | std::tr1::shared_ptr bitdata_; 124 | std::size_t piece_length_; 125 | }; 126 | 127 | void CreateTrackerConnection(); 128 | void UpdateTrackerInfo(); 129 | void InitCreatePeersTimer(); 130 | void PrepareTimerDeadline(); 131 | void ClearTimer(); 132 | void OnTimer(); 133 | void CreateTaskPeer(std::size_t count); 134 | void AddDownloadingInfoObserver(BitPeerConnection *observer); 135 | void RemoveDownloadingInfoObserver(BitPeerConnection *observer); 136 | void SetPeerConnectionBaseData(BitPeerConnection *peer_conn); 137 | void Complete(); 138 | 139 | net::IoService& io_service_; 140 | Timer create_peers_timer_; 141 | ScopePtr create_strategy_; 142 | std::tr1::shared_ptr bitdata_; 143 | 144 | TaskTrackers trackers_; 145 | TaskPeers peers_; 146 | BitDownloadingInfo downloading_info_; 147 | DownloadedUpdater downloaded_updater_; 148 | 149 | std::tr1::shared_ptr cache_; 150 | std::tr1::shared_ptr uploader_; 151 | std::tr1::shared_ptr downloader_; 152 | }; 153 | 154 | } // namespace core 155 | } // namespace bitwave 156 | 157 | #endif // BIT_TASK_H 158 | -------------------------------------------------------------------------------- /core/BitTrackerConnection.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_TRACKER_CONNECTION_H 2 | #define BIT_TRACKER_CONNECTION_H 3 | 4 | #include "BitNetProcessor.h" 5 | #include "../base/BaseTypes.h" 6 | #include "../net/ResolveService.h" 7 | #include "../protocol/Response.h" 8 | #include "../timer/Timer.h" 9 | #include 10 | #include 11 | 12 | namespace bitwave { 13 | namespace core { 14 | 15 | class BitData; 16 | 17 | class BitTrackerConnection : private NotCopyable 18 | { 19 | public: 20 | BitTrackerConnection(const std::string& url, 21 | const std::tr1::shared_ptr& bitdata, 22 | net::IoService& io_service); 23 | 24 | ~BitTrackerConnection(); 25 | 26 | void UpdateTrackerInfo(); 27 | void ProcessProtocol(const char *data, std::size_t size); 28 | void OnConnect(); 29 | void OnDisconnect(); 30 | 31 | private: 32 | typedef BitNetProcessor NetProcessor; 34 | 35 | void ResolveHandler(const std::string& nodename, 36 | const std::string& servname, 37 | const net::ResolveResult& result); 38 | void ConnectTracker(); 39 | void SendRequest(); 40 | void StartReconnectTimer(int seconds); 41 | void ReconnectTimerCallback(); 42 | void CloseReconnectTimer(); 43 | void ClearNetProcessor(); 44 | 45 | net::IoService& io_service_; 46 | net::ResolveResult host_address_; 47 | std::tr1::shared_ptr net_processor_; 48 | Timer reconnect_timer_; 49 | int reconnect_interval_; 50 | 51 | std::tr1::shared_ptr bitdata_; 52 | std::string url_; 53 | std::string host_; 54 | }; 55 | 56 | } // namespace core 57 | } // namespace bitwave 58 | 59 | #endif // BIT_TRACKER_CONNECTION_H 60 | -------------------------------------------------------------------------------- /core/BitUploadDispatcher.cpp: -------------------------------------------------------------------------------- 1 | #ifndef WIN32_LEAN_AND_MEAN 2 | #define WIN32_LEAN_AND_MEAN 3 | #endif // WIN32_LEAN_AND_MEAN 4 | 5 | #include "BitUploadDispatcher.h" 6 | #include "BitCache.h" 7 | #include "BitPeerConnection.h" 8 | #include 9 | 10 | using namespace std::tr1::placeholders; 11 | 12 | namespace { 13 | const std::size_t quota_per_second = 2; 14 | } // unnamed namespace 15 | 16 | namespace bitwave { 17 | namespace core { 18 | 19 | BitUploadDispatcher::BitUploadDispatcher( 20 | const std::tr1::shared_ptr& cache) 21 | : upload_time_(TimeTraits::now()), 22 | upload_blocks_quota_(quota_per_second), 23 | cache_(cache) 24 | { 25 | } 26 | 27 | void BitUploadDispatcher::PendingUpload(const ConnectionWeakPtr& weak_conn, 28 | int index, int begin, int length) 29 | { 30 | pending_list_.push_back(PendingData(weak_conn, index, begin, length)); 31 | } 32 | 33 | void BitUploadDispatcher::ProcessUpload() 34 | { 35 | NormalTimeType now = TimeTraits::now(); 36 | if (now - upload_time_ >= 1000) 37 | { 38 | std::size_t count = upload_blocks_quota_; 39 | upload_blocks_quota_ = quota_per_second; 40 | ProcessPending(count); 41 | upload_time_ = now; 42 | } 43 | } 44 | 45 | void BitUploadDispatcher::ProcessPending(std::size_t count) 46 | { 47 | while (!pending_list_.empty() && count > 0) 48 | { 49 | PendingData data = pending_list_.front(); 50 | pending_list_.pop_front(); 51 | 52 | if (!data.weak_conn.expired()) 53 | { 54 | cache_->Read(data.index, data.begin, data.length, 55 | std::tr1::bind(&BitUploadDispatcher::CacheReadCallback, 56 | this, data, _1, _2)); 57 | --count; 58 | } 59 | } 60 | } 61 | 62 | void BitUploadDispatcher::CacheReadCallback(const PendingData& data, 63 | bool read_ok, 64 | const char *block) 65 | { 66 | if (data.weak_conn.expired() || 67 | !data.weak_conn.lock()->UploadBlock( 68 | data.index, data.begin, data.length, read_ok, block)) 69 | { 70 | // upload failure, do not consume upload_blocks_quota_, 71 | // so increase upload_blocks_quota_, then next upload round 72 | // can consume the upload_blocks_quota_ 73 | ++upload_blocks_quota_; 74 | } 75 | } 76 | 77 | } // namespace core 78 | } // namespace bitwave 79 | -------------------------------------------------------------------------------- /core/BitUploadDispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_UPLOAD_DISPATCHER_H 2 | #define BIT_UPLOAD_DISPATCHER_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include "../timer/TimeTraits.h" 6 | #include 7 | #include 8 | 9 | namespace bitwave { 10 | namespace core { 11 | 12 | class BitCache; 13 | class BitPeerConnection; 14 | 15 | class BitUploadDispatcher : private NotCopyable 16 | { 17 | public: 18 | typedef std::tr1::weak_ptr ConnectionWeakPtr; 19 | 20 | explicit BitUploadDispatcher( 21 | const std::tr1::shared_ptr& cache); 22 | 23 | void PendingUpload(const ConnectionWeakPtr& weak_conn, 24 | int index, int begin, int length); 25 | 26 | void ProcessUpload(); 27 | 28 | private: 29 | typedef time_traits TimeTraits; 30 | 31 | struct PendingData 32 | { 33 | PendingData(const ConnectionWeakPtr& wc, 34 | int i, int b, int l) 35 | : weak_conn(wc), 36 | index(i), 37 | begin(b), 38 | length(l) 39 | { 40 | } 41 | 42 | ConnectionWeakPtr weak_conn; 43 | int index; 44 | int begin; 45 | int length; 46 | }; 47 | 48 | void ProcessPending(std::size_t count); 49 | void CacheReadCallback(const PendingData& data, 50 | bool read_ok, 51 | const char *block); 52 | 53 | NormalTimeType upload_time_; 54 | std::size_t upload_blocks_quota_; 55 | std::list pending_list_; 56 | std::tr1::shared_ptr cache_; 57 | }; 58 | 59 | } // namespace core 60 | } // namespace bitwave 61 | 62 | #endif // BIT_UPLOAD_DISPATCHER_H 63 | -------------------------------------------------------------------------------- /core/BitWave.cpp: -------------------------------------------------------------------------------- 1 | #include "BitWave.h" 2 | #include "BitData.h" 3 | #include "BitService.h" 4 | #include "BitCreator.h" 5 | #include "BitController.h" 6 | #include "BitRepository.h" 7 | #include "BitPeerListener.h" 8 | #include "../base/Console.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace bitwave { 15 | namespace core { 16 | 17 | BitNetWaveObject::BitNetWaveObject() 18 | : sock_initer_(), 19 | io_service_(), 20 | timer_service_(), 21 | resolve_service_() 22 | { 23 | io_service_.AddService(&timer_service_); 24 | io_service_.AddService(&resolve_service_); 25 | BitService::io_service = &io_service_; 26 | } 27 | 28 | BitNetWaveObject::~BitNetWaveObject() 29 | { 30 | BitService::io_service = 0; 31 | } 32 | 33 | bool BitNetWaveObject::Wave() 34 | { 35 | io_service_.Run(); 36 | return true; 37 | } 38 | 39 | BitCoreControlObject::BitCoreControlObject() 40 | { 41 | repository_.Reset(new BitRepository); 42 | controller_.Reset(new BitController); 43 | 44 | assert(BitService::io_service); 45 | new_task_creator_.Reset(new BitNewTaskCreator( 46 | *controller_, *BitService::io_service)); 47 | 48 | BitService::controller = controller_.Get(); 49 | BitService::repository = repository_.Get(); 50 | BitService::new_task_creator = new_task_creator_.Get(); 51 | 52 | peer_listener_.Reset(new BitPeerListener(*BitService::io_service)); 53 | } 54 | 55 | BitCoreControlObject::~BitCoreControlObject() 56 | { 57 | BitService::controller = 0; 58 | BitService::repository = 0; 59 | BitService::new_task_creator = 0; 60 | } 61 | 62 | bool BitCoreControlObject::Wave() 63 | { 64 | controller_->Process(); 65 | return true; 66 | } 67 | 68 | BitConsoleShowerObject::BitConsoleShowerObject() 69 | : console_(new Console) 70 | { 71 | console_->GetCursorPos(cursor_x_, cursor_y_); 72 | console_->SetCursorVisible(false); 73 | last_show_time_ = TimeTraits::now(); 74 | } 75 | 76 | BitConsoleShowerObject::~BitConsoleShowerObject() 77 | { 78 | console_->SetCursorVisible(true); 79 | } 80 | 81 | bool BitConsoleShowerObject::Wave() 82 | { 83 | NormalTimeType now_time = TimeTraits::now(); 84 | if (now_time - last_show_time_ >= 1000) 85 | { 86 | ShowInfo(now_time); 87 | last_show_time_ = now_time; 88 | } 89 | 90 | return true; 91 | } 92 | 93 | void BitConsoleShowerObject::ShowInfo(const NormalTimeType& now_time) 94 | { 95 | std::vector> all_bitdata; 96 | BitService::repository->GetAllBitData(all_bitdata); 97 | 98 | std::size_t size = all_bitdata.size(); 99 | if (download_bytes_.size() != size) 100 | download_bytes_.resize(size); 101 | if (upload_bytes_.size() != size) 102 | upload_bytes_.resize(size); 103 | 104 | for (std::size_t i = 0; i < size; ++i) 105 | { 106 | std::tr1::shared_ptr bitdata = all_bitdata[i]; 107 | NormalTimeType interval = now_time - last_show_time_; 108 | double download_speed = GetDownloadSpeed(bitdata, i, interval); 109 | double upload_speed = GetUploadSpeed(bitdata, i, interval); 110 | double percent = GetDownloadPercent(bitdata); 111 | int peer_count = bitdata->GetPeerDataSet().size(); 112 | 113 | wchar_t str[256] = { 0 }; 114 | swprintf(str, sizeof(str), L"download:%6.2fKB/S upload:%6.2fKB/S peer count:%4d downloaded:%6.2f%%", 115 | download_speed, upload_speed, peer_count, percent); 116 | 117 | console_->SetCursorPos(cursor_x_, cursor_y_ + i); 118 | console_->Write(str, wcslen(str)); 119 | } 120 | } 121 | 122 | double BitConsoleShowerObject::GetDownloadSpeed( 123 | const std::tr1::shared_ptr& bitdata, 124 | std::size_t task_index, 125 | const NormalTimeType& interval) 126 | { 127 | long long current_download_bytes = bitdata->GetCurrentDownload(); 128 | long long new_download_bytes = current_download_bytes - download_bytes_[task_index]; 129 | download_bytes_[task_index] = current_download_bytes; 130 | double speed = static_cast(new_download_bytes) * 1000 / interval; 131 | speed /= 1024; 132 | return speed; 133 | } 134 | 135 | double BitConsoleShowerObject::GetUploadSpeed( 136 | const std::tr1::shared_ptr& bitdata, 137 | std::size_t task_index, 138 | const NormalTimeType& interval) 139 | { 140 | long long current_upload_bytes = bitdata->GetUploaded(); 141 | long long new_upload_bytes = current_upload_bytes - upload_bytes_[task_index]; 142 | upload_bytes_[task_index] = current_upload_bytes; 143 | double speed = static_cast(new_upload_bytes) * 1000 / interval; 144 | speed /= 1024; 145 | return speed; 146 | } 147 | 148 | double BitConsoleShowerObject::GetDownloadPercent( 149 | const std::tr1::shared_ptr& bitdata) 150 | { 151 | long long downloaded = bitdata->GetDownloaded(); 152 | long long total_size = bitdata->GetTotalSize(); 153 | double percent = static_cast(downloaded) * 100 / total_size; 154 | percent = percent > 100.00 ? 100.00 : percent; 155 | return percent; 156 | } 157 | 158 | void BitWave::AddWaveObject(BitWaveObject *object) 159 | { 160 | assert(object); 161 | wave_objects_.push_back(object); 162 | } 163 | 164 | void BitWave::RemoveWaveObject(BitWaveObject *object) 165 | { 166 | assert(object); 167 | WaveObjects::iterator it = std::find( 168 | wave_objects_.begin(), wave_objects_.end(), object); 169 | if (it != wave_objects_.end()) 170 | wave_objects_.erase(it); 171 | } 172 | 173 | void BitWave::Wave() 174 | { 175 | while (true) 176 | { 177 | for (WaveObjects::iterator it = wave_objects_.begin(); 178 | it != wave_objects_.end(); ++it) 179 | { 180 | if (!(*it)->Wave()) 181 | return ; 182 | } 183 | 184 | if (BitService::continue_run) 185 | BitService::continue_run = false; 186 | else 187 | ::Sleep(25); 188 | } 189 | } 190 | 191 | } // namespace core 192 | } // namespace bitwave 193 | -------------------------------------------------------------------------------- /core/BitWave.h: -------------------------------------------------------------------------------- 1 | #ifndef BIT_WAVE_H 2 | #define BIT_WAVE_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include "../base/ScopePtr.h" 6 | #include "../net/WinSockIniter.h" 7 | #include "../net/IoService.h" 8 | #include "../net/TimerService.h" 9 | #include "../net/ResolveService.h" 10 | #include 11 | #include 12 | 13 | class Console; 14 | 15 | namespace bitwave { 16 | namespace core { 17 | 18 | class BitWaveObject 19 | { 20 | public: 21 | // return true the wave continue, or wave stop 22 | virtual bool Wave() = 0; 23 | }; 24 | 25 | class BitNetWaveObject : public BitWaveObject, private NotCopyable 26 | { 27 | public: 28 | BitNetWaveObject(); 29 | ~BitNetWaveObject(); 30 | virtual bool Wave(); 31 | 32 | private: 33 | net::WinSockIniter sock_initer_; 34 | net::IoService io_service_; 35 | net::TimerService timer_service_; 36 | net::ResolveService resolve_service_; 37 | }; 38 | 39 | class BitRepository; 40 | class BitController; 41 | class BitNewTaskCreator; 42 | class BitPeerListener; 43 | 44 | class BitCoreControlObject : public BitWaveObject, private NotCopyable 45 | { 46 | public: 47 | BitCoreControlObject(); 48 | ~BitCoreControlObject(); 49 | virtual bool Wave(); 50 | 51 | private: 52 | ScopePtr repository_; 53 | ScopePtr controller_; 54 | ScopePtr new_task_creator_; 55 | ScopePtr peer_listener_; 56 | }; 57 | 58 | class BitData; 59 | 60 | class BitConsoleShowerObject : public BitWaveObject, private NotCopyable 61 | { 62 | public: 63 | BitConsoleShowerObject(); 64 | ~BitConsoleShowerObject(); 65 | virtual bool Wave(); 66 | 67 | private: 68 | typedef time_traits TimeTraits; 69 | 70 | void ShowInfo(const NormalTimeType& now_time); 71 | double GetDownloadSpeed(const std::tr1::shared_ptr& bitdata, 72 | std::size_t task_index, 73 | const NormalTimeType& interval); 74 | double GetUploadSpeed(const std::tr1::shared_ptr& bitdata, 75 | std::size_t task_index, 76 | const NormalTimeType& interval); 77 | double GetDownloadPercent(const std::tr1::shared_ptr& bitdata); 78 | 79 | std::tr1::shared_ptr console_; 80 | int cursor_x_; 81 | int cursor_y_; 82 | NormalTimeType last_show_time_; 83 | std::vector download_bytes_; 84 | std::vector upload_bytes_; 85 | }; 86 | 87 | class BitWave : private NotCopyable 88 | { 89 | public: 90 | void AddWaveObject(BitWaveObject *object); 91 | void RemoveWaveObject(BitWaveObject *object); 92 | void Wave(); 93 | 94 | private: 95 | typedef std::vector WaveObjects; 96 | WaveObjects wave_objects_; 97 | }; 98 | 99 | } // namespace core 100 | } // namespace bitwave 101 | 102 | #endif // BIT_WAVE_H 103 | -------------------------------------------------------------------------------- /core/Main.cpp: -------------------------------------------------------------------------------- 1 | #include "BitWave.h" 2 | #include "BitCreator.h" 3 | #include "BitService.h" 4 | #include "BitException.h" 5 | #include "../base/StringConv.h" 6 | #include 7 | 8 | void ProcessException(const bitwave::core::BenTypeException& bte) 9 | { 10 | std::cout << "torrent file is invalidate!" << std::endl; 11 | } 12 | 13 | void ProcessException(const bitwave::core::MetainfoFileExeception& mfe) 14 | { 15 | std::cout << mfe.what() << std::endl; 16 | } 17 | 18 | void ProcessException(const bitwave::core::CreateFileException& cfe) 19 | { 20 | std::string file_path = UTF8ToANSI(cfe.GetFilePath()); 21 | 22 | switch (cfe.get_exception_code()) 23 | { 24 | case bitwave::core::PATH_ERROR: 25 | std::cout << "path: " << file_path << " is invalidate, can not create download files!" << std::endl; 26 | break; 27 | case bitwave::core::SPACE_NOT_ENOUGH: 28 | std::cout << "disk space not enough, can not create download files!" << std::endl; 29 | break; 30 | } 31 | } 32 | 33 | void ProcessException(const bitwave::core::ListenPortException& lpe) 34 | { 35 | std::cout << lpe.what() << std::endl; 36 | std::cout << "Program can not start up!" << std::endl; 37 | } 38 | 39 | int main(int argc, const char **argv) 40 | { 41 | if (argc != 3) 42 | { 43 | std::cout << "error command, please input command like this:" << std::endl; 44 | std::cout << "\tBitTorrent torrent download_path" << std::endl; 45 | return 0; 46 | } 47 | 48 | try 49 | { 50 | std::string torrent = ANSIToUTF8(argv[1]); 51 | std::string download_path = ANSIToUTF8(argv[2]); 52 | 53 | bitwave::core::BitWave wave; 54 | bitwave::core::BitNetWaveObject net_wave_object; 55 | bitwave::core::BitCoreControlObject core_control_object; 56 | bitwave::core::BitConsoleShowerObject console_shower_object; 57 | 58 | bitwave::core::BitService::new_task_creator->CreateTask(torrent, download_path); 59 | 60 | wave.AddWaveObject(&net_wave_object); 61 | wave.AddWaveObject(&core_control_object); 62 | wave.AddWaveObject(&console_shower_object); 63 | wave.Wave(); 64 | } 65 | catch (const bitwave::core::BenTypeException& bte) 66 | { 67 | ProcessException(bte); 68 | } 69 | catch (const bitwave::core::MetainfoFileExeception& mfe) 70 | { 71 | ProcessException(mfe); 72 | } 73 | catch (const bitwave::core::CreateFileException& cfe) 74 | { 75 | ProcessException(cfe); 76 | } 77 | catch (const bitwave::core::ListenPortException& lpe) 78 | { 79 | ProcessException(lpe); 80 | } 81 | catch (...) 82 | { 83 | std::cout << "sorry, program occur a problem, need to exit!" << std::endl; 84 | } 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /core/bencode/BenTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "BenTypes.h" 2 | #include "../BitException.h" 3 | #include "../../base/StringConv.h" 4 | #include 5 | #include 6 | #include 7 | 8 | namespace bitwave { 9 | namespace core { 10 | namespace bentypes { 11 | 12 | // BenTypesStreamBuf -------------------------------------------- 13 | BenTypesStreamBuf::BenTypesStreamBuf(const char *buf, std::size_t size) 14 | : streambuf_() 15 | { 16 | assert(buf && size > 0); 17 | streambuf_.resize(size); 18 | memcpy(&streambuf_[0], buf, size); 19 | } 20 | 21 | BenTypesStreamBuf::BenTypesStreamBuf(const char *filename) 22 | : streambuf_() 23 | { 24 | assert(filename); 25 | std::wstring path = UTF8ToUnicode(filename); 26 | std::ifstream fs(path.c_str(), std::ios_base::in | std::ios_base::binary); 27 | 28 | if (fs.is_open()) 29 | { 30 | fs.seekg(0, std::ios_base::end); 31 | std::size_t size = static_cast(fs.tellg()); 32 | fs.seekg(0, std::ios_base::beg); 33 | 34 | if (size > 0) 35 | { 36 | streambuf_.resize(size); 37 | fs.read(&streambuf_[0], size); 38 | } 39 | } 40 | } 41 | 42 | // BenString ---------------------------------------------------- 43 | BenString::BenString( 44 | BenTypesStreamBuf::const_iterator& begin, 45 | BenTypesStreamBuf::const_iterator& end) 46 | : benstr_() 47 | { 48 | srcbufbegin_ = begin; 49 | int stringlen = ReadStringLen(begin, end); 50 | if (stringlen <= 0 || begin == end || *begin != ':') 51 | throw BenTypeException(INVALIDATE_STRING); 52 | 53 | ++begin; 54 | ReadString(begin, end, stringlen); 55 | srcbufend_ = begin; 56 | } 57 | 58 | int BenString::ReadStringLen( 59 | BenTypesStreamBuf::const_iterator& begin, 60 | BenTypesStreamBuf::const_iterator& end) 61 | { 62 | std::string lenbuf; 63 | while (begin != end && isdigit(*begin)) 64 | { 65 | lenbuf.push_back(*begin++); 66 | } 67 | 68 | return atoi(lenbuf.c_str()); 69 | } 70 | 71 | void BenString::ReadString( 72 | BenTypesStreamBuf::const_iterator& begin, 73 | BenTypesStreamBuf::const_iterator& end, int len) 74 | { 75 | BenTypesStreamBuf::const_iterator send = begin + len; 76 | if (send > end) 77 | throw BenTypeException(INVALIDATE_STRING); 78 | 79 | benstr_.assign(begin, send); 80 | begin = send; 81 | } 82 | 83 | // BenInteger --------------------------------------------------- 84 | BenInteger::BenInteger( 85 | BenTypesStreamBuf::const_iterator& begin, 86 | BenTypesStreamBuf::const_iterator& end) 87 | : benint_(0) 88 | { 89 | srcbufbegin_ = begin; 90 | if (begin == end || *begin != 'i') 91 | throw BenTypeException(INVALIDATE_INTERGER); 92 | ++begin; 93 | 94 | std::string intbuf; 95 | while (begin != end && *begin != 'e') 96 | { 97 | intbuf.push_back(*begin++); 98 | } 99 | 100 | // *begin must be 'e' if it is validate BenInteger 101 | if (begin == end) 102 | throw BenTypeException(INVALIDATE_INTERGER); 103 | ++begin; 104 | 105 | benint_ = _atoi64(intbuf.c_str()); 106 | srcbufend_ = begin; 107 | } 108 | 109 | // BenList ------------------------------------------------------ 110 | BenList::BenList( 111 | BenTypesStreamBuf::const_iterator& begin, 112 | BenTypesStreamBuf::const_iterator& end) 113 | : benlist_() 114 | { 115 | srcbufbegin_ = begin; 116 | if (begin == end || *begin != 'l') 117 | throw BenTypeException(INVALIDATE_LIST); 118 | ++begin; 119 | 120 | while (begin != end && *begin != 'e') 121 | { 122 | benlist_.push_back(GetBenObject(begin, end)); 123 | } 124 | 125 | // *begin must be 'e' if it is validate BenList 126 | if (begin == end) 127 | throw BenTypeException(INVALIDATE_LIST); 128 | ++begin; 129 | srcbufend_ = begin; 130 | } 131 | 132 | // BenDictionary ------------------------------------------------ 133 | BenDictionary::BenDictionary( 134 | BenTypesStreamBuf::const_iterator& begin, 135 | BenTypesStreamBuf::const_iterator& end) 136 | : benmap_() 137 | { 138 | srcbufbegin_ = begin; 139 | if (begin == end || *begin != 'd') 140 | throw BenTypeException(INVALIDATE_DICTIONARY); 141 | ++begin; 142 | 143 | while (begin != end && *begin != 'e') 144 | { 145 | BenString key(begin, end); 146 | std::tr1::shared_ptr value = GetBenObject(begin, end); 147 | if (value) 148 | { 149 | benmap_.insert(BenMap::value_type(key.std_string(), value)); 150 | } 151 | } 152 | 153 | // *begin must be 'e' if it is validate BenDictionary 154 | if (begin == end) 155 | throw BenTypeException(INVALIDATE_DICTIONARY); 156 | ++begin; 157 | srcbufend_ = begin; 158 | } 159 | 160 | std::tr1::shared_ptr GetBenObject( 161 | BenTypesStreamBuf::const_iterator& begin, 162 | BenTypesStreamBuf::const_iterator& end) 163 | { 164 | if (begin == end) 165 | throw BenTypeException(INVALIDATE_NOBENTYPE); 166 | 167 | switch (*begin) 168 | { 169 | case 'i': 170 | return std::tr1::shared_ptr(new BenInteger(begin, end)); 171 | 172 | case 'l': 173 | return std::tr1::shared_ptr(new BenList(begin, end)); 174 | 175 | case 'd': 176 | return std::tr1::shared_ptr(new BenDictionary(begin, end)); 177 | 178 | default: 179 | return std::tr1::shared_ptr(new BenString(begin, end)); 180 | } 181 | } 182 | 183 | } // namespace bentypes 184 | } // namespace core 185 | } // namespace bitwave 186 | -------------------------------------------------------------------------------- /core/bencode/MetainfoFile.cpp: -------------------------------------------------------------------------------- 1 | #include "MetainfoFile.h" 2 | #include "../BitException.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace bitwave { 9 | namespace core { 10 | namespace bentypes { 11 | 12 | MetainfoFile::MetainfoFile(const char *filepath) 13 | : metafilebuf_(filepath), 14 | metainfo_(GetBenObject(metafilebuf_)), 15 | ann_(0), 16 | annlist_(0), 17 | infodic_(0), 18 | pieces_(0) 19 | { 20 | if (!metainfo_ || !PrepareBasicData()) 21 | { 22 | std::string info = std::string("invalid torrent file: ") + filepath; 23 | throw MetainfoFileExeception(info); 24 | } 25 | } 26 | 27 | void MetainfoFile::GetAnnounce(std::vector *announce) const 28 | { 29 | assert(announce); 30 | if (annlist_) 31 | { 32 | announce->reserve(annlist_->size()); 33 | 34 | std::vector vl; 35 | annlist_->AllElementPtr(&vl); 36 | 37 | std::vector vs; 38 | std::for_each(vl.begin(), vl.end(), 39 | std::bind2nd( 40 | std::mem_fun(&BenList::AllElementPtr), &vs)); 41 | 42 | std::transform(vs.begin(), vs.end(), 43 | std::back_inserter(*announce), 44 | std::mem_fun(&BenString::std_string)); 45 | } 46 | else 47 | { 48 | announce->push_back(ann_->std_string()); 49 | } 50 | } 51 | 52 | bool MetainfoFile::IsSingleFile() const 53 | { 54 | BenInteger *length = infodic_->ValueBenTypeCast("length"); 55 | return length != 0; 56 | } 57 | 58 | std::string MetainfoFile::Name() const 59 | { 60 | BenString *name = infodic_->ValueBenTypeCast("name"); 61 | if (name) 62 | return name->std_string(); 63 | return std::string(); 64 | } 65 | 66 | std::size_t MetainfoFile::PieceLength() const 67 | { 68 | BenInteger *pl = infodic_->ValueBenTypeCast("piece length"); 69 | if (pl) 70 | return static_cast(pl->GetValue()); 71 | return 0; 72 | } 73 | 74 | std::size_t MetainfoFile::PiecesCount() const 75 | { 76 | return pieces_->length() / 20; 77 | } 78 | 79 | Sha1Value MetainfoFile::GetPieceSha1(std::size_t index) const 80 | { 81 | const char *data = pieces_->data() + index * 20; 82 | const unsigned *sha1 = reinterpret_cast(data); 83 | return Sha1Value(sha1); 84 | } 85 | 86 | long long MetainfoFile::Length() const 87 | { 88 | BenInteger *length = infodic_->ValueBenTypeCast("length"); 89 | if (length) 90 | return length->GetValue(); 91 | return 0; 92 | } 93 | 94 | void MetainfoFile::GetFiles(std::vector *files) const 95 | { 96 | if (IsSingleFile()) 97 | GetTheFile(files); 98 | else 99 | GetFileList(files); 100 | } 101 | 102 | std::pair MetainfoFile::GetRawInfoValue() const 103 | { 104 | const char *begin = metafilebuf_.iter_data(infodic_->GetSrcBufBegin()); 105 | const char *end = metafilebuf_.iter_data(infodic_->GetSrcBufEnd()); 106 | return std::make_pair(begin, end); 107 | } 108 | 109 | bool MetainfoFile::PrepareBasicData() 110 | { 111 | BenDictionary *dic = dynamic_cast(metainfo_.get()); 112 | if (!dic) return false; 113 | 114 | ann_ = dic->ValueBenTypeCast("announce"); 115 | if (!ann_) return false; 116 | 117 | annlist_ = dic->ValueBenTypeCast("announce-list"); 118 | 119 | infodic_ = dic->ValueBenTypeCast("info"); 120 | if (!infodic_) return false; 121 | 122 | pieces_ = infodic_->ValueBenTypeCast("pieces"); 123 | if (!pieces_) return false; 124 | 125 | if (pieces_->length() % 20) return false; 126 | 127 | return true; 128 | } 129 | 130 | void MetainfoFile::GetTheFile(std::vector *files) const 131 | { 132 | assert(files); 133 | FileInfo the_file; 134 | the_file.length = Length(); 135 | the_file.path.push_back(Name()); 136 | files->push_back(the_file); 137 | } 138 | 139 | void MetainfoFile::GetFileList(std::vector *files) const 140 | { 141 | assert(files); 142 | BenList *fs = infodic_->ValueBenTypeCast("files"); 143 | if (!fs) 144 | return ; 145 | files->reserve(fs->size()); 146 | 147 | std::string base_path = Name(); 148 | std::vector vd; 149 | fs->AllElementPtr(&vd); 150 | for (std::vector::iterator it = vd.begin(); it != vd.end(); ++it) 151 | { 152 | BenDictionary *file = *it; 153 | BenInteger *len = file->ValueBenTypeCast("length"); 154 | if (!len) continue; 155 | 156 | FileInfo file_info; 157 | file_info.length = len->GetValue(); 158 | 159 | BenList *pathlist = file->ValueBenTypeCast("path"); 160 | if (!pathlist) continue; 161 | 162 | // reserve for base path and file path 163 | file_info.path.reserve(pathlist->size() + 1); 164 | file_info.path.push_back(base_path); 165 | 166 | std::vector vs; 167 | pathlist->AllElementPtr(&vs); 168 | 169 | std::transform(vs.begin(), vs.end(), 170 | std::back_inserter(file_info.path), 171 | std::mem_fun(&BenString::std_string)); 172 | 173 | files->push_back(file_info); 174 | } 175 | } 176 | 177 | } // namespace bentypes 178 | } // namespace core 179 | } // namespace bitwave 180 | -------------------------------------------------------------------------------- /core/bencode/MetainfoFile.h: -------------------------------------------------------------------------------- 1 | #ifndef METAINFO_FILE_H 2 | #define METAINFO_FILE_H 3 | 4 | #include "BenTypes.h" 5 | #include "../../base/BaseTypes.h" 6 | #include "../../sha1/Sha1Value.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace bitwave { 13 | namespace core { 14 | namespace bentypes { 15 | 16 | // All strings encoded by UTF-8 in this class 17 | class MetainfoFile : private NotCopyable 18 | { 19 | public: 20 | struct FileInfo 21 | { 22 | long long length; 23 | std::vector path; 24 | }; 25 | 26 | explicit MetainfoFile(const char *filepath); 27 | 28 | void GetAnnounce(std::vector *announce) const; 29 | 30 | bool IsSingleFile() const; 31 | 32 | // return file name when IsSingleFile is true, otherwise 33 | // return a directory name, this just advisory. 34 | std::string Name() const; 35 | 36 | std::size_t PieceLength() const; 37 | std::size_t PiecesCount() const; 38 | Sha1Value GetPieceSha1(std::size_t index) const; 39 | 40 | long long Length() const; 41 | void GetFiles(std::vector *files) const; 42 | 43 | // return raw info value buffer, first is begin, second is end 44 | std::pair GetRawInfoValue() const; 45 | 46 | private: 47 | bool PrepareBasicData(); 48 | void GetTheFile(std::vector *files) const; 49 | void GetFileList(std::vector *files) const; 50 | 51 | BenTypesStreamBuf metafilebuf_; 52 | std::tr1::shared_ptr metainfo_; 53 | BenString *ann_; 54 | BenList *annlist_; 55 | BenDictionary *infodic_; 56 | BenString *pieces_; 57 | }; 58 | 59 | } // namespace bentypes 60 | } // namespace core 61 | } // namespace bitwave 62 | 63 | #endif // METAINFO_FILE_H 64 | -------------------------------------------------------------------------------- /core/bencode/TrackerResponse.cpp: -------------------------------------------------------------------------------- 1 | #include "TrackerResponse.h" 2 | #include "../../net/NetHelper.h" 3 | 4 | namespace bitwave { 5 | namespace core { 6 | namespace bentypes { 7 | 8 | TrackerResponse::TrackerResponse(const char *data, std::size_t size) 9 | : response_buffer_(data, size), 10 | ben_dic_(GetBenObject(response_buffer_)), 11 | response_dic_(0), 12 | failure_reason_(0), 13 | interval_(0), 14 | peers_(0) 15 | { 16 | response_dic_ = dynamic_cast(ben_dic_.get()); 17 | if (!response_dic_) return ; 18 | failure_reason_ = response_dic_->ValueBenTypeCast("failure reason"); 19 | interval_ = response_dic_->ValueBenTypeCast("interval"); 20 | peers_ = response_dic_->ValueBenTypeCast("peers"); 21 | } 22 | 23 | bool TrackerResponse::IsFailure() const 24 | { 25 | return failure_reason_ != 0; 26 | } 27 | 28 | std::string TrackerResponse::GetFailureReason() const 29 | { 30 | if (failure_reason_) 31 | return failure_reason_->std_string(); 32 | return std::string("not failure"); 33 | } 34 | 35 | int TrackerResponse::GetInterval() const 36 | { 37 | if (interval_) 38 | return static_cast(interval_->GetValue()); 39 | return 0; 40 | } 41 | 42 | void TrackerResponse::GetPeerInfo(std::vector& peers_info) const 43 | { 44 | if (!peers_) 45 | return ; 46 | 47 | std::size_t number = peers_->length() / 6; 48 | peers_info.reserve(number); 49 | 50 | const char *data = peers_->data(); 51 | for (std::size_t i = 0; i < number; ++i) 52 | { 53 | PeerInfo info; 54 | info.ip = net::NetToHostl(*reinterpret_cast(data)); 55 | data += 4; 56 | info.port = net::NetToHosts(*reinterpret_cast(data)); 57 | data += 2; 58 | 59 | peers_info.push_back(info); 60 | } 61 | } 62 | 63 | } // namespace bentypes 64 | } // namespace core 65 | } // namespace bitwave 66 | -------------------------------------------------------------------------------- /core/bencode/TrackerResponse.h: -------------------------------------------------------------------------------- 1 | #ifndef TRACKER_RESPONSE_H 2 | #define TRACKER_RESPONSE_H 3 | 4 | #include "../../base/BaseTypes.h" 5 | #include "BenTypes.h" 6 | #include 7 | #include 8 | 9 | namespace bitwave { 10 | namespace core { 11 | namespace bentypes { 12 | 13 | class TrackerResponse : private NotCopyable 14 | { 15 | public: 16 | struct PeerInfo 17 | { 18 | unsigned long ip; 19 | unsigned short port; 20 | }; 21 | 22 | TrackerResponse(const char *data, std::size_t size); 23 | 24 | bool IsFailure() const; 25 | std::string GetFailureReason() const; 26 | int GetInterval() const; 27 | void GetPeerInfo(std::vector& peers_info) const; 28 | 29 | private: 30 | BenTypesStreamBuf response_buffer_; 31 | std::tr1::shared_ptr ben_dic_; 32 | BenDictionary *response_dic_; 33 | BenString *failure_reason_; 34 | BenInteger *interval_; 35 | BenString *peers_; 36 | }; 37 | 38 | } // namespace bentypes 39 | } // namespace core 40 | } // namespace bitwave 41 | 42 | #endif // TRACKER_RESPONSE_H 43 | -------------------------------------------------------------------------------- /log/Log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H 2 | #define LOG_H 3 | 4 | #include "LogImpl.h" 5 | #include "../base/BaseTypes.h" 6 | #include 7 | #include 8 | 9 | namespace bitwave { 10 | namespace log { 11 | 12 | template 13 | class Log : private NotCopyable 14 | { 15 | public: 16 | // function prototype of manipulator for the log 17 | typedef void (*Manipulator)(Log& log); 18 | typedef LogImplBase LogImpl; 19 | typedef std::tr1::shared_ptr LogImplPtr; 20 | 21 | explicit Log(const LogImplPtr& log_impl) 22 | : new_record_(false), 23 | record_stream_(), 24 | log_impl_ptr_(log_impl) 25 | { 26 | } 27 | 28 | // a generic operator << to record any type T to the record 29 | // stream buffer 30 | template 31 | Log& operator << (const T& t) 32 | { 33 | record_stream_ << t; 34 | return *this; 35 | } 36 | 37 | // operator << for Manipulator to do some special operation 38 | // on the log 39 | Log& operator << (Manipulator manipulator) 40 | { 41 | manipulator(*this); 42 | return *this; 43 | } 44 | 45 | // write record stream buffer to implement log and clear the 46 | // stream buffer. 47 | void Flush() 48 | { 49 | log_impl_ptr_->LogRecord(record_stream_.str()); 50 | record_stream_.str(std::basic_string()); 51 | } 52 | 53 | // start a record, all operator << call after this function 54 | // will in the record before end the record 55 | // this is an optional operator, call this function you can 56 | // start a record explicitly, then after log some information 57 | // you need call EndRecord function to end the record explicitly 58 | void StartRecord() 59 | { 60 | if (!new_record_) 61 | { 62 | log_impl_ptr_->StartLogRecord(); 63 | new_record_ = true; 64 | } 65 | } 66 | 67 | // end a record, all operator << call before this function 68 | // will in the record after start the record 69 | // call this function you must called StartRecord, this function 70 | // end the record explicitly 71 | void EndRecord() 72 | { 73 | if (new_record_) 74 | { 75 | Flush(); 76 | log_impl_ptr_->EndLogRecord(); 77 | new_record_ = false; 78 | } 79 | } 80 | 81 | private: 82 | // record mode flag 83 | bool new_record_; 84 | // record stream buffer 85 | std::basic_stringstream record_stream_; 86 | // implement log 87 | LogImplPtr log_impl_ptr_; 88 | }; 89 | 90 | } // namespace log 91 | } // namespace bitwave 92 | 93 | #endif // LOG_H 94 | -------------------------------------------------------------------------------- /log/LogFactory.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_FACTORY_H 2 | #define LOG_FACTORY_H 3 | 4 | #include "Log.h" 5 | #include "../base/BaseTypes.h" 6 | #include 7 | 8 | namespace bitwave { 9 | namespace log { 10 | 11 | // this is log implement factory, it can produce a log product through 12 | // several process operations. 13 | template 14 | class LogFactory : private NotCopyable 15 | { 16 | public: 17 | typedef typename Log::LogImplPtr LogImplPtr; 18 | 19 | // make a null log implement as current product 20 | LogFactory& MakeNullLog() 21 | { 22 | product_ptr_.reset(new NullLogImpl); 23 | return *this; 24 | } 25 | 26 | // make a cout log implement as current product 27 | LogFactory& MakeCoutLog() 28 | { 29 | product_ptr_.reset(new CoutLogImpl); 30 | return *this; 31 | } 32 | 33 | // make a file log implement as current product 34 | LogFactory& MakeTextFileLog(const std::basic_string& file_name) 35 | { 36 | product_ptr_.reset(new TextFileLogImpl(file_name)); 37 | return *this; 38 | } 39 | 40 | // add a timestamp log to current product 41 | LogFactory& AddTimestamp() 42 | { 43 | assert(product_ptr_); 44 | LogImplPtr ptr = product_ptr_; 45 | product_ptr_.reset(new TimestampAdderLogImpl(ptr)); 46 | return *this; 47 | } 48 | 49 | // this function do nothing. derived factory could 50 | // override this function to store current product 51 | virtual LogFactory& StoreLog() 52 | { 53 | return *this; 54 | } 55 | 56 | // this function do nothing. derived factory could 57 | // override this function to fetch stored product 58 | virtual LogFactory& FetchLog() 59 | { 60 | return *this; 61 | } 62 | 63 | // get the log product from the factory 64 | LogImplPtr LogLeaveFactory() 65 | { 66 | LogImplPtr product = product_ptr_; 67 | product_ptr_.reset(); 68 | return product; 69 | } 70 | 71 | protected: 72 | LogImplPtr product_ptr_; 73 | }; 74 | 75 | // this factory produce CompositeLogImpl by composite several products 76 | // which produced by base LogFactory. 77 | template 78 | class CompositeLogFactory : public LogFactory 79 | { 80 | public: 81 | CompositeLogFactory() 82 | : composite_log_(new CompositeLogImpl) 83 | { 84 | } 85 | 86 | virtual CompositeLogFactory& StoreLog() 87 | { 88 | if (product_ptr_) 89 | { 90 | // composite current product 91 | composite_log_->AddLogImpl(product_ptr_); 92 | product_ptr_.reset(); 93 | } 94 | return *this; 95 | } 96 | 97 | virtual CompositeLogFactory& FetchLog() 98 | { 99 | // make the composite_log_ as product_ptr_ 100 | // then LogLeaveFactory will get the composite_log_ 101 | product_ptr_ = composite_log_; 102 | composite_log_.reset(new CompositeLogImpl); 103 | return *this; 104 | } 105 | 106 | private: 107 | std::tr1::shared_ptr> composite_log_; 108 | }; 109 | 110 | } // namespace log 111 | } // namespace bitwave 112 | 113 | #endif // LOG_FACTORY_H 114 | -------------------------------------------------------------------------------- /log/LogImpl.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_IMPL_H 2 | #define LOG_IMPL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace bitwave { 14 | namespace log { 15 | 16 | template 17 | class LogImplBase 18 | { 19 | public: 20 | virtual void StartLogRecord() = 0; 21 | virtual void LogRecord(const std::basic_string& record) = 0; 22 | virtual void EndLogRecord() = 0; 23 | virtual ~LogImplBase() { } 24 | }; 25 | 26 | template 27 | class NullLogImpl : public LogImplBase 28 | { 29 | public: 30 | virtual void StartLogRecord() { } 31 | virtual void LogRecord(const std::basic_string&) { } 32 | virtual void EndLogRecord() { } 33 | }; 34 | 35 | template 36 | class CoutLogImpl; 37 | 38 | template<> 39 | class CoutLogImpl : public LogImplBase 40 | { 41 | public: 42 | virtual void StartLogRecord() { } 43 | virtual void LogRecord(const std::string& log) { std::cout << log; } 44 | virtual void EndLogRecord() { } 45 | }; 46 | 47 | template<> 48 | class CoutLogImpl : public LogImplBase 49 | { 50 | public: 51 | virtual void StartLogRecord() { } 52 | virtual void LogRecord(const std::wstring& log) { std::wcout << log; } 53 | virtual void EndLogRecord() { } 54 | }; 55 | 56 | template 57 | class CompositeLogImpl : public LogImplBase 58 | { 59 | public: 60 | typedef LogImplBase BaseType; 61 | typedef std::tr1::shared_ptr BaseTypePtr; 62 | 63 | void AddLogImpl(const BaseTypePtr& log_impl) 64 | { 65 | logs_.push_back(log_impl); 66 | } 67 | 68 | virtual void StartLogRecord() 69 | { 70 | std::for_each(logs_.begin(), logs_.end(), 71 | std::tr1::bind(&BaseType::StartLogRecord, 72 | std::tr1::placeholders::_1)); 73 | } 74 | 75 | virtual void LogRecord(const std::basic_string& log) 76 | { 77 | std::for_each(logs_.begin(), logs_.end(), 78 | std::tr1::bind(&BaseType::LogRecord, 79 | std::tr1::placeholders::_1, std::tr1::cref(log))); 80 | } 81 | 82 | virtual void EndLogRecord() 83 | { 84 | std::for_each(logs_.begin(), logs_.end(), 85 | std::tr1::bind(&BaseType::EndLogRecord, 86 | std::tr1::placeholders::_1)); 87 | } 88 | 89 | private: 90 | std::vector logs_; 91 | }; 92 | 93 | template 94 | class TextFileLogImpl : public LogImplBase 95 | { 96 | public: 97 | explicit TextFileLogImpl(const std::basic_string& file_name) 98 | : file_(file_name.c_str()) 99 | { 100 | } 101 | 102 | virtual void StartLogRecord() { } 103 | virtual void LogRecord(const std::basic_string& log) 104 | { 105 | if (file_.is_open()) 106 | file_ << log; 107 | } 108 | virtual void EndLogRecord() { } 109 | 110 | private: 111 | std::basic_ofstream file_; 112 | }; 113 | 114 | template 115 | class TimestampAdderLogImpl : public LogImplBase 116 | { 117 | public: 118 | typedef LogImplBase BaseType; 119 | typedef std::tr1::shared_ptr BaseTypePtr; 120 | 121 | explicit TimestampAdderLogImpl(const BaseTypePtr& log) 122 | : log_(log) 123 | { 124 | } 125 | 126 | virtual void StartLogRecord() 127 | { 128 | // add timestamp 129 | time_t now = time(0); 130 | tm *ptm = localtime(&now); 131 | ConvertTimeToString(ptm, CharType()); 132 | log_->LogRecord(timestamp_.str()); 133 | timestamp_.str(std::basic_string()); 134 | 135 | log_->StartLogRecord(); 136 | } 137 | 138 | virtual void LogRecord(const std::basic_string& log) 139 | { 140 | log_->LogRecord(log); 141 | } 142 | 143 | virtual void EndLogRecord() 144 | { 145 | log_->EndLogRecord(); 146 | } 147 | 148 | private: 149 | void ConvertTimeToString(const tm *ptm, char) 150 | { 151 | timestamp_ << '[' << 1900 + ptm->tm_year << '-' 152 | << 1 + ptm->tm_mon << '-' << ptm->tm_mday << ' ' 153 | << ptm->tm_hour<< ':' << ptm->tm_min << ':' 154 | << ptm->tm_sec << ']'; 155 | } 156 | 157 | void ConvertTimeToString(const tm *ptm, wchar_t) 158 | { 159 | timestamp_ << L'[' << 1900 + ptm->tm_year << L'-' 160 | << 1 + ptm->tm_mon << L'-' << ptm->tm_mday << L' ' 161 | << ptm->tm_hour<< L':' << ptm->tm_min << L':' 162 | << ptm->tm_sec << L']'; 163 | } 164 | 165 | std::basic_stringstream timestamp_; 166 | BaseTypePtr log_; 167 | }; 168 | 169 | } // namespace log 170 | } // namespace bitwave 171 | 172 | #endif // LOG_IMPL_H 173 | -------------------------------------------------------------------------------- /log/Manipulator.h: -------------------------------------------------------------------------------- 1 | #ifndef MANIPULATOR_H 2 | #define MANIPULATOR_H 3 | 4 | namespace bitwave { 5 | namespace log { 6 | 7 | template 8 | inline void Endl(LogType& log) 9 | { 10 | log << '\n'; 11 | log.Flush(); 12 | } 13 | 14 | template 15 | inline void RecordStarter(LogType& log) 16 | { 17 | log.StartRecord(); 18 | } 19 | 20 | template 21 | inline void RecordEnder(LogType& log) 22 | { 23 | log.EndRecord(); 24 | } 25 | 26 | } // namespace log 27 | } // namespace bitwave 28 | 29 | #endif // MANIPULATOR_H 30 | -------------------------------------------------------------------------------- /net/Address.h: -------------------------------------------------------------------------------- 1 | #ifndef ADDRESS_H 2 | #define ADDRESS_H 3 | 4 | #include "NetHelper.h" 5 | #include 6 | 7 | namespace bitwave { 8 | namespace net { 9 | 10 | class Address 11 | { 12 | public: 13 | static const unsigned long any = INADDR_ANY; 14 | 15 | Address() 16 | : address_(HostToNetl(any)) 17 | { 18 | } 19 | 20 | explicit Address(unsigned long hladdress) 21 | : address_(HostToNetl(hladdress)) 22 | { 23 | } 24 | 25 | explicit Address(const char *address) 26 | : address_(::inet_addr(address)) 27 | { 28 | } 29 | 30 | explicit Address(const sockaddr_in *addr) 31 | : address_(addr->sin_addr.s_addr) 32 | { 33 | } 34 | 35 | operator unsigned long () const 36 | { 37 | return address_; 38 | } 39 | 40 | private: 41 | unsigned long address_; 42 | }; 43 | 44 | class Port 45 | { 46 | public: 47 | explicit Port(unsigned short hsport) 48 | : port_(HostToNets(hsport)) 49 | { 50 | } 51 | 52 | explicit Port(const sockaddr_in *addr) 53 | : port_(addr->sin_port) 54 | { 55 | } 56 | 57 | operator unsigned short () const 58 | { 59 | return port_; 60 | } 61 | 62 | private: 63 | unsigned short port_; 64 | }; 65 | 66 | inline sockaddr_in Ipv4Address(const Address& address, const Port& port) 67 | { 68 | sockaddr_in addr; 69 | addr.sin_family = AF_INET; 70 | addr.sin_addr.s_addr = address; 71 | addr.sin_port = port; 72 | return addr; 73 | } 74 | 75 | } // namespace net 76 | } // namespace bitwave 77 | 78 | #endif // ADDRESS_H 79 | -------------------------------------------------------------------------------- /net/AddressResolver.h: -------------------------------------------------------------------------------- 1 | #ifndef ADDRESS_RESOLVER_H 2 | #define ADDRESS_RESOLVER_H 3 | 4 | #include "NetException.h" 5 | #include "../base/RefCount.h" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace bitwave { 11 | namespace net { 12 | 13 | class ResolveResult : public RefCount 14 | { 15 | public: 16 | class iterator 17 | { 18 | public: 19 | iterator() 20 | : ai_(0) 21 | { 22 | } 23 | 24 | explicit iterator(addrinfo *ai) 25 | : ai_(ai) 26 | { 27 | } 28 | 29 | const addrinfo& operator * () const 30 | { 31 | return *ai_; 32 | } 33 | 34 | const addrinfo* operator -> () const 35 | { 36 | return ai_; 37 | } 38 | 39 | iterator& operator ++ () 40 | { 41 | ai_ = ai_->ai_next; 42 | return *this; 43 | } 44 | 45 | iterator operator ++ (int) 46 | { 47 | iterator res(*this); 48 | ++(*this); 49 | return res; 50 | } 51 | 52 | friend bool operator == (const iterator& rl, const iterator& rr) 53 | { 54 | return rl.ai_ == rr.ai_; 55 | } 56 | 57 | friend bool operator != (const iterator& rl, const iterator& rr) 58 | { 59 | return !(rl == rr); 60 | } 61 | 62 | private: 63 | addrinfo *ai_; 64 | }; 65 | 66 | ResolveResult() 67 | : ai_(0) 68 | { 69 | } 70 | 71 | explicit ResolveResult(addrinfo *ai) 72 | : RefCount(true), 73 | ai_(ai) 74 | { 75 | } 76 | 77 | ~ResolveResult() 78 | { 79 | if (Only()) 80 | ::freeaddrinfo(ai_); 81 | } 82 | 83 | ResolveResult(const ResolveResult& rr) 84 | : RefCount(rr), 85 | ai_(rr.ai_) 86 | { 87 | } 88 | 89 | ResolveResult& operator = (const ResolveResult& rr) 90 | { 91 | ResolveResult(rr).Swap(*this); 92 | return *this; 93 | } 94 | 95 | void Swap(ResolveResult& rr) 96 | { 97 | RefCount::Swap(rr); 98 | std::swap(rr.ai_, ai_); 99 | } 100 | 101 | iterator begin() const 102 | { 103 | return iterator(ai_); 104 | } 105 | 106 | iterator end() const 107 | { 108 | return iterator(); 109 | } 110 | 111 | private: 112 | addrinfo *ai_; 113 | }; 114 | 115 | class ResolveHint 116 | { 117 | public: 118 | ResolveHint() 119 | { 120 | memset(&hint_, 0, sizeof(hint_)); 121 | } 122 | 123 | ResolveHint(int ai_family, int ai_socktype, int ai_protocol) 124 | { 125 | memset(&hint_, 0, sizeof(hint_)); 126 | hint_.ai_family = ai_family; 127 | hint_.ai_socktype = ai_socktype; 128 | hint_.ai_protocol = ai_protocol; 129 | } 130 | 131 | const addrinfo * Get() const 132 | { 133 | return &hint_; 134 | } 135 | 136 | private: 137 | addrinfo hint_; 138 | }; 139 | 140 | inline ResolveResult ResolveAddress(const std::string& nodename, 141 | const std::string& servname, 142 | const ResolveHint& hint) 143 | { 144 | addrinfo *result = 0; 145 | int ec = ::getaddrinfo(nodename.c_str(), servname.c_str(), hint.Get(), &result); 146 | if (ec) 147 | throw AddressResolveException(ec, nodename); 148 | 149 | return ResolveResult(result); 150 | } 151 | 152 | } // namespace net 153 | } // namespace bitwave 154 | 155 | #endif // ADDRESS_RESOLVER_H 156 | -------------------------------------------------------------------------------- /net/BaseSocket.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_SOCKET_H 2 | #define BASE_SOCKET_H 3 | 4 | #include "NetException.h" 5 | #include "../base/RefCount.h" 6 | #include 7 | 8 | namespace bitwave { 9 | namespace net { 10 | 11 | class BaseSocket : public RefCount 12 | { 13 | public: 14 | template 15 | explicit BaseSocket(Service& service) 16 | : RefCount(true), 17 | socket_(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) 18 | { 19 | if (socket_ == INVALID_SOCKET) 20 | throw NetException(CREATE_SOCKET_ERROR); 21 | 22 | service.RegisterSocket(socket_); 23 | } 24 | 25 | ~BaseSocket() 26 | { 27 | if (Only()) 28 | Close(); 29 | } 30 | 31 | BaseSocket(const BaseSocket& si) 32 | : RefCount(si), 33 | socket_(si.socket_) 34 | { 35 | } 36 | 37 | BaseSocket& operator = (const BaseSocket& si) 38 | { 39 | BaseSocket(si).Swap(*this); 40 | return *this; 41 | } 42 | 43 | void Swap(BaseSocket& si) 44 | { 45 | RefCount::Swap(si); 46 | std::swap(si.socket_, socket_); 47 | } 48 | 49 | void Close() 50 | { 51 | if (socket_ == INVALID_SOCKET) 52 | return ; 53 | 54 | ::closesocket(socket_); 55 | socket_ = INVALID_SOCKET; 56 | } 57 | 58 | SOCKET Get() const 59 | { 60 | return socket_; 61 | } 62 | 63 | private: 64 | SOCKET socket_; 65 | }; 66 | 67 | } // namespace net 68 | } // namespace bitwave 69 | 70 | #endif // BASE_SOCKET_H 71 | -------------------------------------------------------------------------------- /net/IoService.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_SERVICE_H 2 | #define IO_SERVICE_H 3 | 4 | #include "Address.h" 5 | #include "Socket.h" 6 | #include "BaseSocket.h" 7 | #include "Overlapped.h" 8 | #include "Iocp.h" 9 | 10 | namespace bitwave { 11 | namespace net { 12 | 13 | typedef IocpService IoService; 14 | typedef Socket AsyncSocket; 15 | typedef Listener AsyncListener; 16 | 17 | // a help function to construct a AsyncSocket by service and BaseSocket 18 | inline AsyncSocket MakeAsyncSocket(IoService& service, 19 | const BaseSocket& socket) 20 | { 21 | return AsyncSocket(service, socket); 22 | } 23 | 24 | } // namespace net 25 | } // namespace bitwave 26 | 27 | #endif // IO_SERVICE_H 28 | -------------------------------------------------------------------------------- /net/NetException.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_EXCEPTION_H 2 | #define NET_EXCEPTION_H 3 | 4 | #include "../base/BaseTypes.h" 5 | 6 | namespace bitwave { 7 | namespace net { 8 | 9 | // net exception code 10 | enum NetExceptionCode 11 | { 12 | CREATE_SOCKET_ERROR, 13 | CREATE_SERVICE_ERROR, 14 | REGISTER_SOCKET_ERROR, 15 | BIND_LISTENER_SOCKET_ERROR, 16 | LISTEN_LISTENER_SOCKET_ERROR, 17 | GET_ACCEPTEX_FUNCTION_ERROR, 18 | GET_CONNECTEX_FUNCTION_ERROR, 19 | CALL_ACCEPTEX_FUNCTION_ERROR, 20 | CALL_CONNECTEX_FUNCTION_ERROR, 21 | CALL_WSARECV_FUNCTION_ERROR, 22 | CALL_WSASEND_FUNCTION_ERROR, 23 | CONNECT_BIND_LOCAL_ERROR, 24 | }; 25 | 26 | // an exception class for net 27 | class NetException : public BaseException 28 | { 29 | public: 30 | explicit NetException(int code) 31 | : BaseException(code) 32 | { 33 | } 34 | }; 35 | 36 | // exception code: 37 | // EAI_AGAIN, EAI_BADFLAGS, EAI_FAIL, EAI_FAMILY, 38 | // EAI_MEMORY, EAI_NONAME, EAI_SERVICE, EAI_SOCKTYPE 39 | class AddressResolveException : public BaseException 40 | { 41 | public: 42 | AddressResolveException(int code, const std::string& w) 43 | : BaseException(code, w) 44 | { 45 | } 46 | }; 47 | 48 | } // namespace net 49 | } // namespace bitwave 50 | 51 | #endif // NET_EXCEPTION_H 52 | -------------------------------------------------------------------------------- /net/NetHelper.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_HELPER_H 2 | #define NET_HELPER_H 3 | 4 | #include "BaseSocket.h" 5 | #include 6 | #include 7 | 8 | namespace bitwave { 9 | namespace net { 10 | 11 | inline unsigned long HostToNetl(unsigned long l) 12 | { 13 | return ::htonl(l); 14 | } 15 | 16 | inline long HostToNetl(long l) 17 | { 18 | return static_cast(::htonl(l)); 19 | } 20 | 21 | template 22 | inline void HostToNetl(T *ary, int size) 23 | { 24 | assert(ary && size > 0); 25 | for (int i = 0; i < size; ++i) 26 | ary[i] = HostToNetl(ary[i]); 27 | } 28 | 29 | inline unsigned int HostToNeti(unsigned int i) 30 | { 31 | return static_cast(::htonl(i)); 32 | } 33 | 34 | inline int HostToNeti(int i) 35 | { 36 | return static_cast(::htonl(i)); 37 | } 38 | 39 | template 40 | inline void HostToNeti(T *ary, int size) 41 | { 42 | assert(ary && size > 0); 43 | for (int i = 0; i < size; ++i) 44 | ary[i] = HostToNeti(ary[i]); 45 | } 46 | 47 | inline unsigned short HostToNets(unsigned short s) 48 | { 49 | return ::htons(s); 50 | } 51 | 52 | inline short HostToNets(short s) 53 | { 54 | return static_cast(::htons(s)); 55 | } 56 | 57 | template 58 | inline void HostToNets(T *ary, int size) 59 | { 60 | assert(ary && size > 0); 61 | for (int i = 0; i < size; ++i) 62 | ary[i] = HostToNets(ary[i]); 63 | } 64 | 65 | inline unsigned long NetToHostl(unsigned long l) 66 | { 67 | return ::ntohl(l); 68 | } 69 | 70 | inline long NetToHostl(long l) 71 | { 72 | return static_cast(::ntohl(l)); 73 | } 74 | 75 | template 76 | inline void NetToHostl(T *ary, int size) 77 | { 78 | assert(ary && size > 0); 79 | for (int i = 0; i < size; ++i) 80 | ary[i] = NetToHostl(ary[i]); 81 | } 82 | 83 | inline unsigned int NetToHosti(unsigned int i) 84 | { 85 | return static_cast(::ntohl(i)); 86 | } 87 | 88 | inline int NetToHosti(int i) 89 | { 90 | return static_cast(::ntohl(i)); 91 | } 92 | 93 | template 94 | inline void NetToHosti(T *ary, int size) 95 | { 96 | assert(ary && size > 0); 97 | for (int i = 0; i < size; ++i) 98 | ary[i] = NetToHosti(ary[i]); 99 | } 100 | 101 | inline unsigned short NetToHosts(unsigned short s) 102 | { 103 | return ::ntohs(s); 104 | } 105 | 106 | inline short NetToHosts(short s) 107 | { 108 | return static_cast(::ntohs(s)); 109 | } 110 | 111 | template 112 | inline void NetToHosts(T *ary, int size) 113 | { 114 | assert(ary && size > 0); 115 | for (int i = 0; i < size; ++i) 116 | ary[i] = NetToHosts(ary[i]); 117 | } 118 | 119 | inline unsigned long GetPendingDataSize(const BaseSocket& base_socket) 120 | { 121 | unsigned long size = 0; 122 | ::ioctlsocket(base_socket.Get(), FIONREAD, &size); 123 | return size; 124 | } 125 | 126 | } // namespace net 127 | } // namespace bitwave 128 | 129 | #endif // NET_HELPER_H 130 | -------------------------------------------------------------------------------- /net/ResolveService.h: -------------------------------------------------------------------------------- 1 | #ifndef RESOLVE_SERVICE_H 2 | #define RESOLVE_SERVICE_H 3 | 4 | #include "ServiceBase.h" 5 | #include "AddressResolver.h" 6 | #include "../base/BaseTypes.h" 7 | #include "../base/ScopePtr.h" 8 | #include "../thread/Atomic.h" 9 | #include "../thread/Thread.h" 10 | #include "../thread/Event.h" 11 | #include "../thread/Mutex.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace bitwave { 18 | namespace net { 19 | 20 | // a service class for resolve address 21 | class ResolveService : public BasicService 22 | { 23 | public: 24 | typedef std::tr1::function ResolveHandler; 26 | 27 | class AsyncResolver 28 | { 29 | public: 30 | AsyncResolver(const std::string& nodename, 31 | const std::string& servname, 32 | const ResolveHint& hint, 33 | const ResolveHandler& handler) 34 | : nodename_(nodename), 35 | servname_(servname), 36 | hint_(hint), 37 | handler_(handler), 38 | result_() 39 | { 40 | } 41 | 42 | void Resolve() 43 | { 44 | try 45 | { 46 | result_ = ResolveAddress(nodename_, servname_, hint_); 47 | } 48 | catch(const AddressResolveException&) 49 | { 50 | // we do nothing, because can not resolve the address 51 | } 52 | } 53 | 54 | void CallHandler() 55 | { 56 | handler_(nodename_, servname_, result_); 57 | } 58 | 59 | private: 60 | std::string nodename_; 61 | std::string servname_; 62 | ResolveHint hint_; 63 | ResolveHandler handler_; 64 | ResolveResult result_; 65 | }; 66 | 67 | ResolveService() 68 | : thread_exit_flag_(0), 69 | resolve_thread_(), 70 | event_(), 71 | resolver_list_(), 72 | resolver_list_mutex_(), 73 | result_list_(), 74 | result_list_mutex_() 75 | { 76 | InitResolveThread(); 77 | } 78 | 79 | ~ResolveService() 80 | { 81 | AtomicAdd(&thread_exit_flag_, 1); 82 | event_.SetEvent(); 83 | resolve_thread_->Join(); 84 | } 85 | 86 | // request an async resolve 87 | void AsyncResolve(const std::string& nodename, 88 | const std::string& servname, 89 | const ResolveHint& hint, 90 | const ResolveHandler& handler) 91 | { 92 | PrepareResolve(nodename, servname, hint, handler); 93 | RequestResolve(); 94 | } 95 | 96 | // prepare a resolver, and do not resolve immediately, 97 | // call RequestResolve to begin resolvers 98 | void PrepareResolve(const std::string& nodename, 99 | const std::string& servname, 100 | const ResolveHint& hint, 101 | const ResolveHandler& handler) 102 | { 103 | // add new resolve request data in resolver_list_ 104 | SpinlocksMutexLocker locker(resolver_list_mutex_); 105 | AsyncResolver new_resolver(nodename, servname, hint, handler); 106 | resolver_list_.push_back(new_resolver); 107 | } 108 | 109 | // request resolve all prepared AsyncResolvers by PrepareResolve 110 | void RequestResolve() 111 | { 112 | // SetEvent then ResolveThread could begin resolve 113 | event_.SetEvent(); 114 | } 115 | 116 | private: 117 | typedef ScopePtr ThreadPtr; 118 | typedef std::list AsyncResolverList; 119 | 120 | virtual void DoRun() 121 | { 122 | ProcessResult(); 123 | } 124 | 125 | void InitResolveThread() 126 | { 127 | resolve_thread_.Reset(new Thread(std::tr1::bind(&ResolveService::ResolveThread, this))); 128 | } 129 | 130 | unsigned ResolveThread() 131 | { 132 | while (true) 133 | { 134 | if (event_.WaitForever()) 135 | { 136 | if (AtomicAdd(&thread_exit_flag_, 0)) 137 | break; 138 | 139 | AsyncResolverList data; 140 | 141 | { 142 | // get all resolve request data 143 | SpinlocksMutexLocker locker(resolver_list_mutex_); 144 | data.swap(resolver_list_); 145 | } 146 | 147 | std::for_each(data.begin(), data.end(), 148 | std::mem_fun_ref(&AsyncResolver::Resolve)); 149 | 150 | { 151 | SpinlocksMutexLocker locker(result_list_mutex_); 152 | result_list_.splice(result_list_.end(), data); 153 | } 154 | } 155 | } 156 | 157 | return 0; 158 | } 159 | 160 | void ProcessResult() 161 | { 162 | AsyncResolverList result; 163 | 164 | { 165 | SpinlocksMutexLocker locker(result_list_mutex_); 166 | result.swap(result_list_); 167 | } 168 | 169 | std::for_each(result.begin(), result.end(), 170 | std::mem_fun_ref(&AsyncResolver::CallHandler)); 171 | } 172 | 173 | volatile long thread_exit_flag_; 174 | ThreadPtr resolve_thread_; 175 | AutoResetEvent event_; 176 | AsyncResolverList resolver_list_; 177 | SpinlocksMutex resolver_list_mutex_; 178 | AsyncResolverList result_list_; 179 | SpinlocksMutex result_list_mutex_; 180 | }; 181 | 182 | } // namespace net 183 | } // namespace bitwave 184 | 185 | #endif // RESOLVE_SERVICE_H 186 | -------------------------------------------------------------------------------- /net/ServiceBase.h: -------------------------------------------------------------------------------- 1 | #ifndef SERVICE_BASE_H 2 | #define SERVICE_BASE_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include 6 | 7 | namespace bitwave { 8 | namespace net { 9 | 10 | // all net service's id type 11 | class ServiceId {}; 12 | 13 | // all net service's base class 14 | class ServiceBase : private NotCopyable 15 | { 16 | public: 17 | ServiceBase() 18 | : next_service_(0) 19 | { 20 | } 21 | 22 | virtual ~ServiceBase() 23 | { 24 | } 25 | 26 | void AddService(ServiceBase *service) 27 | { 28 | assert(service); 29 | if (next_service_) 30 | next_service_->AddService(service); 31 | else 32 | next_service_ = service; 33 | } 34 | 35 | template 36 | Service * GetService() 37 | { 38 | if (&Service::id_ == &GetServiceId()) 39 | return static_cast(this); 40 | else if (next_service_) 41 | return next_service_->GetService(); 42 | else 43 | return 0; 44 | } 45 | 46 | void Run() 47 | { 48 | DoRun(); 49 | if (next_service_) 50 | next_service_->Run(); 51 | } 52 | 53 | private: 54 | virtual void DoRun() = 0; 55 | virtual const ServiceId& GetServiceId() const = 0; 56 | 57 | ServiceBase *next_service_; 58 | }; 59 | 60 | // template Service base class define ServiceId 61 | template 62 | class BasicService : public ServiceBase 63 | { 64 | public: 65 | static ServiceId id_; 66 | 67 | private: 68 | virtual const ServiceId& GetServiceId() const 69 | { 70 | return id_; 71 | } 72 | }; 73 | 74 | template 75 | ServiceId BasicService::id_; 76 | 77 | template 78 | class ServicePtr 79 | { 80 | public: 81 | explicit ServicePtr(ServiceBase& service) 82 | : service_(0) 83 | { 84 | service_ = service.GetService(); 85 | } 86 | 87 | operator bool () const 88 | { 89 | return service_ != 0; 90 | } 91 | 92 | Service * operator -> () const 93 | { 94 | return service_; 95 | } 96 | 97 | Service& operator * () const 98 | { 99 | return *service_; 100 | } 101 | 102 | private: 103 | Service *service_; 104 | }; 105 | 106 | } // namespace net 107 | } // namespace bitwave 108 | 109 | #endif // SERVICE_BASE_H 110 | -------------------------------------------------------------------------------- /net/Socket.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_H 2 | #define SOCKET_H 3 | 4 | #include "Address.h" 5 | #include "NetException.h" 6 | 7 | namespace bitwave { 8 | namespace net { 9 | 10 | // a template class associate socket implement with service 11 | // and provide async-operations for socket implement by service 12 | template 13 | class Socket 14 | { 15 | public: 16 | typedef ImplementType implement_type; 17 | typedef ServiceType service_type; 18 | 19 | // construct a new socket associate with service 20 | explicit Socket(service_type& service) 21 | : service_(service), 22 | implement_(service) 23 | { 24 | } 25 | 26 | // construct a socket handler associate with service and exist socket 27 | Socket(service_type& service, const implement_type& implement) 28 | : service_(service), 29 | implement_(implement) 30 | { 31 | } 32 | 33 | template 34 | void AsyncConnect(const Address& address, const Port& port, const Handler& handler) 35 | { 36 | service_.AsyncConnect(implement_, address, port, handler); 37 | } 38 | 39 | template 40 | void AsyncReceive(Buffer& buffer, const Handler& handler) 41 | { 42 | service_.AsyncReceive(implement_, buffer, handler); 43 | } 44 | 45 | template 46 | void AsyncSend(const Buffer& buffer, const Handler& handler) 47 | { 48 | service_.AsyncSend(implement_, buffer, handler); 49 | } 50 | 51 | service_type& GetService() const 52 | { 53 | return service_; 54 | } 55 | 56 | void Close() 57 | { 58 | implement_.Close(); 59 | } 60 | 61 | const implement_type& GetImplement() const 62 | { 63 | return implement_; 64 | } 65 | 66 | private: 67 | service_type& service_; 68 | implement_type implement_; 69 | }; 70 | 71 | // a template Listener class associate socket implement with service 72 | // and provide AsyncAccept operation for socket implement by service 73 | template 74 | class Listener 75 | { 76 | public: 77 | typedef ImplementType implement_type; 78 | typedef ServiceType service_type; 79 | 80 | // construct a Listener associate with service and listen address, port 81 | Listener(const Address& address, const Port& port, service_type& service) 82 | : address_(address), 83 | port_(port), 84 | service_(service), 85 | implement_(service) 86 | { 87 | sockaddr_in name = Ipv4Address(address_, port_); 88 | int result = ::bind(implement_.Get(), (sockaddr *)&name, sizeof(name)); 89 | if (result == SOCKET_ERROR) 90 | throw NetException(BIND_LISTENER_SOCKET_ERROR); 91 | 92 | result = ::listen(implement_.Get(), SOMAXCONN); 93 | if (result == SOCKET_ERROR) 94 | throw NetException(LISTEN_LISTENER_SOCKET_ERROR); 95 | } 96 | 97 | template 98 | void AsyncAccept(const Handler& handler) 99 | { 100 | service_.AsyncAccept(implement_, handler); 101 | } 102 | 103 | service_type& GetService() const 104 | { 105 | return service_; 106 | } 107 | 108 | void Close() 109 | { 110 | implement_.Close(); 111 | } 112 | 113 | const implement_type& GetImplement() const 114 | { 115 | return implement_; 116 | } 117 | 118 | private: 119 | Address address_; 120 | Port port_; 121 | service_type& service_; 122 | implement_type implement_; 123 | }; 124 | 125 | } // namespace net 126 | } // namespace bitwave 127 | 128 | #endif // SOCKET_H 129 | -------------------------------------------------------------------------------- /net/StreamUnpacker.h: -------------------------------------------------------------------------------- 1 | #ifndef STREAM_UNPACKER_H 2 | #define STREAM_UNPACKER_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include 6 | #include 7 | 8 | namespace bitwave { 9 | namespace net { 10 | 11 | // a template class use UnpackRuler to unpack tcp stream data, if unpack 12 | // success, then call the OnUnpackOne function 13 | template 14 | class StreamUnpacker : private NotCopyable 15 | { 16 | public: 17 | typedef std::vector Stream; 18 | 19 | StreamUnpacker() 20 | : stream_buffer_() 21 | { 22 | stream_buffer_.reserve(base_buffer_size); 23 | } 24 | 25 | // Tcp stream data arrival, then call this function to unpack data 26 | void StreamDataArrive(const char *data, std::size_t size) 27 | { 28 | assert(data); 29 | stream_buffer_.insert(stream_buffer_.end(), data, data + size); 30 | 31 | std::size_t pack_start = 0; 32 | while (true) 33 | { 34 | std::size_t pack_len = 0; 35 | std::size_t pack_remain = stream_buffer_.size() - pack_start; 36 | if (pack_remain == 0) break; 37 | 38 | bool is_can_unpack = UnpackRuler::CanUnpack( 39 | &stream_buffer_[pack_start], 40 | pack_remain, &pack_len); 41 | if (!is_can_unpack) break; 42 | 43 | OnUnpackOne(&stream_buffer_[pack_start], pack_len); 44 | pack_start += pack_len; 45 | } 46 | 47 | Stream::iterator unpacked_begin = stream_buffer_.begin(); 48 | Stream::iterator unpacked_end = unpacked_begin + pack_start; 49 | stream_buffer_.erase(unpacked_begin, unpacked_end); 50 | } 51 | 52 | // clear tcp stream buffer 53 | void Clear() 54 | { 55 | stream_buffer_.clear(); 56 | } 57 | 58 | private: 59 | virtual void OnUnpackOne(const char *data, std::size_t size) = 0; 60 | 61 | Stream stream_buffer_; 62 | }; 63 | 64 | } // namespace net 65 | } // namespace bitwave 66 | 67 | #endif // STREAM_UNPACKER_H 68 | -------------------------------------------------------------------------------- /net/TimerService.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_SERVICE_H 2 | #define TIMER_SERVICE_H 3 | 4 | #include "ServiceBase.h" 5 | #include "../timer/TimerQueue.h" 6 | 7 | namespace bitwave { 8 | namespace net { 9 | 10 | class TimerService : public BasicService 11 | { 12 | public: 13 | typedef TimerQueue::TimerType TimerType; 14 | 15 | void AddTimer(TimerType *new_timer) 16 | { 17 | timer_queue_.AddTimer(new_timer); 18 | } 19 | 20 | void DelTimer(TimerType *timer) 21 | { 22 | timer_queue_.DelTimer(timer); 23 | } 24 | 25 | private: 26 | virtual void DoRun() 27 | { 28 | timer_queue_.Schedule(); 29 | } 30 | 31 | TimerQueue timer_queue_; 32 | }; 33 | 34 | } // namespace net 35 | } // namespace bitwave 36 | 37 | #endif // TIMER_SERVICE_H 38 | -------------------------------------------------------------------------------- /net/WinSockIniter.h: -------------------------------------------------------------------------------- 1 | #ifndef WIN_SOCK_INITER_H 2 | #define WIN_SOCK_INITER_H 3 | 4 | #include 5 | 6 | namespace bitwave { 7 | namespace net { 8 | 9 | class WinSockIniter 10 | { 11 | public: 12 | WinSockIniter() 13 | { 14 | ::WSAStartup(MAKEWORD(2, 2), &wsadata_); 15 | } 16 | 17 | ~WinSockIniter() 18 | { 19 | ::WSACleanup(); 20 | } 21 | 22 | private: 23 | WSADATA wsadata_; 24 | }; 25 | 26 | } // namespace net 27 | } // namespace bitwave 28 | 29 | #endif // WIN_SOCK_INITER_H 30 | -------------------------------------------------------------------------------- /protocol/HttpException.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_EXCEPTION_H 2 | #define HTTP_EXCEPTION_H 3 | 4 | #include "../base/BaseTypes.h" 5 | 6 | namespace bitwave { 7 | namespace http { 8 | 9 | enum URIExceptionCode 10 | { 11 | NO_SCHEME, 12 | NO_AUTHORITY, 13 | }; 14 | 15 | // an exception class for URI 16 | class URIException : public BaseException 17 | { 18 | public: 19 | explicit URIException(int code) 20 | : BaseException(code) 21 | { 22 | } 23 | }; 24 | 25 | // an exception class of construct Response 26 | class ResponseException : public BaseException 27 | { 28 | public: 29 | explicit ResponseException(const std::string& w) 30 | : BaseException(w) 31 | { 32 | } 33 | }; 34 | 35 | } // namespace http 36 | } // namespace bitwave 37 | 38 | #endif // HTTP_EXCEPTION_H 39 | -------------------------------------------------------------------------------- /protocol/Request.cpp: -------------------------------------------------------------------------------- 1 | #include "Request.h" 2 | 3 | namespace bitwave { 4 | namespace http { 5 | 6 | Request::Request(const URI& uri) 7 | : text_() 8 | { 9 | text_.append("GET "); 10 | text_.append(uri.GetQueryString()); 11 | text_.append(" HTTP/1.1\r\n"); 12 | text_.append("Host: "); 13 | text_.append(uri.GetHost()); 14 | text_.append("\r\n\r\n"); 15 | } 16 | 17 | } // namespace http 18 | } // namespace bitwave 19 | -------------------------------------------------------------------------------- /protocol/Request.h: -------------------------------------------------------------------------------- 1 | #ifndef REQUEST_H 2 | #define REQUEST_H 3 | 4 | #include "URI.h" 5 | #include 6 | 7 | namespace bitwave { 8 | namespace http { 9 | 10 | // this is a simply http GET request just hold an URI. 11 | class Request 12 | { 13 | public: 14 | explicit Request(const URI& uri); 15 | 16 | std::string GetRequestText() const 17 | { 18 | return text_; 19 | } 20 | 21 | private: 22 | std::string text_; 23 | }; 24 | 25 | } // namespace http 26 | } // namespace bitwave 27 | 28 | #endif // REQUEST_H 29 | -------------------------------------------------------------------------------- /protocol/Response.h: -------------------------------------------------------------------------------- 1 | #ifndef RESPONSE_H 2 | #define RESPONSE_H 3 | 4 | #include 5 | 6 | namespace bitwave { 7 | namespace http { 8 | 9 | // a simply http Response unpack ruler to unpack tcp stream 10 | class ResponseUnpackRuler 11 | { 12 | public: 13 | static bool CanUnpack(const char *stream, 14 | std::size_t size, std::size_t *pack_len); 15 | }; 16 | 17 | class Response 18 | { 19 | public: 20 | enum { 21 | INFORMATION = 1, 22 | SUCCESS, 23 | REDIRECTION, 24 | CLIENT_ERROR, 25 | SERVER_ERROR 26 | }; 27 | 28 | Response(const char *stream, std::size_t size); 29 | 30 | int GetStatusCode() const; 31 | int GetStatusCodeType() const; 32 | double GetHttpVersion() const; 33 | std::string GetReasonPhrase() const; 34 | 35 | // get response content, pointer to content buffer, 36 | // return zero when the response has no content 37 | const char * GetContentBufPointer() const; 38 | std::size_t GetContentSize() const; 39 | 40 | private: 41 | typedef std::vector ContentBuffer; 42 | 43 | int status_code_; 44 | int status_code_type_; 45 | double http_version_; 46 | std::string reason_phrase_; 47 | ContentBuffer content_buffer_; 48 | }; 49 | 50 | } // namespace http 51 | } // namespace bitwave 52 | 53 | #endif // RESPONSE_H 54 | -------------------------------------------------------------------------------- /protocol/URI.cpp: -------------------------------------------------------------------------------- 1 | #include "URI.h" 2 | #include "HttpException.h" 3 | #include 4 | 5 | namespace { 6 | 7 | // convert lower 4 bits to a hex char 8 | char X16(int c) 9 | { 10 | c &= 0x0F; 11 | if (c >= 0 && c <= 9) 12 | return '0' + c; 13 | c -= 10; 14 | return 'A' + c; 15 | } 16 | 17 | } // namespace 18 | 19 | namespace bitwave { 20 | namespace http { 21 | 22 | void URI::AddQuery(const char *kbegin, const char *kend, 23 | const char *vbegin, const char *vend) 24 | { 25 | AppendQueryBeginChar(); 26 | AppendEscapeData(kbegin, kend); 27 | AppendQueryLinkChar(); 28 | AppendEscapeData(vbegin, vend); 29 | ++numofquery_; 30 | } 31 | 32 | bool URI::IsUnReserved(char c) const 33 | { 34 | return isalnum((unsigned char)c) || c == '.' || c == '_' || c == '~' || c == '-'; 35 | } 36 | 37 | void URI::AppendPercentEncode(char c) 38 | { 39 | char str[4] = { 0 }; 40 | str[0] = '%'; 41 | str[1] = X16(c >> 4); 42 | str[2] = X16(c); 43 | query_.append(str); 44 | } 45 | 46 | void URI::AppendQueryLinkChar() 47 | { 48 | query_.push_back('='); 49 | } 50 | 51 | void URI::AppendQueryBeginChar() 52 | { 53 | if (numofquery_ == 0) 54 | query_.push_back('?'); 55 | else 56 | query_.push_back('&'); 57 | } 58 | 59 | void URI::AppendEscapeData(const char *begin, const char *end) 60 | { 61 | for (; begin != end; ++begin) 62 | { 63 | if (IsUnReserved(*begin)) 64 | query_.push_back(*begin); 65 | else 66 | AppendPercentEncode(*begin); 67 | } 68 | } 69 | 70 | void URI::ParseHostFromUri() 71 | { 72 | std::string::size_type begin = query_.find("://"); 73 | if (begin == std::string::npos) 74 | throw URIException(NO_SCHEME); 75 | else if (begin + 3 >= query_.size()) 76 | throw URIException(NO_AUTHORITY); 77 | 78 | begin += 3; 79 | std::string::size_type end = query_.find_first_of("/?#", begin); 80 | if (end == std::string::npos) 81 | { 82 | host_ = query_.substr(begin); 83 | query_ = "/"; 84 | } 85 | else 86 | { 87 | host_ = query_.substr(begin, end - begin); 88 | query_ = query_.substr(end); 89 | } 90 | 91 | end = host_.find(':'); 92 | if (end != std::string::npos) 93 | host_.erase(end, host_.size() - end); 94 | } 95 | 96 | } // namespace http 97 | } // namespace bitwave 98 | -------------------------------------------------------------------------------- /protocol/URI.h: -------------------------------------------------------------------------------- 1 | #ifndef URI_H 2 | #define URI_H 3 | 4 | #include 5 | #include 6 | 7 | namespace bitwave { 8 | namespace http { 9 | 10 | // a simply URI class to present a uri. 11 | // use a valid url string to construct a object, then we can get host 12 | // from the url, and we can add query to URI, then we can get a query uri string 13 | class URI 14 | { 15 | public: 16 | explicit URI(const std::string& url) 17 | : numofquery_(0), 18 | query_(url), 19 | host_() 20 | { 21 | ParseHostFromUri(); 22 | } 23 | 24 | std::string GetHost() const 25 | { 26 | return host_; 27 | } 28 | 29 | std::string GetQueryString() const 30 | { 31 | return query_; 32 | } 33 | 34 | void AddQuery(const char *kbegin, const char *kend, 35 | const char *vbegin, const char *vend); 36 | 37 | template 38 | void AddQuery(const Key& key, const Value& value) 39 | { 40 | std::string kstr = TransformToString(key); 41 | std::string vstr = TransformToString(value); 42 | AddQuery(kstr.c_str(), kstr.c_str() + kstr.size(), vstr.c_str(), vstr.c_str() + vstr.size()); 43 | } 44 | 45 | template 46 | void AddQuery(const Key& key, const char *binary, int binlen) 47 | { 48 | std::string kstr = TransformToString(key); 49 | AddQuery(kstr.c_str(), kstr.c_str() + kstr.size(), binary, binary + binlen); 50 | } 51 | 52 | private: 53 | template 54 | std::string TransformToString(const T& t) const 55 | { 56 | std::ostringstream oss; 57 | oss << t; 58 | return oss.str(); 59 | } 60 | 61 | bool IsUnReserved(char c) const; 62 | void AppendPercentEncode(char c); 63 | void AppendQueryLinkChar(); 64 | void AppendQueryBeginChar(); 65 | void AppendEscapeData(const char *begin, const char *end); 66 | void ParseHostFromUri(); 67 | 68 | int numofquery_; 69 | std::string query_; 70 | std::string host_; 71 | }; 72 | 73 | } // namespace http 74 | } // namespace bitwave 75 | 76 | #endif // URI_H 77 | -------------------------------------------------------------------------------- /sha1/NetSha1Value.cpp: -------------------------------------------------------------------------------- 1 | #include "NetSha1Value.h" 2 | #include "Sha1Value.h" 3 | #include "../net/NetHelper.h" 4 | #include 5 | 6 | namespace bitwave { 7 | 8 | Sha1Value NetByteOrder(const Sha1Value& value) 9 | { 10 | Sha1Value result(value); 11 | unsigned *v = reinterpret_cast( 12 | const_cast(result.GetData()) 13 | ); 14 | net::HostToNeti(v, result.GetDataSize() / sizeof(unsigned)); 15 | 16 | return result; 17 | } 18 | 19 | Sha1Value NetStreamToSha1Value(const char *stream) 20 | { 21 | Sha1Value result; 22 | unsigned *v = reinterpret_cast( 23 | const_cast(result.GetData()) 24 | ); 25 | memcpy(v, stream, result.GetDataSize()); 26 | net::NetToHosti(v, result.GetDataSize() / sizeof(unsigned)); 27 | 28 | return result; 29 | } 30 | 31 | } // namespace bitwave 32 | -------------------------------------------------------------------------------- /sha1/NetSha1Value.h: -------------------------------------------------------------------------------- 1 | #ifndef NET_SHA1_VALUE_H 2 | #define NET_SHA1_VALUE_H 3 | 4 | namespace bitwave { 5 | 6 | class Sha1Value; 7 | 8 | Sha1Value NetByteOrder(const Sha1Value& value); 9 | Sha1Value NetStreamToSha1Value(const char *stream); 10 | 11 | } // namespace bitwave 12 | 13 | #endif // NET_SHA1_VALUE_H 14 | -------------------------------------------------------------------------------- /sha1/Sha1Value.cpp: -------------------------------------------------------------------------------- 1 | #include "Sha1Value.h" 2 | #include "sha1.h" 3 | #include 4 | 5 | namespace bitwave { 6 | 7 | Sha1Value::Sha1Value() 8 | { 9 | memset(value_, 0, sizeof(value_)); 10 | } 11 | 12 | Sha1Value::Sha1Value(const unsigned *value_ary) 13 | { 14 | memcpy(value_, value_ary, sizeof(value_)); 15 | } 16 | 17 | Sha1Value::Sha1Value(const char *begin, const char *end) 18 | { 19 | Calculate(begin, end - begin); 20 | } 21 | 22 | Sha1Value::Sha1Value(const char *begin, std::size_t length) 23 | { 24 | Calculate(begin, length); 25 | } 26 | 27 | std::string Sha1Value::GetReadableString() const 28 | { 29 | std::ostringstream oss; 30 | oss << std::hex; 31 | for (int i = 0; i < 5; ++i) 32 | oss << value_[i]; 33 | return oss.str(); 34 | } 35 | 36 | const char * Sha1Value::GetData() const 37 | { 38 | return reinterpret_cast(value_); 39 | } 40 | 41 | int Sha1Value::GetDataSize() const 42 | { 43 | return sizeof(value_); 44 | } 45 | 46 | void Sha1Value::Calculate(const char *begin, std::size_t length) 47 | { 48 | SHA1 sha1; 49 | sha1.Input(begin, length); 50 | sha1.Result(value_); 51 | } 52 | 53 | } // namespace bitwave 54 | -------------------------------------------------------------------------------- /sha1/Sha1Value.h: -------------------------------------------------------------------------------- 1 | #ifndef SHA1_VALUE_H 2 | #define SHA1_VALUE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace bitwave { 8 | 9 | class Sha1Value 10 | { 11 | public: 12 | Sha1Value(); 13 | explicit Sha1Value(const unsigned *value_ary); 14 | Sha1Value(const char *begin, const char *end); 15 | Sha1Value(const char *begin, std::size_t length); 16 | 17 | std::string GetReadableString() const; 18 | const char * GetData() const; 19 | int GetDataSize() const; 20 | 21 | friend bool operator == (const Sha1Value& left, const Sha1Value& right) 22 | { 23 | return memcmp(left.value_, right.value_, sizeof(left.value_)) == 0; 24 | } 25 | 26 | friend bool operator != (const Sha1Value& left, const Sha1Value& right) 27 | { 28 | return !(left == right); 29 | } 30 | 31 | friend bool operator < (const Sha1Value& left, const Sha1Value& right) 32 | { 33 | return memcmp(left.value_, right.value_, sizeof(left.value_)) < 0; 34 | } 35 | 36 | friend bool operator > (const Sha1Value& left, const Sha1Value& right) 37 | { 38 | return memcmp(left.value_, right.value_, sizeof(left.value_)) > 0; 39 | } 40 | 41 | private: 42 | void Calculate(const char *begin, std::size_t length); 43 | unsigned value_[5]; 44 | }; 45 | 46 | } // namespace bitwave 47 | 48 | #endif // SHA1_VALUE_H 49 | -------------------------------------------------------------------------------- /sha1/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 1998 2 | Paul E. Jones 3 | All Rights Reserved. 4 | 5 | This software is licensed as "freeware." Permission to distribute 6 | this software in source and binary forms is hereby granted without 7 | a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED 8 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 10 | THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING 11 | FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, 12 | BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. 13 | 14 | -------------------------------------------------------------------------------- /sha1/sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.h 3 | * 4 | * Copyright (C) 1998 5 | * Paul E. Jones 6 | * All Rights Reserved. 7 | * 8 | ***************************************************************************** 9 | * $Id: sha1.h,v 1.6 2004/03/27 18:02:26 paulej Exp $ 10 | ***************************************************************************** 11 | * 12 | * Description: 13 | * This class implements the Secure Hashing Standard as defined 14 | * in FIPS PUB 180-1 published April 17, 1995. 15 | * 16 | * Many of the variable names in this class, especially the single 17 | * character names, were used because those were the names used 18 | * in the publication. 19 | * 20 | * Please read the file sha1.cpp for more information. 21 | * 22 | */ 23 | 24 | #ifndef _SHA1_H_ 25 | #define _SHA1_H_ 26 | 27 | class SHA1 28 | { 29 | 30 | public: 31 | 32 | SHA1(); 33 | virtual ~SHA1(); 34 | 35 | /* 36 | * Re-initialize the class 37 | */ 38 | void Reset(); 39 | 40 | /* 41 | * Returns the message digest 42 | */ 43 | bool Result(unsigned *message_digest_array); 44 | 45 | /* 46 | * Provide input to SHA1 47 | */ 48 | void Input( const unsigned char *message_array, 49 | unsigned length); 50 | void Input( const char *message_array, 51 | unsigned length); 52 | void Input(unsigned char message_element); 53 | void Input(char message_element); 54 | SHA1& operator<<(const char *message_array); 55 | SHA1& operator<<(const unsigned char *message_array); 56 | SHA1& operator<<(const char message_element); 57 | SHA1& operator<<(const unsigned char message_element); 58 | 59 | private: 60 | 61 | /* 62 | * Process the next 512 bits of the message 63 | */ 64 | void ProcessMessageBlock(); 65 | 66 | /* 67 | * Pads the current message block to 512 bits 68 | */ 69 | void PadMessage(); 70 | 71 | /* 72 | * Performs a circular left shift operation 73 | */ 74 | inline unsigned CircularShift(int bits, unsigned word); 75 | 76 | unsigned H[5]; // Message digest buffers 77 | 78 | unsigned Length_Low; // Message length in bits 79 | unsigned Length_High; // Message length in bits 80 | 81 | unsigned char Message_Block[64]; // 512-bit message blocks 82 | int Message_Block_Index; // Index into message block array 83 | 84 | bool Computed; // Is the digest computed? 85 | bool Corrupted; // Is the message digest corruped? 86 | 87 | }; 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /test/TestAddressResolver.cpp: -------------------------------------------------------------------------------- 1 | #include "../net/AddressResolver.h" 2 | #include "../net/WinSockIniter.h" 3 | #include 4 | 5 | using namespace bittorrent; 6 | using namespace net; 7 | 8 | int main(int argc, char **argv) 9 | { 10 | if (argc != 2) 11 | { 12 | std::cout << "useage: test addressname" << std::endl; 13 | return 0; 14 | } 15 | 16 | WinSockIniter initer; 17 | 18 | try 19 | { 20 | ResolveHint hint(AF_INET, SOCK_STREAM, IPPROTO_TCP); 21 | ResolveResult result = ResolveAddress(argv[1], "", hint); 22 | 23 | std::size_t count = 0; 24 | for (ResolveResult::iterator it = result.begin(); 25 | it != result.end(); ++it) 26 | { 27 | std::cout << "ai_family: " << it->ai_family << std::endl; 28 | std::cout << "ai_socktype: " << it->ai_socktype << std::endl; 29 | std::cout << "ai_protocol: " << it->ai_protocol << std::endl; 30 | std::cout << "ai_canonname: " << (it->ai_canonname ? it->ai_canonname : "") << std::endl; 31 | std::cout << std::endl; 32 | ++count; 33 | } 34 | 35 | std::cout << "there are " << count << " address." << std::endl; 36 | } 37 | catch (const AddressResolveException& are) 38 | { 39 | std::cerr << "exception EAI code is: " << are.get_exception_code() << std::endl; 40 | std::cerr << "address is: " << are.what() << std::endl; 41 | } 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /test/TestBenType.cpp: -------------------------------------------------------------------------------- 1 | #include "../unittest/UnitTest.h" 2 | #include "../core/bencode/BenTypes.h" 3 | #include 4 | 5 | using namespace bittorrent; 6 | using namespace bittorrent::core; 7 | using namespace bittorrent::core::bentypes; 8 | 9 | TEST_CASE(BenInteger) 10 | { 11 | const char *beninteger = "i3e"; 12 | BenTypesStreamBuf buf(beninteger, strlen(beninteger)); 13 | BenTypesStreamBuf::const_iterator begin = buf.begin(); 14 | BenTypesStreamBuf::const_iterator end = buf.end(); 15 | BenInteger i(begin, end); 16 | CHECK_TRUE(i.GetValue() == 3); 17 | } 18 | 19 | TEST_CASE(BenString) 20 | { 21 | const char *benstring = "4:spam"; 22 | BenTypesStreamBuf buf(benstring, strlen(benstring)); 23 | BenTypesStreamBuf::const_iterator begin = buf.begin(); 24 | BenTypesStreamBuf::const_iterator end = buf.end(); 25 | BenString s(begin, end); 26 | CHECK_TRUE(s.std_string() == "spam"); 27 | } 28 | 29 | TEST_CASE(BenList) 30 | { 31 | const char *benlist = "l4:spam4:eggse"; 32 | BenTypesStreamBuf buf(benlist, strlen(benlist)); 33 | BenTypesStreamBuf::const_iterator begin = buf.begin(); 34 | BenTypesStreamBuf::const_iterator end = buf.end(); 35 | BenList l(begin, end); 36 | CHECK_TRUE(l.size() == 2); 37 | 38 | std::vector benstrings; 39 | l.AllElementPtr(&benstrings); 40 | CHECK_TRUE(benstrings.size() == 2); 41 | CHECK_TRUE(benstrings[0]->std_string() == "spam"); 42 | CHECK_TRUE(benstrings[1]->std_string() == "eggs"); 43 | } 44 | 45 | TEST_CASE(BenDictionary) 46 | { 47 | const char *bendict = "d3:cow3:moo4:spam4:eggse"; 48 | BenTypesStreamBuf buf(bendict, strlen(bendict)); 49 | BenTypesStreamBuf::const_iterator begin = buf.begin(); 50 | BenTypesStreamBuf::const_iterator end = buf.end(); 51 | BenDictionary d(begin, end); 52 | CHECK_TRUE(d.size() == 2); 53 | BenDictionary::value_type v1 = d["cow"]; 54 | BenDictionary::value_type v2 = d["spam"]; 55 | BenString *pv1 = dynamic_cast(v1.get()); 56 | BenString *pv2 = dynamic_cast(v2.get()); 57 | CHECK_TRUE(v1 && pv1); 58 | CHECK_TRUE(v2 && pv2); 59 | CHECK_TRUE(pv1->std_string() == "moo"); 60 | CHECK_TRUE(pv2->std_string() == "eggs"); 61 | } 62 | 63 | int main() 64 | { 65 | TestCollector.RunCases(); 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /test/TestLog.cpp: -------------------------------------------------------------------------------- 1 | #include "../log/LogFactory.h" 2 | #include "../log/Manipulator.h" 3 | #include 4 | 5 | using namespace bitwave; 6 | using namespace log; 7 | 8 | int main() 9 | { 10 | CompositeLogFactory<> log_factory; 11 | CompositeLogFactory<>::LogImplPtr log_impl = log_factory 12 | .MakeTextFileLog("log.txt").AddTimestamp().StoreLog() 13 | .MakeCoutLog().AddTimestamp().StoreLog() 14 | .MakeNullLog().StoreLog() 15 | .FetchLog().LogLeaveFactory(); 16 | Log<> log(log_impl); 17 | 18 | log << "abcdefg" << Endl; 19 | log << 123456 << Endl; 20 | log << 1.23456 << Endl; 21 | log << RecordStarter << std::string("hijklmn") << Endl << RecordEnder; 22 | 23 | log << RecordStarter << "this is record start" << Endl; 24 | log << "this is record" << Endl; 25 | log << "this is record end\n" << RecordEnder; 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /test/TestNetClient.cpp: -------------------------------------------------------------------------------- 1 | #include "../net/IoService.h" 2 | #include "../net/WinSockIniter.h" 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace bittorrent; 8 | using namespace net; 9 | 10 | class Buffer 11 | { 12 | public: 13 | explicit Buffer(int len) 14 | : buffer_(len) 15 | { 16 | } 17 | 18 | char * GetBuffer() const 19 | { 20 | return const_cast(&buffer_[0]); 21 | } 22 | 23 | int BufferLen() const 24 | { 25 | return static_cast(buffer_.size()); 26 | } 27 | 28 | private: 29 | std::vector buffer_; 30 | }; 31 | 32 | class Client 33 | { 34 | public: 35 | explicit Client(IoService& service) 36 | : close_(false), 37 | socket_(service), 38 | send_buffer_(100) 39 | { 40 | Address server_address("127.0.0.1"); 41 | Port server_port(5150); 42 | socket_.AsyncConnect(server_address, server_port, 43 | std::tr1::bind(&Client::ConnectCallback, this, std::tr1::placeholders::_1)); 44 | } 45 | 46 | void ConnectCallback(bool success) 47 | { 48 | if (success) 49 | { 50 | std::cout << "connect server success\n"; 51 | 52 | const char *request = "client request server"; 53 | strncpy(send_buffer_.GetBuffer(), request, send_buffer_.BufferLen()); 54 | socket_.AsyncSend(send_buffer_, 55 | std::tr1::bind(&Client::SendCallback, this, 56 | std::tr1::placeholders::_1, std::tr1::placeholders::_2)); 57 | } 58 | else 59 | { 60 | std::cout << "connect server failure\n"; 61 | Close(); 62 | } 63 | } 64 | 65 | void SendCallback(bool success, int send) 66 | { 67 | if (success) 68 | { 69 | std::cout << "send request success, send: " << send << '\n'; 70 | } 71 | else 72 | { 73 | std::cout << "send request error\n"; 74 | } 75 | 76 | Close(); 77 | } 78 | 79 | bool IsClose() const 80 | { 81 | return close_; 82 | } 83 | 84 | void Close() 85 | { 86 | if (!IsClose()) 87 | { 88 | socket_.Close(); 89 | close_ = true; 90 | } 91 | } 92 | 93 | private: 94 | bool close_; 95 | AsyncSocket socket_; 96 | Buffer send_buffer_; 97 | }; 98 | 99 | int main() 100 | { 101 | WinSockIniter initer; 102 | IoService io_service; 103 | Client client(io_service); 104 | 105 | int i = 0; 106 | while (true) 107 | { 108 | io_service.Run(); 109 | if (client.IsClose()) 110 | break; 111 | ::Sleep(100); 112 | } 113 | 114 | std::cout << "exiting..." << std::endl; 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /test/TestNetServer.cpp: -------------------------------------------------------------------------------- 1 | #include "../net/IoService.h" 2 | #include "../net/WinSockIniter.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace bittorrent; 10 | using namespace net; 11 | 12 | class Buffer 13 | { 14 | public: 15 | explicit Buffer(int len) 16 | : buffer_(len) 17 | { 18 | } 19 | 20 | char * GetBuffer() const 21 | { 22 | return const_cast(&buffer_[0]); 23 | } 24 | 25 | int BufferLen() const 26 | { 27 | return static_cast(buffer_.size()); 28 | } 29 | 30 | private: 31 | std::vector buffer_; 32 | }; 33 | 34 | class Connection 35 | { 36 | public: 37 | Connection(int number, IoService& service, const BaseSocket& new_connect) 38 | : number_(number), 39 | socket_(service, new_connect), 40 | receive_buffer_(100), 41 | send_buffer_(100) 42 | { 43 | Receive(); 44 | } 45 | 46 | private: 47 | void Receive() 48 | { 49 | socket_.AsyncReceive(receive_buffer_, 50 | std::tr1::bind(&Connection::ReceiveCallback, this, 51 | std::tr1::placeholders::_1, std::tr1::placeholders::_2)); 52 | } 53 | 54 | void Send() 55 | { 56 | const char *respond = "Respond"; 57 | strncpy(send_buffer_.GetBuffer(), respond, send_buffer_.BufferLen()); 58 | 59 | socket_.AsyncSend(send_buffer_, 60 | std::tr1::bind(&Connection::SendCallback, this, 61 | std::tr1::placeholders::_1, std::tr1::placeholders::_2)); 62 | } 63 | 64 | void ReceiveCallback(bool success, int received) 65 | { 66 | if (success) 67 | { 68 | std::cout << "No." << number_ << " Connection receive success, received: " 69 | << received << "\n\t" << "data is: " << receive_buffer_.GetBuffer() << '\n'; 70 | Send(); 71 | Receive(); 72 | } 73 | else 74 | { 75 | std::cout << "No." << number_ << " Connection receive error!\n\t" 76 | << "No." << number_ << " Connection close!\n"; 77 | socket_.Close(); 78 | } 79 | } 80 | 81 | void SendCallback(bool success, int send) 82 | { 83 | if (success) 84 | { 85 | std::cout << "No." << number_ << " Connection send success, send: " 86 | << send << '\n'; 87 | } 88 | else 89 | { 90 | std::cout << "No." << number_ << " Connection send error!\n\t" 91 | << "No." << number_ << " Connection close!\n"; 92 | socket_.Close(); 93 | } 94 | } 95 | 96 | std::size_t number_; 97 | AsyncSocket socket_; 98 | Buffer receive_buffer_; 99 | Buffer send_buffer_; 100 | }; 101 | 102 | class Server 103 | { 104 | public: 105 | explicit Server(IoService& service, const Address& address, const Port& port) 106 | : service_(service), 107 | listen_(address, port, service), 108 | connection_list_() 109 | { 110 | Accept(); 111 | } 112 | 113 | private: 114 | typedef std::tr1::shared_ptr ConnectionPtr; 115 | typedef std::vector ConnectionList; 116 | 117 | void Accept() 118 | { 119 | listen_.AsyncAccept( 120 | std::tr1::bind(&Server::AcceptCallback, this, 121 | std::tr1::placeholders::_1, std::tr1::placeholders::_2)); 122 | } 123 | 124 | void AcceptCallback(bool success, BaseSocket new_connect) 125 | { 126 | if (success) 127 | { 128 | std::size_t number = connection_list_.size() + 1; 129 | ConnectionPtr ptr(new Connection(number, service_, new_connect)); 130 | connection_list_.push_back(ptr); 131 | std::cout << "accept new Connection success, No." 132 | << number << '\n'; 133 | } 134 | else 135 | { 136 | std::cout << "accept new Connection error!\n"; 137 | } 138 | 139 | Accept(); 140 | } 141 | 142 | IoService& service_; 143 | AsyncListener listen_; 144 | ConnectionList connection_list_; 145 | }; 146 | 147 | int main() 148 | { 149 | WinSockIniter initer; 150 | IoService service; 151 | Server server(service, Address(), Port(5150)); 152 | 153 | while (true) 154 | { 155 | service.Run(); 156 | Sleep(100); 157 | } 158 | 159 | return 0; 160 | } 161 | -------------------------------------------------------------------------------- /test/TestObjectPool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "base/ObjectPool.h" 3 | 4 | struct TestPod 5 | { 6 | int i; 7 | char c; 8 | }; 9 | 10 | int main() 11 | { 12 | ObjectPool pool; 13 | std::vector temp; 14 | 15 | for (int i = 0; i < 1000; ++i) 16 | { 17 | temp.push_back(pool.ObtainObject()); 18 | } 19 | 20 | for (int i = 0; i < 1000; ++i) 21 | { 22 | pool.ReturnObject(temp[i]); 23 | } 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/TestRefCount.cpp: -------------------------------------------------------------------------------- 1 | #include "../base/RefCount.h" 2 | #include 3 | 4 | class RefObject : public RefCount 5 | { 6 | public: 7 | RefObject() 8 | : RefCount(true), 9 | data_(new int(10)) 10 | { 11 | } 12 | 13 | ~RefObject() 14 | { 15 | if (Only()) 16 | delete data_; 17 | } 18 | 19 | RefObject(const RefObject& ro) 20 | : RefCount(ro), 21 | data_(ro.data_) 22 | { 23 | } 24 | 25 | RefObject& operator = (const RefObject& ro) 26 | { 27 | RefObject(ro).Swap(*this); 28 | return *this; 29 | } 30 | 31 | void Swap(RefObject& ro) 32 | { 33 | RefCount::Swap(ro); 34 | std::swap(ro.data_, data_); 35 | } 36 | 37 | int *data_; 38 | }; 39 | 40 | int main() 41 | { 42 | RefObject obj; 43 | std::cout << "use count: " << obj.UseCount() << std::endl; 44 | std::cout << "obj: " << *obj.data_ << "\n\n"; 45 | 46 | { 47 | RefObject obj1(obj); 48 | std::cout << "obj use count: " << obj.UseCount() << std::endl; 49 | std::cout << "obj1 use count: " << obj1.UseCount() << std::endl; 50 | std::cout << "obj: " << *obj.data_ << std::endl; 51 | std::cout << "obj1: " << *obj1.data_ << "\n\n"; 52 | } 53 | 54 | { 55 | RefObject obj2; 56 | obj2 = obj; 57 | std::cout << "obj use count: " << obj.UseCount() << std::endl; 58 | std::cout << "obj2 use count: " << obj2.UseCount() << std::endl; 59 | std::cout << "obj: " << *obj.data_ << std::endl; 60 | std::cout << "obj2: " << *obj2.data_ << "\n\n"; 61 | } 62 | 63 | std::cout << "use count: " << obj.UseCount() << std::endl; 64 | std::cout << "obj: " << *obj.data_ << "\n\n"; 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /test/TestResolveService.cpp: -------------------------------------------------------------------------------- 1 | #include "../net/ResolveService.h" 2 | #include "../net/WinSockIniter.h" 3 | #include 4 | 5 | using namespace bittorrent; 6 | using namespace net; 7 | 8 | void PrintResult(const std::string& nodename, 9 | const std::string& servname, 10 | const ResolveResult& result) 11 | { 12 | std::cout << "\naddress: " << nodename << std::endl; 13 | std::size_t count = 0; 14 | for (ResolveResult::iterator it = result.begin(); 15 | it != result.end(); ++it) 16 | { 17 | std::cout << "ai_family: " << it->ai_family << std::endl; 18 | std::cout << "ai_socktype: " << it->ai_socktype << std::endl; 19 | std::cout << "ai_protocol: " << it->ai_protocol << std::endl; 20 | std::cout << "ai_canonname: " << (it->ai_canonname ? it->ai_canonname : "") << std::endl; 21 | std::cout << std::endl; 22 | ++count; 23 | } 24 | 25 | std::cout << "there are " << count << " address." << std::endl; 26 | } 27 | 28 | int main(int argc, char **argv) 29 | { 30 | if (argc < 2) 31 | { 32 | std::cout << "usage: test www.sample.com ..." << std::endl; 33 | return 0; 34 | } 35 | 36 | WinSockIniter initer; 37 | ResolveService service; 38 | ResolveHint hint(AF_INET, SOCK_STREAM, IPPROTO_TCP); 39 | 40 | for (int i = 1; i < argc; ++i) 41 | { 42 | service.AsyncResolve(argv[i], "", hint, PrintResult); 43 | } 44 | 45 | for (int i = 0; i < 50; ++i) 46 | { 47 | service.Run(); 48 | Sleep(100); 49 | } 50 | 51 | std::cout << "\nexiting..." << std::endl; 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /test/TestScopePtr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../base/ScopePtr.h" 3 | 4 | struct Test 5 | { 6 | int a_; 7 | int b_; 8 | 9 | Test(int a, int b) 10 | : a_(a), b_(b) 11 | { 12 | } 13 | 14 | void print() const 15 | { 16 | std::cout << "print in Test: " << a_ << " " << b_ << std::endl; 17 | } 18 | }; 19 | 20 | int main() 21 | { 22 | ScopePtr pint(new int(10)); 23 | std::cout << "before assign " << *pint << std::endl; 24 | *pint = 5; 25 | std::cout << "after assign " << *pint << std::endl; 26 | 27 | ScopePtr ptest(new Test(5, 10)); 28 | std::cout << "print out Test: " << ptest->a_ << " " << ptest->b_ << std::endl; 29 | ptest->print(); 30 | 31 | return 0; 32 | } -------------------------------------------------------------------------------- /test/TestSha1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../sha1/sha1.h" 4 | 5 | int main() 6 | { 7 | SHA1 sha; 8 | sha.Input("airtrack", 8); 9 | unsigned message_digest_array[5]; 10 | if (!sha.Result(message_digest_array)) 11 | { 12 | std::cerr << "error" << std::endl; 13 | } 14 | 15 | std::cout << std::hex 16 | << message_digest_array[0] << ' ' 17 | << message_digest_array[1] << ' ' 18 | << message_digest_array[2] << ' ' 19 | << message_digest_array[3] << ' ' 20 | << message_digest_array[4] << std::endl; 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/TestThread.cpp: -------------------------------------------------------------------------------- 1 | #include "../thread/Thread.h" 2 | #include 3 | #include 4 | 5 | using namespace bittorrent; 6 | 7 | unsigned Threadn(int n) 8 | { 9 | for (int i = 0; i < 10; ++i) 10 | printf("print in thread %d\n", n); 11 | 12 | return 0; 13 | } 14 | 15 | int main() 16 | { 17 | Thread t1(std::tr1::bind(Threadn, 1)); 18 | Thread t2(std::tr1::bind(Threadn, 2)); 19 | Thread t3(std::tr1::bind(Threadn, 3)); 20 | 21 | Sleep(1000); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /test/TestTimer.cpp: -------------------------------------------------------------------------------- 1 | #include "../timer/Timer.h" 2 | #include "../timer/TimerQueue.h" 3 | #include "../unittest/UnitTest.h" 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace bittorrent; 9 | 10 | TimerQueue timer_queue; 11 | std::vector dead_timer; 12 | 13 | void RecordTimer(Timer *timer) 14 | { 15 | timer_queue.DelTimer(timer); 16 | dead_timer.push_back(timer); 17 | } 18 | 19 | TEST_CASE(test_timer) 20 | { 21 | Timer t1(1000); 22 | t1.SetCallback(std::tr1::bind(&RecordTimer, &t1)); 23 | timer_queue.AddTimer(&t1); 24 | 25 | Timer t2(2000); 26 | t2.SetCallback(std::tr1::bind(&RecordTimer, &t2)); 27 | timer_queue.AddTimer(&t2); 28 | 29 | Timer t3(5000); 30 | t3.SetCallback(std::tr1::bind(&RecordTimer, &t3)); 31 | timer_queue.AddTimer(&t3); 32 | 33 | for (int i = 0; i < 100; ++i) 34 | { 35 | timer_queue.Schedule(); 36 | ::Sleep(60); 37 | } 38 | 39 | CHECK_TRUE(dead_timer.size() == 3); 40 | CHECK_TRUE(dead_timer[0] == &t1); 41 | CHECK_TRUE(dead_timer[1] == &t2); 42 | CHECK_TRUE(dead_timer[2] == &t3); 43 | } 44 | 45 | int main() 46 | { 47 | TestCollector.RunCases(); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /test/TestTorrentFile.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/bencode/MetainfoFile.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace bittorrent; 10 | using namespace bittorrent::core; 11 | using namespace bittorrent::core::bentypes; 12 | 13 | struct OutPutString : public std::unary_function 14 | { 15 | OutPutString(std::ostream& os) : os_(os) { } 16 | 17 | void operator () (const std::string& str) const 18 | { 19 | os_ << str << '\n'; 20 | } 21 | 22 | std::ostream& os_; 23 | }; 24 | 25 | struct OutPutFileInfo : public std::unary_function 26 | { 27 | OutPutFileInfo(std::ostream& os) : os_(os) { } 28 | 29 | void operator () (const MetainfoFile::FileInfo& info) const 30 | { 31 | for (std::vector::const_iterator 32 | it = info.path.begin(); it != info.path.end(); ++it) 33 | { 34 | os_ << '\\' << *it; 35 | } 36 | os_ << '\t' << info.length << '\n'; 37 | } 38 | 39 | std::ostream& os_; 40 | }; 41 | 42 | int main() 43 | { 44 | try 45 | { 46 | std::string filename; 47 | std::cin >> filename; 48 | 49 | MetainfoFile torrentfile(filename.c_str()); 50 | std::ofstream infofile(std::string(filename + "_result.txt").c_str()); 51 | 52 | infofile << "is single file: "; 53 | if (torrentfile.IsSingleFile()) 54 | infofile << "true\n"; 55 | else 56 | infofile << "false\n"; 57 | 58 | infofile << "name: " << torrentfile.Name() << '\n'; 59 | infofile << "piece length: " << torrentfile.PieceLength() << '\n'; 60 | infofile << "piece count: " << torrentfile.PiecesCount() << '\n'; 61 | infofile << "length: " << torrentfile.Length() << '\n'; 62 | infofile << '\n'; 63 | 64 | std::vector announce; 65 | torrentfile.GetAnnounce(&announce); 66 | infofile << "announce:\n"; 67 | std::for_each(announce.begin(), announce.end(), OutPutString(infofile)); 68 | 69 | std::vector files; 70 | torrentfile.Files(&files); 71 | infofile << "\nfiles: \n"; 72 | std::for_each(files.begin(), files.end(), OutPutFileInfo(infofile)); 73 | } 74 | catch (const BaseException& be) 75 | { 76 | std::cout << be.what() << std::endl; 77 | } 78 | 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /test/TestTracker.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/BitCreator.h" 2 | #include "../core/BitController.h" 3 | #include "../core/BitData.h" 4 | #include "../core/BitPeerData.h" 5 | #include "../core/BitRepository.h" 6 | #include "../core/BitTask.h" 7 | #include "../core/BitService.h" 8 | #include "../net/WinSockIniter.h" 9 | #include "../net/IoService.h" 10 | #include "../net/ResolveService.h" 11 | #include "../net/TimerService.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace bittorrent; 19 | using namespace bittorrent::core; 20 | using namespace bittorrent::net; 21 | 22 | std::string ReadableIp(unsigned long ip) 23 | { 24 | std::ostringstream oss; 25 | oss << ((ip >> 24) & 0xFF) << '.' 26 | << ((ip >> 16) & 0xFF) << '.' 27 | << ((ip >> 8) & 0xFF) << '.' 28 | << ((ip) & 0xFF); 29 | return oss.str(); 30 | } 31 | 32 | int main(int argc, char **argv) 33 | { 34 | if (argc != 2) 35 | { 36 | std::cout << "usage: TestTracker torrent_file" << std::endl; 37 | return 0; 38 | } 39 | 40 | const char *torrent_file = argv[1]; 41 | WinSockIniter sock_initer; 42 | IoService io_service; 43 | TimerService timer_service; 44 | ResolveService resolve_service; 45 | io_service.AddService(&timer_service); 46 | io_service.AddService(&resolve_service); 47 | 48 | BitRepository repository; 49 | BitController bit_controller; 50 | BitNewTaskCreator bit_creator(bit_controller, io_service); 51 | 52 | BitService::io_service = &io_service; 53 | BitService::repository = &repository; 54 | BitService::controller = &bit_controller; 55 | BitService::new_task_creator = &bit_creator; 56 | 57 | repository.SetListenPort(6881); 58 | 59 | if (!bit_creator.CreateTask(torrent_file)) 60 | { 61 | std::cout << torrent_file << " not exist or not legal." << std::endl; 62 | return 0; 63 | } 64 | 65 | for (int i = 0; i < 600; ++i) 66 | { 67 | io_service.Run(); 68 | ::Sleep(100); 69 | } 70 | 71 | std::vector data; 72 | repository.GetAllBitData(data); 73 | assert(data.size() == 1); 74 | BitRepository::BitDataPtr bitdata = data[0]; 75 | 76 | BitData::ListenInfoSet& unused_info_set = bitdata->GetUnusedListenInfo(); 77 | BitData::ListenInfoSet& used_info_set = bitdata->GetUsedListenInfo(); 78 | 79 | std::ofstream peers_info_file(std::string(torrent_file) + std::string("_peers_info.txt")); 80 | 81 | for (BitData::ListenInfoSet::iterator it = unused_info_set.begin(); it != unused_info_set.end(); ++it) 82 | { 83 | peers_info_file << "ip: " << ReadableIp(it->ip) << "\t" 84 | << "port: " << it->port << "\n"; 85 | } 86 | 87 | for (BitData::ListenInfoSet::iterator it = used_info_set.begin(); it != used_info_set.end(); ++it) 88 | { 89 | peers_info_file << "ip: " << ReadableIp(it->ip) << "\t" 90 | << "port: " << it->port << "\n"; 91 | } 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /test/TestURI.cpp: -------------------------------------------------------------------------------- 1 | #include "../protocol/URI.h" 2 | #include "../unittest/UnitTest.h" 3 | 4 | using namespace bittorrent; 5 | using namespace http; 6 | 7 | TEST_CASE(host_name) 8 | { 9 | URI uri("http://www.sample.com"); 10 | std::string host = uri.GetHost(); 11 | CHECK_TRUE(host == "www.sample.com"); 12 | } 13 | 14 | TEST_CASE(querys) 15 | { 16 | char data[2] = { 0x0F, 0x0E }; 17 | URI uri("http://www.sample.com/announce.php"); 18 | uri.AddQuery("id", 123); 19 | uri.AddQuery("data", data, 2); 20 | std::string uristr = uri.GetQueryString(); 21 | CHECK_TRUE(uristr == "/announce.php?id=123&data=%0F%0E"); 22 | } 23 | 24 | int main() 25 | { 26 | TestCollector.RunCases(); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /test/TestUnitTest.cpp: -------------------------------------------------------------------------------- 1 | #include "../unittest/UnitTest.h" 2 | 3 | TEST_CASE(test1) 4 | { 5 | CHECK_TRUE(1 == 1); 6 | CHECK_TRUE(true == false); 7 | } 8 | 9 | TEST_CASE(test2) 10 | { 11 | CHECK_TRUE(true); 12 | CHECK_TRUE(1 == 1); 13 | } 14 | 15 | int main() 16 | { 17 | TestCollector.RunCases(); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /thread/Atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef ATOMIC_H 2 | #define ATOMIC_H 3 | 4 | #include 5 | 6 | namespace bitwave { 7 | 8 | inline long AtomicIncrement(long volatile *addend) 9 | { 10 | return ::InterlockedIncrement(addend); 11 | } 12 | 13 | inline long AtomicDecrement(long volatile *addend) 14 | { 15 | return ::InterlockedDecrement(addend); 16 | } 17 | 18 | inline long AtomicAdd(long volatile *addend, long value) 19 | { 20 | return ::InterlockedExchangeAdd(addend, value); 21 | } 22 | 23 | } // namespace bitwave 24 | 25 | #endif // ATOMIC_H 26 | -------------------------------------------------------------------------------- /thread/Event.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENT_H 2 | #define EVENT_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include 6 | 7 | namespace bitwave { 8 | 9 | // a simply Event template wrapper for Windows event. 10 | template 11 | class Event : private NotCopyable 12 | { 13 | public: 14 | enum WAIT_RESULT 15 | { 16 | SUCCESS, 17 | TIMEOUT, 18 | FAILED, 19 | }; 20 | 21 | // default construct an Event without set 22 | explicit Event(bool init_set = false) 23 | { 24 | event_ = ::CreateEvent(0, ManualReset, init_set, 0); 25 | } 26 | 27 | ~Event() 28 | { 29 | ::CloseHandle(event_); 30 | } 31 | 32 | void SetEvent() 33 | { 34 | ::SetEvent(event_); 35 | } 36 | 37 | void ResetEvent() 38 | { 39 | ::ResetEvent(event_); 40 | } 41 | 42 | WAIT_RESULT Wait(DWORD milliseconds) 43 | { 44 | DWORD result = ::WaitForSingleObject(event_, milliseconds); 45 | 46 | switch (result) 47 | { 48 | case WAIT_OBJECT_0: 49 | return SUCCESS; 50 | case WAIT_TIMEOUT: 51 | return TIMEOUT; 52 | default: 53 | return FAILED; 54 | } 55 | } 56 | 57 | bool WaitForever() 58 | { 59 | return Wait(INFINITE) == SUCCESS; 60 | } 61 | 62 | private: 63 | HANDLE event_; 64 | }; 65 | 66 | typedef Event ManualResetEvent; 67 | typedef Event AutoResetEvent; 68 | 69 | } // namespace bitwave 70 | 71 | #endif // EVENT_H 72 | -------------------------------------------------------------------------------- /thread/Mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef MUTEX_H 2 | #define MUTEX_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include 6 | #include 7 | 8 | namespace bitwave { 9 | 10 | template 11 | struct InitMutexWithSpinlocks 12 | { 13 | static void Init(CRITICAL_SECTION *cs) 14 | { 15 | ::InitializeCriticalSectionAndSpinCount(cs, spincount); 16 | } 17 | }; 18 | 19 | struct InitMutexWithNormal 20 | { 21 | static void Init(CRITICAL_SECTION *cs) 22 | { 23 | ::InitializeCriticalSection(cs); 24 | } 25 | }; 26 | 27 | template 28 | class Mutex : private NotCopyable 29 | { 30 | public: 31 | Mutex() 32 | { 33 | InitMethod::Init(&cs_); 34 | } 35 | 36 | ~Mutex() 37 | { 38 | ::DeleteCriticalSection(&cs_); 39 | } 40 | 41 | void Lock() 42 | { 43 | ::EnterCriticalSection(&cs_); 44 | } 45 | 46 | void UnLock() 47 | { 48 | ::LeaveCriticalSection(&cs_); 49 | } 50 | 51 | private: 52 | CRITICAL_SECTION cs_; 53 | }; 54 | 55 | typedef Mutex NormalMutex; 56 | typedef Mutex > SpinlocksMutex; 57 | 58 | template 59 | class Locker : private NotCopyable 60 | { 61 | public: 62 | explicit Locker(Mutex& m) : m_(m) 63 | { 64 | m_.Lock(); 65 | } 66 | 67 | ~Locker() 68 | { 69 | m_.UnLock(); 70 | } 71 | 72 | private: 73 | Mutex& m_; 74 | }; 75 | 76 | typedef Locker NormalMutexLocker; 77 | typedef Locker > SpinlocksMutexLocker; 78 | 79 | template 80 | struct LockerType; 81 | 82 | template<> 83 | struct LockerType 84 | { 85 | typedef NormalMutexLocker type; 86 | }; 87 | 88 | template<> 89 | struct LockerType 90 | { 91 | typedef SpinlocksMutexLocker type; 92 | }; 93 | 94 | } // namespace bitwave 95 | 96 | #endif // MUTEX_H 97 | -------------------------------------------------------------------------------- /thread/ReadWriteLock.h: -------------------------------------------------------------------------------- 1 | #ifndef READ_WRITE_H 2 | #define READ_WRITE_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include 6 | #include 7 | 8 | namespace bitwave { 9 | 10 | class ReadWriteLock : private NotCopyable 11 | { 12 | public: 13 | ReadWriteLock() 14 | { 15 | ::InitializeSRWLock(&lock_); 16 | } 17 | 18 | void LockForRead() 19 | { 20 | ::AcquireSRWLockShared(&lock_); 21 | } 22 | 23 | void UnLockForRead() 24 | { 25 | ::ReleaseSRWLockShared(&lock_); 26 | } 27 | 28 | void LockForWrite() 29 | { 30 | ::AcquireSRWLockExclusive(&lock_); 31 | } 32 | 33 | void UnLockForWrite() 34 | { 35 | ::ReleaseSRWLockExclusive(&lock_); 36 | } 37 | 38 | private: 39 | SRWLOCK lock_; 40 | }; 41 | 42 | class ReadLocker : private NotCopyable 43 | { 44 | public: 45 | explicit ReadLocker(ReadWriteLock& lock) 46 | : lock_(lock) 47 | { 48 | lock_.LockForRead(); 49 | } 50 | 51 | ~ReadLocker() 52 | { 53 | lock_.UnLockForRead(); 54 | } 55 | 56 | private: 57 | ReadWriteLock& lock_; 58 | }; 59 | 60 | class WriteLocker : private NotCopyable 61 | { 62 | public: 63 | explicit WriteLocker(ReadWriteLock& lock) 64 | : lock_(lock) 65 | { 66 | lock_.LockForWrite(); 67 | } 68 | 69 | ~WriteLocker() 70 | { 71 | lock_.UnLockForWrite(); 72 | } 73 | 74 | private: 75 | ReadWriteLock& lock_; 76 | }; 77 | 78 | } // namespace bitwave 79 | 80 | #endif // READ_WRITE_H 81 | -------------------------------------------------------------------------------- /thread/Thread.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_H 2 | #define THREAD_H 3 | 4 | #include "../base/BaseTypes.h" 5 | #include 6 | #include 7 | #include 8 | 9 | namespace bitwave { 10 | 11 | class Thread : private NotCopyable 12 | { 13 | public: 14 | typedef std::tr1::function thread_function; 15 | 16 | explicit Thread(const thread_function& fun) 17 | : thread_fun_(fun), 18 | handle_(INVALID_HANDLE_VALUE) 19 | { 20 | StartThread(); 21 | } 22 | 23 | ~Thread() 24 | { 25 | ::CloseHandle(handle_); 26 | } 27 | 28 | void Join() 29 | { 30 | ::WaitForSingleObject(handle_, INFINITE); 31 | } 32 | 33 | HANDLE GetHandle() const 34 | { 35 | return handle_; 36 | } 37 | 38 | private: 39 | static unsigned __stdcall ThreadFunction(void *arg) 40 | { 41 | thread_function *thread_fun = reinterpret_cast(arg); 42 | return (*thread_fun)(); 43 | } 44 | 45 | void StartThread() 46 | { 47 | handle_ = (HANDLE)::_beginthreadex(0, 0, ThreadFunction, &thread_fun_, 0, 0); 48 | } 49 | 50 | thread_function thread_fun_; 51 | HANDLE handle_; 52 | }; 53 | 54 | } // namespace bitwave 55 | 56 | #endif // THREAD_H 57 | -------------------------------------------------------------------------------- /timer/TimeTraits.h: -------------------------------------------------------------------------------- 1 | #ifndef TIME_TRAITS_H 2 | #define TIME_TRAITS_H 3 | 4 | #include 5 | 6 | namespace bitwave { 7 | 8 | typedef DWORD NormalTimeType; 9 | 10 | template 11 | struct time_traits; 12 | 13 | template<> 14 | struct time_traits 15 | { 16 | static bool less(DWORD left, DWORD right) 17 | { 18 | return left < right; 19 | } 20 | 21 | static bool equal(DWORD left, DWORD right) 22 | { 23 | return left == right; 24 | } 25 | 26 | static bool less_equal(DWORD left, DWORD right) 27 | { 28 | return left <= right; 29 | } 30 | 31 | static DWORD add(DWORD base, int millisecond) 32 | { 33 | if (millisecond >= 0) 34 | return base + millisecond; 35 | else 36 | return base - (-millisecond); 37 | } 38 | 39 | static DWORD invalid() 40 | { 41 | return -1; 42 | } 43 | 44 | static DWORD now() 45 | { 46 | return ::GetTickCount(); 47 | } 48 | }; 49 | 50 | } // namespace bitwave 51 | 52 | #endif // TIME_TRAITS_H 53 | -------------------------------------------------------------------------------- /timer/Timer.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_H 2 | #define TIMER_H 3 | 4 | #include "TimeTraits.h" 5 | #include "../base/BaseTypes.h" 6 | #include 7 | #include 8 | 9 | namespace bitwave { 10 | 11 | template 12 | class BasicTimer : private NotCopyable 13 | { 14 | public: 15 | typedef time_traits TimeTraits; 16 | typedef std::tr1::function TimerCallback; 17 | 18 | BasicTimer() 19 | : deadline_(TimeTraits::invalid()) 20 | { 21 | } 22 | 23 | explicit BasicTimer(int millisecond) 24 | { 25 | SetDeadline(millisecond); 26 | } 27 | 28 | void Schedule(const TimeType& now) 29 | { 30 | if (TimeTraits::less_equal(deadline_, now)) 31 | { 32 | assert(callback_); 33 | callback_(); 34 | } 35 | } 36 | 37 | void SetCallback(const TimerCallback& callback) 38 | { 39 | callback_ = callback; 40 | } 41 | 42 | void SetDeadline(int millisecond) 43 | { 44 | TimeType now = TimeTraits::now(); 45 | deadline_ = TimeTraits::add(now, millisecond); 46 | } 47 | 48 | private: 49 | TimeType deadline_; 50 | TimerCallback callback_; 51 | }; 52 | 53 | typedef BasicTimer Timer; 54 | 55 | } // namespace bitwave 56 | 57 | #endif // TIMER_H 58 | -------------------------------------------------------------------------------- /timer/TimerQueue.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_QUEUE_H 2 | #define TIMER_QUEUE_H 3 | 4 | #include "Timer.h" 5 | #include "../base/BaseTypes.h" 6 | #include 7 | 8 | namespace bitwave { 9 | 10 | template 11 | class BasicTimerQueue : private NotCopyable 12 | { 13 | public: 14 | typedef BasicTimer TimerType; 15 | typedef typename TimerType::TimeTraits TimeTraits; 16 | typedef std::set TimerList; 17 | typedef typename TimerList::iterator Iterator; 18 | 19 | BasicTimerQueue() 20 | : timers_(), 21 | schedule_it_(timers_.end()) 22 | { 23 | } 24 | 25 | void AddTimer(TimerType *new_timer) 26 | { 27 | timers_.insert(new_timer); 28 | } 29 | 30 | void DelTimer(TimerType *timer) 31 | { 32 | Iterator it = timers_.find(timer); 33 | if (it != timers_.end()) 34 | { 35 | if (it == schedule_it_) 36 | { 37 | // keep schedule_it_ validate 38 | ++schedule_it_; 39 | } 40 | 41 | timers_.erase(it); 42 | } 43 | } 44 | 45 | void Schedule() 46 | { 47 | TimeType now = TimeTraits::now(); 48 | schedule_it_ = timers_.begin(); 49 | while (schedule_it_ != timers_.end()) 50 | { 51 | TimerType *timer = *schedule_it_++; 52 | timer->Schedule(now); 53 | } 54 | } 55 | 56 | private: 57 | TimerList timers_; 58 | Iterator schedule_it_; 59 | }; 60 | 61 | typedef BasicTimerQueue TimerQueue; 62 | 63 | } // namespace bitwave 64 | 65 | #endif // TIMER_QUEUE_H 66 | -------------------------------------------------------------------------------- /unittest/UnitTest.h: -------------------------------------------------------------------------------- 1 | #ifndef _UNIT_TEST_H_ 2 | #define _UNIT_TEST_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class TestResultReporter; 13 | 14 | class TestErrorsCollector 15 | { 16 | public: 17 | void Register(TestResultReporter *reporter) 18 | { 19 | reporters_.push_back(reporter); 20 | } 21 | 22 | void RunCases(std::ostream& os); 23 | 24 | private: 25 | typedef std::vector Reporters; 26 | Reporters reporters_; 27 | }TestCollector; 28 | 29 | class TestResultReporter 30 | { 31 | protected: 32 | TestResultReporter() 33 | { 34 | TestCollector.Register(this); 35 | } 36 | 37 | public: 38 | virtual void ReportErrors( 39 | std::string& casename, 40 | std::vector& errors) = 0; 41 | }; 42 | 43 | void TestErrorsCollector::RunCases(std::ostream& os = std::cout) 44 | { 45 | std::size_t failed = 0; 46 | for (Reporters::iterator it = reporters_.begin(); it != reporters_.end(); ++it) 47 | { 48 | std::string casename; 49 | std::vector errors; 50 | (*it)->ReportErrors(casename, errors); 51 | if (errors.empty()) 52 | { 53 | os << "[" << casename << "]" << " passed!" << std::endl; 54 | } 55 | else 56 | { 57 | os << "[" << casename << "]" << " failed:" << std::endl; 58 | std::copy(errors.begin(), errors.end(), 59 | std::ostream_iterator(os, "\n")); 60 | ++failed; 61 | } 62 | } 63 | 64 | os << reporters_.size() << " cases has been run, passed: " 65 | << reporters_.size() - failed << ", failed: " << failed << std::endl; 66 | } 67 | 68 | #define TEST_CASE(case_name) \ 69 | class test_##case_name : public TestResultReporter \ 70 | { \ 71 | public: \ 72 | test_##case_name(); \ 73 | virtual void ReportErrors( \ 74 | std::string& casename, \ 75 | std::vector& errors) \ 76 | { \ 77 | casename = #case_name; \ 78 | errors = errors_; \ 79 | } \ 80 | void RecordError(const std::string& expression, \ 81 | const std::string& file, int line) \ 82 | { \ 83 | std::ostringstream oss; \ 84 | oss << "\"" + expression + "\" fail at file: " \ 85 | << file + " line: " << line; \ 86 | errors_.push_back(oss.str()); \ 87 | } \ 88 | std::vector errors_; \ 89 | }test_##case_name##_object; \ 90 | \ 91 | test_##case_name::test_##case_name() 92 | 93 | #define CHECK_TRUE(expression) \ 94 | (expression) ? static_cast(0) : \ 95 | RecordError(#expression, __FILE__, __LINE__) 96 | 97 | #endif // _UNIT_TEST_H_ 98 | --------------------------------------------------------------------------------