📄 ctcs.cpp
字号:
#include "ctcs.h" // def.h#include <stdlib.h>#include <string.h>#include <errno.h>#include <ctype.h>#include "btcontent.h"#include "setnonblock.h"#include "connect_nonb.h"#include "tracker.h"#include "peerlist.h"#include "peer.h"#include "btconfig.h"#include "bttime.h"#include "console.h"#ifndef HAVE_SNPRINTF#include "compat.h"#endif#define CTCS_PROTOCOL 3#define compset(a,member) ( (a.member==member)? 0 : ((a.member = member)||1) )Ctcs CTCS;Ctcs::Ctcs(){ memset(m_host,0,MAXHOSTNAMELEN); m_sock = INVALID_SOCKET; m_port = 2780; m_status = T_FREE; m_interval = 5; m_protocol = CTCS_PROTOCOL; m_last_timestamp = m_sent_ctstatus_time = m_statustime = (time_t) 0; m_sent_ctstatus = 0; m_sent_ctbw = 0;}Ctcs::~Ctcs(){ if( m_sock != INVALID_SOCKET) CLOSE_SOCKET(m_sock);}void Ctcs::Reset(time_t new_interval){ int warn = 0; if(new_interval) m_interval = new_interval; if( INVALID_SOCKET != m_sock ){ if( T_READY==m_status ) warn = 1; CLOSE_SOCKET(m_sock); m_sock = INVALID_SOCKET; } in_buffer.Reset(); out_buffer.Reset(); m_last_timestamp = now; m_sent_ctstatus = 0; m_sent_ctbw = 0; m_status = T_FREE; if( warn ) CONSOLE.Warning(2, "Connection to CTCS closed");}// borrowed from tracker.cpp (with changes)int Ctcs:: _s2sin(char *h,int p,struct sockaddr_in *psin){ psin->sin_family = AF_INET; psin->sin_port = htons(p); psin->sin_addr.s_addr = inet_addr(h); if(psin->sin_addr.s_addr == INADDR_NONE){ struct hostent *ph = gethostbyname(h); if( !ph || ph->h_addrtype != AF_INET){ memset(psin,0,sizeof(struct sockaddr_in)); return -1; } memcpy(&psin->sin_addr,ph->h_addr_list[0],sizeof(struct in_addr)); } return ( psin->sin_addr.s_addr == INADDR_NONE ) ? -1 : 0;}int Ctcs::CheckMessage(){ ssize_t r; size_t q; r = in_buffer.FeedIn(m_sock); // This differs from tracker.cpp since we maintain a persistent connection. if( r == 0 ) return 0; // no data (should return an error) q = in_buffer.Count(); if( !q ){ int error = 0; socklen_t n = sizeof(error); if( getsockopt(m_sock, SOL_SOCKET,SO_ERROR,&error,&n) < 0 ) error = errno; if( error != 0 ) CONSOLE.Warning(2, "warn, received nothing from CTCS: %s", strerror(error)); Reset(5); return -1; } char *s, *msgbuf; while(in_buffer.Count() && (s=strpbrk(msgbuf=in_buffer.BasePointer(), "\r\n"))){ *s = '\0'; if(arg_verbose && s!=msgbuf) CONSOLE.Debug("CTCS: %s", msgbuf); if( !strncmp("SETDLIMIT",msgbuf,9) ){ int arg = (int)strtod(msgbuf+10, NULL); if( !BTCONTENT.IsFull() || arg < cfg_max_bandwidth_down ){ cfg_max_bandwidth_down = arg; if(arg_verbose) CONSOLE.Debug("DLimit=%d", cfg_max_bandwidth_down); } }else if( !strncmp("SETULIMIT",msgbuf,9) ){ cfg_max_bandwidth_up = (int)(strtod(msgbuf+10, NULL)); if(arg_verbose) CONSOLE.Debug("ULimit=%d", cfg_max_bandwidth_up); }else if( !strncmp("SENDPEERS",msgbuf,9) ){ Send_Peers(); }else if( !strncmp("SENDSTATUS",msgbuf,10) ){ Send_Status(); }else if( !strncmp("SENDCONF",msgbuf,8) ){ Send_Config(); }else if( !strncmp("CTCONFIG",msgbuf,8) ){ Set_Config(msgbuf); }else if( !strncmp("SENDDETAIL",msgbuf,10) ){ Send_Detail(); }else if( !strncmp("CTQUIT",msgbuf,6) ){ CONSOLE.Print("CTCS sent Quit command"); Tracker.ClearRestart(); Tracker.SetStoped(); }else if( !strncmp("CTRESTART",msgbuf,9) ){ Tracker.RestartTracker(); }else if( !strncmp("CTUPDATE",msgbuf,8) ){ Tracker.Reset(15); }else if( !strncmp("PROTOCOL",msgbuf,8) ){ int proto = atoi(msgbuf+9); if( proto <= CTCS_PROTOCOL ) m_protocol = proto; else m_protocol = CTCS_PROTOCOL; }else if( s!=msgbuf ){ if(arg_verbose) CONSOLE.Debug("unknown CTCS message: %s", msgbuf); } in_buffer.PickUp(s-msgbuf + 1); } m_last_timestamp = now; return 0;}int Ctcs::SendMessage(const char *message){ int len, r=0; char buf[CTCS_BUFSIZE]; if( m_status == T_READY ){ len = strlen(message); strncpy(buf, message, len); if( len+1 < CTCS_BUFSIZE ){ buf[len] = '\n'; buf[len+1] = '\0'; }else{ buf[CTCS_BUFSIZE-2] = '\n'; buf[CTCS_BUFSIZE-1] = '\0'; } r = out_buffer.PutFlush(m_sock, buf, len+1); if( r<0 ) Reset(5); else m_last_timestamp = now; } return (r < 0) ? r : 0;}int Ctcs::Send_Auth(){ char message[CTCS_BUFSIZE]; if(!*m_pass) return 0; snprintf(message, CTCS_BUFSIZE, "AUTH %s", m_pass); return SendMessage(message);}int Ctcs::Send_Protocol(){ char message[CTCS_BUFSIZE]; snprintf(message, CTCS_BUFSIZE, "PROTOCOL %04d", CTCS_PROTOCOL); return SendMessage(message);}int Ctcs::Send_Torrent(const unsigned char *peerid, char *torrent){ char message[CTCS_BUFSIZE]; char txtid[PEER_ID_LEN*2+3]; TextPeerID(peerid, txtid); snprintf(message, CTCS_BUFSIZE, "CTORRENT %s %ld %ld %s", txtid, (long)(BTCONTENT.GetStartTime()), (long)now, torrent); return SendMessage(message);}int Ctcs::Report_Status(){ int changebw; size_t dlrate, ulrate, dlimit, ulimit; if( T_READY != m_status ) return 0; dlrate = Self.RateDL(); ulrate = Self.RateUL(); dlimit = cfg_max_bandwidth_down; ulimit = cfg_max_bandwidth_up; changebw = ( compset(m_ctstatus, dlrate) | compset(m_ctstatus, ulrate) | compset(m_ctstatus, dlimit) | compset(m_ctstatus, ulimit) ); m_statustime = now; if( !m_sent_ctstatus || (Tracker.GetStatus() && now > m_sent_ctstatus_time+30) ) return Send_Status(); else return (changebw || !m_sent_ctbw) ? Send_bw() : 0;}int Ctcs::Send_Status(){ char message[CTCS_BUFSIZE]; size_t seeders, leechers, nhave, ntotal, dlrate, ulrate, dlimit, ulimit, cacheused; uint64_t dltotal, ultotal; if( T_READY != m_status ) return 0; seeders = WORLD.GetSeedsCount(); leechers = WORLD.GetPeersCount() - seeders - WORLD.GetConnCount(); nhave = BTCONTENT.pBF->Count(); ntotal = BTCONTENT.GetNPieces(); dlrate = m_ctstatus.dlrate; ulrate = m_ctstatus.ulrate; dltotal = Self.TotalDL(); ultotal = Self.TotalUL(); dlimit = cfg_max_bandwidth_down; ulimit = cfg_max_bandwidth_up; cacheused = BTCONTENT.CacheUsed()/1024; if( m_protocol == 1 ) snprintf( message, CTCS_BUFSIZE, "CTSTATUS %d/%d %d/%d/%d %d,%d %llu,%llu %d,%d", (int)seeders, (int)leechers, (int)nhave, (int)ntotal, (int)(WORLD.Pieces_I_Can_Get()), (int)dlrate, (int)ulrate, (unsigned long long)dltotal, (unsigned long long)ultotal, (int)dlimit, (int)ulimit ); else snprintf( message, CTCS_BUFSIZE, "CTSTATUS %d:%d/%d:%d/%d %d/%d/%d %d,%d %llu,%llu %d,%d %d", (int)seeders, (int)(Tracker.GetSeedsCount()) - (BTCONTENT.IsFull() ? 1 : 0), (int)leechers, (int)(Tracker.GetPeersCount()) - Tracker.GetSeedsCount() - (!BTCONTENT.IsFull() ? 1 : 0), (int)(WORLD.GetConnCount()), (int)nhave, (int)ntotal, (int)(WORLD.Pieces_I_Can_Get()), (int)dlrate, (int)ulrate, (unsigned long long)dltotal, (unsigned long long)ultotal, (int)dlimit, (int)ulimit, (int)cacheused ); m_sent_ctstatus = m_sent_ctbw = 1; m_sent_ctstatus_time = now; return SendMessage(message);}int Ctcs::Send_bw(){ char message[CTCS_BUFSIZE]; snprintf(message, CTCS_BUFSIZE, "CTBW %d,%d %d,%d", (int)(m_ctstatus.dlrate), (int)(m_ctstatus.ulrate), (int)(m_ctstatus.dlimit), (int)(m_ctstatus.ulimit) ); m_sent_ctbw = 1; return SendMessage(message);}int Ctcs::Send_Config(){ char message[CTCS_BUFSIZE]; if( m_protocol >= 3 ){ int r = 0; char value[MAXPATHLEN], desc[MAXPATHLEN], maxlen[10]; if( (r=SendMessage("CTCONFIGSTART")) < 0 ) return r; snprintf(maxlen, sizeof(maxlen), "%u", (unsigned int)MAXPATHLEN); if( (r = SendMessage(ConfigMsg("verbose", "B", "0", arg_verbose?"1":"0", "Verbose output [-v]", arg_verbose ? "Enabled" : "Disabled"))) < 0 ) return r; double num = BTCONTENT.GetSeedTime() ? (cfg_seed_hours - (now - BTCONTENT.GetSeedTime())/3600.0) : cfg_seed_hours; unsigned long tmp = (unsigned long)(num * 100); int pre = (tmp % 10) ? 2 : (tmp % 100) ? 1 : 0; snprintf(value, MAXPATHLEN, "%.*f", pre, num); snprintf(desc, MAXPATHLEN, "~hours remaining (-e %lu)", (unsigned long)cfg_seed_hours); if( (r = SendMessage(ConfigMsg("seed_time", "F", "0", value, "Seed time [-e]", desc))) < 0 ) return r; snprintf(value, MAXPATHLEN, "%.2f", (double)cfg_seed_ratio); if( (r = SendMessage(ConfigMsg("seed_ratio", "F", "0", value, "Seed ratio [-E]", "Upload:Download"))) < 0 ) return r; snprintf(value, MAXPATHLEN, "%d", (int)cfg_max_peers); snprintf(desc, MAXPATHLEN, "Current peers: %d", (int)(WORLD.GetPeersCount())); if( (r = SendMessage(ConfigMsg("max_peers", "I", "20-1000", value, "Max peers [-M]", desc))) < 0 ) return r; snprintf(value, MAXPATHLEN, "%d", (int)cfg_min_peers); snprintf(desc, MAXPATHLEN, "Current peers: %d", (int)(WORLD.GetPeersCount())); if( (r = SendMessage(ConfigMsg("min_peers", "I", "1-1000", value, "Min peers [-m]", desc))) < 0 ) return r; if( !BTCONTENT.IsFull() && (r = SendMessage(ConfigMsg("file_list", "S", maxlen, arg_file_to_download ? arg_file_to_download : "", "Download files [-n]", ""))) < 0 ) return r; snprintf(value, MAXPATHLEN, "%d", (int)cfg_cache_size); snprintf(desc, MAXPATHLEN, "MB; %dKB now in use", (int)(BTCONTENT.CacheUsed()/1024)); if( (r = SendMessage(ConfigMsg("cache", "I", "0", value, "Cache size [-C]", desc))) < 0 ) return r; if( (r = SendMessage(ConfigMsg("pause", "B", "0", WORLD.IsPaused()?"1":"0", "Pause torrent", "Stop upload/download"))) < 0 ) return r; if( !BTCONTENT.IsFull() && (r = SendMessage(ConfigMsg("user_exit", "S", maxlen, arg_completion_exit ? arg_completion_exit : "", "Completion command [-X]", ""))) < 0 ) return r; if( (r = SendMessage(ConfigMsg("out_normal", "S", maxlen, CONSOLE.GetChannel(O_NORMAL), "Normal/status output", ""))) < 0 ) return r; if( (r = SendMessage(ConfigMsg("out_interact", "S", maxlen, CONSOLE.GetChannel(O_INTERACT), "Interactive output", ""))) < 0 ) return r; if( (r = SendMessage(ConfigMsg("out_error", "S", maxlen, CONSOLE.GetChannel(O_WARNING), "Error/warning output", ""))) < 0 ) return r; if( (r = SendMessage(ConfigMsg("out_debug", "S", maxlen, CONSOLE.GetChannel(O_DEBUG), "Debug/verbose output", ""))) < 0 ) return r; if( (r = SendMessage(ConfigMsg("input", "S", maxlen, CONSOLE.GetChannel(O_INPUT), "Console input", ""))) < 0 ) return r; if( (r = SendMessage(ConfigMsg("ctcs_server", "S", maxlen, arg_ctcs, "CTCS server", ""))) < 0 ) return r; sprintf(message, "CTCONFIGDONE"); } else if( m_protocol == 2 ) snprintf(message, CTCS_BUFSIZE, "CTCONFIG %d %d %f %d %d %d %d %d", (int)arg_verbose, (int)cfg_seed_hours, cfg_seed_ratio, (int)cfg_max_peers, (int)cfg_min_peers, BTCONTENT.GetFilter() ? atoi(BTCONTENT.GetFilterName()) : 0, (int)cfg_cache_size, WORLD.IsPaused()); else // m_protocol == 1 snprintf(message, CTCS_BUFSIZE, "CTCONFIG %d %d %f %d %d %d %d %d %d", (int)arg_verbose, (int)cfg_seed_hours, cfg_seed_ratio, (int)cfg_max_peers, (int)cfg_min_peers, BTCONTENT.GetFilter() ? atoi(BTCONTENT.GetFilterName()) : 0, 0, WORLD.IsPaused(), 0); return SendMessage(message);}char *Ctcs::ConfigMsg(const char *name, const char *type, const char *range, const char *value, const char *short_desc, const char *long_desc){ static char *message = (char *)0; if( !message ){ message = new char[CTCS_BUFSIZE]; if( !message ){ CONSOLE.Warning(1, "error, failed to allocate memory for CTCS message"); return (char *)0; } } snprintf(message, CTCS_BUFSIZE, "CTCONFIG %s %s %s %d:%s %d:%s %d:%s", name, type, range, (int)strlen(value), value, (int)strlen(short_desc), short_desc, (int)strlen(long_desc), long_desc); return message;}int Ctcs::Set_Config(const char *origmsg){ char *msgbuf = new char[strlen(origmsg)+1]; if( !msgbuf ){ CONSOLE.Warning(1, "error, failed to allocate memory for config"); return -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -