Example #1
0
void server::handle_request_campaign(const server::request& req)
{
	LOG_CS << "sending campaign '" << req.cfg["name"] << "' to " << req.addr << " using gzip\n";

	config& campaign = get_campaign(req.cfg["name"]);

	if(!campaign) {
		send_error("Add-on '" + req.cfg["name"].str() + "' not found.", req.sock);
	} else {
		const int size = filesystem::file_size(campaign["filename"]);

		if(size < 0) {
			std::cerr << " size: <unknown> KiB\n";
			ERR_CS << "File size unknown, aborting send.\n";
			send_error("Add-on '" + req.cfg["name"].str() + "' could not be read by the server.", req.sock);
			return;
		}

		std::cerr << " size: " << size/1024 << "KiB\n";
		async_send_file(req.sock, campaign["filename"],
				std::bind(&server::handle_new_client, this, _1), null_handler);
		// Clients doing upgrades or some other specific thing shouldn't bump
		// the downloads count. Default to true for compatibility with old
		// clients that won't tell us what they are trying to do.
		if(req.cfg["increase_downloads"].to_bool(true)) {
			const int downloads = campaign["downloads"].to_int() + 1;
			campaign["downloads"] = downloads;
		}
	}
}
Example #2
0
void server::handle_delete(const server::request& req)
{
	const config& erase = req.cfg;

	if(read_only_) {
		LOG_CS << "in read-only mode, request to delete '" << erase["name"] << "' from " << req.addr << " denied\n";
		send_error("Cannot delete add-on: The server is currently in read-only mode.", req.sock);
		return;
	}

	LOG_CS << "deleting campaign '" << erase["name"] << "' requested from " << req.addr << "\n";

	config& campaign = get_campaign(erase["name"]);

	if(!campaign) {
		send_error("The add-on does not exist.", req.sock);
		return;
	}

	if(!authenticate(campaign, erase["passphrase"])
		&& (campaigns()["master_password"].empty()
		|| campaigns()["master_password"] != erase["passphrase"]))
	{
		send_error("The passphrase is incorrect.", req.sock);
		return;
	}

	// Erase the campaign.
	filesystem::write_file(campaign["filename"], std::string());
	if(remove(campaign["filename"].str().c_str()) != 0) {
		ERR_CS << "failed to delete archive for campaign '" << erase["name"]
			   << "' (" << campaign["filename"] << "): " << strerror(errno)
			   << '\n';
	}

	config::child_itors itors = campaigns().child_range("campaign");
	for(size_t index = 0; !itors.empty(); ++index, itors.pop_front())
	{
		if(&campaign == &itors.front()) {
			campaigns().remove_child("campaign", index);
			break;
		}
	}

	write_config();

	send_message("Add-on deleted.", req.sock);

	fire("hook_post_erase", erase["name"]);

}
Example #3
0
void server::handle_change_passphrase(const server::request& req)
{
	const config& cpass = req.cfg;

	if(read_only_) {
		LOG_CS << "in read-only mode, request to change passphrase denied\n";
		send_error("Cannot change passphrase: The server is currently in read-only mode.", req.sock);
		return;
	}

	config& campaign = get_campaign(cpass["name"]);

	if(!campaign) {
		send_error("No add-on with that name exists.", req.sock);
	} else if(!authenticate(campaign, cpass["passphrase"])) {
		send_error("Your old passphrase was incorrect.", req.sock);
	} else if(cpass["new_passphrase"].empty()) {
		send_error("No new passphrase was supplied.", req.sock);
	} else {
		set_passphrase(campaign, cpass["new_passphrase"]);
		write_config();
		send_message("Passphrase changed.", req.sock);
	}
}
Example #4
0
void server::run()
{
	network::connection sock = 0;

	time_t last_ts = monotonic_clock();

	for(;;)
	{
		if(need_reload) {
			load_config(); // TODO: handle port number config changes

			need_reload = 0;
			last_ts = 0;

			LOG_CS << "Reloaded configuration\n";
		}

		try {
			bool force_flush = false;
			std::string admin_cmd;

			if(input_ && input_->read_line(admin_cmd)) {
				control_line ctl = admin_cmd;

				if(ctl == "shut_down") {
					LOG_CS << "Shut down requested by admin, shutting down...\n";
					break;
				} else if(ctl == "readonly") {
					if(ctl.args_count()) {
						cfg_["read_only"] = read_only_ = utils::string_bool(ctl[1], true);
					}

					LOG_CS << "Read only mode: " << (read_only_ ? "enabled" : "disabled") << '\n';
				} else if(ctl == "flush") {
					force_flush = true;
					LOG_CS << "Flushing config to disk...\n";
				} else if(ctl == "reload") {
					if(ctl.args_count()) {
						if(ctl[1] == "blacklist") {
							LOG_CS << "Reloading blacklist...\n";
							load_blacklist();
						} else {
							ERR_CS << "Unrecognized admin reload argument: " << ctl[1] << '\n';
						}
					} else {
						LOG_CS << "Reloading all configuration...\n";
						need_reload = 1;
						// Avoid flush timer ellapsing
						continue;
					}
				} else if(ctl == "setpass") {
					if(ctl.args_count() != 2) {
						ERR_CS << "Incorrect number of arguments for 'setpass'\n";
					} else {
						const std::string& addon_id = ctl[1];
						const std::string& newpass = ctl[2];
						config& campaign = get_campaign(addon_id);

						if(!campaign) {
							ERR_CS << "Add-on '" << addon_id << "' not found, cannot set passphrase\n";
						} else if(newpass.empty()) {
							// Shouldn't happen!
							ERR_CS << "Add-on passphrases may not be empty!\n";
						} else {
							campaign["passphrase"] = newpass;
							write_config();

							LOG_CS << "New passphrase set for '" << addon_id << "'\n";
						}
					}
				} else {
					ERR_CS << "Unrecognized admin command: " << ctl.full() << '\n';
				}
			}

			const time_t cur_ts = monotonic_clock();
			// Write config to disk every ten minutes.
			if(force_flush || labs(cur_ts - last_ts) >= 10*60) {
				write_config();
				last_ts = cur_ts;
			}

			network::process_send_queue();

			sock = network::accept_connection();
			if(sock) {
				LOG_CS << "received connection from " << network::ip_address(sock) << "\n";
			}

			config data;

			while((sock = network::receive_data(data, 0)) != network::null_connection)
			{
				config::all_children_iterator i = data.ordered_begin();

				if(i != data.ordered_end()) {
					// We only handle the first child.
					const config::any_child& c = *i;

					request_handlers_table::const_iterator j
							= handlers_.find(c.key);

					if(j != handlers_.end()) {
						// Call the handler.
						j->second(this, request(c.key, c.cfg, sock));
					} else {
						send_error("Unrecognized [" + c.key + "] request.",
								   sock);
					}
				}
			}
		} catch(network::error& e) {
			if(!e.socket) {
				ERR_CS << "fatal network error: " << e.message << "\n";
				throw;
			} else {
				LOG_CS << "client disconnect: " << e.message << " " << network::ip_address(e.socket) << "\n";
				e.disconnect();
			}
		} catch(const config::error& e) {
			network::connection err_sock = 0;
			network::connection const * err_connection = boost::get_error_info<network::connection_info>(e);

			if(err_connection != NULL) {
				err_sock = *err_connection;
			}

			if(err_sock == 0 && sock > 0) {
				err_sock = sock;
			}

			if(err_sock) {
				ERR_CS << "client disconnect due to exception: " << e.what() << " " << network::ip_address(err_sock) << "\n";
				network::disconnect(err_sock);
			} else {
				throw;
			}
		}

		SDL_Delay(20);
	}
}
Example #5
0
void server::handle_read_from_fifo(const boost::system::error_code& error, std::size_t)
{
	if(error) {
		if(error == boost::asio::error::operation_aborted)
			// This means fifo was closed by load_config() to open another fifo
			return;
		ERR_CS << "Error reading from fifo: " << error.message() << '\n';
		return;
	}

	std::istream is(&admin_cmd_);
	std::string cmd;
	std::getline(is, cmd);

	const control_line ctl = cmd;

	if(ctl == "shut_down") {
		LOG_CS << "Shut down requested by admin, shutting down...\n";
		throw server_shutdown("Shut down via fifo command");
	} else if(ctl == "readonly") {
		if(ctl.args_count()) {
			cfg_["read_only"] = read_only_ = utils::string_bool(ctl[1], true);
		}

		LOG_CS << "Read only mode: " << (read_only_ ? "enabled" : "disabled") << '\n';
	} else if(ctl == "flush") {
		LOG_CS << "Flushing config to disk...\n";
		write_config();
	} else if(ctl == "reload") {
		if(ctl.args_count()) {
			if(ctl[1] == "blacklist") {
				LOG_CS << "Reloading blacklist...\n";
				load_blacklist();
			} else {
				ERR_CS << "Unrecognized admin reload argument: " << ctl[1] << '\n';
			}
		} else {
			LOG_CS << "Reloading all configuration...\n";
			load_config();
			LOG_CS << "Reloaded configuration\n";
		}
	} else if(ctl == "setpass") {
		if(ctl.args_count() != 2) {
			ERR_CS << "Incorrect number of arguments for 'setpass'\n";
		} else {
			const std::string& addon_id = ctl[1];
			const std::string& newpass = ctl[2];
			config& campaign = get_campaign(addon_id);

			if(!campaign) {
				ERR_CS << "Add-on '" << addon_id << "' not found, cannot set passphrase\n";
			} else if(newpass.empty()) {
				// Shouldn't happen!
				ERR_CS << "Add-on passphrases may not be empty!\n";
			} else {
				set_passphrase(campaign, newpass);
				write_config();
				LOG_CS << "New passphrase set for '" << addon_id << "'\n";
			}
		}
	} else {
		ERR_CS << "Unrecognized admin command: " << ctl.full() << '\n';
	}

	read_from_fifo();
}