void sendAnnounce(std::string action, const std::vector<std::string> & clients_names, double uptime, u32 game_time, float lag, std::string gameid, std::vector<ModSpec> mods) { Json::Value server; if (action.size()) server["action"] = action; server["port"] = g_settings->get("port"); server["address"] = g_settings->get("server_address"); if (action != "delete") { server["name"] = g_settings->get("server_name"); server["description"] = g_settings->get("server_description"); server["version"] = minetest_version_simple; server["url"] = g_settings->get("server_url"); server["creative"] = g_settings->get("creative_mode"); server["damage"] = g_settings->get("enable_damage"); server["password"] = g_settings->getBool("disallow_empty_password"); server["pvp"] = g_settings->getBool("enable_pvp"); server["clients"] = (int)clients_names.size(); server["clients_max"] = g_settings->get("max_users"); server["clients_list"] = Json::Value(Json::arrayValue); for(u32 i = 0; i < clients_names.size(); ++i) { server["clients_list"].append(clients_names[i]); } if (uptime >= 1) server["uptime"] = (int)uptime; if (gameid != "") server["gameid"] = gameid; if (game_time >= 1) server["game_time"] = game_time; } if(server["action"] == "start") { server["dedicated"] = g_settings->get("server_dedicated"); server["privs"] = g_settings->get("default_privs"); server["rollback"] = g_settings->getBool("enable_rollback_recording"); server["liquid_finite"] = g_settings->getBool("liquid_finite"); server["mapgen"] = g_settings->get("mg_name"); server["can_see_far_names"] = g_settings->getBool("unlimited_player_transfer_distance"); server["mods"] = Json::Value(Json::arrayValue); for(std::vector<ModSpec>::iterator m = mods.begin(); m != mods.end(); m++) { server["mods"].append(m->name); } actionstream << "announcing to " << g_settings->get("serverlist_url") << std::endl; } else { if (lag) server["lag"] = lag; } Json::FastWriter writer; HTTPFetchRequest fetchrequest; fetchrequest.url = g_settings->get("serverlist_url") + std::string("/announce"); std::string query = std::string("json=") + urlencode(writer.write(server)); if (query.size() < 1000) fetchrequest.url += "?" + query; else fetchrequest.post_fields = query; httpfetch_async(fetchrequest); }
void sendAnnounce(const std::string &action, const std::vector<std::string> &clients_names, const double uptime, const u32 game_time, const float lag, const std::string &gameid, const std::string &mg_name, const std::vector<ModSpec> &mods) { #if USE_CURL Json::Value server; server["action"] = action; server["port"] = g_settings->getU16("port"); if (g_settings->exists("server_address")) { server["address"] = g_settings->get("server_address"); } if (action != "delete") { server["name"] = g_settings->get("server_name"); server["description"] = g_settings->get("server_description"); server["version"] = minetest_version_simple; server["url"] = g_settings->get("server_url"); server["creative"] = g_settings->getBool("creative_mode"); server["damage"] = g_settings->getBool("enable_damage"); server["password"] = g_settings->getBool("disallow_empty_password"); server["pvp"] = g_settings->getBool("enable_pvp"); if (uptime >= 1) server["uptime"] = (int) uptime; if (game_time >= 1) server["game_time"]= game_time; server["clients"] = (int) clients_names.size(); server["clients_max"] = g_settings->getU16("max_users"); server["clients_list"] = Json::Value(Json::arrayValue); for (std::vector<std::string>::const_iterator it = clients_names.begin(); it != clients_names.end(); ++it) { server["clients_list"].append(*it); } if (gameid != "") server["gameid"] = gameid; } if (action == "start") { server["dedicated"] = g_settings->getBool("server_dedicated"); server["rollback"] = g_settings->getBool("enable_rollback_recording"); server["mapgen"] = mg_name; server["privs"] = g_settings->get("default_privs"); server["can_see_far_names"] = g_settings->getS16("player_transfer_distance") <= 0; server["liquid_real"] = g_settings->getBool("liquid_real"); server["mods"] = Json::Value(Json::arrayValue); for (std::vector<ModSpec>::const_iterator it = mods.begin(); it != mods.end(); ++it) { server["mods"].append(it->name); } actionstream << "Announcing to " << g_settings->get("serverlist_url") << std::endl; } else { if (lag) server["lag"] = lag; } Json::FastWriter writer; HTTPFetchRequest fetch_request; fetch_request.timeout = fetch_request.connect_timeout = 59000; fetch_request.url = g_settings->get("serverlist_url") + std::string("/announce"); std::string query = std::string("json=") + urlencode(writer.write(server)); if (query.size() < 1000) fetch_request.url += "?" + query; else fetch_request.post_data = query; /* fetch_request.post_fields["json"] = writer.write(server); fetch_request.multipart = true; */ httpfetch_async(fetch_request); #endif }
void ClientMediaDownloader::startRemoteMediaTransfers() { bool changing_name_bound = true; for (std::map<std::string, FileStatus*>::iterator files_iter = m_files.upper_bound(m_name_bound); files_iter != m_files.end(); ++files_iter) { // Abort if active fetch limit is exceeded if (m_httpfetch_active >= m_httpfetch_active_limit) break; const std::string &name = files_iter->first; FileStatus *filestatus = files_iter->second; if (!filestatus->received && filestatus->current_remote < 0) { // File has not been received yet and is not currently // being transferred. Choose a server for it. s32 remote_id = selectRemoteServer(filestatus); if (remote_id >= 0) { // Found a server, so start fetching RemoteServerStatus *remote = m_remotes[remote_id]; std::string url = remote->baseurl + (remote->request_by_filename ? name : hex_encode(filestatus->sha1)); verbosestream << "Client: " << "Requesting remote media file " << "\"" << name << "\" " << "\"" << url << "\"" << std::endl; HTTPFetchRequest fetchrequest; fetchrequest.url = url; fetchrequest.caller = m_httpfetch_caller; fetchrequest.request_id = m_httpfetch_next_id; fetchrequest.timeout = 0; // no data timeout! fetchrequest.connect_timeout = m_httpfetch_timeout; httpfetch_async(fetchrequest); m_remote_file_transfers.insert(std::make_pair( m_httpfetch_next_id, name)); filestatus->current_remote = remote_id; remote->active_count++; m_httpfetch_active++; m_httpfetch_next_id++; } } if (filestatus->received || (filestatus->current_remote < 0 && !m_outstanding_hash_sets)) { // If we arrive here, we conclusively know that we // won't fetch this file from a remote server in the // future. So update the name bound if possible. if (changing_name_bound) m_name_bound = name; } else changing_name_bound = false; } }
void ClientMediaDownloader::initialStep(Client *client) { // Check media cache m_uncached_count = m_files.size(); for (std::map<std::string, FileStatus*>::iterator it = m_files.begin(); it != m_files.end(); ++it) { std::string name = it->first; FileStatus *filestatus = it->second; const std::string &sha1 = filestatus->sha1; std::ostringstream tmp_os(std::ios_base::binary); bool found_in_cache = m_media_cache.load(hex_encode(sha1), tmp_os); // If found in cache, try to load it from there if (found_in_cache) { bool success = checkAndLoad(name, sha1, tmp_os.str(), true, client); if (success) { filestatus->received = true; m_uncached_count--; } } } assert(m_uncached_received_count == 0); // Create the media cache dir if we are likely to write to it if (m_uncached_count != 0) { bool did = fs::CreateAllDirs(getMediaCacheDir()); if (!did) { errorstream << "Client: " << "Could not create media cache directory: " << getMediaCacheDir() << std::endl; } } // If we found all files in the cache, report this fact to the server. // If the server reported no remote servers, immediately start // conventional transfers. Note: if cURL support is not compiled in, // m_remotes is always empty, so "!USE_CURL" is redundant but may // reduce the size of the compiled code if (!USE_CURL || m_uncached_count == 0 || m_remotes.empty()) { startConventionalTransfers(client); } else { // Otherwise start off by requesting each server's sha1 set // This is the first time we use httpfetch, so alloc a caller ID m_httpfetch_caller = httpfetch_caller_alloc(); m_httpfetch_timeout = g_settings->getS32("curl_timeout"); // Set the active fetch limit to curl_parallel_limit or 84, // whichever is greater. This gives us some leeway so that // inefficiencies in communicating with the httpfetch thread // don't slow down fetches too much. (We still want some limit // so that when the first remote server returns its hash set, // not all files are requested from that server immediately.) // One such inefficiency is that ClientMediaDownloader::step() // is only called a couple times per second, while httpfetch // might return responses much faster than that. // Note that httpfetch strictly enforces curl_parallel_limit // but at no inter-thread communication cost. This however // doesn't help with the aforementioned inefficiencies. // The signifance of 84 is that it is 2*6*9 in base 13. m_httpfetch_active_limit = g_settings->getS32("curl_parallel_limit"); m_httpfetch_active_limit = MYMAX(m_httpfetch_active_limit, 84); // Write a list of hashes that we need. This will be POSTed // to the server using Content-Type: application/octet-stream std::string required_hash_set = serializeRequiredHashSet(); // minor fixme: this loop ignores m_httpfetch_active_limit // another minor fixme, unlikely to matter in normal usage: // these index.mth fetches do (however) count against // m_httpfetch_active_limit when starting actual media file // requests, so if there are lots of remote servers that are // not responding, those will stall new media file transfers. for (u32 i = 0; i < m_remotes.size(); ++i) { assert(m_httpfetch_next_id == i); RemoteServerStatus *remote = m_remotes[i]; actionstream << "Client: Contacting remote server \"" << remote->baseurl << "\"" << std::endl; HTTPFetchRequest fetchrequest; fetchrequest.url = remote->baseurl + MTHASHSET_FILE_NAME; fetchrequest.caller = m_httpfetch_caller; fetchrequest.request_id = m_httpfetch_next_id; // == i fetchrequest.timeout = m_httpfetch_timeout; fetchrequest.connect_timeout = m_httpfetch_timeout; fetchrequest.post_data = required_hash_set; fetchrequest.extra_headers.push_back( "Content-Type: application/octet-stream"); httpfetch_async(fetchrequest); m_httpfetch_active++; m_httpfetch_next_id++; m_outstanding_hash_sets++; } } }
void sendAnnounce(const std::string &action, const u16 port, const std::vector<std::string> &clients_names, const double uptime, const u32 game_time, const float lag, const std::string &gameid, const std::string &mg_name, const std::vector<ModSpec> &mods) { Json::Value server; server["action"] = action; server["port"] = port; if (g_settings->exists("server_address")) { server["address"] = g_settings->get("server_address"); } if (action != "delete") { bool strict_checking = g_settings->getBool("strict_protocol_version_checking"); server["name"] = g_settings->get("server_name"); server["description"] = g_settings->get("server_description"); server["version"] = g_version_string; server["proto_min"] = strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MIN; server["proto_max"] = strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MAX; server["url"] = g_settings->get("server_url"); server["creative"] = g_settings->getBool("creative_mode"); server["damage"] = g_settings->getBool("enable_damage"); server["password"] = g_settings->getBool("disallow_empty_password"); server["pvp"] = g_settings->getBool("enable_pvp"); server["uptime"] = (int) uptime; server["game_time"] = game_time; server["clients"] = (int) clients_names.size(); server["clients_max"] = g_settings->getU16("max_users"); server["clients_list"] = Json::Value(Json::arrayValue); for (std::vector<std::string>::const_iterator it = clients_names.begin(); it != clients_names.end(); ++it) { server["clients_list"].append(*it); } if (gameid != "") server["gameid"] = gameid; } if (action == "start") { server["dedicated"] = g_settings->getBool("server_dedicated"); server["rollback"] = g_settings->getBool("enable_rollback_recording"); server["mapgen"] = mg_name; server["privs"] = g_settings->get("default_privs"); server["can_see_far_names"] = g_settings->getS16("player_transfer_distance") <= 0; server["mods"] = Json::Value(Json::arrayValue); for (std::vector<ModSpec>::const_iterator it = mods.begin(); it != mods.end(); ++it) { server["mods"].append(it->name); } actionstream << "Announcing to " << g_settings->get("serverlist_url") << std::endl; } else { if (lag) server["lag"] = lag; } Json::FastWriter writer; HTTPFetchRequest fetch_request; fetch_request.url = g_settings->get("serverlist_url") + std::string("/announce"); fetch_request.post_fields["json"] = writer.write(server); fetch_request.multipart = true; httpfetch_async(fetch_request); }