www.pudn.com > acdx.rar > acdx.cpp
/*============================================================= Function: core call ACD entry Author: Leon Wang==============================================================*/ #include "stdafx.h" #include "acdx.h" #include #include #include "endpoint.h" #include "H323Utils.h" #include "socket/lock.h" //#include class Lock; Lock g_lock("global_lock");// creat mutex alias list Lock g_lock_pend("pendlist"); //##ModelId=424BB647014F ACDX* ACDX::instance = 0; //##ModelId=424BB64700D2 ACDX::ACDX() { } //##ModelId=424BB64700D3 ACDX::~ACDX() { if (gkclient != NULL ) { delete gkclient; gkclient = NULL; } if (backlog != NULL) { delete backlog; backlog = NULL; } if (houseKeeping != NULL) { delete houseKeeping; houseKeeping = NULL; } if (commandListener != NULL) { delete commandListener; commandListener = NULL; } } /* start major logic */ //##ModelId=424BB64700F2 void ACDX::Start() { // read ACDX config config = ACDConfig::getInstance(); gkHost = config->getConfigKey("Main","gnugk_host", "127.0.0.1"); gkPort = config->getConfigKey("Main","gnugk_port", 7000); listenPort = config->getConfigKey("Main","listen_port", 7001); redirLocation = config->getConfigKey("Main","redir_location", "http://www.google.com/"); distribution = config->getDistributionAlgorithm(); // connect to the gatekeeper gkclient = new GkClient(); gkclient->init(ACDX::getInstance(), gkHost, gkPort);// first parameter send acdx instance -> gkclient backlog = new CCallBacklog(gkclient); houseKeeping = new HouseKeeper(); houseKeeping->init(this, backlog); CString logfile = config->getConfigKey("Main","logfile", ""); int debugLevel = config->getConfigKey("Main","debug", 0); Logger::setDebug(debugLevel); //print welcome screen Logger::log("--- GnuGk ACDX config ---"); Logger::log("GnuGk host: " + gkHost); char ch[8]; itoa(gkPort,ch,10); Logger::log("GnuGk status port: " + CString(ch)); itoa(listenPort,ch,10); Logger::log("ACDX listen port: " + CString(ch)); itoa(distribution,ch,10); Logger::log("ACDX distribution algo: " + CString(ch)); Logger::log("ACDX redir location: " + redirLocation); Logger::log("ACDX logfile: " + logfile); itoa(debugLevel,ch,10); Logger::log("ACDX debug level: " + CString(ch)); Logger::log("--- starting ACDX ---"); memset(ch,0,sizeof(ch)); //Logger logger; if (logfile.GetLength()>0) { Logger::setLogfile(logfile); } //begin call gkclient thread //new Thread(gkclient).start();//thread gk //DWORD ip = inet_addr("192.168.1.43"); unsigned long hThread_gk = _beginthreadex(0,0, GkClient::_RUN, gkclient,0,0); // perview list function over [3/28/2005] //waitQueues.startWaitQueues(gkclient); // not need now --> change it in furture // start listening for commands to the ACD commandListener = new ACDCommandListener(); commandListener->init(this,listenPort, redirLocation); // first parameter is acdx point //HTTP server monitor unsigned long hThread_commandListener = _beginthreadex(0,0, ACDCommandListener::_RUN, commandListener,0,0); //new Thread(houseKeeping).start();//thread housekeeping //unsigned long hThread_houseKeeping = _beginthreadex(0,0, // HouseKeeper::_RUN, // houseKeeping,0,0); WaitForSingleObject((HANDLE)hThread_gk, INFINITE); WaitForSingleObject((HANDLE)hThread_commandListener, INFINITE); //WaitForSingleObject((HANDLE)hThread_houseKeeping, INFINITE); } /** * Singleton access. * @return singleton object */ //##ModelId=424BB64700E2 ACDX* ACDX::getInstance() { if (instance == 0) { instance = new ACDX(); } return instance; } //##ModelId=424BB64700C3 void ACDX::addAlias(CString _alias, CString _epid) { if (!aliasById(_alias, _epid).isOK) { Agent* newAgent = new Agent(_epid, _alias); //newAgent->alias = ""; if (g_lock.lock()) { aliasList.push_back(*newAgent); g_lock.unlock(); } // check if we have pending calls for this now available agent backlog->checkPending(newAgent,aliasList); } } /** * Endpoint has unregistered, get rid of all it's aliases. * Also cancel all pending calls. * @param _epid */ //##ModelId=424BB64700B4 void ACDX::removeAllAliases(CString _epid) { std::list ::iterator AliasElement; Alias alias; for(AliasElement= aliasList.begin();AliasElement!=aliasList.end();AliasElement++) { alias = (Alias)*AliasElement; if (_epid==alias.getEpid()) { if (g_lock.lock()) { if(!aliasList.empty()) AliasElement = aliasList.erase(AliasElement); //here this return element is next call g_lock.unlock(); } } } backlog->removeAllRequests(_epid); } /** * Set _all_ aliases on this endpoint with this CRV to available. * @param _epid endpoint ID * @param _crv CRV */ //##ModelId=424BB64700A6 void ACDX::setAliasAvailable(CString _epid, CString _crv) { std::list ::iterator agentElment; Agent _agent; Agent agent = agentByCrv(_epid, _crv); // find first alias while ((agent.isOK) && (_crv.GetLength() > 0)) { // in alias list update element for(agentElment = aliasList.begin(); agentElment != aliasList.end();agentElment++) { _agent = *agentElment; if (agent.getAlias()==_agent.getAlias()) { if (g_lock.lock()) { agentElment->setState(Alias::AVAILABLE); agentElment->setLastCall(); agentElment->setLastTime(); agentElment->setCrv(""); backlog->checkPending((&(Agent)*agentElment),aliasList); //------> need test it agent in checkpending g_lock.unlock(); }// if lock }//if alias == }// for // check if we have pending calls for this now available agent //backlog->checkPending(&agent); //------> need test it agent in checkpending agent = agentByCrv(_epid, _crv); // find next alias } } /** * Set this alias on this endpoint to TALKING and remember the CRV. * @param _alias H.323 alias * @param _crv CRV */ //##ModelId=424BB6470095 void ACDX::setAliasTalking(CString _alias, CString _crv) { std::list ::iterator aliasElement; Alias _alias_temp; Alias alias = aliasByName(_alias); if (alias.isOK) { for(aliasElement = aliasList.begin(); aliasElement != aliasList.end();aliasElement++) { _alias_temp = (Alias)*aliasElement; if (alias.getAlias()== _alias_temp.getAlias()) { if (g_lock.lock()) { aliasElement->setState(Alias::TALKING); aliasElement->setCrv(_crv); g_lock.unlock(); }// lock }//if == }//for }//if isok } //##ModelId=424BB6470094 void ACDX::clearAllAliasStates() { aliasList.clear(); } //##ModelId=42198D1803E6 //synchronized //##ModelId=424BB6470088 void ACDX::agentSanityCheck() { if (!g_lock.lock()) { return; } std::list ::iterator aliasElement; Alias alias; for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); aliasElement++ ) { //alias = (Alias)*aliasElement; aliasElement->setState(Alias::AVAILABLE); } g_lock.unlock(); gkclient->getCurrentCalls(); } //##ModelId=424BB6470133 Alias ACDX::aliasByName(CString _alias) { std::list ::iterator aliasElement; Alias alias; for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); aliasElement++ ) { alias = (Alias)*aliasElement; if (_alias==alias.getAlias()) { alias.isOK = TRUE; return alias; } } return alias; } /* void ACDX::_aliasById (CString _alias, CString _epid,Alias& StringToPrint) { // cout << StringToPrint << endl; cout< ::iterator aliasElement; Alias alias; //std::for_each (aliasList.begin(),aliasList.end(),PrintIt(_alias,_epid)); for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); ++aliasElement ) { alias = (Alias)*aliasElement; if (_alias==alias.getAlias() && _epid==alias.getEpid()) { alias.isOK = TRUE; return alias; } } return alias; } //##ModelId=424BB6470121 Agent ACDX::agentByCrv(CString _epid, CString _crv) { std::list ::iterator aliasElement; Agent agent; for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); ++aliasElement ) { agent = *aliasElement; if (_epid==agent.getEpid() && _crv==agent.getCrv()) { agent.isOK = TRUE; return agent; } } return agent; } //##ModelId=42198D1803D5 // major route call for queue logic //##ModelId=424BB6470077 void ACDX::routeCall(CString queue, CString callerEndId, CString callRef, CString callerAlias, CString callerIp) { Agent agent; if (distribution == ACDConfig::FIRST_FIT) { agent = firstFitRouter(queue);//give the call to the first suited agent that is //found (unfair, but fast) } else if (distribution == ACDConfig::ROUND_ROBIN) { agent = roundRobinRouter(queue);//give work to the next agent who is suited (fair) } else if (distribution == ACDConfig::LONGEST_IDLE) { agent = longestIdleRouter(queue);//choose an agent who is suited for this group, and //has been without a call the longest (fair) } // agent is not in list obj???-- if (agent.isOK) { std::list ::iterator agentElement; Agent _agent; for(agentElement = aliasList.begin(); agentElement != aliasList.end(); agentElement++) { _agent = *agentElement; //here use point to set list state is very important if (agent.getAlias() == _agent.getAlias()) { if (g_lock.lock()) { (agentElement)->setState(Alias::TALKING); (agentElement)->setLastCall(); (agentElement)->setLastTime(); g_lock.unlock(); } //agent.setState(Agent::TALKING); //agent.setLastCall(); } } Logger::log("Routing call for " + queue + " to " + agent.getAlias()); gkclient->routeToAlias(agent.getAlias(), callerEndId, callRef); } else { int queueingMode = config->getQueueingMode(queue); CString wqName; char qch[4]; itoa(queueingMode,qch,10); Logger::log("No agent available for call to " + queue + " (" + CString(qch) + ")"); if ( (queueingMode == ACDConfig::QUEUEING_MODE_RINGING) || (queueingMode == ACDConfig::QUEUEING_MODE_RINGANDTALK) ) { // store the request in the backlog, in case an agent becomes available before timeout backlog->store(queue, callerEndId, callRef, callerAlias, callerIp, PendingRequest::RINGING); } else if ( (queueingMode == ACDConfig::QUEUEING_MODE_TALKING) && ((wqName = getWaitQueue(queue)) != "") ) { Logger::debug("*---acdx routecall-waiting queue name "+wqName);//test wqueue name gkclient->routeToAlias(wqName, callerEndId, callRef); // store the request in the backlog, in case an agent becomes available before timeout backlog->store(queue, callerEndId, callRef, callerAlias, callerIp, PendingRequest::TALKING); } else { // reject the call right away gkclient->routeReject(callerEndId, callRef); } } } //##ModelId=42198D1803D3 /** * Find available wait queue for this queue. * @param queue name of called queue * @return alias of wait queue agent or null if noe is found */ //##ModelId=424BB6470075 CString ACDX::getWaitQueue(CString queue) { std::list ::iterator aliasElement; Agent agent; for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); ++aliasElement ) { agent = *aliasElement; if ( (agent.getAlias().Find(queue + "_wq_")==0) && (agent.getState() == Endpoint::AVAILABLE) ) { return agent.getAlias(); } } return ""; } //##ModelId=42198D190049 // Algo: first-fit (unfair) //##ModelId=424BB6470103 Agent ACDX::firstFitRouter(CString queue) { return firstFitRouter(0, queue); } //##ModelId=42198D190057 // Algo: first-fit (unfair) //##ModelId=424BB6470112 Agent ACDX::firstFitRouter(int start, CString queue) { if (start > aliasList.size()) { start = 0; } std::list ::iterator aliasElement; Agent agent; for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); ++aliasElement ) { agent = *aliasElement;// look state and blocked if (agent.isAvailable(queue)) { agent.isOK = TRUE; return agent; } } agent.isOK = FALSE; return agent; } //##ModelId=42198D19003C // Algo: round-robin (fair) //##ModelId=424BB6470101 Agent ACDX::roundRobinRouter(CString queue) { std::list ::iterator aliasElement; Agent agent; int i = 0; if (lastPick.isOK) { for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); ++aliasElement ) { i++; // compare address of class if (&lastPick == &(*aliasElement)) { // find the next available agent (position to list end) agent = firstFitRouter(i + 1, queue); break; } } } if (!agent.isOK) { // go around to the start and look again agent = firstFitRouter(0, queue); } lastPick = agent; lastPick.isOK = TRUE; return agent; } //##ModelId=42198D19003A] // Algo: longest-idle (fair) //##ModelId=424BB64700F3 Agent ACDX::longestIdleRouter(CString queue) { // pick the first available agent Agent longestIdle = firstFitRouter(0, queue); // see if we can find anyone that has been idle longer if (longestIdle.isOK) { // no need to look if everybody is talking std::list ::iterator aliasElement; Agent agent; for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); ++aliasElement ) { agent = *aliasElement; if (agent.isAvailable(queue) && (agent.getLastCall() < longestIdle.getLastCall())) { longestIdle = agent; longestIdle.isOK = TRUE; } }//for }// if return longestIdle; } //##ModelId=42198D1803C6 /** * agent is not available for ACD work. * @param agent */ //##ModelId=424BB6470067 void ACDX::logout(CString agent) { std::list ::iterator aliasElement; Agent ag; for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); ++aliasElement ) { ag = *aliasElement; if (agent==(H323Utils::extractAliasName(ag.getAlias()))) { if (g_lock.lock()) { aliasElement->setBlocked(TRUE); Logger::log("Logout agent " + agent); g_lock.unlock(); }// lock }// == }// for } //##ModelId=42198D1803C4 /** * set agent to be available for ACD work again. * @param agent */ //##ModelId=424BB6470065 void ACDX::login(CString agent) { std::list ::iterator aliasElement; Agent ag; for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); ++aliasElement ) { ag = *aliasElement; if (agent==(H323Utils::extractAliasName(ag.getAlias()))) { if (g_lock.lock()) { aliasElement->setBlocked(FALSE); Logger::log("Login agent " + agent); g_lock.unlock(); }//lock }// == }// for } //##ModelId=42198D1803C3 /** * Dump the list of agents with their current state. * @return formatted list */ //##ModelId=424BB6470058 CString ACDX::dumpAgentStates() { //SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss"); //SYSTEMTIME systemtime; CString result = "Agent list\n"; std::list ::iterator aliasElement; Agent ag; for(aliasElement = aliasList.begin(); aliasElement != aliasList.end(); ++aliasElement ) { ag = *aliasElement; //systemtime.wMilliseconds = ag.getLastCall();//? here to h m s maybe case error struct tm * t = (struct tm *)ag.getLastTime(); //t->tm_mon+1 t->tm_hour; t->tm_min; t->tm_sec; char c_hour[sizeof(int)]; char c_min[sizeof(int)]; char c_sec[sizeof(int)]; itoa(t->tm_hour,c_hour,10); itoa(t->tm_min,c_min,10); itoa(t->tm_sec,c_sec,10); // agent last call time CString cs_time = CString(c_hour)+":"+CString(c_min)+":"+CString(c_sec); //t->tm_mon+1; //CTime t(systemtime); if (ag.isAgent()) { // agent list contains all GK registration, only list configured agents result += ag.getAlias() + " (" + ag.getEpid() + "):\t" + (ag.isBlocked() ? "NOT logged in" : " logged in") + "\tstate: " + (ag.getState()==0 ? "AVAILABLE" : "TALKING " ) + //"\tlast call: " + t.Format("%H:%M:%S") + "\tlast call: " + cs_time + "\n
"; } } return result; } //##ModelId=42198D1803C2 /** * Dumnp list of pending calls. * @return formatted list */ //##ModelId=424BB6470057 CString ACDX::dumpPendingList() { return backlog->dumpPendingList(); //return ""; } //=============================================================================================== void initNetwork() { #ifdef WIN32 WORD wVersionRequested = MAKEWORD( 2, 2 ); WSADATA wsaData; int err; err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { // could not find a usable WinSock DLL //cerr << "Could not load winsock" << endl; assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work exit(1); } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ WSACleanup( ); //cerr << "Bad winsock verion" << endl; assert(0); // is this is failing, try a different version that 2.2, 1.0 or later will likely work exit(1); } #endif } /* * main entry */ int main(int argc, char* argv[]) { if (argc > 1) { printf("usage: acdx\n"); exit(1); } initNetwork(); printf("Welcome to ACDX system!\n"); // new acd instance start work thread ACDX::getInstance()->Start(); return 0; }