#define MAX_JOBS 5000 #define DOWNLOAD_DIR "/dev/null" #define TMP_DIR "/mnt/d/webdata/torrents" #define UPLOAD_DIR "/root/torup/" #define DB_HOST "127.0.0.1" #define DB_PORT 3306 #define DB_DATABASE "dbooster_torrents" #define DB_USER "dbooster" #define DB_PASSWORD "UxtmU6w3wNjYUMvV" #include #include #include #include #include #include #include #include #include #include #include #include "P2SP.h" #include "libtorrent/utf8.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/session.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/magnet_uri.hpp" #include "libtorrent/create_torrent.hpp" #include "libtorrent/peer_info.hpp" using namespace std; using namespace libtorrent; using namespace boost; struct HASH_HANDLE { sha1_hash info_hash; DWORD hTorrent; }; struct SETTINGS { BOOL bInited; libtorrent::session* ses; std::map handle_map; std::list list_hash; libtorrent::dht_settings dht_set; libtorrent::session_settings ses_set; libtorrent::pe_settings pe_set; int outstanding_resume_data; }; SETTINGS g_Settings = {0}; bool g_bNewTaskAdd = false; unsigned int g_nFileProcessed = 0; pthread_mutex_t g_ThreadLocker; #define INIT_THREAD_LOCKER pthread_mutex_init(&g_ThreadLocker, 0); #define DESTROY_THREAD_LOCKER pthread_mutex_destroy(&g_ThreadLocker); #define LOCK_THREAD pthread_mutex_lock(&g_ThreadLocker); #define UNLOCK_THREAD pthread_mutex_unlock(&g_ThreadLocker); void TextLog( const char* fmt, ... ) { #ifdef LOG va_list ap; va_start(ap, fmt); vfprintf(stdout, fmt, ap); fprintf(stdout, "\n"); va_end(ap); return; #endif } extern "C" BOOL WINAPI BT_Init( ) { LOCK_THREAD; if ( g_Settings.bInited ) { UNLOCK_THREAD; return TRUE; } libtorrent::error_code ec; g_Settings.ses = new session ( fingerprint("LT", LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0) , session::add_default_plugins , alert::dht_notification | alert::status_notification ); if ( !g_Settings.ses ) { UNLOCK_THREAD; return FALSE; } //DHT相关设置 g_Settings.ses_set.use_dht_as_fallback = false; //是否允许同一台机器的多个连接 g_Settings.ses_set.allow_multiple_connections_per_ip = false; //在内网进行广播,用于组播无法使用的情况 g_Settings.ses_set.broadcast_lsd = false; //不设置半开连接数的限制 g_Settings.ses_set.half_open_limit = -1; g_Settings.ses_set.connection_speed = 50; g_Settings.ses_set.dht_upload_rate_limit = 20000; g_Settings.ses_set.recv_socket_buffer_size = 1024 * 1024; g_Settings.ses_set.send_socket_buffer_size = 1024 * 1024; g_Settings.ses_set.optimize_hashing_for_speed = true; g_Settings.ses_set.request_timeout = 10; //g_Settings.ses_set.peer_timeout = 20; //g_Settings.ses_set.inactivity_timeout = 20; g_Settings.ses_set.max_out_request_queue = 15000; g_Settings.ses_set.max_allowed_in_request_queue = 20000; g_Settings.ses_set.mixed_mode_algorithm = session_settings::prefer_tcp; g_Settings.ses_set.alert_queue_size = 50000; g_Settings.ses_set.file_pool_size = 500; g_Settings.ses_set.no_atime_storage = true; g_Settings.ses_set.connections_limit = 8000; g_Settings.ses_set.listen_queue_size = 2000; g_Settings.ses_set.unchoke_slots_limit = 500; g_Settings.ses_set.read_job_every = 1000; //g_Settings.ses_set.cache_size = 32768 * 2; //内存做磁盘缓存,太大了不好,用默认的16M即可 g_Settings.ses_set.use_read_cache = true; g_Settings.ses_set.cache_buffer_chunk_size = 128; g_Settings.ses_set.read_cache_line_size = 32; g_Settings.ses_set.write_cache_line_size = 32; g_Settings.ses_set.low_prio_disk = false; g_Settings.ses_set.cache_expiry = 60 * 60; g_Settings.ses_set.lock_disk_cache = false; g_Settings.ses_set.max_queued_disk_bytes = 10 * 1024 * 1024; g_Settings.ses_set.disk_cache_algorithm = session_settings::avoid_readback; g_Settings.ses_set.explicit_read_cache = false; g_Settings.ses_set.allowed_fast_set_size = 0; g_Settings.ses_set.suggest_mode = session_settings::suggest_read_cache; g_Settings.ses_set.close_redundant_connections = true; g_Settings.ses_set.max_rejects = 10; g_Settings.ses_set.active_limit = MAX_JOBS; g_Settings.ses_set.active_tracker_limit = 2000; g_Settings.ses_set.active_dht_limit = MAX_JOBS; g_Settings.ses_set.active_seeds = 10; g_Settings.ses_set.choking_algorithm = session_settings::fixed_slots_choker; g_Settings.ses_set.send_buffer_watermark = 3 * 1024 * 1024; g_Settings.ses_set.send_buffer_watermark_factor = 150; g_Settings.ses_set.send_buffer_low_watermark = 1 * 1024 * 1024; g_Settings.ses_set.max_failcount = 3; g_Settings.ses_set.utp_dynamic_sock_buf = true; g_Settings.ses_set.max_http_recv_buffer_size = 6 * 1024 * 1024; g_Settings.ses_set.use_disk_cache_pool = true; //g_Settings.ses_set.dht_announce_interval = 60; //给Session应用设置 g_Settings.ses->set_settings( g_Settings.ses_set ); //加密相关的 g_Settings.pe_set.out_enc_policy = pe_settings::enabled; g_Settings.pe_set.in_enc_policy = pe_settings::enabled; g_Settings.pe_set.allowed_enc_level = pe_settings::both; g_Settings.pe_set.prefer_rc4 = true; g_Settings.ses->set_pe_settings( g_Settings.pe_set ); //开启端口准备开始上传和下载 ec.clear(); g_Settings.ses->listen_on(std::make_pair(6881, 7081), ec); if ( ec ) { UNLOCK_THREAD; return FALSE; } //设置DHT路由器 g_Settings.ses->add_dht_router(std::make_pair( std::string("router.bittorrent.com"), 6881)); g_Settings.ses->add_dht_router(std::make_pair( std::string("router.utorrent.com"), 6881)); g_Settings.ses->add_dht_router(std::make_pair( std::string("dht.transmissionbt.com"), 6881)); g_Settings.ses->add_dht_router(std::make_pair( std::string("router.bitcomet.com"), 6881)); //给Session应用设置 g_Settings.dht_set.privacy_lookups = true; g_Settings.dht_set.max_dht_items = MAX_JOBS; g_Settings.dht_set.ignore_dark_internet = true; g_Settings.ses->set_dht_settings( g_Settings.dht_set ); //开启DHT模式 g_Settings.ses->start_dht(); g_Settings.bInited = TRUE; UNLOCK_THREAD; return TRUE; } DWORD FindEmptyHandle() { static DWORD hTemp = 0; hTemp++; if ( hTemp > MAX_JOBS * 2 ) { hTemp = 1; } return hTemp; } BOOL FindSameTask( const sha1_hash & sha1Hash ) { if ( !g_Settings.bInited ) { return FALSE; } if( g_Settings.ses->find_torrent( sha1Hash ).is_valid() ) { return TRUE; } return FALSE; } extern "C" VOID WINAPI BT_LimitWANSpeed( INT DownLoadLimit, INT UpLoadLimit ) { LOCK_THREAD if ( !g_Settings.bInited ) { UNLOCK_THREAD; return; } g_Settings.ses_set.upload_rate_limit = DownLoadLimit; g_Settings.ses_set.download_rate_limit = UpLoadLimit; g_Settings.ses->set_settings( g_Settings.ses_set ); UNLOCK_THREAD; return; } extern "C" VOID WINAPI BT_LimitTaskSpeed( HANDLE hTorrent, INT DownLoadLimit, INT UpLoadLimit ) { LOCK_THREAD; if ( !g_Settings.bInited ) { UNLOCK_THREAD; return; } DWORD dwTorrent = (DWORD)hTorrent; UpLoadLimit = UpLoadLimit < 0 ? -1 : UpLoadLimit; DownLoadLimit = DownLoadLimit < 0 ? -1 : DownLoadLimit; if ( g_Settings.handle_map.find(dwTorrent) == g_Settings.handle_map.end() ) { UNLOCK_THREAD; return; } g_Settings.handle_map[dwTorrent].set_upload_limit( UpLoadLimit ); g_Settings.handle_map[dwTorrent].set_download_limit( DownLoadLimit ); UNLOCK_THREAD; return; } extern "C" VOID WINAPI BT_DeleteTask( HANDLE hTorrent ) { LOCK_THREAD; DWORD dwTorrent = (DWORD)hTorrent; if ( g_Settings.handle_map.find(dwTorrent) == g_Settings.handle_map.end() ) { UNLOCK_THREAD; return; } if ( !g_Settings.handle_map[dwTorrent].is_valid() ) { UNLOCK_THREAD; return; } g_Settings.handle_map[dwTorrent].pause(); g_Settings.ses->remove_torrent( g_Settings.handle_map[dwTorrent] ); g_Settings.handle_map.erase( g_Settings.handle_map.find(dwTorrent) ); UNLOCK_THREAD; return; } extern "C" VOID WINAPI BT_Release() { LOCK_THREAD; if ( !g_Settings.bInited ) { UNLOCK_THREAD; return; } g_Settings.bInited = FALSE; //删除session内的全部torrent std::map::iterator iter = g_Settings.handle_map.begin(); while ( iter != g_Settings.handle_map.end() ) { iter->second.pause(); while( iter->second.status().paused != true ) { sleep(100); } g_Settings.ses->remove_torrent( iter->second ); while( iter->second.is_valid() ) { sleep(100); } g_Settings.handle_map.erase( iter++ ); } g_Settings.ses->stop_dht(); while ( g_Settings.ses->is_dht_running() ) { sleep(100); } g_Settings.ses->stop_lsd(); g_Settings.ses->stop_natpmp(); g_Settings.ses->stop_upnp(); g_Settings.ses->pause(); while( g_Settings.ses->is_paused() != true ) { sleep(100); } g_Settings.ses->abort(); UNLOCK_THREAD; } extern "C" HANDLE WINAPI BT_Add_From_File( const CHAR* szAsciiFileName, const CHAR* szSavePath ) { LOCK_THREAD; if ( !g_Settings.bInited ) { UNLOCK_THREAD; return INVALID_HANDLE_VALUE; } if ( !szAsciiFileName || !szSavePath ) { UNLOCK_THREAD; return INVALID_HANDLE_VALUE; } error_code ec; ec.clear(); boost::intrusive_ptr t = new torrent_info(szAsciiFileName, ec); if ( ec ) { UNLOCK_THREAD; return INVALID_HANDLE_VALUE; } add_torrent_params param; param.ti = t; param.auto_managed = false; param.upload_mode = true; param.share_mode = true; param.save_path = szSavePath; //看看是否有重复的HASH及保存路径 if ( FindSameTask( t->info_hash() ) ) { UNLOCK_THREAD; return DUPLICATE_TASK_HANDLE; } DWORD hTorrent = FindEmptyHandle(); ec.clear(); g_Settings.handle_map[hTorrent] = g_Settings.ses->add_torrent( param, ec ); if ( ec ) { UNLOCK_THREAD; return INVALID_HANDLE_VALUE; } if( g_Settings.ses->is_paused() ) { g_Settings.ses->resume(); } g_Settings.handle_map[hTorrent].pause(); g_Settings.handle_map[hTorrent].resume(); UNLOCK_THREAD; return (HANDLE)hTorrent; } extern "C" HANDLE WINAPI BT_Add_From_MagNet( const CHAR* szUrl, const CHAR* szSavePath ) { LOCK_THREAD; if ( !g_Settings.bInited ) { UNLOCK_THREAD; return INVALID_HANDLE_VALUE; } if ( !szUrl || !szSavePath ) { UNLOCK_THREAD; return INVALID_HANDLE_VALUE; } add_torrent_params param; param.save_path = szSavePath; param.auto_managed = false; param.upload_mode = true; param.share_mode = true; error_code ec; ec.clear(); parse_magnet_uri(szUrl, param, ec); if ( ec ) { UNLOCK_THREAD; return INVALID_HANDLE_VALUE; } //看看是否有重复的HASH及保存路径 if ( FindSameTask( param.info_hash ) ) { UNLOCK_THREAD; return DUPLICATE_TASK_HANDLE; } DWORD hTorrent = FindEmptyHandle(); ec.clear(); torrent_handle thTemp = g_Settings.ses->add_torrent( param, ec ); if ( ec ) { UNLOCK_THREAD; return INVALID_HANDLE_VALUE; } g_Settings.handle_map[hTorrent] = thTemp; HASH_HANDLE temp_hash_handle = { param.info_hash, hTorrent }; g_Settings.list_hash.push_back( temp_hash_handle ); if( g_Settings.ses->is_paused() ) { g_Settings.ses->resume(); } g_Settings.handle_map[hTorrent].pause(); g_Settings.handle_map[hTorrent].resume(); UNLOCK_THREAD; return (HANDLE)hTorrent; } BOOL save_torrent( torrent_handle & hTorrent, const CHAR* szFilePath ) { if ( !szFilePath ) { return FALSE; } torrent_info ti = *hTorrent.torrent_file().get(); create_torrent new_torrent(ti); std::vector out; bencode(std::back_inserter(out), new_torrent.generate()); FILE* fDest = fopen( szFilePath, "wb" ); if ( !fDest ) { UNLOCK_THREAD; return FALSE; } for ( unsigned int nIndex = 0; nIndex < out.size(); nIndex++ ) { if( 1 != fwrite( &out[nIndex], 1, 1, fDest ) ) { UNLOCK_THREAD; return FALSE; } } fclose(fDest); return TRUE; } string ws2s(const wstring& ws) { string curLocale = setlocale(LC_ALL, NULL); // curLocale = "C"; setlocale(LC_ALL, "chs"); const wchar_t* _Source = ws.c_str(); size_t _Dsize = 2 * ws.size() + 1; char *_Dest = new char[_Dsize]; memset(_Dest,0,_Dsize); wcstombs(_Dest,_Source,_Dsize); string result = _Dest; delete []_Dest; setlocale(LC_ALL, curLocale.c_str()); return result; } int CreateDir(const char *sPathName) { char DirName[256]; strcpy(DirName, sPathName); int i,len = strlen(DirName); if(DirName[len-1]!='/') strcat(DirName, "/"); len = strlen(DirName); for(i=1; itm_year, 1 + p->tm_mon, p->tm_mday ); return string(szTime); } string create_torrent_dir( string save_dir ) { char dir_path[260] = {0}; sprintf( dir_path, "%s/%s", TMP_DIR, save_dir.c_str() ); CreateDir( dir_path ); return string(dir_path); } bool test_mysql_conn() { bool bRet = false; //连接MYSQL服务器 unsigned int conntime = 5; MYSQL* sqlconn = mysql_init( 0 ); if ( !sqlconn ) { TextLog( "mysql_init Fail" ); mysql_close( sqlconn ); return bRet; } mysql_options( sqlconn, MYSQL_OPT_CONNECT_TIMEOUT, (const char*)&conntime ); sqlconn = mysql_real_connect( sqlconn, DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE, DB_PORT, 0, 0 ); if ( !sqlconn ) { TextLog( "MySQL Conn Fail..." ); mysql_close( sqlconn ); return bRet; } mysql_close( sqlconn ); return true; } bool save_to_database( const string & info_hash, const string & filepath, const string & strtime, const torrent_info * torinfo ) { bool bRet = false; //连接MYSQL服务器 unsigned int conntime = 5; MYSQL_RES* ret_ptr = 0; MYSQL_ROW row = 0; MYSQL* sqlconn = mysql_init( 0 ); if ( !sqlconn ) { TextLog( "mysql_init Fail" ); mysql_close( sqlconn ); return bRet; } mysql_options( sqlconn, MYSQL_OPT_CONNECT_TIMEOUT, (const char*)&conntime ); sqlconn = mysql_real_connect( sqlconn, DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE, DB_PORT, 0, 0 ); if ( !sqlconn ) { TextLog( "MySQL Conn Fail..." ); mysql_close( sqlconn ); return bRet; } if( mysql_query(sqlconn, "set names utf8") ) { TextLog( "Set UTF8 Success..." ); } char szMySQLCmd[1024] = {0}; sprintf( szMySQLCmd, "INSERT INTO db_torrents (`hash`, `path`, `date`, `name`, `length`, `ctime`) VALUES('%s','%s', '%s', '%s', '%llu', '%llu') on duplicate key update path='%s'", info_hash.c_str(), filepath.c_str(), strtime.c_str(), torinfo->name().c_str(), torinfo->total_size(), torinfo->creation_date().get_value_or(0), filepath.c_str() ); if ( 0 != mysql_query( sqlconn, szMySQLCmd ) ) { TextLog( "Fail: %s", szMySQLCmd ); mysql_close( sqlconn ); return bRet; } TextLog( "Success: %s", szMySQLCmd ); //取刚刚插入进去的id sprintf( szMySQLCmd, "SELECT `id` from db_torrents where `hash` = '%s'", info_hash.c_str() ); if ( 0 != mysql_query( sqlconn, szMySQLCmd ) ) { TextLog( "Fail: %s", szMySQLCmd ); mysql_close( sqlconn ); return bRet; } ret_ptr = mysql_use_result( sqlconn ); if ( !ret_ptr ) { TextLog( "Fail mysql_use_result: ", szMySQLCmd ); mysql_close( sqlconn ); return bRet; } row = mysql_fetch_row( ret_ptr ); if ( !row ) { mysql_free_result(ret_ptr); TextLog( "Fail mysql_free_result: ", szMySQLCmd ); mysql_close( sqlconn ); return bRet; } long long torrent_id = 0; sscanf( row[0], "%llu", &torrent_id ); mysql_free_result(ret_ptr); //获取这个种子内的全部文件 string strSQLCmd("INSERT INTO `db_files` (`tid`, `fname`, `fpath`, `fsize`) VALUES "); for ( int nIndex = 0; nIndex < torinfo->num_files(); nIndex++ ) { //拼接要插入的字符串 char szTmp[1024] = {0}; sprintf( szTmp, "('%llu','%s', '%s', '%llu')", torrent_id, torinfo->files().file_name(nIndex).c_str(), torinfo->files().file_path(nIndex).c_str(), torinfo->file_at(nIndex).size ); strSQLCmd += szTmp; if ( nIndex == torinfo->num_files()-1 ) { strSQLCmd += ";"; } else { strSQLCmd += ","; } } if ( 0 != mysql_query( sqlconn, strSQLCmd.c_str() ) ) { TextLog( "Fail: %s", strSQLCmd.c_str() ); mysql_close( sqlconn ); return bRet; } mysql_close( sqlconn ); return true; } bool is_database_recorded( string info_hash ) { bool bRet = false; MYSQL_ROW row = 0; MYSQL_RES* ret_ptr = 0; //连接MYSQL服务器 unsigned int conntime = 5; MYSQL* sqlconn = mysql_init( 0 ); if ( !sqlconn ) { TextLog( "mysql_init Fail" ); mysql_close( sqlconn ); return bRet; } mysql_options( sqlconn, MYSQL_OPT_CONNECT_TIMEOUT, (const char*)&conntime ); sqlconn = mysql_real_connect( sqlconn, DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE, DB_PORT, 0, 0 ); if ( !sqlconn ) { TextLog( "MySQL Conn Fail...\n" ); mysql_close( sqlconn ); return bRet; } char szMySQLCmd[1024] = {0}; sprintf( szMySQLCmd, "SELECT hash FROM db_torrents where `hash` = '%s'", info_hash.c_str() ); if ( mysql_query( sqlconn, szMySQLCmd ) ) { TextLog( "Fail: %s\n", szMySQLCmd ); mysql_close( sqlconn ); return bRet; } else { ret_ptr = mysql_use_result( sqlconn ); if ( ret_ptr ) { row = mysql_fetch_row( ret_ptr ); if ( row ) { TextLog( "InDB: %s", info_hash.c_str() ); bRet = true; } else { TextLog( "NoDB: %s", info_hash.c_str() ); } } mysql_free_result(ret_ptr); } mysql_close( sqlconn ); return bRet; } string hash_2_str( sha1_hash info_hash ) { char szHash[60] = {0}; int n = 0; for ( ; n < 20; n++ ) { sprintf(szHash+n*2, "%02hhx", info_hash[n]); } szHash[n*2] = 0; return string(szHash); } void process_torrents() { //看看有哪些任务的状态变成了3,如果变成了3,则暂停这些任务,并保存其种子 //批量获取种子信息 std::map::iterator iter = g_Settings.handle_map.begin(); while ( iter != g_Settings.handle_map.end() ) { if ( !(*iter).second.is_valid() ) { iter++; continue; } if ( (*iter).second.status().state == torrent_status::downloading || (*iter).second.status().state == torrent_status::queued_for_checking || (*iter).second.status().state == torrent_status::checking_files || (*iter).second.status().state == torrent_status::finished || (*iter).second.status().state == torrent_status::seeding || (*iter).second.status().state == torrent_status::allocating || (*iter).second.status().state == torrent_status::checking_resume_data ) { g_nFileProcessed++; (*iter).second.pause(); //TODO:在此处保存种子文件 string szHash = hash_2_str( (*iter).second.info_hash() ); std::string strFilePath = szHash + ".torrent"; string time_str = get_time_string(); string save_dir = get_save_dir( szHash ); string fullpath = create_torrent_dir( save_dir ) + strFilePath; save_torrent( (*iter).second, fullpath.c_str() ); TextLog( "Meta Down: %s", szHash.c_str() ); if ( !save_to_database( szHash.c_str(), save_dir + strFilePath, time_str, (*iter).second.torrent_file().get() ) ) { //保存到数据库失败了 TextLog( "Fail Save to DB: %s", strFilePath.c_str() ); } //从全局数据里删除当前任务 std::list::iterator iter_hash = g_Settings.list_hash.begin(); while ( iter_hash != g_Settings.list_hash.end() ) { if ( iter_hash->info_hash == (*iter).second.info_hash() ) { g_Settings.list_hash.erase(iter_hash); break; } iter_hash++; } g_Settings.ses->remove_torrent( g_Settings.ses->find_torrent( (*iter).second.info_hash() ) ); g_Settings.handle_map.erase( iter++ ); //移除结束 continue; } iter++; } } void my_handle_alert(libtorrent::alert* a) { if ( metadata_received_alert* s = alert_cast(a) ) { process_torrents(); } else if ( state_changed_alert* s = alert_cast(a) ) { process_torrents(); } else if ( torrent_added_alert* s = alert_cast(a) ) { process_torrents(); } else if ( dht_announce_alert* s = alert_cast(a) ) { //拿到HASH了,先查数据库有没有这个hash,没有的话,就添加成BT任务 string strHash = hash_2_str( s->info_hash ); TextLog( "Hash Recved: %s", strHash.c_str() ); //看看现有任务里面有没有,有的话就直接放弃 if( FindSameTask( s->info_hash ) ) { TextLog("InTask: %s", strHash.c_str()); return; } if ( is_database_recorded( strHash ) ) { //数据库里已有,不再添加任务了 return; } std::string strMagNet = std::string("magnet:?xt=urn:btih:") + strHash; //如果任务超过MAX_JOBS个,则删除头部的那一个 if ( g_Settings.ses->get_torrents().size() >= MAX_JOBS ) { HASH_HANDLE head_hash_handle = *g_Settings.list_hash.begin(); std::map::iterator iter_handle_map = g_Settings.handle_map.find( head_hash_handle.hTorrent ); TextLog("Del_Task: Handle: %u -- Hash: %s", head_hash_handle.hTorrent, hash_2_str(head_hash_handle.info_hash).c_str() ); iter_handle_map->second.pause(); g_Settings.ses->remove_torrent( iter_handle_map->second ); g_Settings.handle_map.erase( g_Settings.handle_map.find( head_hash_handle.hTorrent ) ); g_Settings.list_hash.pop_front(); } HANDLE hTask = BT_Add_From_MagNet( strMagNet.c_str(), DOWNLOAD_DIR ); BT_LimitTaskSpeed( hTask, 4096, 4096 ); if( hTask == INVALID_HANDLE_VALUE ) { TextLog( "Fail to add magnet: %s", strMagNet.c_str() ); return; } g_bNewTaskAdd = true; TextLog("AddTask: %s", strHash.c_str()); } else if( dht_get_peers_alert* s = alert_cast(a) ) { //拿到HASH了,先查数据库有没有这个hash,没有的话,就添加成BT任务 string strHash = hash_2_str( s->info_hash ); TextLog( "Hash Recved: %s", strHash.c_str() ); //看看现有任务里面有没有,有的话就直接放弃 if( FindSameTask( s->info_hash ) ) { TextLog("InTask: %s", strHash.c_str()); return; } if ( is_database_recorded( strHash ) ) { //数据库里已有,不再添加任务了 return; } std::string strMagNet = std::string("magnet:?xt=urn:btih:") + strHash; //如果任务超过MAX_JOBS个,则删除头部的那一个 if ( g_Settings.ses->get_torrents().size() >= MAX_JOBS ) { HASH_HANDLE head_hash_handle = *g_Settings.list_hash.begin(); std::map::iterator iter_handle_map = g_Settings.handle_map.find( head_hash_handle.hTorrent ); TextLog("Del_Task: Handle: %u -- Hash: %s", head_hash_handle.hTorrent, hash_2_str(head_hash_handle.info_hash).c_str() ); iter_handle_map->second.pause(); g_Settings.ses->remove_torrent( iter_handle_map->second ); g_Settings.handle_map.erase( g_Settings.handle_map.find( head_hash_handle.hTorrent ) ); g_Settings.list_hash.pop_front(); } HANDLE hTask = BT_Add_From_MagNet( strMagNet.c_str(), DOWNLOAD_DIR ); BT_LimitTaskSpeed( hTask, 4096, 4096 ); if( hTask == INVALID_HANDLE_VALUE ) { TextLog( "Fail to add magnet: %s", strMagNet.c_str() ); return; } g_bNewTaskAdd = true; TextLog("AddTask: %s", strHash.c_str()); } return; } void* WorkThread(void* arg) { #define EVENT_SIZE ( sizeof (struct inotify_event) ) #define EVENT_BUF_LEN ( 10 * ( EVENT_SIZE + 16 ) ) int fd = inotify_init(); char buffer[EVENT_BUF_LEN]; if (fd < 0) { perror("inotify_init"); return 0; } int wd = inotify_add_watch( fd, UPLOAD_DIR, IN_CLOSE_WRITE ); while(1) { int length = read(fd, buffer, EVENT_BUF_LEN); if (length < 0) { perror("read"); } int i = 0; while (i < length) { struct inotify_event *event = (struct inotify_event *) &buffer[i]; if (event->len) { if (event->mask & IN_CLOSE_WRITE) { if (event->mask & IN_ISDIR) { TextLog("New directory %s created.\n", event->name); } else { string strTorPath(UPLOAD_DIR); strTorPath += event->name; TextLog("New file %s created.\n", strTorPath.c_str()); HANDLE hTask = BT_Add_From_File( strTorPath.c_str(), DOWNLOAD_DIR ); BT_LimitTaskSpeed( hTask, 4096, 4096 ); unlink( strTorPath.c_str() ); } } } i += EVENT_SIZE + event->len; } } inotify_rm_watch(fd, wd); close(fd); return 0; } int main(int argc, char* argv[]) { pid_t pid = -1; int status = 0; while( 1 ) { pid = fork(); if ( pid < 0 ) { TextLog( "fork err,exit..." ); return 0; } else if ( pid > 0 ) { //如果我就是父进程 waitpid( pid, &status, 0 ); } else if ( pid == 0 ) { //如果我就是子进程 break; } } mysql_thread_init(); string str_time; TextLog( "Date: %s -- LibTorrent: %u.%u.%u\n", get_time_string().c_str(), LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, LIBTORRENT_VERSION_TINY ); if ( !test_mysql_conn() ) { TextLog("Fatal error: Can't conn to MySQL server..."); return 0; } INIT_THREAD_LOCKER; BT_Init(); //开启一个线程,去监听种子上传目录 pthread_attr_t tattr; int stacksize = PTHREAD_STACK_MIN; int ret; ret = pthread_attr_init( &tattr ); pthread_attr_setstacksize( &tattr, stacksize /*128 * 1024*/ ); pthread_t threadid = 0; pthread_create( &threadid, &tattr, WorkThread, NULL ); //开启线程结束 HANDLE x = BT_Add_From_MagNet( "magnet:?xt=urn:btih:5a3cddafece8cd324b1e2b6d9f118a09e66f349a", DOWNLOAD_DIR ); BT_LimitTaskSpeed( x, 4096, 4096 ); int nCount = 0; std::deque vec_pa; std::deque::iterator iter_pa; while ( 1 ) { alert const* a = g_Settings.ses->wait_for_alert( seconds(1) ); if ( !a ) { continue; } session_status sess_stat = g_Settings.ses->status(); if ( g_bNewTaskAdd == true ) { g_bNewTaskAdd = false; TextLog("TorCount:%u -- Done:%u -- HandleCoun: %u -- HashCount: %u", g_Settings.ses->get_torrents().size(), g_nFileProcessed, g_Settings.handle_map.size(), g_Settings.list_hash.size() ); TextLog("DHT nodes: %u DHT cached nodes: %u total DHT size: %llu total observers: %u\n" , sess_stat.dht_nodes, sess_stat.dht_node_cache, sess_stat.dht_global_nodes , sess_stat.dht_total_allocations); } std::auto_ptr alert = g_Settings.ses->pop_alert(); my_handle_alert( &*alert ); if ( g_Settings.handle_map.size() > 1 ) { g_Settings.handle_map[(DWORD)x].pause(); } else { if ( g_Settings.handle_map[(DWORD)x].status().paused ) { g_Settings.handle_map[(DWORD)x].resume(); } } } mysql_thread_end(); BT_Release(); return 0; }