directory::directory(std::string const& path, error_code& ec) : m_done(false) { ec.clear(); #ifdef TORRENT_WINDOWS // the path passed to FindFirstFile() must be // a pattern std::string f = convert_separators(path); if (!f.empty() && f[f.size()-1] != '\\') f += "\\*"; else f += "*"; #if TORRENT_USE_WSTRING #define FindFirstFile_ FindFirstFileW std::wstring p = convert_to_wstring(f); #else #define FindFirstFile_ FindFirstFileA std::string p = convert_to_native(f); #endif m_handle = FindFirstFile_(p.c_str(), &m_fd); if (m_handle == INVALID_HANDLE_VALUE) { ec.assign(GetLastError(), boost::system::get_system_category()); m_done = true; return; } #else memset(&m_dirent, 0, sizeof(dirent)); m_name[0] = 0; // the path passed to opendir() may not // end with a / std::string p = path; if (!path.empty() && path[path.size()-1] == '/') p.resize(path.size()-1); p = convert_to_native(p); m_handle = opendir(p.c_str()); if (m_handle == 0) { ec.assign(errno, boost::system::get_generic_category()); m_done = true; return; } // read the first entry next(ec); #endif }
std::string get_symlink_path(std::string const& p) { #if defined TORRENT_WINDOWS return ""; #else std::string path = convert_to_native(p); return get_symlink_path_impl(p.c_str()); #endif }
void rename(std::string const& inf, std::string const& newf, error_code& ec) { ec.clear(); #if TORRENT_USE_WSTRING && defined TORRENT_WINDOWS std::wstring f1 = convert_to_wstring(inf); std::wstring f2 = convert_to_wstring(newf); if (_wrename(f1.c_str(), f2.c_str()) < 0) #else std::string f1 = convert_to_native(inf); std::string f2 = convert_to_native(newf); if (::rename(f1.c_str(), f2.c_str()) < 0) #endif { ec.assign(errno, boost::system::get_generic_category()); return; } }
void add_transfer_params::dump() const { DBG("add_transfer_params::dump"); DBG("file hash: " << file_hash << " all hashes size: " << piece_hashses.size()); DBG("file path: " << convert_to_native(file_path)); DBG("file size: " << file_size); DBG("accepted: " << accepted << " requested: " << requested << " transf: " << transferred << " priority: " << priority); }
void remove(std::string const& inf, error_code& ec) { ec.clear(); #ifdef TORRENT_WINDOWS // windows does not allow trailing / or \ in // the path when removing files std::string pruned; if (inf[inf.size() - 1] == '/' || inf[inf.size() - 1] == '\\') pruned = inf.substr(0, inf.size() - 1); else pruned = inf; #if TORRENT_USE_WSTRING #define DeleteFile_ DeleteFileW #define RemoveDirectory_ RemoveDirectoryW std::wstring f = convert_to_wstring(pruned); #else #define DeleteFile_ DeleteFileA #define RemoveDirectory_ RemoveDirectoryA std::string f = convert_to_native(pruned); #endif if (DeleteFile_(f.c_str()) == 0) { if (GetLastError() == ERROR_ACCESS_DENIED) { if (RemoveDirectory_(f.c_str()) != 0) return; } ec.assign(GetLastError(), boost::system::get_system_category()); return; } #else // TORRENT_WINDOWS std::string f = convert_to_native(inf); if (::remove(f.c_str()) < 0) { ec.assign(errno, boost::system::get_generic_category()); return; } #endif // TORRENT_WINDOWS }
void stat_file(std::string inf, file_status* s , error_code& ec, int flags) { ec.clear(); #ifdef TORRENT_WINDOWS // apparently windows doesn't expect paths // to directories to ever end with a \ or / if (!inf.empty() && (inf[inf.size() - 1] == '\\' || inf[inf.size() - 1] == '/')) inf.resize(inf.size() - 1); #endif #if TORRENT_USE_WSTRING && defined TORRENT_WINDOWS std::wstring f = convert_to_wstring(inf); #else std::string f = convert_to_native(inf); #endif #ifdef TORRENT_WINDOWS struct _stati64 ret; #if TORRENT_USE_WSTRING if (_wstati64(f.c_str(), &ret) < 0) #else if (_stati64(f.c_str(), &ret) < 0) #endif { ec.assign(errno, boost::system::get_generic_category()); return; } #else struct stat ret; int retval; if (flags & dont_follow_links) retval = ::lstat(f.c_str(), &ret); else retval = ::stat(f.c_str(), &ret); if (retval < 0) { ec.assign(errno, boost::system::get_generic_category()); return; } #endif // TORRENT_WINDOWS s->file_size = ret.st_size; s->atime = ret.st_atime; s->mtime = ret.st_mtime; s->ctime = ret.st_ctime; s->mode = ret.st_mode; }
void create_directory(std::string const& f, error_code& ec) { ec.clear(); #if defined TORRENT_WINDOWS && TORRENT_USE_WSTRING #define CreateDirectory_ CreateDirectoryW std::wstring n = convert_to_wstring(f); #else #define CreateDirectory_ CreateDirectoryA std::string n = convert_to_native(f); #endif #ifdef TORRENT_WINDOWS if (CreateDirectory_(n.c_str(), 0) == 0 && GetLastError() != ERROR_ALREADY_EXISTS) ec.assign(GetLastError(), boost::system::get_system_category()); #else int ret = mkdir(n.c_str(), 0777); if (ret < 0 && errno != EEXIST) ec.assign(errno, boost::system::get_generic_category()); #endif }
bool read_data(char* data, size_type offset, size_type size, size_type& read_size) { if (m_abort) return false; boost::mutex::scoped_lock lock(m_notify_mutex); const torrent_info& info = m_handle.get_torrent_info(); bool ret = false; read_size = 0; #if defined(_DEBUG) && defined(WIN32) unsigned int time = GetTickCount(); #endif // 计算偏移所在的片. int index = offset / info.piece_length(); BOOST_ASSERT(index >= 0 && index < info.num_pieces()); if (index >= info.num_pieces() || index < 0) return ret; torrent_status status = m_handle.status(torrent_handle::query_pieces); bitfield &pieces = status.pieces; if (!pieces.empty()) { if (status.state != torrent_status::finished && status.state != torrent_status::seeding && status.state != torrent_status::downloading) return ret; // 查看是否需要计算新的下载位置. bool set_download_point = true; int min_piece_position = std::min(index, m_cache_offset); int max_piece_position = std::max(index, m_cache_offset); if (min_piece_position != -1)// min_piece_position 为-1, 需要设置下载位置, 也就是首次下载位置. { // 不为-1, 先计算下载点位置, 如果相等, 说明上一次已经设置过下载点位置. if (min_piece_position == max_piece_position) set_download_point = false; else { // 查看上次请求的位置和当前位置是否连接已经下载的分块区域, 如果下载区域已经连接成块. // 那么也不需要再设置下载点位置. for (; min_piece_position < max_piece_position; min_piece_position++) if (!pieces.get_bit(min_piece_position)) break; // 表示下载块连接成区域. if (min_piece_position == max_piece_position) set_download_point = false; } } // 缓存下载位置. m_cache_offset = index; // 计算下载位置, 如果有需要, 则修改下载位置. if (set_download_point) { std::vector<int> new_point(pieces.size(), 1); new_point[index] = 7; m_handle.prioritize_pieces(new_point); } // 如果有数据, 则进入读取. if (pieces.get_bit(index)) { // 保存参数信息. m_current_buffer = data; m_read_offset = offset; m_read_size = &read_size; m_request_size = size; // 提交请求. m_handle.read_piece(index, boost::bind(&extern_read_op::on_read, this, _1, _2, _3)); // 等待请求返回. m_notify.wait(lock); // 读取字节数. if (read_size != 0) ret = true; } } else { // 直接读取文件. if (m_file_path.string() == "" || !m_file.is_open()) { boost::filesystem::path path = m_handle.save_path(); const file_storage& stor = info.files(); std::string name = stor.name(); m_file_path = path / name; name = convert_to_native(m_file_path.string()); // 打开文件, 直接从文件读取数据. if (!m_file.is_open()) { m_file.open(name.c_str(), std::ios::in | std::ios::binary); if (!m_file.is_open()) return ret; } } if (!m_file.is_open()) return ret; m_file.clear(); m_file.seekg(offset, std::ios::beg); m_file.read(data, size); read_size = m_file.gcount(); if (read_size != -1) ret = true; } #if defined(_DEBUG) && defined(WIN32) static unsigned int cur_time = GetTickCount(); char str_info[8192] = { 0 }; char *ptr = (char*)str_info; if (GetTickCount() - cur_time >= 5000) { cur_time = GetTickCount(); sprintf(str_info, "request: %d, size: %d, request time: %d, peers: %d\n", index, (int)size, cur_time - time, status.num_peers); ptr = ptr + strlen(str_info); for (int i = 0; i < status.pieces.size() / 8; i++) { if (i % 32 == 0) { sprintf(ptr, "\n"); ptr += 1; } sprintf(ptr, "%02X", (unsigned char)status.pieces.bytes()[i]); ptr += 2; } if (status.pieces.size() % 8 != 0) { sprintf(ptr, "%02X", (unsigned char)status.pieces.bytes()[status.pieces.size() / 8]); ptr += 2; } sprintf(ptr, "\n\n"); // 显示当前正在下载的分片信息. std::string out; char str[500]; std::vector<cached_piece_info> pieces; torrent_handle &h = m_handle; std::vector<partial_piece_info> queue; std::vector<peer_info> peers; m_ses.get_cache_info(h.info_hash(), pieces); h.get_download_queue(queue); h.get_peer_info(peers); std::sort(queue.begin(), queue.end(), boost::bind(&partial_piece_info::piece_index, _1) < boost::bind(&partial_piece_info::piece_index, _2)); std::sort(pieces.begin(), pieces.end(), boost::bind(&cached_piece_info::last_use, _1) > boost::bind(&cached_piece_info::last_use, _2)); for (std::vector<cached_piece_info>::iterator i = pieces.begin(); i != pieces.end(); ++i) { partial_piece_info* pp = 0; partial_piece_info tmp; tmp.piece_index = i->piece; std::vector<partial_piece_info>::iterator ppi = std::lower_bound(queue.begin(), queue.end(), tmp , boost::bind(&partial_piece_info::piece_index, _1) < boost::bind(&partial_piece_info::piece_index, _2)); if (ppi != queue.end() && ppi->piece_index == i->piece) pp = &*ppi; print_piece(pp, &*i, peers, out); if (pp) queue.erase(ppi); } for (std::vector<partial_piece_info>::iterator i = queue.begin() , end(queue.end()); i != end; ++i) { print_piece(&*i, 0, peers, out); } snprintf(str, sizeof(str), "%s %s: read cache %s %s: downloading %s %s: cached %s %s: flushed\n" , esc("34;7"), esc("0") // read cache , esc("33;7"), esc("0") // downloading , esc("36;7"), esc("0") // cached , esc("32;7"), esc("0")); // flushed out += str; out += "___________________________________\n"; strcat(str_info, out.c_str()); OutputDebugStringA(str_info); printf(str_info); } #endif return ret; }
void copy_file(std::string const& inf, std::string const& newf, error_code& ec) { ec.clear(); #if TORRENT_USE_WSTRING && defined TORRENT_WINDOWS #define CopyFile_ CopyFileW std::wstring f1 = convert_to_wstring(inf); std::wstring f2 = convert_to_wstring(newf); #else #define CopyFile_ CopyFileA std::string f1 = convert_to_native(inf); std::string f2 = convert_to_native(newf); #endif #ifdef TORRENT_WINDOWS if (CopyFile_(f1.c_str(), f2.c_str(), false) == 0) ec.assign(GetLastError(), boost::system::get_system_category()); #elif defined __APPLE__ && defined __MACH__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 // this only works on 10.5 copyfile_state_t state = copyfile_state_alloc(); if (copyfile(f1.c_str(), f2.c_str(), state, COPYFILE_ALL) < 0) ec.assign(errno, boost::system::get_generic_category()); copyfile_state_free(state); #else int infd = ::open(inf.c_str(), O_RDONLY); if (infd < 0) { ec.assign(errno, boost::system::get_generic_category()); return; } // rely on default umask to filter x and w permissions // for group and others // TODO: copy the mode from the source file int permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; int outfd = ::open(newf.c_str(), O_WRONLY | O_CREAT, permissions); if (outfd < 0) { close(infd); ec.assign(errno, boost::system::get_generic_category()); return; } char buffer[4096]; for (;;) { int num_read = read(infd, buffer, sizeof(buffer)); if (num_read == 0) break; if (num_read < 0) { ec.assign(errno, boost::system::get_generic_category()); break; } int num_written = write(outfd, buffer, num_read); if (num_written < num_read) { ec.assign(errno, boost::system::get_generic_category()); break; } if (num_read < int(sizeof(buffer))) break; } close(infd); close(outfd); #endif // TORRENT_WINDOWS }
bool torrent_source::open(boost::any ctx) { // 保存打开指针. m_open_data.reset(boost::any_cast<open_torrent_data*>(ctx)); // 开启下载对象. add_torrent_params p; p.save_path = m_open_data->save_path; error_code ec; // 打开种子, 开始下载. if (m_open_data->is_file) { p.ti = new torrent_info(m_open_data->filename, ec); if (ec) { printf("%s\n", ec.message().c_str()); return false; } } // 非文件的种子, 直接使用种子数据打开torrent. if (!m_open_data->is_file) { p.ti = new torrent_info((const char*)m_open_data->torrent_data.get(), m_open_data->data_size, ec); if (ec) { printf("%s\n", ec.message().c_str()); return false; } } int index = 0; // 遍历视频文件. const file_storage &fs = p.ti->files(); for (file_storage::iterator i = fs.begin(); i != fs.end(); i++) { boost::filesystem::path p(convert_to_native(i->filename())); std::string ext = p.extension().string(); if (ext == ".rmvb" || ext == ".wmv" || ext == ".avi" || ext == ".mkv" || ext == ".flv" || ext == ".rm" || ext == ".mp4" || ext == ".3gp" || ext == ".webm" || ext == ".mpg") { video_file_info vfi; vfi.filename = convert_to_native(i->filename()); vfi.base_offset = i->offset; vfi.offset = i->offset; vfi.data_size = i->size; vfi.index = index++; vfi.status = 0; // 当前视频默认置为第一个视频. if (m_current_video.index == -1) m_current_video = vfi; // 保存到视频列表中. m_videos.push_back(vfi); } } m_session.add_dht_router(std::make_pair( std::string("router.bittorrent.com"), 6881)); m_session.add_dht_router(std::make_pair( std::string("router.utorrent.com"), 6881)); m_session.add_dht_router(std::make_pair( std::string("router.bitcomet.com"), 6881)); m_session.start_dht(); // m_session.load_asnum_db("GeoIPASNum.dat"); // m_session.load_country_db("GeoIP.dat"); m_session.listen_on(std::make_pair(6881, 6889)); // 设置缓冲. session_settings settings = m_session.settings(); settings.use_read_cache = false; settings.disk_io_read_mode = session_settings::disable_os_cache; settings.broadcast_lsd = true; settings.allow_multiple_connections_per_ip = true; settings.local_service_announce_interval = 15; settings.min_announce_interval = 20; m_session.set_settings(settings); // 添加到session中. m_torrent_handle = m_session.add_torrent(p, ec); if (ec) { printf("%s\n", ec.message().c_str()); return false; } m_torrent_handle.force_reannounce(); // 自定义播放模式下载. m_torrent_handle.set_user_defined_download(true); // 限制上传速率为测试. // m_session.set_upload_rate_limit(80 * 1024); // m_session.set_local_upload_rate_limit(80 * 1024); // 创建bt数据读取对象. m_read_op.reset(new extern_read_op(m_torrent_handle, m_session)); m_abort = false; return true; }