/** ** File ......... PeerHandler.cpp ** Published .... 2005-06-14 ** Author ....... grymse@alhem.net **/ /* Copyright (C) 2005 Anders Hedstrom This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef _WIN32 #pragma warning(disable:4786) #include #endif #include #include #include #include "Session.h" #include "tSocket.h" #include "cstring.h" #include "pSocket.h" #include "Peer.h" #include "StatusSocket.h" #include "PeerHandler.h" #define DEB(x) x PeerHandler::PeerHandler() :SocketHandler() ,m_listen_port(0) ,m_choke_timer(300) ,m_min_peers(10) ,m_max_peers(20) ,m_local_choke_time(30) ,m_ignore_choke(false) ,m_max_request_age(30) ,m_quit(false) ,m_debug(0) ,m_downloaders(4) ,m_optimistic(1) { srand(time(NULL) * (time_t)this); } PeerHandler::PeerHandler(StdLog *p) :SocketHandler(p) ,m_listen_port(0) ,m_choke_timer(300) ,m_min_peers(10) ,m_max_peers(20) ,m_local_choke_time(30) ,m_ignore_choke(false) ,m_max_request_age(30) ,m_quit(false) ,m_debug(0) ,m_downloaders(4) ,m_optimistic(1) { } PeerHandler::~PeerHandler() { while (m_sessions.size()) { session_m::iterator it = m_sessions.begin(); Session *p = (*it).second; delete p; m_sessions.erase(it); } } void PeerHandler::RegSession(Session *p) { m_sessions[p -> GetInfoHash()] = p; } bool PeerHandler::SessionExists(const std::string& hash) { for (session_m::iterator it = m_sessions.begin(); it != m_sessions.end(); it++) { if ((*it).first == hash && dynamic_cast((*it).second)) return true; } return false; } void PeerHandler::mkpath(const std::string& path) { for (size_t i = 0; i < path.size(); i++) { if (path[i] == '/') { #ifdef _WIN32 _mkdir(path.substr(0, i).c_str()); #else mkdir(path.substr(0, i).c_str(), 0750); #endif } } } Session *PeerHandler::GetSession(const std::string& hash) { for (session_m::iterator it = m_sessions.begin(); it != m_sessions.end(); it++) { if ((*it).first == hash && dynamic_cast((*it).second)) return (*it).second; } return NULL; } void PeerHandler::Tick(time_t now) { for (session_m::iterator it = m_sessions.begin(); it != m_sessions.end(); it++) { Session *sess = (*it).second; if (sess) { if (now > sess -> GetTimeTracker() + sess -> GetInterval()) { tSocket *p = new tSocket(*this, sess -> GetInfoHash()); p -> SetDeleteByHandler(); Add(p); sess -> SetTimeTracker(); } sess -> Update(); } } } void PeerHandler::dprintf(int id, char *format, ...) { // char *colors = "rgybmcwlRGYBMCWL"; char *colors = "rgymcRGYBMCWL"; va_list ap; va_start(ap, format); char tmp[5000]; #ifdef _WIN32 vsprintf(tmp, format, ap); va_end(ap); printf("%s\n", tmp); #else vsnprintf(tmp, 5000, format, ap); va_end(ap); cstring str; char slask[10]; sprintf(slask, "&%c", colors[id % strlen(colors)]); str = slask; str += tmp; str += "&n"; printf("%s\n", str.c_str()); if (0) { FILE *fil = fopen("btlog","at"); if (!fil) fil = fopen("btlog","wt"); fprintf(fil,"%s\n", str.c_str()); fclose(fil); } #endif } size_t PeerHandler::PeerCount(const std::string& hash) { size_t q = 0; for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) { pSocket *p = dynamic_cast((*it).second); if (p && p -> GetHash() == hash) { q++; } } return q; } bool PeerHandler::Connected(Peer *peer) { for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) { pSocket *p = dynamic_cast((*it).second); if (p && p -> GetHash() == peer -> GetHash() && p -> GetRemoteAddress() == peer -> GetIP()) { return true; } } return false; } pSocket *PeerHandler::PeerSocket(Peer *peer) { for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) { pSocket *p = dynamic_cast((*it).second); if (p && p -> GetHash() == peer -> GetHash() && p -> GetRemoteAddress() == peer -> GetIP()) { return p; } } return NULL; } void PeerHandler::SendHave(const std::string& hash,size_t piece) { for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) { pSocket *p = dynamic_cast((*it).second); if (p && p -> GetHash() == hash && p -> CTS() ) { p -> SendHave(piece); } } } void PeerHandler::Save() { for (session_m::iterator it = m_sessions.begin(); it != m_sessions.end(); it++) { Session *sess = (*it).second; sess -> Save(); } } void PeerHandler::Show(StatusSocket *sock) { for (session_m::iterator it = m_sessions.begin(); it != m_sessions.end(); it++) { Session *sess = (*it).second; sess -> Status(sock); } } void PeerHandler::CheckDownloadRate() { // TODO: disabled return; std::map mmap; size_t max = 0; DEB(printf("CheckDownloadRate()\n");) for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) { pSocket *p = dynamic_cast((*it).second); if (p) { Peer *peer = p -> GetPeer(); if (p && peer && p -> CTS() && !peer -> IsChoked()) { size_t sz; if (p -> GetDownloadRate(sz)) { mmap[p] = sz; max = MAX(max,sz); } } } } if (mmap.size() == GetDownloaders() + GetOptimistic() ) { pSocket *least = NULL; for (std::map::iterator it = mmap.begin(); it != mmap.end(); it++) { pSocket *sock = (*it).first; size_t sz = (*it).second; if (sz < max) { least = sock; max = sz; } } if (least) { //DEB(printf("Kicking pSocket with download rate %d bytes/sec\n", max);) least -> SendChoke(true); } } } std::string PeerHandler::GetTime() { char slask[100]; #ifdef _WIN32 SYSTEMTIME time; ::GetLocalTime(&time); sprintf(slask, "%ld.%03ld", time.wHour * 3600 + time.wMinute + 60 + time.wSecond, time.wMilliseconds); #else struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); sprintf(slask, "%ld.%06ld", tv.tv_sec, tv.tv_usec); #endif return slask; }