#include "CustMngrAuthFSM.h" #include "CustMngrAuth_UserErrorCode.h" #include "SpHelper.h" #include "fileutil.h" #include #include #include #include #include #include #include #include using std::string; const int UPDATE_INTERNAL = 10 * 60 * 1000; //query data from branch server internal, 10min const int CONNECT_INTERNAL = 30 * 1000; //connect branch server internal, 30s const int FINGER_NUM = 8; //suuport max register finger num const int COLLECT_TIMES = 3; //press finger times #define RUNINFOFILE "CustMngrAuth.ini" #define RUNINFOFILE_BAK "CustMngrAuth_bak.ini" class CCustMngrAuthEntity; #pragma region event response void CCustMngrAuthFSM::s0_on_entry() { LOG_FUNCTION(); FSMEvent* pEvt = new FSMEvent(USER_EVT_INIT); PostEventFIFO(pEvt); } void CCustMngrAuthFSM::s0_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s0_on_event(FSMEvent* pEvt) { LOG_FUNCTION(); Dbg("s0 evt %d", pEvt->iEvt); switch (pEvt->iEvt) { case USER_EVT_INIT: { InitTask* task = new InitTask(this); GetEntityBase()->GetFunction()->PostThreadPoolTask(task); pEvt->SetHandled(); return 0; } break; default: break; } return 0; } void CCustMngrAuthFSM::s1_on_entry() { LOG_FUNCTION(); } void CCustMngrAuthFSM::s1_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s1_on_event(FSMEvent* pEvt) { LOG_FUNCTION(); Dbg("s1 evt %d", pEvt->iEvt); switch (pEvt->iEvt) { case USER_EVT_INIT_FINISHED: pEvt->SetHandled(); return pEvt->param1; default: break; } return 0; } void CCustMngrAuthFSM::s2_on_entry() { LOG_FUNCTION(); } void CCustMngrAuthFSM::s2_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s2_on_event(FSMEvent* pEvt) { LOG_FUNCTION(); Dbg("s2 evt(%d)", pEvt->iEvt); switch (pEvt->iEvt) { case USER_EVT_AUTHORIZE_START: { pEvt->SetHandled(); AuthorizeStartEvent* authorEvt = dynamic_cast(pEvt); if (authorEvt->ctx->Req.TimeLimit <= 0) { AuthorizeFinishedEvent* e = new AuthorizeFinishedEvent(); e->ctx = authorEvt->ctx; e->param1 = Error_Param; this->PostEventFIFO(e); break; } //time here should be less than the web m_TimeLimit = (authorEvt->ctx->Req.TimeLimit - 3) * 1000; m_bCancelAuthorize = false; /*ErrorCodeEnum errCode = SwitchUSB(true); if (errCode != Error_Succeed) Dbg("open usb failed with eErr(%s)", SpStrError(errCode)); else { Dbg("open usb successfully."); m_ctx = authorEvt->ctx; }*/ MatchFingerPrintTask* matchTask = new MatchFingerPrintTask(this); matchTask->ctx = authorEvt->ctx; GetEntityBase()->GetFunction()->PostThreadPoolTask(matchTask); } break; case USER_EVT_COLLECTFINGERPRINT_START: { pEvt->SetHandled(); CollectFingerPrintStartEvent* collectEvt = dynamic_cast(pEvt); CollectFingerPrintTask* collectTask = new CollectFingerPrintTask(this); collectTask->ctx = collectEvt->ctx; GetEntityBase()->GetFunction()->PostThreadPoolTask(collectTask); } break; case USER_EVT_SAVEFINGERPRINT_START: { pEvt->SetHandled(); SaveFingerPrintStartEvent* saveEvtfpe = dynamic_cast(pEvt); SaveFingerPrintTask* saveTask = new SaveFingerPrintTask(this); saveTask->ctx = saveEvtfpe->ctx; GetEntityBase()->GetFunction()->PostThreadPoolTask(saveTask); } break; case USER_EVT_CHECKUKEY: { pEvt->SetHandled(); //SwitchUSB(true); } break; default: break; } return 0; } void CCustMngrAuthFSM::s3_on_entry() { LOG_FUNCTION(); ScheduleTimer(1, m_TimeLimit); Dbg("set timer when match, %dms", m_TimeLimit); } void CCustMngrAuthFSM::s3_on_exit() { LOG_FUNCTION(); CancelTimer(1); Dbg("exit match event, timer canceled"); } unsigned int CCustMngrAuthFSM::s3_on_event(FSMEvent* pEvt) { LOG_FUNCTION(); Dbg("s3 evt %d, %d", pEvt->iEvt, pEvt->param1); switch (pEvt->iEvt) { case USER_EVT_HOLDON: { pEvt->SetHandled(); CancelTimer(1); HoldOnEvent* holdEvt = dynamic_cast(pEvt); if (holdEvt->ctx == NULL) Dbg("HoldOnEvent->ctx is NULL"); Dbg("HoldOn with MoreTime: %d second", holdEvt->ctx->Req.MoreTime); int moreTime = holdEvt->ctx->Req.MoreTime * 1000; ScheduleTimer(1, (moreTime > 0) ? moreTime : m_TimeLimit); } break; case EVT_TIMER: { pEvt->SetHandled(); Dbg("Hit Timer"); m_bAuthorizeTimeout = true; m_bCancelAuthorize = true; CancelAuthorize(); } break; case USER_EVT_AUTHORIZE_FINISHED: { pEvt->SetHandled(); AuthorizeFinishedEvent* authorEvt = dynamic_cast(pEvt); Dbg("Checking m_authCtx and answer ctx"); //SwitchUSB(false); if (authorEvt->param1 == 0) { if (m_authCtx.eAuthByWhich == AuthByUkey) { Dbg("m_authCtx.eAuthByWhich == AuthByUkey"); if (m_pFingerPrint != NULL && !m_pFingerPrint->QuerySessionClosed()) { Dbg("Invoke cancel match."); m_pFingerPrint->CancelMatch(); } authorEvt->ctx->Ans.WayofAuth = AuthByUkey; authorEvt->ctx->Ans.UkeyID = m_authCtx.UkeyID; authorEvt->ctx->Answer(Error_Succeed); } else if (m_authCtx.eAuthByWhich == AuthByFngPrnt) { Dbg("m_authCtx.eAuthByWhich == AuthByFngPrnt"); authorEvt->ctx->Ans.WayofAuth = AuthByFngPrnt; authorEvt->ctx->Ans.CustomerID = m_authCtx.CustomerID; authorEvt->ctx->Answer(Error_Succeed); } } else { Dbg("authorize finished with param1 as %d", authorEvt->param1); authorEvt->ctx->Answer((ErrorCodeEnum)authorEvt->param1); } if (m_pFingerPrint != NULL && !m_pFingerPrint->QuerySessionClosed()) { m_bCancelAuthorize = true; m_pFingerPrint->GetFunction()->CloseSession(); m_pFingerPrint = NULL; } m_authCtx.eAuthByWhich = AuthByNone; m_authCtx.CustomerID = ""; m_authCtx.UkeyID = ""; m_ctx = NULL; } break; case USER_EVT_AUTHORIZE_CANCEL: { pEvt->SetHandled(); m_bCancelAuthorize = true; CancelAuthorize(); } break; default: break; } return 0; } void CCustMngrAuthFSM::s4_on_entry() { LOG_FUNCTION(); } void CCustMngrAuthFSM::s4_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s4_on_event(FSMEvent* pEvt) { LOG_FUNCTION(); Dbg("s4 evt %d, %d", pEvt->iEvt, pEvt->param1); switch (pEvt->iEvt) { case USER_EVT_COLLECTFINGERPRINT_FINISHED: pEvt->SetHandled(); break; case USER_EVT_COLLECTFINGERPRINT_CANCEL: { pEvt->SetHandled(); if (m_pFingerPrint != NULL && !m_pFingerPrint->QuerySessionClosed()) m_pFingerPrint->CancelRegister(); } break; case USER_EVT_SAVEFINGERPRINT_FINISHED: pEvt->SetHandled(); break; case USER_EVT_CHECKUKEY_FINISHED: { pEvt->SetHandled(); //SwitchUSB(false); } break; default: break; } return 0; } void CCustMngrAuthFSM::s5_on_entry() { LOG_FUNCTION(); } void CCustMngrAuthFSM::s5_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s5_on_event(FSMEvent* pEvt) { LOG_FUNCTION(); Dbg("s5 evt %d, %d", pEvt->iEvt, pEvt->param1); return 0; } ErrorCodeEnum CCustMngrAuthFSM::WaitForUkey(ErrorCodeEnum eErr) { int status = (eErr == Error_NoTarget) ? 4 : 3;//4: no data in local, 3:enitty exception BroadcastGetFinger(status); while (1) { SLEEP(300); if (m_bCancelAuthorize) { m_bCancelAuthorize = false; if (m_bAuthorizeTimeout) { m_bAuthorizeTimeout = false; return Error_TimeOut; } else return Error_Cancel; } } } void CCustMngrAuthFSM::CancelAuthorize() { Dbg("Invoke m_pFingerPrint->CancelMatch()"); if (m_pFingerPrint != NULL && !m_pFingerPrint->QuerySessionClosed()) m_pFingerPrint->CancelMatch(); } ErrorCodeEnum CCustMngrAuthFSM::SwitchUSB(bool bOpen) { LOG_FUNCTION(); Dbg("connecting DeviceControl"); ErrorCodeEnum errCode; m_pDeviceControl = new DeviceControlService_ClientBase(GetEntityBase()); if (m_pDeviceControl != NULL) { errCode = m_pDeviceControl->Connect(); if (errCode != Error_Succeed) { Dbg("m_pDeviceControl connect failed with errCode(%s)", SpStrError(errCode)); m_pDeviceControl->SafeDelete(); }else { if (bOpen) Dbg("Open USB"); else Dbg("Close USB"); DeviceControlService_USB_Req usbReq; DeviceControlService_USB_Ans usbAns; usbReq.open = bOpen;//open or close usb errCode = m_pDeviceControl->USB(usbReq, usbAns, 2000); if (errCode != Error_Succeed) Dbg("Open/Close usb failed."); else Dbg("Open/Close usb success."); m_pDeviceControl->GetFunction()->CloseSession(); } m_pDeviceControl = NULL; return errCode; } else { Dbg("DeviceControl is null."); return Error_Unexpect; } } #pragma endregion #pragma region entity init ErrorCodeEnum CCustMngrAuthFSM::OnInit() { LOG_FUNCTION(); CSystemStaticInfo staticInfo; m_pEntity->GetFunction()->GetSystemStaticInfo(staticInfo); m_TerminalID = staticInfo.strTerminalID; m_csMachineType = staticInfo.strMachineType; m_authCtx.eAuthByWhich = AuthByNone; m_FingerSection = "FingerInfo"; return Error_Succeed; } int CCustMngrAuthFSM::Initial() { ErrorCodeEnum errCode = OpenRunInfoFile(); if (errCode != Error_Succeed) return 1; FeatureUpdateTask* pTask = new FeatureUpdateTask(this); GetEntityBase()->GetFunction()->PostThreadPoolTask(pTask); return 0; } ErrorCodeEnum CCustMngrAuthFSM::OpenRunInfoFile() { ErrorCodeEnum errCode; errCode = GetEntityBase()->GetFunction()->GetPath("RunInfo", m_RunInfoPath); if (errCode != Error_Succeed) { LogError(Severity_High, Error_DevLoadFileFailed , LOG_ERR_CUSTMNGRAUTH_GET_RUNINFO_PATH_FAILED_Init , "get runinfo path failed while init"); errCode = Error_Unexpect; } Dbg("runinfo path: %s", m_RunInfoPath.GetData()); return errCode; } #pragma endregion #pragma region entity exit ErrorCodeEnum CCustMngrAuthFSM::OnExit() { LOG_FUNCTION(); FSMImpl::OnExit(); return Error_Succeed; } #pragma endregion #pragma region update feature process void CCustMngrAuthFSM::FeatureUpdate() { LOG_FUNCTION(); InitBeforeUpdateData(); int waitInternal = UPDATE_INTERNAL; while (true) { do { int connectFailedTimes = 0; m_pConnection = new FeatureUpdateConn(m_pEntity, this); if (m_pConnection->ConnectFromCentralSetting() && m_pConnection->IsConnectionOK()) { connectFailedTimes = 0; waitInternal = UPDATE_INTERNAL; ErrorCodeEnum errCode; CSmartPointer spConfig; CAutoArray transArray; RunInfoParams runInfoParam; memset(&runInfoParam, 0, sizeof(runInfoParam)); errCode = InitBeforeQueryData(runInfoParam, spConfig); if (errCode != Error_Succeed) break; errCode = ReceiveDataFromServer(transArray, runInfoParam); if (errCode != Error_Succeed) break; errCode = BackupBeforeWriteData(runInfoParam, spConfig); if (errCode != Error_Succeed) break; errCode = WriteData(runInfoParam, transArray, spConfig); if (errCode != Error_Succeed) break; }else { connectFailedTimes++; Dbg("connect branchserver failed for %d times, try again in %d ms." , connectFailedTimes, CONNECT_INTERNAL); if (connectFailedTimes >= 60) { //30min give a warn LogWarn(Severity_Middle, Error_Unexpect , LOG_ERR_CUSTMNGRAUTH_FEATUPDATE_CONNECT_FAILED , "Connect branch server failed."); connectFailedTimes = 0; } waitInternal = CONNECT_INTERNAL; } } while (false); if (m_pConnection) { m_pConnection->Close(); m_pConnection->DecRefCount(); m_pConnection = NULL; } Dbg("Feature-update processed, wait until next"); //wait for next query if (WaitForSingleObject(hStopUpdate, waitInternal) == WAIT_OBJECT_0) break; } } /// /// Init memory data /// void CCustMngrAuthFSM::InitBeforeUpdateData() { bool bHasData = false; bool bReadResult = ReadDataIntoMemory(bHasData); if (bReadResult && bHasData) { Dbg("Read feature data into memory success."); } else if (bReadResult && !bHasData) { Dbg("Has no data in local file."); } else { Dbg("Read feature data into memory failed, wait next read."); } } /// /// read fingerprint feature data into memory from local file /// /// output param /// bool CCustMngrAuthFSM::ReadDataIntoMemory(bool& bHasData) { LOG_FUNCTION(); CSimpleStringA runInfoFile(true); runInfoFile = CSimpleStringA::Format("%s" SPLIT_SLASH_STR "runcfg" SPLIT_SLASH_STR RUNINFOFILE , m_RunInfoPath.GetData()); std::ifstream inFile(runInfoFile.GetData()); string line; int customerNum = 0; ULLINT startReadFile = RVCGetTickCount(); ULLINT endReadFile = RVCGetTickCount(); while (getline(inFile, line)) { if (line.length() <= 0) continue; string tempLine = ClearStringSpaceHeadTail(line); if (!tempLine.compare("[UpdateTime]") || string::npos != tempLine.find("UpdateTime") || !tempLine.compare("[LatestTime]") || string::npos != tempLine.find("LatestTime") || !tempLine.compare("[FingerInfo]") || !tempLine.compare("[FaceInfo]") || string::npos != tempLine.find("FaceInfo1") || string::npos != tempLine.find("FaceInfo2")) { continue; } string::size_type pos = tempLine.find("="); if (pos != 16) continue; string keys = tempLine.substr(0, pos); string values = tempLine.substr(pos + 1); Json::Reader reader; Json::Value root; if (reader.parse((const char*)values.c_str(), root)) { customerNum++; FeatureData* fd = new FeatureData(); fd->FingerIDArray.Init(FINGER_NUM); fd->FingerIDLenArray.Init(FINGER_NUM); char index[20]; for (int i = 0; i < FINGER_NUM; ++i) { memset(index, 0, sizeof(index)); #ifdef RVC_OS_WIN _snprintf_s(index, 10, "FingerID%d", i + 1); #else snprintf(index, 10, "FingerID%d", i + 1); #endif // RVC_OS_WIN fd->FingerIDArray[i] = root.isMember(index) ? CSimpleStringA(root[index].asCString()) : ""; fd->FingerIDLenArray[i] = root.isMember(index) ? fd->FingerIDArray[i].GetLength() : 0; } m_featureData[CSimpleStringA(keys.c_str())] = fd; } else { Dbg("Error: parse jsonFingerInfo failed."); LogWarn(Severity_Middle, Error_Unexpect , LOG_ERR_CUSTMNGRAUTH_AUTHORIZATION_READFEAT_FAILED , "Read fingerprint feature json failed."); return false; } } Dbg("Total CustomerNum:%d in local file.", customerNum); endReadFile = RVCGetTickCount(); ULLINT duration = endReadFile - startReadFile; LogWarn(Severity_Middle, Error_Debug , LOG_ERR_CUSTMNGRAUTH_READ_INTO_MEMORY_TIME , GenerateAlarmJson("CustMngrAuth", duration).GetData()); bHasData = true; return true; } CSimpleString CCustMngrAuthFSM::GenerateAlarmJson(CSimpleString entityName, int cost) { return CSimpleString::Format("[{\"name\":\"%s\",\"cost\":%d}]" , entityName.GetData(), cost); } string CCustMngrAuthFSM::ClearStringSpaceHeadTail(string& line) { if (line.empty()) return line; line.erase(0, line.find_first_not_of(" ")); line.erase(line.find_last_not_of(" ") + 1); return line; } /// /// init runinfo pointer and some time parameters /// /// out param /// out param /// ErrorCodeEnum CCustMngrAuthFSM::InitBeforeQueryData(RunInfoParams& runInfoParam, CSmartPointer& spConfig) { ErrorCodeEnum errCode = Error_Succeed; EnterCriticalSection(&m_cs);//临时锁一下运行时,防止在写入 errCode = LoadRunConfig(spConfig); if (Error_Succeed != errCode) { LeaveCriticalSection(&m_cs); return errCode; } InitTimeParams(runInfoParam, spConfig); LeaveCriticalSection(&m_cs); return errCode; } ErrorCodeEnum CCustMngrAuthFSM::LoadRunConfig(CSmartPointer& spConfig) { ErrorCodeEnum errCode = Error_Succeed; errCode = GetEntityBase()->GetFunction()->OpenConfig(Config_Run, spConfig); if (errCode != Error_Succeed) { Dbg("Open runcfg file failed before query data."); LogError(Severity_High, Error_Unexpect , LOG_ERR_CUSTMNGRAUTH_OPEN_RUNINFO_FAILED_UPDATE , "open runcfg failed before query data."); } return errCode; } void CCustMngrAuthFSM::InitTimeParams(RunInfoParams& runInfoParam, CSmartPointer& spConfig) { ErrorCodeEnum errCode = Error_Succeed; runInfoParam.LatestTime = ""; runInfoParam.UpdateTime = ""; CSimpleStringA latestTime(""), updateTime(""); spConfig->ReadConfigValue("LatestTime", "LatestTime", latestTime); spConfig->ReadConfigValue("UpdateTime", "UpdateTime", updateTime); //query current time CSimpleStringA newTime = GetCurrentDate(); runInfoParam.UpdateTime = newTime; runInfoParam.LatestTime = latestTime; //当前日期大于文件中日期时,需要做全量更新 if (updateTime.GetLength() <= 0 || (updateTime.GetLength() > 0 && CompareTime(newTime, updateTime) > 0) || latestTime.GetLength() <= 0) { runInfoParam.IsFirstTimeQueryData = true; } } CSimpleStringA CCustMngrAuthFSM::GetCurrentDate() { time_t curTime = time(NULL); tm* p = localtime(&curTime); char cTime[100] = { 0 }; #ifdef RVC_OS_WIN _snprintf_s(cTime, 100, "%d%02d%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday); #else snprintf(cTime, 100, "%d%02d%02d", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday); #endif // RVC_OS_WIN CSimpleStringA curDate(cTime); return curDate; } int CCustMngrAuthFSM::CompareTime(CSimpleStringA time1, CSimpleStringA time2) { if (time1.GetLength() > 0 && time2.GetLength() > 0) { int year1 = atoi((const char*)time1.SubString(0, 4)); int month1 = atoi((const char*)time1.SubString(4, 2)); int day1 = atoi((const char*)time1.SubString(6, 2)); int year2 = atoi((const char*)time2.SubString(0, 4)); int month2 = atoi((const char*)time2.SubString(4, 2)); int day2 = atoi((const char*)time2.SubString(6, 2)); int temp1 = year1 * 10000 + month1 * 100 + day1; int temp2 = year2 * 10000 + month2 * 100 + day2; if (temp1 > temp2) return 1; else if (temp1 < temp2) return -1; else return 0; } return 0; } /// /// receive fingerprint feature from branch server /// /// out param /// in param /// ErrorCodeEnum CCustMngrAuthFSM::ReceiveDataFromServer(CAutoArray& dataArray, RunInfoParams runInfoParam) { LOG_FUNCTION(); char currAgent[16]; char branchID[16]; memset(currAgent, 0, sizeof(currAgent)); memset(branchID, 0, sizeof(currAgent)); bool bResumeTrans = true; ErrorCodeEnum errCode = Error_Unexpect; while (bResumeTrans) { if (runInfoParam.IsFirstTimeQueryData) m_pConnection->SendFeatReq(currAgent, branchID); else m_pConnection->SendFeatReq(currAgent, branchID, runInfoParam.LatestTime.GetData()); ResetEvent(m_pConnection->m_hPkgAnswer); DWORD dw = WaitForSingleObject(m_pConnection->m_hPkgAnswer, 20000); //10->20 20200430@liuwentao switch (dw) { case WAIT_FAILED: Dbg("WAIT_FAILED!"); break; case WAIT_TIMEOUT: Dbg("WAIT_TIMEOUT"); case WAIT_OBJECT_0: Dbg("WAIT_OBJECT_0"); break; } ResetEvent(m_pConnection->m_hPkgAnswer); if (m_pConnection->m_reply == NULL) { Dbg("m_reply still null after m_hPkgAnswer handled"); break; } if (m_pConnection->m_GetErrMsg) { Dbg("get error message, check dbg log"); break; } if (m_pConnection->m_reply->ResultCode == 2) { Dbg("remote server uninitialized yet, unable to excute query"); break; } else { if (m_pConnection->m_reply->ResultCode == 0) { Dbg("All package downloaded from branch server."); bResumeTrans = false; errCode = Error_Succeed; } memcpy(currAgent, m_pConnection->m_reply->CurrentAgent, 16); memcpy(branchID, m_pConnection->m_reply->BranchID, 16); CSimpleStringA jbuf(m_pConnection->m_reply->Data, m_pConnection->m_jsonLen); dataArray.Append(&jbuf, 0, 1); } } if (bResumeTrans) Dbg("some errors happened, check the related log"); if (dataArray.GetCount() <= 0) Dbg("query no data from branchServer."); return errCode; } /// /// backup runinfo file, in case some error occurs when process data /// /// input/output param /// input param /// ErrorCodeEnum CCustMngrAuthFSM::BackupBeforeWriteData(RunInfoParams& runInfoParam, CSmartPointer& spConfig) { LOG_FUNCTION(); ErrorCodeEnum errCode = Error_Succeed; runInfoParam.SrcFile = CSimpleStringA::Format("%s" SPLIT_SLASH_STR "runcfg" SPLIT_SLASH_STR RUNINFOFILE , m_RunInfoPath.GetData()); runInfoParam.BackupFile = CSimpleStringA::Format("%s" SPLIT_SLASH_STR "runcfg" SPLIT_SLASH_STR RUNINFOFILE_BAK , m_RunInfoPath.GetData()); EnterCriticalSection(&m_cs); if (!BackupFile(runInfoParam.SrcFile, runInfoParam.BackupFile)) Dbg("Backup runinfo file failed."); if (runInfoParam.IsFirstTimeQueryData) { //首次更新,需清除数据,全量写入,并更新时间 ofstream fileOut((const char*)runInfoParam.SrcFile, ios::trunc); fileOut.close(); } errCode = GetEntityBase()->GetFunction()->OpenConfig(Config_Run, spConfig); if (errCode != Error_Succeed) { Dbg("error: open runcfg failed with errCode(%s)", SpStrError(errCode)); BackupFile(runInfoParam.BackupFile, runInfoParam.SrcFile);// if backup fail, recover LeaveCriticalSection(&m_cs); } spConfig->WriteConfigValue("UpdateTime", "UpdateTime", runInfoParam.UpdateTime.GetData()); if (runInfoParam.IsFirstTimeQueryData) { spConfig->WriteConfigValue("LatestTime", "LatestTime", ""); } return errCode; } bool CCustMngrAuthFSM::BackupFile(CSimpleStringA srcFile, CSimpleStringA dstFile) { if (!ExistsFile(srcFile.GetData())) return true; int result = fileutil_copy_file(dstFile.GetData(), srcFile.GetData()); return (result == 0) ? true : false; } /// /// write data into local file and memory /// /// input/output param /// input param /// input param /// ErrorCodeEnum CCustMngrAuthFSM::WriteData(RunInfoParams& runInfoParam , CAutoArray dataArray , CSmartPointer& spConfig) { ErrorCodeEnum errCode = Error_Unexpect; TempFeatureData tmpFeatureData; tmpFeatureData.MaxUpdateTime = runInfoParam.LatestTime; bool bExitLoop = false; for (int transTime = 0; transTime < dataArray.GetCount(); ++transTime) { Json::Value root; Json::Reader reader; //only 3-4 data, cause the limit of transfer amount CSimpleStringA transBuffer = dataArray[transTime]; if (reader.parse(transBuffer.GetData(), root)) { for (int i = 0; i < (int)root.size(); ++i) { JsonParams jsonParam; jsonParam.Root = root; jsonParam.Index = i; errCode = ProcessFeatureData(jsonParam, tmpFeatureData, runInfoParam, spConfig); if (Error_Succeed != errCode) { bExitLoop = true; break; } } if (bExitLoop) break; }else { Dbg("fail to parse transArray[%d]!", transTime); LeaveCriticalSection(&m_cs); bExitLoop = true; break; } } if (bExitLoop) return Error_Unexpect; if (tmpFeatureData.MaxUpdateTime.GetLength() > 0) { spConfig->WriteConfigValue("LatestTime", "LatestTime" , tmpFeatureData.MaxUpdateTime.GetData()); } Dbg("updateNum=%d", tmpFeatureData.tmpFeatureMap.size()); UpdateDataIntoMemory(tmpFeatureData.tmpFeatureMap, runInfoParam.IsFirstTimeQueryData); LeaveCriticalSection(&m_cs); return Error_Succeed; } /// /// process feature data /// /// /// /// /// /// ErrorCodeEnum CCustMngrAuthFSM::ProcessFeatureData(JsonParams& jsonParam, TempFeatureData& tmpFeatureData , RunInfoParams runinfoParam, CSmartPointer& spConfig) { ErrorCodeEnum errCode = Error_Succeed; FeatureData* fd = new FeatureData(); fd->FingerIDArray.Init(FINGER_NUM); fd->FingerIDLenArray.Init(FINGER_NUM); char FingerID[20];//runinfo file is named "FingerID" char fingerId[20];//branchserver is named "fingerId" , history bug for (int fingerIndex = 0; fingerIndex < FINGER_NUM; ++fingerIndex) { ZeroMemory(FingerID, sizeof(FingerID)); ZeroMemory(fingerId, sizeof(fingerId)); #ifdef RVC_OS_WIN _snprintf_s(FingerID, 10, "FingerID%d", fingerIndex + 1); _snprintf_s(fingerId, 10, "fingerId%d", fingerIndex + 1); #else snprintf(FingerID, 10, "FingerID%d", fingerIndex + 1); snprintf(fingerId, 10, "fingerId%d", fingerIndex + 1); #endif // RVC_OS_WIN jsonParam.FingerInfo[FingerID] = jsonParam.Root[jsonParam.Index][fingerId].asCString(); fd->FingerIDArray[fingerIndex] = CSimpleStringA(jsonParam.Root[jsonParam.Index][fingerId].asCString()); fd->FingerIDLenArray[fingerIndex] = fd->FingerIDArray[fingerIndex].GetLength(); } CSimpleStringA customerID = CSimpleStringA(jsonParam.Root[jsonParam.Index]["customerID"].asCString()); if (tmpFeatureData.tmpFeatureMap.find(customerID) == tmpFeatureData.tmpFeatureMap.end()) { // if not exist , insert directly tmpFeatureData.tmpFeatureMap[customerID] = fd; }else { auto tempFD = tmpFeatureData.tmpFeatureMap[customerID]; tmpFeatureData.tmpFeatureMap[customerID] = fd; if (tempFD) { delete tempFD; tempFD = NULL; } } CSimpleStringA tempMaxUpdateTime = CSimpleStringA(jsonParam.Root[jsonParam.Index]["updateTime"].asCString()); tmpFeatureData.MaxUpdateTime = GetMaxTime(tmpFeatureData.MaxUpdateTime, tempMaxUpdateTime); int fingerDataState = jsonParam.Root[jsonParam.Index]["state"].asCString()[0] - '0'; if (fingerDataState == 0) { Json::FastWriter writer; CSimpleStringA jsonFingerStr(writer.write(jsonParam.FingerInfo).c_str()); int jlen = jsonFingerStr.GetLength() - 1; char* jstr = new char[jlen + 1]; memcpy(jstr, jsonFingerStr.GetData(), jlen); jstr[jlen] = '\0'; //in case no \n in the end errCode = spConfig->WriteConfigValue(m_FingerSection.GetData(), customerID.GetData(), jstr); delete[] jstr; if (errCode != Error_Succeed) { BackupFile(runinfoParam.BackupFile, runinfoParam.SrcFile); LeaveCriticalSection(&m_cs); errCode = Error_Unexpect; } }else if (fingerDataState == 2) { Dbg("state(2): customer %s is currently unavailable.", customerID.GetData()); spConfig->WriteConfigValue((const char*)m_FingerSection, customerID.GetData(), ""); }else { Dbg("unexpected customer(%s)'s state is either 0 or 2", customerID.GetData()); } return errCode; } CSimpleStringA CCustMngrAuthFSM::GetMaxTime(CSimpleStringA maxTime, CSimpleStringA tempTime) { if (tempTime.GetLength() <= 0) return maxTime; if (maxTime.GetLength() <= 0) { maxTime = tempTime; } else { int compareResult = CompareUpdateTime((const char*)maxTime, (const char*)tempTime); if (compareResult == 0) { maxTime = tempTime; } } return maxTime; } int CCustMngrAuthFSM::CompareUpdateTime(const char* time1, const char* time2) { int year1, month1, day1, hour1, minute1, second1; int year2, month2, day2, hour2, minute2, second2; sscanf(time1, "%d-%d-%d %d:%d:%d", &year1, &month1, &day1, &hour1, &minute1, &second1); sscanf(time2, "%d-%d-%d %d:%d:%d", &year2, &month2, &day2, &hour2, &minute2, &second2); int tm1 = year1 * 10000 + month1 * 100 + day1; int tm2 = year2 * 10000 + month2 * 100 + day2; if (tm1 != tm2) return (tm1 > tm2) ? 1 : 0; tm1 = hour1 * 3600 + minute1 * 60 + second1; tm2 = hour2 * 3600 + minute2 * 60 + second2; if (tm1 != tm2) return (tm1 > tm2) ? 1 : 0; return 2; } /// /// write data into memory when update fingerprint feature /// /// /// void CCustMngrAuthFSM::UpdateDataIntoMemory(map tempFeature, bool bIsFirstTimeQueryData) { if (!bIsFirstTimeQueryData) { for (auto it = tempFeature.begin(); it != tempFeature.end(); ++it) { if (m_featureData.find(it->first) == m_featureData.end()) {//if not exist,insert immediately m_featureData[it->first] = it->second; } else {//if exist already, release memory first, then insert auto tempFD = m_featureData[it->first]; m_featureData[it->first] = it->second; if (tempFD != NULL) { delete tempFD; tempFD = NULL; } } } }else { for (auto iter = m_featureData.begin(); iter != m_featureData.end();) { auto fd = iter->second; if (fd) { delete fd; fd = NULL; m_featureData.erase(iter++); } } m_featureData.insert(tempFeature.begin(), tempFeature.end()); } } #pragma endregion #pragma region Registe process ErrorCodeEnum CCustMngrAuthFSM::CollectFingerPrint(SpReqAnsContext::Pointer ctx, DWORD& dwUserErrCode) { LOG_FUNCTION(); ErrorCodeEnum errCode = ConnectFingerPrintEntity(); if (errCode != Error_Succeed) return errCode; errCode = CollectProcess(ctx, dwUserErrCode); if (errCode == Error_Succeed) { Dbg("Register FingerPrint successfully."); return Error_Succeed; } else { Dbg("Register FingerPrint failed!"); return errCode; } } ErrorCodeEnum CCustMngrAuthFSM::CollectProcess(SpReqAnsContext::Pointer& ctx, DWORD& dwUserErrCode) { ErrorCodeEnum errCode = Error_Succeed; vector imgPaths; CSimpleStringA depPath(true); m_pEntity->GetFunction()->GetPath("Dep", depPath); ctx->Ans.FingerImgs.Init(COLLECT_TIMES); for (int i = 0; i < COLLECT_TIMES; ++i) { if (i) SLEEP(2000); if (m_pFingerPrint == NULL || m_pFingerPrint->QuerySessionClosed()) { Dbg("m_pFingerPrint is NULL or connection closed."); return Error_NoTarget; } BroadcastPressFinger(i + 1, true);//press finger FingerPrintService_GetImageAndFeature_Req collecetReq; FingerPrintService_GetImageAndFeature_Ans collecetAns; collecetReq.times = i + 1;//the num from 1 start , 1/2/3 errCode = m_pFingerPrint->GetImageAndFeature(collecetReq, collecetAns, 16000, dwUserErrCode);//fingerprint entity loop duration is 15s if (errCode == Error_Succeed) { BroadcastPressFinger(i + 1, false);//lift finger CBlob data; CSimpleStringA imgFullPath(true); imgFullPath = CSimpleStringA::Format("%s" SPLIT_SLASH_STR "%s" , depPath.GetData(), collecetAns.imageName.GetData()); errCode = GetImgBlob(data, imgFullPath); imgPaths.push_back(imgFullPath); if (errCode != Error_Succeed) { Dbg("Failed to load finger image, %s", imgFullPath.GetData()); errCode = Error_Unexpect; break; } switch (i) { case 0: ctx->Ans.FingerImg1 = data; break; case 1: ctx->Ans.FingerImg2 = data; break; case 2: ctx->Ans.FingerImg3 = data; break; } ctx->Ans.FingerImgs[i] = data; if (i == (COLLECT_TIMES - 1)) { ctx->Ans.feature = collecetAns.feature; Dbg("feature = %s", ctx->Ans.feature.GetData()); } } else { Dbg("invoke GetImageAndFeature failed in %dth time, errCode(%s)", i + 1, SpStrError(errCode)); break; } } for (size_t i = 0; i < imgPaths.size(); ++i) { if (ExistsFileA(imgPaths[i])) RemoveFileA(imgPaths[i]); } return errCode; } void CCustMngrAuthFSM::BroadcastPressFinger(int times, bool bPressFinger) { if (bPressFinger) { PressFinger pfEvt;// pfEvt.FingerNo = 1;//maybe no use,control by @zhuyi pfEvt.Times = times; SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(PressFinger) , SP_MSG_SIG_OF(PressFinger), pfEvt); } else { LiftFinger lfEvt; lfEvt.FingerNo = 1; lfEvt.Times = times; SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(LiftFinger) , SP_MSG_SIG_OF(LiftFinger), lfEvt); } } ErrorCodeEnum CCustMngrAuthFSM::GetImgBlob(CBlob& data, CSimpleStringA imgPath) { Dbg("image full path: %s", imgPath.GetData()); FILE* fp = fopen(imgPath, "rb"); if (fp) { Dbg("fopen succeed."); fseek(fp, 0, SEEK_END); long flen = ftell(fp); fseek(fp, 0, SEEK_SET); data.Alloc(flen); fread(data.m_pData, 1, flen, fp); fclose(fp); return Error_Succeed; } else { Dbg("fopen %s failed!", imgPath.GetData()); return Error_IO; } } #pragma endregion #pragma region Save fingerprint process ErrorCodeEnum CCustMngrAuthFSM::SaveFingerPrint(SpReqAnsContext::Pointer ctx) { LOG_FUNCTION(); EnterCriticalSection(&m_cs); CSmartPointer spConfig; Json::FastWriter writer; ErrorCodeEnum errCode; errCode = GetEntityBase()->GetFunction()->OpenConfig(Config_Run, spConfig); if (errCode != Error_Succeed) { LogError(Severity_High, Error_DevLoadFileFailed , LOG_ERR_CUSTMNGRAUTH_OPEN_RUNINFO_FAILED_SAVEFINGERPRINT , "open runinfo file failed while save data to local."); LeaveCriticalSection(&m_cs); return Error_Unexpect; } if (ctx->Req.FPFeatureList == nullptr) return Error_Param; int fingerIDNum = ctx->Req.FingerIdList.GetCount(); Dbg("FingerIDNum=%d", fingerIDNum); FeatureData* fd = new FeatureData(); fd->FingerIDArray.Init(fingerIDNum); fd->FingerIDLenArray.Init(fingerIDNum); char fingerID[20]; Json::Value fingerInfo; for (int i = 0; i < fingerIDNum; ++i) { memset(fingerID, 0, sizeof(fingerID)); #ifdef RVC_OS_WIN _snprintf_s(fingerID, 10, "FingerID%d", ctx->Req.FingerIdList[i]); #else snprintf(fingerID, 10, "FingerID%d", ctx->Req.FingerIdList[i]); #endif // RVC_OS_WIN Dbg("writing %s", fingerID); fingerInfo[fingerID] = ctx->Req.FPFeatureList[i].GetData(); fd->FingerIDArray[i] = ctx->Req.FPFeatureList[i]; fd->FingerIDLenArray[i] = fd->FingerIDArray[i].GetLength(); } if (m_featureData.find(ctx->Req.CustomerID) == m_featureData.end()) { //not exist, insert directly m_featureData[ctx->Req.CustomerID] = fd; } else { auto tempFD = m_featureData[ctx->Req.CustomerID]; m_featureData[ctx->Req.CustomerID] = fd; if (tempFD) { delete tempFD; tempFD = NULL; } } errCode = spConfig->WriteConfigValue(m_FingerSection.GetData() , ctx->Req.CustomerID.GetData() , writer.write(fingerInfo).c_str()); if (errCode != Error_Succeed) { LogError(Severity_High, Error_DevLoadFileFailed , LOG_ERR_CUSTMNGRAUTH_REGISTER_WRITE_RUNINFO_FAILED , "write data into runinfo failed when commit."); LeaveCriticalSection(&m_cs); return Error_Unexpect; } Dbg("write data into runinfo success when commit."); LeaveCriticalSection(&m_cs); return errCode; } #pragma endregion #pragma region authorize process ErrorCodeEnum CCustMngrAuthFSM::MatchFingerPrint(SpReqAnsContext::Pointer ctx, bool& bStopAuthorize) { LOG_FUNCTION(); ErrorCodeEnum errCode = ConnectFingerPrintEntity(); if (errCode != Error_Succeed) return errCode; MatchParams* matchParam = new MatchParams(); matchParam->sTotalNumOfTemplate = 0; errCode = PrepareDataBeforeMatch(matchParam); if (errCode != Error_Succeed) return errCode; errCode = MatchProcess(matchParam, bStopAuthorize); return errCode; } ErrorCodeEnum CCustMngrAuthFSM::ConnectFingerPrintEntity() { ErrorCodeEnum errCode = Error_Succeed; m_pFingerPrint = new FingerPrintService_ClientBase(m_pEntity); errCode = m_pFingerPrint->Connect(); if (errCode != Error_Succeed) { Dbg("ERROR: connect to fingerprint entity failed!"); m_pFingerPrint->SafeDelete(); errCode = Error_NoTarget; //TODO::give one other errCode } return errCode; } ErrorCodeEnum CCustMngrAuthFSM::PrepareDataBeforeMatch(MatchParams* matchParam) { EnterCriticalSection(&m_cs); CAutoArray tempFeatureArray; CAutoArray tempFeatureLenArray; int totalCustomerID = m_featureData.size(); int totalTemplate = totalCustomerID * FINGER_NUM; tempFeatureArray.Init(totalTemplate); tempFeatureLenArray.Init(totalTemplate); if (totalCustomerID <= 0) { Dbg("No FingerPrint data in local file or read local file failed."); LeaveCriticalSection(&m_cs); if (matchParam != NULL) delete matchParam; return Error_NoTarget; } Dbg("begin copy feature to reqParams"); for (auto it = m_featureData.begin(); it != m_featureData.end(); ++it) { TemplateInfo ti; memset(&ti, 0, sizeof(ti)); ti.CustomerID = it->first; ti.TemplateNum = 0; for (int index = 0; index < FINGER_NUM; ++index) { if (index >= it->second->FingerIDArray.GetCount()) //旧版本可能只有2个 break; if (it->second->FingerIDArray[index].GetLength() <= 0) continue; tempFeatureArray[matchParam->sTotalNumOfTemplate] = it->second->FingerIDArray[index]; tempFeatureLenArray[matchParam->sTotalNumOfTemplate] = it->second->FingerIDLenArray[index]; ti.TemplateNum = ti.TemplateNum + 1; ++matchParam->sTotalNumOfTemplate; } if (ti.TemplateNum > 0) matchParam->sFingerCount.push_back(ti); } LeaveCriticalSection(&m_cs); Dbg("num of template not empty:%d", matchParam->sTotalNumOfTemplate); matchParam->sMatchReq.templateNum = matchParam->sTotalNumOfTemplate; matchParam->sMatchReq.templates.Init(matchParam->sTotalNumOfTemplate); matchParam->sMatchReq.templateLen.Init(matchParam->sTotalNumOfTemplate); for (int i = 0; i < matchParam->sTotalNumOfTemplate; ++i) { matchParam->sMatchReq.templates[i] = tempFeatureArray[i]; matchParam->sMatchReq.templateLen[i] = tempFeatureLenArray[i]; } Dbg("end copy feature to reqParams"); Dbg("templateNum: %d", matchParam->sMatchReq.templateNum); return Error_Succeed; } ErrorCodeEnum CCustMngrAuthFSM::MatchProcess(MatchParams* matchParam, bool& bStopAuthorize) { ErrorCodeEnum errCode = Error_Succeed; while (true) { if (m_pFingerPrint == NULL || m_pFingerPrint->QuerySessionClosed()) { Dbg("m_pFingerPrint is NULL or connection closed."); return Error_Unexpect; } //fingerprint entity may not return immediately SLEEP(100); Dbg("begin next invoke match."); errCode = m_pFingerPrint->Match(matchParam->sMatchReq, matchParam->sMatchAns, 20000); if (m_bCancelAuthorize || errCode == Error_Cancel) { Dbg("cancel authorize task."); bStopAuthorize = true; m_bCancelAuthorize = false; if (m_bAuthorizeTimeout) { m_bAuthorizeTimeout = false; return Error_TimeOut; } return Error_Cancel; } else if (errCode == Error_Unexpect || errCode == Error_TimeOut) { Dbg("invoke match error with errCode(%s)", SpStrError(errCode)); BroadcastGetFinger(2); } else if (errCode == Error_Succeed) { Dbg("invoke match success, start analyze result."); errCode = AnalyzeMatchResult(matchParam, bStopAuthorize); if (errCode == Error_Succeed) return Error_Succeed; //continue if other errCode } else { Dbg("invole match error(%s), stop authorize", SpStrError(errCode)); return Error_Unexpect; } } } void CCustMngrAuthFSM::BroadcastGetFinger(int status) { GetFinger evt; evt.Status = status; SpSendBroadcast(GetEntityBase()->GetFunction() , SP_MSG_OF(GetFinger), SP_MSG_SIG_OF(GetFinger) , evt); } ErrorCodeEnum CCustMngrAuthFSM::AnalyzeMatchResult(MatchParams* matchParam, bool& bStopAuthorize) { int resTemplateNum = matchParam->sMatchAns.result.GetCount(); if (resTemplateNum != matchParam->sTotalNumOfTemplate) { Dbg("result templateNum(%d) is not equale to the Req's(%d)." , resTemplateNum, matchParam->sTotalNumOfTemplate); return Error_Unexpect; } std::vectortmpFingerCountInfo(matchParam->sFingerCount); int matchIndex = -1; //matched CustomerID's index in array int matchCount = 0; //num of matched int fingerCountIndex = 0; //index of fingerCountInfo int FINGER_NUM = tmpFingerCountInfo[fingerCountIndex].TemplateNum; for (int i = 0; i < resTemplateNum; i += FINGER_NUM) { int oneCustMatchResult = 0; FINGER_NUM = tmpFingerCountInfo[fingerCountIndex].TemplateNum; for (int j = 0; j < FINGER_NUM; ++j) { oneCustMatchResult += matchParam->sMatchAns.result[i + j]; } if (oneCustMatchResult > 0) //one customer has more than one match, just as one { matchCount++; matchIndex = fingerCountIndex; } if (matchCount > 1) //more than one customer's finger matched break; fingerCountIndex++; } int matchResult = matchCount;//0:no match; 1:just one match; 2: muti match switch (matchResult) { case 0: { Dbg("MatchResult: 0| no match"); BroadcastGetFinger(0); } break; case 1: { Dbg("MatchResult: 1| one and only one match, authorize done."); Dbg("Match Finger(CustomerID=%s)", (const char*)tmpFingerCountInfo[matchIndex].CustomerID); m_authCtx.eAuthByWhich = AuthByFngPrnt; m_authCtx.CustomerID = tmpFingerCountInfo[matchIndex].CustomerID; bStopAuthorize = true; return Error_Succeed; } break; case 2: { Dbg("MatchResult: 2 | two and more matches. be alerted"); BroadcastGetFinger(1); } break; default:break; } return Error_Unexpect; } #pragma endregion