-//\r
+//\r
// Server.cpp\r
//\r
\r
#include <algorithm>\r
#include <boost/make_shared.hpp>\r
#include <boost/foreach.hpp>\r
+#include <boost/archive/text_oarchive.hpp>\r
+#include <boost/property_tree/ptree_serialization.hpp>\r
#include "../common/Logger.hpp"\r
#include "../common/network/Command.hpp"\r
#include "../common/network/Utils.hpp"\r
\r
namespace network {\r
\r
- Server::Server(const Config& config) :\r
- config_(config),\r
- endpoint_(tcp::v4(), config.port()),\r
+ Server::Server() :\r
+ endpoint_(tcp::v4(), config_.port()),\r
acceptor_(io_service_, endpoint_),\r
- socket_udp_(io_service_, udp::endpoint(udp::v4(), config.port())),\r
- udp_packet_count_(0)\r
+ socket_udp_(io_service_, udp::endpoint(udp::v4(), config_.port())),\r
+ udp_packet_count_(0),\r
+ recent_chat_log_(10)\r
{\r
}\r
\r
[&](network::Command c){\r
\r
// ログアウト\r
- if (c.header() == network::header::FatalConnectionError) {\r
+ if (c.header() == network::header::FatalConnectionError || \r
+ c.header() == network::header::UserFatalConnectionError) {\r
if (callback) {\r
(*callback)(c);\r
}\r
} else if (auto session = c.session().lock()) {\r
auto read_average = session->GetReadByteAverage();\r
if (read_average > config_.receive_limit_2()) {\r
- Logger::Info(_T("Banished session: %d"), session->id());\r
+ Logger::Info(_T("Banished a session: %d %dbyte/s"), session->id(), read_average);\r
session->Close();\r
} else if(read_average > config_.receive_limit_1()) {\r
Logger::Info(_T("Receive limit exceeded: %d: %d byte/s"), session->id(), read_average);\r
\r
});\r
\r
+ BOOST_FOREACH(const auto& host, config().lobby_servers()) {\r
+ udp::resolver resolver(io_service_);\r
+ udp::resolver::query query(udp::v4(), host.c_str(), "39380");\r
+ lobby_hosts_.push_back(resolver.resolve(query));\r
+ }\r
+\r
{\r
auto new_session = boost::make_shared<ServerSession>(io_service_);\r
acceptor_.async_accept(new_session->tcp_socket(),\r
int Server::GetUserCount() const\r
{\r
auto count = std::count_if(sessions_.begin(), sessions_.end(),\r
- [](const SessionWeakPtr& s){ return !s.expired() && s.lock()->online(); });\r
+ [](const SessionWeakPtr& s){ \r
+ return !s.expired() && s.lock()->online() && s.lock()->id() > 0; \r
+ });\r
\r
return count;\r
}\r
return msg;\r
}\r
\r
+ std::string Server::GetFullStatus() const\r
+ {\r
+ using namespace boost::property_tree;\r
+ ptree xml_ptree;\r
+\r
+ xml_ptree.put_child("config", config_.pt());\r
+ xml_ptree.put("version", (boost::format("%d.%d.%d") \r
+ % MMO_VERSION_MAJOR % MMO_VERSION_MINOR % MMO_VERSION_REVISION).str());\r
+ xml_ptree.put("protocol_version", MMO_PROTOCOL_VERSION);\r
+\r
+ {\r
+ ptree player_array;\r
+ auto id_list = account_.GetIDList();\r
+ BOOST_FOREACH(const auto& s, sessions_) {\r
+ if (!s.expired() && s.lock()->online() && s.lock()->id() > 0) {\r
+ auto id = s.lock()->id();\r
+ ptree player;\r
+ player.put("name", account_.GetUserName(id));\r
+ player.put("model_name", account_.GetUserModelName(id));\r
+ player_array.push_back(std::make_pair("", player));\r
+ }\r
+ }\r
+ xml_ptree.put_child("players", player_array);\r
+ }\r
+\r
+ //{\r
+ // ptree log_array;\r
+ // BOOST_FOREACH(const std::string& msg, recent_chat_log_) {\r
+ // log_array.push_back(std::make_pair("", msg));\r
+ // }\r
+ // xml_ptree.put_child("recent_chat_log", log_array);\r
+ //}\r
+\r
+ xml_ptree.put_child("channels", channel_.pt());\r
+ std::stringstream stream;\r
+ boost::archive::text_oarchive oa(stream);\r
+ oa << xml_ptree;\r
+\r
+ return stream.str();\r
+ }\r
+\r
+ const Config& Server::config() const\r
+ {\r
+ return config_;\r
+ }\r
+\r
+ Account& Server::account()\r
+ {\r
+ return account_;\r
+ }\r
+ \r
+ void Server::AddChatLog(const std::string& msg)\r
+ {\r
+ recent_chat_log_.push_back(msg);\r
+ }\r
+\r
bool Server::Empty() const\r
{\r
return GetUserCount() == 0;\r
\r
void Server::ReceiveSession(const SessionPtr& session, const boost::system::error_code& error)\r
{\r
+ \r
+ config_.Reload();\r
+\r
const auto address = session->tcp_socket().remote_endpoint().address();\r
+\r
+ // 拒否IPでないか判定\r
if(IsBlockedAddress(address)) {\r
Logger::Info("Blocked IP Address: %s", address);\r
session->Close();\r
\r
- } else if (GetUserCount() >= config_.capacity()) {\r
- Logger::Info("Refused Session");\r
- session->SyncSend(ClientReceiveServerCrowdedError());\r
- session->Close();\r
-\r
- } else {\r
+ } else {\r
session->set_on_receive(callback_);\r
session->Start();\r
sessions_.push_back(SessionWeakPtr(session));\r
}\r
\r
auto new_session = boost::make_shared<ServerSession>(io_service_);\r
- acceptor_.async_accept(new_session->tcp_socket(),\r
- boost::bind(&Server::ReceiveSession, this, new_session, boost::asio::placeholders::error));\r
+ acceptor_.async_accept(new_session->tcp_socket(),\r
+ boost::bind(&Server::ReceiveSession, this, new_session, boost::asio::placeholders::error));\r
\r
RefreshSession();\r
}\r
Logger::Info("Active connection: %d", GetUserCount());\r
}\r
\r
- void Server::SendAll(const Command& command)\r
+ void Server::SendAll(const Command& command, int channel, bool limited)\r
{\r
BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {\r
if (auto session = ptr.lock()) {\r
- session->Send(command);\r
+ if (channel < 0 || (channel >= 0 && session->channel() == channel)) {\r
+ if (!limited || session->write_average_limit() > session->GetWriteByteAverage()) {\r
+ if (session->id() > 0) {\r
+ session->Send(command);\r
+ }\r
+ }\r
+ }\r
}\r
}\r
}\r
\r
- void Server::SendAllLimited(const Command& command)\r
+ void Server::SendOthers(const Command& command, uint32_t self_id, int channel, bool limited)\r
{\r
BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {\r
if (auto session = ptr.lock()) {\r
- if (session->write_average_limit() > session->GetWriteByteAverage()) {\r
- session->Send(command);\r
+ if (channel < 0 || (channel >= 0 && session->channel() == channel)) {\r
+ if (!limited || session->write_average_limit() > session->GetWriteByteAverage()) {\r
+ if (session->id() > 0 && session->id() != self_id) {\r
+ session->Send(command);\r
+ }\r
+ }\r
}\r
}\r
}\r
}\r
}\r
\r
- void Server::SendOthers(const Command& command, SessionWeakPtr self_ptr)\r
- {\r
- BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {\r
- if (auto session = ptr.lock()) {\r
- if (auto self = self_ptr.lock()) {\r
- if (*session != *self) {\r
- session->Send(command);\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
- void Server::SendOthersLimited(const Command& command, SessionWeakPtr self_ptr)\r
- {\r
- BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {\r
- if (auto session = ptr.lock()) {\r
- if (auto self = self_ptr.lock()) {\r
- if (*session != *self) {\r
- if (session->write_average_limit() > session->GetWriteByteAverage()) {\r
- session->Send(command);\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
void Server::SendUDPTestPacket(const std::string& ip_address, uint16_t port)\r
{\r
using boost::asio::ip::udp;\r
}\r
}\r
\r
+ void Server::SendPublicPing()\r
+ {\r
+ static char request[] = "P";\r
+ BOOST_FOREACH(const auto& iterator, lobby_hosts_) {\r
+ io_service_.post(boost::bind(&Server::DoWriteUDP, this, request, *iterator));\r
+ }\r
+ }\r
+\r
void Server::SendUDP(const std::string& message, const boost::asio::ip::udp::endpoint endpoint)\r
{\r
io_service_.post(boost::bind(&Server::DoWriteUDP, this, message, endpoint));\r
void Server::FetchUDP(const std::string& buffer, const boost::asio::ip::udp::endpoint endpoint)\r
{\r
uint8_t header;\r
- uint32_t user_id;\r
- uint8_t count;\r
std::string body;\r
- SessionPtr session;\r
+ SessionWeakPtr session;\r
+\r
+ // IPアドレスとポートからセッションを特定\r
+ auto it = std::find_if(sessions_.begin(), sessions_.end(),\r
+ [&endpoint](const SessionWeakPtr& session) -> bool {\r
+ if (auto session_ptr = session.lock()) {\r
+\r
+ const auto session_endpoint = session_ptr->tcp_socket().remote_endpoint();\r
+ const auto session_port = session_ptr->udp_port();\r
+\r
+ return (session_endpoint.address() == endpoint.address() &&\r
+ session_port == endpoint.port());\r
+\r
+ } else {\r
+ return false;\r
+ }\r
+ });\r
+\r
+ if (it != sessions_.end()) {\r
+ session = *it;\r
+ Logger::Debug("Receive UDP Command: %d", session.lock()->id());\r
+ } else {\r
+ Logger::Debug("Receive anonymous UDP Command");\r
+ }\r
\r
- size_t readed = 0;\r
if (buffer.size() > network::Utils::Deserialize(buffer, &header)) {\r
- readed = network::Utils::Deserialize(buffer, &user_id, &count);\r
+ body = buffer.substr(sizeof(header));\r
}\r
\r
- // 現在コマンドがひとつしか無いのでそれ以外は無視\r
+ // 復号\r
+ if (session.lock() && header == header::ENCRYPT_HEADER) {\r
+ body.erase(0, sizeof(header));\r
+ body = session.lock()->encrypter().Decrypt(body);\r
+ Utils::Deserialize(body, &header);\r
+ body = buffer.substr(sizeof(header));\r
+ }\r
+\r
if (header == network::header::ServerRequstedStatus) {\r
SendUDP(GetStatusJSON(), endpoint);\r
- }\r
- else if(header != network::header::ServerReceiveWriteLimit) {\r
- if (readed < buffer.size()) {\r
- body = buffer.substr(readed);\r
- }\r
} else {\r
- return;\r
+ if (callback_) {\r
+ (*callback_)(Command(static_cast<network::header::CommandHeader>(header), body, session));\r
+ }\r
}\r
\r
- \r
- // if (callback_) {\r
- //(*callback_)(Command(static_cast<network::header::CommandHeader>(header), body, endpoint));\r
- // }\r
}\r
\r
void Server::ServerSession::Start()\r