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; }