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 "Account.hpp"
\r
20 #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 int main(int argc, char* argv[])
\r
38 Logger::Info(_T("%s"), unicode::ToTString(MMO_VERSION_TEXT));
\r
43 network::Signature sign("server_key");
\r
46 Account account("account.db");
\r
47 network::Server server(config);
\r
49 auto callback = std::make_shared<std::function<void(network::Command)>>(
\r
50 [&server, &account, &sign, &config](network::Command c){
\r
53 auto msg = (boost::format("Receive: 0x%08x %dbyte") % c.header() % c.body().size()).str();
\r
54 if (auto session = c.session().lock()) {
\r
55 msg += " from " + session->global_ip();
\r
58 // if (auto session = c.session().lock()) {
\r
59 // std::cout << "Write Average: " << session->GetReadByteAverage() << "bytes" << std::endl;
\r
62 switch (c.header()) {
\r
65 case network::header::ServerRequstedStatus:
\r
68 server.SendUDP(server.GetStatusJSON(), c.udp_endpoint());
\r
73 case network::header::ServerReceiveJSON:
\r
75 if (auto session = c.session().lock()) {
\r
76 uint32_t id = static_cast<unsigned int>(session->id());
\r
78 Logger::Error(_T("Invalid session id"));
\r
82 std::stringstream message_json(c.body());
\r
84 using namespace boost::property_tree;
\r
86 json_parser::read_json(message_json, message_tree);
\r
89 std::list<uint32_t> destination_list;
\r
90 auto private_list_tree = message_tree.get_child("private", ptree());
\r
91 BOOST_FOREACH(const auto& user_id, private_list_tree) {
\r
92 destination_list.push_back(user_id.second.get_value<uint32_t>());
\r
95 ptime now = second_clock::universal_time();
\r
96 auto time_string = to_iso_extended_string(now);
\r
98 std::string info_json;
\r
100 info_json += (boost::format("\"id\":\"%d\",") % id).str();
\r
101 info_json += (boost::format("\"time\":\"%s\"") % time_string).str();
\r
104 auto send_command = network::ClientReceiveJSON(info_json, message_json.str());
\r
106 if (destination_list.size() > 0) {
\r
107 BOOST_FOREACH(uint32_t user_id, destination_list) {
\r
108 server.SendTo(send_command, user_id);
\r
111 server.SendAll(send_command, session->channel());
\r
114 Logger::Info("Receive JSON: %s", message_json.str());
\r
121 case network::header::ServerUpdatePlayerPosition:
\r
123 if (auto session = c.session().lock()) {
\r
124 PlayerPosition pos;
\r
125 network::Utils::Deserialize(c.body(), &pos.x, &pos.y, &pos.z, &pos.theta, &pos.vy);
\r
126 account.SetUserPosition(session->id(), pos);
\r
127 server.SendOthers(network::ClientUpdatePlayerPosition(session->id(),
\r
128 pos.x,pos.y,pos.z,pos.theta, pos.vy), session->id(), session->channel(), true);
\r
134 case network::header::ServerReceiveClientInfo:
\r
136 if (auto session = c.session().lock()) {
\r
138 session->ResetReadByteAverage();
\r
140 std::string finger_print;
\r
144 network::Utils::Deserialize(c.body(), &finger_print, &version, &udp_port);
\r
146 // クライアントのプロトコルバージョンをチェック
\r
147 if (version != MMO_PROTOCOL_VERSION) {
\r
148 Logger::Info("Unsupported Client Version : v%d", version);
\r
149 session->Send(network::ClientReceiveUnsupportVersionError(1));
\r
154 session->set_udp_port(udp_port);
\r
156 Logger::Info("UDP destination is %s:%d", session->global_ip(), session->udp_port());
\r
159 server.SendUDPTestPacket(session->global_ip(), session->udp_port());
\r
161 uint32_t id = account.GetUserIdFromFingerPrint(finger_print);
\r
164 session->Send(network::ClientRequestedPublicKey());
\r
166 uint32_t user_id = static_cast<uint32_t>(id);
\r
168 session->set_id(user_id);
\r
169 account.LogIn(user_id);
\r
170 session->encrypter().SetPublicKey(account.GetPublicKey(user_id));
\r
172 account.SetUserIPAddress(session->id(), session->global_ip());
\r
173 account.SetUserUDPPort(session->id(), session->udp_port());
\r
176 auto key = session->encrypter().GetCryptedCommonKey();
\r
177 session->Send(network::ClientReceiveCommonKey(key, sign.Sign(key), user_id));
\r
186 case network::header::ServerReceivePublicKey:
\r
188 if (auto session = c.session().lock()) {
\r
189 uint32_t user_id = account.RegisterPublicKey(c.body());
\r
190 assert(user_id > 0);
\r
192 session->ResetReadByteAverage();
\r
195 session->set_id(user_id);
\r
196 account.LogIn(user_id);
\r
197 session->encrypter().SetPublicKey(account.GetPublicKey(user_id));
\r
199 account.SetUserIPAddress(session->id(), session->global_ip());
\r
200 account.SetUserUDPPort(session->id(), session->udp_port());
\r
203 auto key = session->encrypter().GetCryptedCommonKey();
\r
204 session->Send(network::ClientReceiveCommonKey(key, sign.Sign(key), user_id));
\r
212 case network::header::ServerStartEncryptedSession:
\r
214 if (auto session = c.session().lock()) {
\r
216 session->Send(network::ClientReceiveServerInfo(config.stage()));
\r
218 session->Send(network::ClientStartEncryptedSession());
\r
219 session->EnableEncryption();
\r
227 case network::header::ServerReceiveAccountInitializeData:
\r
229 if (auto session = c.session().lock()) {
\r
230 account.LoadInitializeData(session->id(), c.body());
\r
232 const auto& list = account.GetIDList();
\r
233 BOOST_FOREACH(UserID user_id, list) {
\r
234 session->Send(network::ClientReceiveAccountRevisionUpdateNotify(user_id,
\r
235 account.GetUserRevision(user_id)));
\r
239 network::ClientReceiveAccountRevisionUpdateNotify(session->id(),
\r
240 account.GetUserRevision(session->id())), session->id());
\r
248 case network::header::ServerRequestedAccountRevisionPatch:
\r
250 if (auto session = c.session().lock()) {
\r
252 uint32_t client_revision;
\r
253 network::Utils::Deserialize(c.body(), &user_id, &client_revision);
\r
255 if (client_revision < account.GetUserRevision(user_id)) {
\r
256 session->Send(network::ClientReceiveAccountRevisionPatch(
\r
257 account.GetUserRevisionPatch(user_id, client_revision)));
\r
264 case network::header::ServerUpdateAccountProperty:
\r
266 if (auto session = c.session().lock()) {
\r
267 AccountProperty property;
\r
268 std::string buffer = c.body().substr(sizeof(AccountProperty));
\r
269 network::Utils::Deserialize(c.body(), &property);
\r
271 auto old_revision = account.GetUserRevision(session->id());
\r
273 switch (property) {
\r
278 network::Utils::Deserialize(buffer, &value);
\r
279 account.SetUserName(session->id(), buffer);
\r
285 network::Utils::Deserialize(buffer, &value);
\r
286 account.SetUserTrip(session->id(), value);
\r
292 network::Utils::Deserialize(buffer, &value);
\r
293 account.SetUserModelName(session->id(), value);
\r
298 //unsigned char value;
\r
299 //network::Utils::Deserialize(buffer, &value);
\r
300 // account.SetUserChannel(session->id(), value);
\r
301 //session->set_channel(value);
\r
308 auto new_revison = account.GetUserRevision(session->id());
\r
309 if (new_revison > old_revision) {
\r
311 network::ClientReceiveAccountRevisionUpdateNotify(
\r
312 session->id(),new_revison));
\r
321 case network::header::FatalConnectionError:
\r
323 if (c.body().size() > 0) {
\r
325 network::Utils::Deserialize(c.body(), &user_id);
\r
326 account.LogOut(user_id);
\r
329 network::ClientReceiveAccountRevisionUpdateNotify(user_id,
\r
330 account.GetUserRevision(user_id)));
\r
332 Logger::Info("Logout User: %d", user_id);
\r
333 account.Remove(user_id);
\r
345 bool execute_with_client;
\r
348 using namespace boost::interprocess;
\r
349 windows_shared_memory shm(open_only, "MMO_SERVER_WITH_CLIENT", read_only);
\r
351 execute_with_client = true;
\r
352 } catch(std::exception& e) {
\r
353 Logger::Info("Stand-alone Mode");
\r
354 execute_with_client = false;
\r
357 // クライアントから起動している場合、クライアントの状態を監視
\r
359 if (execute_with_client) {
\r
360 boost::thread([&server](){
\r
362 boost::this_thread::sleep(boost::posix_time::milliseconds(4000));
\r
364 using namespace boost::interprocess;
\r
365 windows_shared_memory shm(open_only, "MMO_SERVER_WITH_CLIENT", read_only);
\r
366 } catch(std::exception& e) {
\r
375 network::ServerSigHandler handler(SIGINT,&server);
\r
377 server.Start(callback);
\r
379 } catch (std::exception& e) {
\r
380 Logger::Error(e.what());
\r
382 Logger::Info("Stop Server");
\r