8 #include <boost/format.hpp>
\r
9 #include <boost/date_time/posix_time/posix_time.hpp>
\r
10 #include <boost/property_tree/json_parser.hpp>
\r
11 #include <boost/foreach.hpp>
\r
12 #include "version.hpp"
\r
13 #include "Server.hpp"
\r
14 #include "../common/network/Encrypter.hpp"
\r
15 #include "../common/network/Signature.hpp"
\r
16 #include "../common/database/AccountProperty.hpp"
\r
17 #include "../common/Logger.hpp"
\r
18 #include "Config.hpp"
\r
19 #include "version.hpp"
\r
22 #include "ServerSigHandler.hpp"
\r
27 #include <boost/interprocess/windows_shared_memory.hpp>
\r
28 #include <boost/interprocess/mapped_region.hpp>
\r
31 using namespace boost::posix_time;
\r
33 void client_sync(network::Server& server);
\r
34 void public_ping(network::Server& server);
\r
37 int main(int argc, char* argv[])
\r
39 Logger::Info(_T("%s"), unicode::ToTString(MMO_VERSION_TEXT));
\r
48 } catch (std::exception& e) {
\r
49 Logger::Error(e.what());
\r
50 Logger::Info("Stop Server");
\r
62 network::Signature sign("server_key");
\r
65 network::Server server;
\r
67 auto callback = std::make_shared<std::function<void(network::Command)>>(
\r
68 [&server, &sign](network::Command c){
\r
71 auto msg = (boost::format("Receive: 0x%08x %dbyte") % c.header() % c.body().size()).str();
\r
72 if (auto session = c.session().lock()) {
\r
73 msg += " from " + session->global_ip();
\r
76 // if (auto session = c.session().lock()) {
\r
77 // std::cout << "Write Average: " << session->GetReadByteAverage() << "bytes" << std::endl;
\r
79 auto header = c.header();
\r
80 switch (c.header()) {
\r
82 case network::header::ServerRequestedFullServerInfo:
\r
84 if (auto session = c.session().lock()) {
\r
85 session->Send(network::ClientReceiveFullServerInfo(server.GetFullStatus()));
\r
90 case network::header::ServerRequestedPlainFullServerInfo:
\r
92 //if (auto session = c.session().lock()) {
\r
93 // session->Send(network::ClientReceivePlainFullServerInfo(server.GetFullStatus()));
\r
99 case network::header::ServerRequstedStatus:
\r
102 server.SendUDP(server.GetStatusJSON(), c.udp_endpoint());
\r
107 case network::header::ServerReceiveJSON:
\r
109 if (auto session = c.session().lock()) {
\r
110 uint32_t id = static_cast<unsigned int>(session->id());
\r
112 Logger::Error(_T("Invalid session id"));
\r
116 std::stringstream message_json(network::Utils::Deserialize<std::string>(c.body()));
\r
118 using namespace boost::property_tree;
\r
119 ptree message_tree;
\r
120 json_parser::read_json(message_json, message_tree);
\r
123 std::list<uint32_t> destination_list;
\r
124 auto private_list_tree = message_tree.get_child("private", ptree());
\r
125 BOOST_FOREACH(const auto& user_id, private_list_tree) {
\r
126 destination_list.push_back(user_id.second.get_value<uint32_t>());
\r
129 ptime now = second_clock::universal_time();
\r
130 auto time_string = to_iso_extended_string(now);
\r
132 std::string info_json;
\r
134 info_json += (boost::format("\"id\":\"%d\",") % id).str();
\r
135 info_json += (boost::format("\"time\":\"%s\"") % time_string).str();
\r
138 auto send_command = network::ClientReceiveJSON(info_json, message_json.str());
\r
140 if (destination_list.size() > 0) {
\r
141 BOOST_FOREACH(uint32_t user_id, destination_list) {
\r
142 server.SendTo(send_command, user_id);
\r
145 auto name = server.account().GetUserName(id);
\r
146 auto body = message_tree.get<std::string>("body", std::string());
\r
147 server.AddChatLog((boost::format("[%s] %s") % name % body).str());
\r
149 server.SendAll(send_command, session->channel());
\r
152 Logger::Info("Receive JSON: %s", message_json.str());
\r
159 case network::header::ServerUpdatePlayerPosition:
\r
161 if (auto session = c.session().lock()) {
\r
162 PlayerPosition pos;
\r
163 network::Utils::Deserialize(c.body(), &pos.x, &pos.y, &pos.z, &pos.theta, &pos.vy);
\r
164 server.account().SetUserPosition(session->id(), pos);
\r
165 server.SendOthers(network::ClientUpdatePlayerPosition(session->id(),
\r
166 pos.x,pos.y,pos.z,pos.theta, pos.vy), session->id(), session->channel(), true);
\r
172 case network::header::ServerReceiveClientInfo:
\r
174 if (auto session = c.session().lock()) {
\r
177 if (server.GetUserCount() >= server.config().capacity()) {
\r
178 Logger::Info("Refused Session");
\r
179 session->SyncSend(network::ClientReceiveServerCrowdedError());
\r
184 session->ResetReadByteAverage();
\r
186 std::string finger_print;
\r
190 network::Utils::Deserialize(c.body(), &finger_print, &version, &udp_port);
\r
192 // クライアントのプロトコルバージョンをチェック
\r
193 if (version != MMO_PROTOCOL_VERSION) {
\r
194 Logger::Info("Unsupported Client Version : v%d", version);
\r
195 session->Send(network::ClientReceiveUnsupportVersionError(1));
\r
200 session->set_udp_port(udp_port);
\r
202 Logger::Info("UDP destination is %s:%d", session->global_ip(), session->udp_port());
\r
205 server.SendUDPTestPacket(session->global_ip(), session->udp_port());
\r
207 uint32_t id = server.account().GetUserIdFromFingerPrint(finger_print);
\r
210 session->Send(network::ClientRequestedPublicKey());
\r
212 uint32_t user_id = static_cast<uint32_t>(id);
\r
214 session->set_id(user_id);
\r
215 server.account().LogIn(user_id);
\r
216 session->encrypter().SetPublicKey(server.account().GetPublicKey(user_id));
\r
218 server.account().SetUserIPAddress(session->id(), session->global_ip());
\r
219 server.account().SetUserUDPPort(session->id(), session->udp_port());
\r
222 auto key = session->encrypter().GetCryptedCommonKey();
\r
223 session->Send(network::ClientReceiveCommonKey(key, sign.Sign(key), user_id));
\r
232 case network::header::ServerReceivePublicKey:
\r
234 if (auto session = c.session().lock()) {
\r
235 auto public_key = network::Utils::Deserialize<std::string>(c.body());
\r
236 uint32_t user_id = server.account().RegisterPublicKey(public_key);
\r
238 assert(user_id > 0);
\r
240 session->ResetReadByteAverage();
\r
243 session->set_id(user_id);
\r
244 server.account().LogIn(user_id);
\r
245 session->encrypter().SetPublicKey(server.account().GetPublicKey(user_id));
\r
247 server.account().SetUserIPAddress(session->id(), session->global_ip());
\r
248 server.account().SetUserUDPPort(session->id(), session->udp_port());
\r
251 auto key = session->encrypter().GetCryptedCommonKey();
\r
252 session->Send(network::ClientReceiveCommonKey(key, sign.Sign(key), user_id));
\r
260 case network::header::ServerStartEncryptedSession:
\r
262 if (auto session = c.session().lock()) {
\r
264 session->Send(network::ClientReceiveServerInfo(server.config().stage()));
\r
266 session->Send(network::ClientStartEncryptedSession());
\r
267 session->EnableEncryption();
\r
275 case network::header::ServerReceiveAccountInitializeData:
\r
277 if (auto session = c.session().lock()) {
\r
278 auto data = network::Utils::Deserialize<std::string>(c.body());
\r
279 server.account().LoadInitializeData(session->id(), data);
\r
281 const auto& list = server.account().GetIDList();
\r
282 BOOST_FOREACH(UserID user_id, list) {
\r
283 session->Send(network::ClientReceiveAccountRevisionUpdateNotify(user_id,
\r
284 server.account().GetUserRevision(user_id)));
\r
288 network::ClientReceiveAccountRevisionUpdateNotify(session->id(),
\r
289 server.account().GetUserRevision(session->id())), session->id());
\r
297 case network::header::ServerRequestedAccountRevisionPatch:
\r
299 if (auto session = c.session().lock()) {
\r
301 uint32_t client_revision;
\r
302 network::Utils::Deserialize(c.body(), &user_id, &client_revision);
\r
304 if (client_revision < server.account().GetUserRevision(user_id)) {
\r
305 session->Send(network::ClientReceiveAccountRevisionPatch(
\r
306 server.account().GetUserRevisionPatch(user_id, client_revision)));
\r
313 case network::header::ServerUpdateAccountProperty:
\r
315 if (auto session = c.session().lock()) {
\r
316 AccountProperty property;
\r
317 std::string buffer = c.body().substr(sizeof(AccountProperty));
\r
318 network::Utils::Deserialize(c.body(), &property);
\r
320 auto old_revision = server.account().GetUserRevision(session->id());
\r
322 switch (property) {
\r
327 network::Utils::Deserialize(buffer, &value);
\r
328 server.account().SetUserName(session->id(), value);
\r
334 network::Utils::Deserialize(buffer, &value);
\r
335 server.account().SetUserTrip(session->id(), value);
\r
341 network::Utils::Deserialize(buffer, &value);
\r
342 server.account().SetUserModelName(session->id(), value);
\r
348 network::Utils::Deserialize(buffer, &value);
\r
349 auto channel = *reinterpret_cast<const unsigned int*>(value.data());
\r
350 server.account().SetUserChannel(session->id(), channel);
\r
351 session->set_channel(channel);
\r
358 auto new_revison = server.account().GetUserRevision(session->id());
\r
359 if (new_revison > old_revision) {
\r
361 network::ClientReceiveAccountRevisionUpdateNotify(
\r
362 session->id(),new_revison));
\r
371 case network::header::UserFatalConnectionError:
\r
373 if (c.body().size() > 0) {
\r
374 uint32_t user_id = network::Utils::Deserialize<uint32_t>(c.body());
\r
375 server.account().LogOut(user_id);
\r
378 network::ClientReceiveAccountRevisionUpdateNotify(user_id,
\r
379 server.account().GetUserRevision(user_id)));
\r
381 Logger::Info("Logout User: %d", user_id);
\r
382 server.account().Remove(user_id);
\r
394 client_sync(server);
\r
396 if (server.config().is_public()) {
\r
397 public_ping(server);
\r
400 server.Start(callback);
\r
403 void public_ping(network::Server& server)
\r
405 boost::thread([&server](){
\r
407 boost::this_thread::sleep(boost::posix_time::seconds(10));
\r
408 server.SendPublicPing();
\r
413 void client_sync(network::Server& server)
\r
415 bool execute_with_client;
\r
418 using namespace boost::interprocess;
\r
419 windows_shared_memory shm(open_only, "MMO_SERVER_WITH_CLIENT", read_only);
\r
421 execute_with_client = true;
\r
422 } catch(std::exception& e) {
\r
423 Logger::Info("Stand-alone Mode");
\r
424 execute_with_client = false;
\r
427 // クライアントから起動している場合、クライアントの状態を監視
\r
429 if (execute_with_client) {
\r
430 boost::thread([&server](){
\r
432 boost::this_thread::sleep(boost::posix_time::seconds(4));
\r
434 using namespace boost::interprocess;
\r
435 windows_shared_memory shm(open_only, "MMO_SERVER_WITH_CLIENT", read_only);
\r
436 } catch(std::exception& e) {
\r
445 network::ServerSigHandler handler(SIGINT,&server);
\r