8 #include <boost/make_shared.hpp>
9 #include <boost/foreach.hpp>
10 #include "../common/Logger.hpp"
11 #include "../common/network/Command.hpp"
12 #include "../common/network/Utils.hpp"
16 Server::Server(const Config& config) :
18 endpoint_(tcp::v4(), config.port()),
19 acceptor_(io_service_, endpoint_),
20 socket_udp_(io_service_, udp::endpoint(udp::v4(), config.port())),
25 void Server::Start(CallbackFuncPtr callback)
27 callback_ = std::make_shared<CallbackFunc>(
28 [&](network::Command c){
31 if (c.header() == network::header::FatalConnectionError) {
35 } else if (auto session = c.session().lock()) {
36 auto read_average = session->GetReadByteAverage();
37 if (read_average > config_.receive_limit_2()) {
38 Logger::Info(_T("Banished session: %d"), session->id());
40 } else if(read_average > config_.receive_limit_1()) {
41 Logger::Info(_T("Receive limit exceeded: %d: %d byte/s"), session->id(), read_average);
52 auto new_session = boost::make_shared<ServerSession>(io_service_);
53 acceptor_.async_accept(new_session->tcp_socket(),
54 boost::bind(&Server::ReceiveSession, this, new_session, boost::asio::placeholders::error));
58 socket_udp_.async_receive_from(
59 boost::asio::buffer(receive_buf_udp_, UDP_MAX_RECEIVE_LENGTH), sender_endpoint_,
60 boost::bind(&Server::ReceiveUDP, this,
61 boost::asio::placeholders::error,
62 boost::asio::placeholders::bytes_transferred));
65 boost::asio::io_service::work work(io_service_);
72 Logger::Info("stop server");
74 void Server::Stop(int innterrupt_type)
77 Logger::Info(_T("stop server innterrupt_type=%d"),innterrupt_type);
80 int Server::GetUserCount() const
82 auto count = std::count_if(sessions_.begin(), sessions_.end(),
83 [](const SessionWeakPtr& s){ return !s.expired() && s.lock()->online(); });
88 std::string Server::GetStatusJSON() const
91 boost::format("{\"nam\":\"%s\",\"ver\":\"%d.%d.%d\",\"cnt\":%d,\"cap\":%d,\"stg\":\"%s\"}")
92 % config_.server_name()
93 % MMO_VERSION_MAJOR % MMO_VERSION_MINOR % MMO_VERSION_REVISION
102 bool Server::Empty() const
104 return GetUserCount() == 0;
107 bool Server::IsBlockedAddress(const boost::asio::ip::address& address)
109 BOOST_FOREACH(const auto& pattern, config_.blocking_address_patterns()) {
110 if (network::Utils::MatchWithWildcard(pattern, address.to_string())) {
117 void Server::ReceiveSession(const SessionPtr& session, const boost::system::error_code& error)
119 const auto address = session->tcp_socket().remote_endpoint().address();
120 if(IsBlockedAddress(address)) {
121 Logger::Info("Blocked IP Address: %s", address);
124 } else if (GetUserCount() >= config_.capacity()) {
125 Logger::Info("Refused Session");
126 session->SyncSend(ClientReceiveServerCrowdedError());
130 session->set_on_receive(callback_);
132 sessions_.push_back(SessionWeakPtr(session));
135 session->Send(ClientRequestedClientInfo());
138 auto new_session = boost::make_shared<ServerSession>(io_service_);
139 acceptor_.async_accept(new_session->tcp_socket(),
140 boost::bind(&Server::ReceiveSession, this, new_session, boost::asio::placeholders::error));
145 void Server::RefreshSession()
148 auto it = std::remove_if(sessions_.begin(), sessions_.end(),
149 [](const SessionWeakPtr& ptr){
150 return ptr.expired();
152 sessions_.erase(it, sessions_.end());
153 Logger::Info("Active connection: %d", GetUserCount());
156 void Server::SendAll(const Command& command)
158 BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {
159 if (auto session = ptr.lock()) {
160 session->Send(command);
165 void Server::SendTo(const Command& command, uint32_t user_id)
167 auto it = std::find_if(sessions_.begin(), sessions_.end(),
168 [user_id](SessionWeakPtr& ptr){
169 return ptr.lock()->id() == user_id;
172 if (it != sessions_.end()) {
173 it->lock()->Send(command);
177 void Server::SendOthers(const Command& command, SessionWeakPtr self_ptr)
179 BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {
180 if (auto session = ptr.lock()) {
181 if (auto self = self_ptr.lock()) {
182 if (*session != *self) {
183 session->Send(command);
190 void Server::SendUDPTestPacket(const std::string& ip_address, uint16_t port)
192 using boost::asio::ip::udp;
194 std::stringstream port_str;
195 port_str << (int)port;
197 udp::resolver resolver(io_service_);
198 udp::resolver::query query(udp::v4(), ip_address.c_str(), port_str.str().c_str());
199 udp::resolver::iterator iterator = resolver.resolve(query);
201 static char request[] = "MMO UDP Test Packet";
202 for (int i = 0; i < UDP_TEST_PACKET_TIME; i++) {
204 io_service_.post(boost::bind(&Server::DoWriteUDP, this, request, *iterator));
208 void Server::SendUDP(const std::string& message, const boost::asio::ip::udp::endpoint endpoint)
210 io_service_.post(boost::bind(&Server::DoWriteUDP, this, message, endpoint));
213 void Server::ReceiveUDP(const boost::system::error_code& error, size_t bytes_recvd)
215 if (bytes_recvd > 0) {
216 std::string buffer(receive_buf_udp_, bytes_recvd);
217 FetchUDP(buffer, sender_endpoint_);
220 socket_udp_.async_receive_from(
221 boost::asio::buffer(receive_buf_udp_, UDP_MAX_RECEIVE_LENGTH), sender_endpoint_,
222 boost::bind(&Server::ReceiveUDP, this,
223 boost::asio::placeholders::error,
224 boost::asio::placeholders::bytes_transferred));
226 Logger::Error("%s", error.message());
230 void Server::DoWriteUDP(const std::string& msg, const udp::endpoint& endpoint)
232 boost::shared_ptr<std::string> s =
233 boost::make_shared<std::string>(msg.data(), msg.size());
235 socket_udp_.async_send_to(
236 boost::asio::buffer(s->data(), s->size()), endpoint,
237 boost::bind(&Server::WriteUDP, this,
238 boost::asio::placeholders::error, s));
241 void Server::WriteUDP(const boost::system::error_code& error, boost::shared_ptr<std::string> holder)
244 // if (!send_queue_.empty()) {
245 // send_queue_.pop();
246 // if (!send_queue_.empty())
248 // boost::asio::async_write(socket_tcp_,
249 // boost::asio::buffer(send_queue_.front().data(),
250 // send_queue_.front().size()),
251 // boost::bind(&Session::WriteTCP, this,
252 // boost::asio::placeholders::error));
260 void Server::FetchUDP(const std::string& buffer, const boost::asio::ip::udp::endpoint endpoint)
269 if (buffer.size() > network::Utils::Deserialize(buffer, &header)) {
270 readed = network::Utils::Deserialize(buffer, &user_id, &count);
273 // 現在コマンドがひとつしか無いのでそれ以外は無視
274 if (header != network::header::ServerRequstedStatus) {
278 if (readed < buffer.size()) {
279 body = buffer.substr(readed);
283 (*callback_)(Command(static_cast<network::header::CommandHeader>(header), body, endpoint));
287 void Server::ServerSession::Start()
292 socket_tcp_.set_option(boost::asio::ip::tcp::no_delay(true));
295 boost::asio::socket_base::receive_buffer_size option(1048576);
296 socket_tcp_.set_option(option);
299 global_ip_ = socket_tcp_.remote_endpoint().address().to_string();
301 boost::asio::async_read_until(socket_tcp_,
302 receive_buf_, NETWORK_UTILS_DELIMITOR,
304 &ServerSession::ReceiveTCP, shared_from_this(),
305 boost::asio::placeholders::error));