OSDN Git Service

プライベートメッセージの仕様を変更
[mmo/main.git] / server / Server.cpp
1 //
2 // Server.cpp
3 //
4
5 #include "Server.hpp"
6 #include "version.hpp"
7 #include <algorithm>
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"
13
14 namespace network {
15
16     Server::Server(const Config& config) :
17                         config_(config),
18             endpoint_(tcp::v4(), config.port()),
19             acceptor_(io_service_, endpoint_),
20             socket_udp_(io_service_, udp::endpoint(udp::v4(), config.port())),
21             udp_packet_count_(0)
22     {
23     }
24
25     void Server::Start(CallbackFuncPtr callback)
26     {
27         callback_ = std::make_shared<CallbackFunc>(
28                 [&](network::Command c){
29
30             // ログアウト
31             if (c.header() == network::header::FatalConnectionError) {
32                 if (callback) {
33                                         (*callback)(c);
34                                 }
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());
39                                         session->Close();
40                                 } else if(read_average > config_.receive_limit_1()) {
41                                         Logger::Info(_T("Receive limit exceeded: %d: %d byte/s"), session->id(), read_average);
42                                 } else {
43                                         if (callback) {
44                                                 (*callback)(c);
45                                         }
46                 }
47             }
48
49         });
50
51         {
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));
55         }
56
57         {
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));
63         }
64
65         boost::asio::io_service::work work(io_service_);
66         io_service_.run();
67     }
68
69     void Server::Stop()
70     {
71         io_service_.stop();
72                 Logger::Info("stop server");
73     }
74     void Server::Stop(int innterrupt_type)
75     {
76         io_service_.stop();
77         Logger::Info(_T("stop server innterrupt_type=%d"),innterrupt_type);
78     }
79
80         int Server::GetUserCount() const
81         {
82                 auto count = std::count_if(sessions_.begin(), sessions_.end(),
83                         [](const SessionWeakPtr& s){ return !s.expired() && s.lock()->online(); });
84
85                 return count;
86         }
87
88         std::string Server::GetStatusJSON() const
89         {
90                 auto msg = (
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
94                                                 % GetUserCount()
95                                                 % config_.capacity()
96                                                 % config_.stage()
97                                         ).str();
98
99                 return msg;
100         }
101
102     bool Server::Empty() const
103     {
104         return GetUserCount() == 0;
105     }
106
107         bool Server::IsBlockedAddress(const boost::asio::ip::address& address)
108         {
109                 BOOST_FOREACH(const auto& pattern, config_.blocking_address_patterns()) {
110                         if (network::Utils::MatchWithWildcard(pattern, address.to_string())) {
111                                 return true;
112                         }
113                 }
114                 return false;
115         }
116
117     void Server::ReceiveSession(const SessionPtr& session, const boost::system::error_code& error)
118     {
119                 const auto address = session->tcp_socket().remote_endpoint().address();
120                 if(IsBlockedAddress(address)) {
121                         Logger::Info("Blocked IP Address: %s", address);
122             session->Close();
123
124                 } else if (GetUserCount() >= config_.capacity()) {
125                         Logger::Info("Refused Session");
126             session->SyncSend(ClientReceiveServerCrowdedError());
127             session->Close();
128
129         } else {
130             session->set_on_receive(callback_);
131             session->Start();
132             sessions_.push_back(SessionWeakPtr(session));
133
134             // クライアント情報を要求
135             session->Send(ClientRequestedClientInfo());
136         }
137
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));
141
142                 RefreshSession();
143     }
144
145         void Server::RefreshSession()
146         {
147                 // 使用済のセッションのポインタを破棄
148         auto it = std::remove_if(sessions_.begin(), sessions_.end(),
149                 [](const SessionWeakPtr& ptr){
150             return ptr.expired();
151         });
152         sessions_.erase(it, sessions_.end());
153                 Logger::Info("Active connection: %d", GetUserCount());
154         }
155
156     void Server::SendAll(const Command& command)
157     {
158         BOOST_FOREACH(SessionWeakPtr& ptr, sessions_) {
159             if (auto session = ptr.lock()) {
160                 session->Send(command);
161             }
162         }
163     }
164         \r
165     void Server::SendTo(const Command& command, uint32_t user_id)
166         {
167                 auto it = std::find_if(sessions_.begin(), sessions_.end(),
168                         [user_id](SessionWeakPtr& ptr){
169                                 return ptr.lock()->id() == user_id;
170                         });
171                 
172                 if (it != sessions_.end()) {
173                         it->lock()->Send(command);
174                 }
175         }
176
177     void Server::SendOthers(const Command& command, SessionWeakPtr self_ptr)
178     {
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);
184                     }
185                 }
186             }
187         }
188     }
189
190     void Server::SendUDPTestPacket(const std::string& ip_address, uint16_t port)
191     {
192         using boost::asio::ip::udp;
193
194         std::stringstream port_str;
195         port_str << (int)port;
196
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);
200
201         static char request[] = "MMO UDP Test Packet";
202         for (int i = 0; i < UDP_TEST_PACKET_TIME; i++) {
203
204             io_service_.post(boost::bind(&Server::DoWriteUDP, this, request, *iterator));
205         }
206     }
207
208     void Server::SendUDP(const std::string& message, const boost::asio::ip::udp::endpoint endpoint)
209     {
210                 io_service_.post(boost::bind(&Server::DoWriteUDP, this, message, endpoint));
211     }
212
213     void Server::ReceiveUDP(const boost::system::error_code& error, size_t bytes_recvd)
214     {
215         if (bytes_recvd > 0) {
216             std::string buffer(receive_buf_udp_, bytes_recvd);
217             FetchUDP(buffer, sender_endpoint_);
218         }
219         if (!error) {
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));
225         } else {
226             Logger::Error("%s", error.message());
227         }
228     }
229
230     void Server::DoWriteUDP(const std::string& msg, const udp::endpoint& endpoint)
231     {
232         boost::shared_ptr<std::string> s = 
233               boost::make_shared<std::string>(msg.data(), msg.size());
234
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));
239     }
240
241     void Server::WriteUDP(const boost::system::error_code& error, boost::shared_ptr<std::string> holder)
242     {
243 //        if (!error) {
244 //            if (!send_queue_.empty()) {
245 //                  send_queue_.pop();
246 //                  if (!send_queue_.empty())
247 //                  {
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));
253 //                  }
254 //            }
255 //        } else {
256 //            FatalError();
257 //        }
258     }
259
260     void Server::FetchUDP(const std::string& buffer, const boost::asio::ip::udp::endpoint endpoint)
261     {
262         uint8_t header;\r
263                 uint32_t user_id;
264         uint8_t count;\r
265         std::string body;
266         SessionPtr session;
267
268                 size_t readed = 0;
269         if (buffer.size() > network::Utils::Deserialize(buffer, &header)) {
270                         readed = network::Utils::Deserialize(buffer, &user_id, &count);
271                 }
272
273                 // 現在コマンドがひとつしか無いのでそれ以外は無視
274                 if (header != network::header::ServerRequstedStatus) {
275                         return;
276                 }
277
278         if (readed < buffer.size()) {
279             body = buffer.substr(readed);
280         }
281
282         if (callback_) {
283                         (*callback_)(Command(static_cast<network::header::CommandHeader>(header), body, endpoint));
284         }
285     }
286
287     void Server::ServerSession::Start()
288     {
289         online_ = true;
290
291         // Nagleアルゴリズムを無効化
292         socket_tcp_.set_option(boost::asio::ip::tcp::no_delay(true));
293
294                 // バッファサイズを変更 1MiB
295                 boost::asio::socket_base::receive_buffer_size option(1048576);
296                 socket_tcp_.set_option(option);
297
298         // IPアドレスを取得
299         global_ip_ = socket_tcp_.remote_endpoint().address().to_string();
300
301         boost::asio::async_read_until(socket_tcp_,
302             receive_buf_, NETWORK_UTILS_DELIMITOR,
303             boost::bind(
304               &ServerSession::ReceiveTCP, shared_from_this(),
305               boost::asio::placeholders::error));
306     }
307 }