#define ACE_BUILD_SVC_DLL #include "MessageHandler.h" #include "md5.h" #include "../ServiceSpaceDBLib/DBQueryObject.h" #include "../ServiceSpaceLib/ObjectMessageBlock.h" #include "../ServiceSpaceLib/TcpService.h" #include "../RelationService/MessageTool.h" #include "../ServiceSpaceLib/utilib/split.h" #include "../ServiceSpaceLib/utilib/vectorN.h" #include "../ServiceSpaceLib/StreamBuffer.h" #include #include #include #include #include __SERVICE_SPACE_BEGIN_NS__ const char * _id() { return "Account"; } const char * _id2() { return "accountid"; } const char * _passwrd() { return "Password"; } const char * _state() { return "State"; } const char * _account() { return "account"; } const char * _last_upline_time() { return "lastuplinetime"; } const char * _last_offline_time() { return "lastofflinetime"; } const char * _last_acc_upline_time() { return "lastaccuplinetime"; } const char * _last_acc_offline_time() { return "lastaccofflinetime"; } const char * _user_game_state() { return "usergamestate"; } const char * _user_identification() { return "identification"; } const char * _user_identification_type() { return "identificationtype"; } const char * _user_age() { return "age"; } const char * gm_account() { return "gmaccount"; } const char * gm_account_id() { return "accountid"; } const char * gm_account_passwrd() { return "passwrd"; } const char * gm_account_level() { return "level"; } const char * _filed_user_seq() { return "seq"; } /*序号,DB自动增加 整数*/ const char * _field_user_id() { return "userid"; } /*用户帐号 字符串*/ const char * _field_passwrd() { return "passwrd"; } /*用户密码 字符串*/ const char * _field_baninfo() { return "baninfo"; } /*封停信息 */ const char * _field_verifyflag(){ return "verifyflag"; } /*公安验证标记 */ const char * _field_origin() { return "origin"; } /*用户来源*/ const char * _field_sex() { return "sex"; } /*用户性别*/ const char * _field_regdate() { return "regdate"; } /*用户注册时间*/ const char * _field_activedate(){ return "activedate"; } /*用户激活时间*/ const char * _field_regip() { return "regip"; } /*注册时用户IP*/ const char * _field_activeip() { return "activeip"; } /*激活时用户IP*/ const char * _field_matrixcard(){ return "matrixcard"; } /*密保卡信息*/ const char * _field_tokenb() { return "token"; } /*令牌*/ const char * _field_memo() { return "memo"; } /*备注*/ const char * _field_otherdata() { return "otherdata"; } /*游戏内用到的其他信息,如角色列表 */ typedef field<_id, std::string, true> ID; typedef field<_id2, std::string, true> ID2; typedef field<_passwrd, std::string> Passwrd; typedef field<_state, unsigned char> State; typedef field<_last_acc_upline_time, unsigned> LastAccUplineTime; typedef field<_last_acc_offline_time, unsigned> LastAccOfflineTime; typedef field<_last_upline_time, unsigned> LastUplineTime; typedef field<_last_offline_time, unsigned> LastOfflineTime; typedef field<_user_identification, std::string> UserIdentification; typedef field<_user_identification_type, unsigned> UserIdentificationType; typedef field<_user_age, unsigned> UserAge; typedef object<_account, ID, Passwrd, State> Account; typedef object<_user_game_state, ID2, LastUplineTime, LastOfflineTime, LastAccUplineTime, LastAccOfflineTime, UserIdentification, UserIdentificationType, UserAge> UserGameState; typedef field GmAccountID; typedef field GmAccountPasswrd; typedef field GmAccountLevel; typedef object GmAccount; const int MESSAGE_TYPE = 0; int tired_time = 3600 * 3; int illhealth_time = 3600 * 5; int leavenow_time = 3600 * 5; std::vector > account_table_lst; unsigned get_account_value(const std::string & id) { MD5_CTX_t ctx; md5::MD5Init(&ctx); md5::MD5Update(&ctx, (unsigned char *)id.data(), id.size()); md5::MD5Final(&ctx); int i = *((int *)((char *)ctx.digest)); int j = *((int *)((char *)ctx.digest + 4)); int m = *((int *)((char *)ctx.digest + 8)); int n = *((int *)((char *)ctx.digest + 12)); return i + j + m + n; } void build_account_table_lst(std::vector & vec) { std::sort(vec.begin(), vec.end()); if (vec.empty()) return; if (vec.front() < 0 || vec.back() != 13) { SS_ERROR("错误的分表\n"); return; } for(std::size_t i = 0; i < vec.size() - 1; ++i) { std::stringstream s; s << "mux_account_table" << vec[i]; account_table_lst.push_back(std::pair(vec[i], s.str())); } } /* const std::string & get_account_table(const std::string & id) { int val = get_account_value(id) % 13; for(std::size_t i = 0; i < account_table_lst.size(); ++i) { if (account_table_lst[i].first >= val) ; } }*/ bool check_md5(const char * md1, const char * md2) { for (int i = 0; i < 16; ++i) { if (md1[i] != md2[i]) { return false; } } return true; } void generate_random_string(char * buf) { time_t te; ::time(&te); te *= te; te *= te; build_md5((char *)&te, sizeof(te), buf, 16); } const bool user_id_check(const user_id_type & user, const char * fcm) { size_t sz = strlen(fcm); size_t i = 0, j = 0; while(i < user.size() && j < sz) { if (toupper(user[i]) != toupper(fcm[j])) return false; ++i; ++j; } return true; } const bool user_state_check_list(const user_id_type & user) { return user_id_check(user, "fcm1") || user_id_check(user, "fcm2") || user_id_check(user, "fcm3") || user_id_check(user, "fcm4") || user_id_check(user, "fcm5") || user_id_check(user, "fcm6") || user_id_check(user, "fcm7") || user_id_check(user, "fcm8"); } LoginServiceMessageHandler * LoginServiceMessageHandler::instance() { static LoginServiceMessageHandler inst; return &inst; } int LoginServiceMessageHandler::get_message_id(ACE_Message_Block * message) { short len; short id; char type; parse_message_header(message->rd_ptr(), len, type, id); return (int)id; } ACE_Message_Block * LoginServiceMessageHandler::build_result_message(void * data, int msgId) { ACE_Message_Block * message = new MessageBlock(); message->wr_ptr(5); size_t size = protocol_.EnCode(msgId, data, message->wr_ptr(), message->space()); message->wr_ptr(size); build_message_header(message->rd_ptr(), (short)size + 5, MESSAGE_TYPE, msgId); return message; } int LoginServiceMessageHandler::send_result_message(ss::tcp_session &session, void *data, int msgId) { if (!check_session(session)) return -1; session->post_asynch_write(build_result_message(data, msgId)); return 0; } int LoginServiceMessageHandler::init(int argc, ACE_TCHAR * argv[]) { SS_DEBUG("\n\n\n=======LoginServiceMessageHandler * init()\n\n\n"); GetOpts opts(argc, argv); int err = 0; const ACE_TCHAR * options = ACE_TEXT(":h:p:e:y:z:"); ACE_Get_Opt get_opt(argc, (ACE_TCHAR **)opts.argv, options); char c; utilib::stringN<128> db_opt; while((c = get_opt()) != EOF) { switch(c) { case 'z': db_opt = get_opt.optarg; break; case 'h': { unsigned long addr = ::inet_addr(get_opt.optarg); listen_addr_.set_address((const char *)&addr, sizeof(addr), 0); } break; case 'p': listen_addr_.set_port_number(ACE_OS::atoi(get_opt.optarg)); break; case 'e': tired_time = atoi(get_opt.optarg); break; case 'y': { illhealth_time = atoi(get_opt.optarg); leavenow_time = illhealth_time + 100; } break; } } err = base::init(argc, argv); md5::init(); utilib::vectorN, 6> vec; utilib::split(vec, db_opt.c_str(), db_opt.c_str() + db_opt.size(), ':'); dbdesc desc; strcpy(desc.charset, ""); strcpy(desc.host, vec[0].c_str()); desc.port = ACE_OS::atoi(vec[1].c_str()); strcpy(desc.user, vec[2].c_str()); strcpy(desc.passwrd, vec[3].c_str()); strcpy(desc.dbname, vec[4].c_str()); desc.flags = 0; try{ database_.reset(new database(desc)); load_gm_account(); }catch(const std::exception & e) { SS_ERROR(ACE_TEXT("%s\n"), e.what()); //exit(-1); err = -1; } return err; } int LoginServiceMessageHandler::open(void *args /* = 0 */) { int err = base::open(args); if (-1 == err) return -1; this->register_handler(G_L_REPORT_USER, &LoginServiceMessageHandler::handle_report_user_account); this->register_handler(G_L_CHECK_USER_MD5, &LoginServiceMessageHandler::handle_check_user_md5); this->register_handler(G_L_REPORT_USER_ENTER_GAME, &LoginServiceMessageHandler::handle_report_user_enter_game); this->register_handler(G_L_REPORT_USER_LEAVE_GAME, &LoginServiceMessageHandler::handle_report_user_leave_game); #ifdef WIN32 TcpService * tcp = ACE_Dynamic_Service::instance("listener"); #else const ACE_Service_Type * svc_rec; if (ACE_Service_Repository::instance()->find("listener", &svc_rec) == -1) return -1; const ACE_Service_Type_Impl * type = svc_rec->type(); if (type == 0) return -1; ACE_Service_Object * obj = ACE_static_cast (ACE_Service_Object *, type->object()); TcpService * tcp = (TcpService *)obj; #endif tcp->create_tcp_acceptor(listen_addr_, 0); ACE_Time_Value tv(30); ACE_Reactor::instance()->schedule_timer(this, 0, tv); SS_DEBUG("\n\n\n=======LoginServiceMessageHandler * open():create_tcp_acceptor\n\n\n"); return 0; } int LoginServiceMessageHandler::handle_task_message(ACE_Message_Block * message) { ACE_Guard guard(users_lock_); try{ #ifdef WIN32 ObjectMessageBlock * notif_message = dynamic_cast *>(message); #else ObjectMessageBlock * notif_message = (ObjectMessageBlock *)message; #endif if (!notif_message) { SS_ERROR(ACE_TEXT("LoginServiceMessageHandler::handle_task_message | cast error\n")); return -1; } TcpService::Tcp_Notify & notify = notif_message->obj(); int err = -1; if (notify.flag == TcpService::Tcp_Notify::TCP_RECEIVED) { ACE_Message_Block * real_message = notify.message; err = StreamBuffer(real_message, 0, 2, false); if (err == 0) { dispatch_message_handler(notify.session, real_message); while (real_message->cont()) { dispatch_message_handler(notify.session, real_message->cont()); real_message = real_message->cont(); } } else if (err == 1) { while (real_message->cont()) { dispatch_message_handler(notify.session, real_message); ACE_Message_Block * tmp = real_message; real_message = real_message->cont(); if (!real_message->cont()) { tmp->cont(0); } } if (notify.message == real_message) notify.message = 0; notify.session->post_asynch_read(real_message); } else if (err == -1) { SS_ERROR(ACE_TEXT("error message from [%s:%d]\n"), notify.session->remote_address().get_host_addr(), notify.session->remote_address().get_port_number()); } if (err != 1) { notify.session->post_asynch_read(); } } else if (notify.flag == TcpService::Tcp_Notify::TCP_SESSION_BUILT && check_session(notify.session)) { SS_DEBUG(ACE_TEXT("session[%s:%d] built\n"), notify.session->remote_address().get_host_addr(), notify.session->remote_address().get_port_number()); } else if (notify.flag == TcpService::Tcp_Notify::TCP_SESSION_CLOSED && check_session(notify.session)) { SS_DEBUG(ACE_TEXT("session[%s:%d] closed\n"), notify.session->remote_address().get_host_addr(), notify.session->remote_address().get_port_number()); } else if (notify.flag == TcpService::Tcp_Notify::TCP_SEND && check_session(notify.session)) { SS_DEBUG(ACE_TEXT("sent message error: %d\n"), notify.error); } else { SS_ERROR(ACE_TEXT("[ERROR]handle_task_message | error notify type: %d\n"), notify.flag); } }catch (const std::exception & e) { SS_ERROR(ACE_TEXT("handle_task_message | exception: %s\n"), e.what() ? e.what() : ACE_TEXT("unknown")); } message->release(); return 0; } extern "C" ACE_Svc_Export void ____to_gdb_break() { ACE_TRACE(ACE_TEXT("____to_gdb_break")); } int LoginServiceMessageHandler::handle_report_user_account(tcp_session & session, const char * message, unsigned len) { message += 5; GL_ReportUserRequest req; if(0XFFFFFFFF == protocol_.DeCode(GL_ReportUserRequest::wCmd, &req, sizeof(req), const_cast(message), len - 5)) { SS_ERROR(ACE_TEXT("protocol decode error\n")); return -1; } LG_ReportUserResultWithKey result; result.returnCode = L_G_RESULT_SUCCEED; result.requestSeq = req.requestSeq; result.randomString.randomStringLen = 16; result.randomKey.randomStringLen = 16; result.gateId = req.gateId; result.playerId = req.playerId; result.userId = req.userId; generate_random_string(result.randomString.randomString); generate_random_string(result.randomKey.randomString); user_id_type user_id(req.userId.userId, (req.userId.userIdLen - 1) < MAX_USER_ID_LEN ? (req.userId.userIdLen - 1): MAX_USER_ID_LEN); SS_DEBUG(ACE_TEXT("reporting user[%s]\n"), user_id.c_str()); user_data & ud = users_[user_id]; ud.gateId = req.gateId; ud.playerId = req.playerId; ud.session = session; ud.md5Value[0] = 0; ::memcpy(ud.randomString, result.randomString.randomString, 16); int err = 0; try { std::map::const_iterator gmIt = gms_.find(user_id.c_str()); if (gmIt == gms_.end()) { Account * account = new Account(); equal_strict st(user_id.c_str()); ID & id = account->get(); id.set_strict(&st); if (1 != database_->query(*account)) { result.returnCode = L_G_RESULT_ERROR_USER; } /*else if (account->get().value != user_id.c_str()) { result.returnCode = L_G_RESULT_ERROR_USER; }*/ else { Passwrd & passwrd = account->get(); user_passwrd_type user_passwrd(passwrd.value.c_str()); build_md5(user_id.c_str(), user_passwrd.c_str(), ud.randomString, 16, ud.md5Value, 16); build_md5(user_id.c_str(), user_passwrd.c_str(), result.randomKey.randomString, 16, ud.randomKey, 16); } account->destroy(); } else { build_md5(user_id.c_str(), gmIt->second.passwrd, ud.randomString, 16, ud.md5Value, 16); build_md5(user_id.c_str(), gmIt->second.passwrd.c_str(), result.randomKey.randomString, 16, ud.randomKey, 16); } } catch (const std::exception & e) { SS_ERROR(ACE_TEXT("%s\n"), e.what() ? e.what() : "unknown exception"); } SS_DEBUG(ACE_TEXT("handle_report_user_account | request user result: %u\n"), result.returnCode); err = send_result_message(session, &result, LG_ReportUserResultWithKey::wCmd); return err; } int LoginServiceMessageHandler::handle_check_user_md5(ss::tcp_session &session, const char *message, unsigned int len) { message += 5; GL_CheckUserMD5Request req; if (0XFFFFFFFF == protocol_.DeCode(GL_CheckUserMD5Request::wCmd, &req, sizeof(req), const_cast(message), len - 5)) { SS_ERROR(ACE_TEXT("protocol decode error\n")); return -1; } user_id_type user_id(req.userId.userId, (req.userId.userIdLen - 1) < MAX_USER_ID_LEN ? (req.userId.userIdLen - 1) : MAX_USER_ID_LEN); std::map::iterator it = users_.find(user_id); if (it == users_.end()) { SS_DEBUG(ACE_TEXT("checking md5...result:cannot find user[%s]\n"), user_id.c_str()); return -1; } LG_CheckUserMD5dResultWithKey result; if (check_md5(it->second.md5Value, req.md5Value.md5Value)) result.returnCode = L_G_RESULT_SUCCEED; else result.returnCode = L_G_RESULT_ERROR_PASSWRD; SS_DEBUG(ACE_TEXT("[%s]checking md5...result:%d\n"), user_id.c_str(), result.returnCode); gate_session_[req.gateId] = session; result.requestSeq = req.requestSeq; result.gateId = req.gateId; result.playerId = req.playerId; result.userId = req.userId; if (result.returnCode == L_G_RESULT_SUCCEED && user_state_check_list(it->first)) { user_state state; state.gateId = it->second.gateId; state.playerId = it->second.playerId; state.notifyIllhealth = false; state.notifyTired = false; state.notifyTired = false; state.uplineTime = time(0); int res = query_user_game_state(user_id, state); if ((res == 1 || res == 0) && state.age < 18) { if (!check_user_adult(state.identification, state.identType)) { state.userId.userIdLen = user_id.size() < sizeof(state.userId.userId) ? user_id.size() : sizeof(state.userId.userId); memcpy(state.userId.userId, user_id.c_str(), state.userId.userIdLen); if (state.accOfflinePeriod >= illhealth_time) { state.accOnlinePeriod = 0; state.accOfflinePeriod = 0; } if(state.accOnlinePeriod >= illhealth_time) { state.state = USER_GAME_STATE_ILLHEALTH; } else if(state.accOnlinePeriod >= tired_time) { state.state = USER_GAME_STATE_TIRED; } else { state.state = USER_GAME_STATE_HEALTH; } usersstate_[user_id] = state; send_result_message(session, &state, LG_UserGameStateNotify::wCmd); } } } ::memcpy(result.key.randomString, it->second.randomKey, 16); result.key.randomStringLen = 16; users_.erase(it); std::map::const_iterator gmIt = gms_.find(user_id.c_str()); if (gmIt != gms_.end()) result.requestSeq = gmIt->second.level; send_result_message(session, &result, LG_CheckUserMD5dResultWithKey::wCmd); return 0; } int LoginServiceMessageHandler::handle_report_user_enter_game(tcp_session & session, const char * message, unsigned len) { message += 5; GL_ReportUserEnterGame rep; if (0XFFFFFFFF == protocol_.DeCode(GL_ReportUserEnterGame::wCmd, &rep, sizeof(GL_ReportUserEnterGame), const_cast(message), len - 5)) { SS_ERROR(ACE_TEXT("protocol decode error\n")); return -1; } user_id_type user(rep.userId.userId, rep.userId.userIdLen); return 0; } int LoginServiceMessageHandler::handle_report_user_leave_game(tcp_session & session, const char * message, unsigned len) { message += 5; GL_ReportUserLeaveGame rep; if (0XFFFFFFFF == protocol_.DeCode(GL_ReportUserLeaveGame::wCmd, &rep, sizeof(GL_ReportUserLeaveGame), const_cast(message), len - 5)) { SS_ERROR(ACE_TEXT("protocol decode error\n")); return -1; } user_id_type user(rep.userId.userId, rep.userId.userIdLen); save_user_game_state(user); usersstate_.erase(user); return 0; } int LoginServiceMessageHandler::handle_timeout (const ACE_Time_Value ¤t_time, const void *act) { SS_DEBUG("handle_timeout\n"); ACE_Guard guard(users_lock_); time_t curTime = time(0); LG_UserGameStateNotify notify; for(std::map::iterator it = usersstate_.begin(); it != usersstate_.end();) { time_t accUplineTime = it->second.accOnlinePeriod + curTime - it->second.uplineTime; notify.gateId = it->second.gateId; notify.playerId = it->second.playerId; notify.accOnlinePeriod = accUplineTime; notify.accOfflinePeriod = it->second.accOfflinePeriod; notify.userId.userIdLen = it->first.size() < sizeof(notify.userId.userId) ? it->first.size() : sizeof(notify.userId.userId); memcpy(notify.userId.userId, it->first.c_str(), notify.userId.userIdLen); notify.state = USER_GAME_STATE_HEALTH; if (accUplineTime >= illhealth_time/* 5 * 3600*/ && !it->second.notifyIllhealth) { notify.state = USER_GAME_STATE_ILLHEALTH; it->second.notifyIllhealth = true; } else if (accUplineTime >= tired_time/*3 * 3600*/ && !it->second.notifyTired) { notify.state = USER_GAME_STATE_TIRED; it->second.notifyTired = true; } if (notify.state != USER_GAME_STATE_HEALTH) { this->save_user_game_state(it->first); if (notify.state == USER_GAME_STATE_ILLHEALTH) { usersstate_.erase(it++); } else ++it; std::map::iterator git = gate_session_.find(notify.gateId); if (git != gate_session_.end()) send_result_message(git->second, ¬ify, LG_UserGameStateNotify::wCmd); } else ++it; } ACE_Time_Value tv(30); ACE_Reactor::instance()->schedule_timer(this, 0, tv); return 0; } int LoginServiceMessageHandler::query_user_game_state(const user_id_type & user, user_state & userstate) { userstate.userId.userIdLen = user.size() > sizeof(userstate.userId.userId) ? sizeof(userstate.userId.userId) : user.size(); memcpy(userstate.userId.userId, user.c_str(), userstate.userId.userIdLen); std::map::iterator it = usersstate_.find(user); if (it != usersstate_.end()) { userstate = it->second; return 0; } int res = -1; UserGameState * state = new UserGameState(); try { state->get().max_size(32); equal_strict st(user.c_str()); state->get().set_strict(&st); if (1 == database_->query(*state)) { userstate.accOfflinePeriod = state->get().value; userstate.accOnlinePeriod = state->get().value; userstate.lastOfflineTime = state->get().value; userstate.lastUplineTime = state->get().value; userstate.uplineTime = time(0); userstate.accOfflinePeriod += (userstate.uplineTime - userstate.lastOfflineTime); //userstate.age = state->get().value; res = 0; } else { res = 1; } } catch (const std::exception & e) { SS_ERROR(ACE_TEXT("%s\n"), e.what() ? e.what() : "unknown exception"); res = -1; } state->destroy(); return res; } int LoginServiceMessageHandler::save_user_game_state(const user_id_type & user) { std::map::iterator it = usersstate_.find(user); if (it == usersstate_.end()) return -1; UserGameState * state = new UserGameState(); try { state->get().set(user.c_str()); time_t curTime = time(0); state->get().set(it->second.uplineTime); state->get().set(curTime); state->get().set(it->second.accOnlinePeriod + curTime - it->second.uplineTime); state->get().set(it->second.accOfflinePeriod); database_->replace(*state); } catch (const std::exception & e) { SS_ERROR(ACE_TEXT("%s\n"), e.what() ? e.what() : "unknown exception"); } state->destroy(); return 0; } const bool LoginServiceMessageHandler::check_user_adult(const std::string & ident, unsigned type) { std::string birth; if (type == 0) { if (ident.size() == 18) birth = ident.substr(6, 8); else if (ident.size() == 15) birth = std::string("19") + ident.substr(5, 6); } if (birth.empty()) return false; time_t tmp = time(0); tm now = *localtime(&tmp); now.tm_year -= 18; now.tm_yday += 1900; std::stringstream sstream; sstream << now.tm_year << std::setw(2) << now.tm_mon + 1 << std::setw(2) << now.tm_yday; return birth < sstream.str(); } void LoginServiceMessageHandler::load_gm_account() { bool loop = true; for(size_t i = 0; loop; ++i) { GmAccount * gm = new GmAccount(); try { gm->get().max_size(32); gm->get().max_size(32); unsigned n = database_->query(*gm, i * 500, 500); if (0 == n) break; const GmAccount * next = gm; while(next) { gm_data tmp; tmp.account = next->get().value; tmp.passwrd = next->get().value; tmp.level = next->get().value; gms_[tmp.account] = tmp; next = next->next(); } if (n < 500) break; }catch(const std::exception & e) { SS_ERROR("%s\n", e.what() ? e.what() : "unknown"); loop = false; } gm->destroy(); } // end for } extern "C" ACE_Svc_Export LoginServiceMessageHandler * CreateMessageHandler() { SS_DEBUG("\n\n\n=======LoginServiceMessageHandler * CreateMessageHandler()\n\n\n"); //return LoginServiceMessageHandler::instance(); return new LoginServiceMessageHandler(); } ACE_SVC_FACTORY_DECLARE(LoginServiceMessageHandler); ACE_SVC_FACTORY_DEFINE(LoginServiceMessageHandler); __SERVICE_SPACE_END_NS__