bool ClientController::route_request_inside_invite( const string& rawSipMsg, const SipMsgData_t& meta, nta_incoming_t* irq, sip_t const *sip, 
        const string& transactionId, const string& dialogId  ) {
        //client_ptr client = this->findClientForDialog( dialogId );
        //if( !client ) {
            client_ptr client = this->findClientForNetTransaction( transactionId );
            if( !client ) {
                DR_LOG(log_warning) << "ClientController::route_response_inside_invite - client managing transaction has disconnected: " << transactionId  ;
                return false ;
            }
        //}
 
        DR_LOG(log_debug) << "ClientController::route_response_inside_invite - sending response to client"  ;
        m_ioservice.post( boost::bind(&Client::sendSipMessageToClient, client, transactionId, dialogId, rawSipMsg, meta) ) ;

        return true ;
    }
Exemple #2
0
void Pdb::WriteContext(HANDLE hThread, Context& context)
{
	DR_LOG("WriteContext");
#ifdef CPU_64
	if(win64) {
		CONTEXT ctx;
		memcpy(&ctx, &context.context64, sizeof(CONTEXT));
		ctx.ContextFlags = CONTEXT_CONTROL;
		if(!SetThreadContext(hThread, &ctx))
			Error("SetThreadContext failed");
	}
	else {
		WOW64_CONTEXT ctx;
		memcpy(&ctx, &context.context32, sizeof(WOW64_CONTEXT));
		ctx.ContextFlags = CONTEXT_CONTROL;
		if(!Wow64SetThreadContext(hThread, &ctx))
			Error("Wow64SetThreadContext failed");
	}
#else
	CONTEXT ctx;
	memcpy(&ctx, &context.context32, sizeof(WOW64_CONTEXT));
	ctx.ContextFlags = CONTEXT_CONTROL;
	if(!SetThreadContext(hThread, &ctx))
		Error("SetThreadContext failed");
#endif
}
 void DrachtioController::handleSigHup( int signal ) {
     
     if( !m_ConfigNew ) {
         DR_LOG(log_notice) << "Re-reading configuration file" << endl ;
         m_ConfigNew.reset( new DrachtioConfig( m_configFilename.c_str() ) ) ;
         if( !m_ConfigNew->isValid() ) {
             DR_LOG(log_error) << "Error reading configuration file; no changes will be made.  Please correct the configuration file and try to reload again" << endl ;
             m_ConfigNew.reset() ;
         }
     }
     else {
         DR_LOG(log_error) << "Ignoring signal; already have a new configuration file to install" << endl ;
     }
     
 
 }
Exemple #4
0
Pdb::Context Pdb::ReadContext(HANDLE hThread)
{
	DR_LOG("ReadContext");
	Context r;
#ifdef CPU_64
	if(win64) {
		CONTEXT ctx;
		ctx.ContextFlags = CONTEXT_FULL;
		if(!GetThreadContext(hThread, &ctx))
			Error("GetThreadContext failed");
		memcpy(&r.context64, &ctx, sizeof(CONTEXT));
	}
	else {
		WOW64_CONTEXT ctx;
		ctx.ContextFlags = WOW64_CONTEXT_FULL;
		if(!Wow64GetThreadContext(hThread, &ctx))
			Error("Wow64GetThreadContext failed");
		memcpy(&r.context32, &ctx, sizeof(WOW64_CONTEXT));
	}
#else
	CONTEXT ctx;
	ctx.ContextFlags = CONTEXT_FULL;
	if(!GetThreadContext(hThread, &ctx))
			Error("GetThreadContext failed");
	memcpy(&r.context32, &ctx, sizeof(CONTEXT));
#endif
	return r;
}
    client_ptr ClientController::selectClientForRequestOutsideDialog( const char* keyword ) {
        string method_name = keyword ;
        transform(method_name.begin(), method_name.end(), method_name.begin(), ::tolower);

        /* round robin select a client that has registered for this request type */
        boost::lock_guard<boost::mutex> l( m_lock ) ;
        client_ptr client ;
        string matchId ;
        pair<map_of_request_types::iterator,map_of_request_types::iterator> pair = m_request_types.equal_range( method_name ) ;
        unsigned int nPossibles = std::distance( pair.first, pair.second ) ;
        if( 0 == nPossibles ) {
            if( 0 == method_name.find("cdr") ) {
                DR_LOG(log_debug) << "No connected clients found to handle incoming " << method_name << " request"  ;
            }
            else {
                DR_LOG(log_info) << "No connected clients found to handle incoming " << method_name << " request"  ;
            }
           return client ;           
        }

        unsigned int nOffset = 0 ;
        map_of_request_type_offsets::const_iterator itOffset = m_map_of_request_type_offsets.find( method_name ) ;
        if( m_map_of_request_type_offsets.end() != itOffset ) {
            unsigned int i = itOffset->second;
            if( i < nPossibles ) nOffset = i ;
            else nOffset = 0;
        }
        DR_LOG(log_debug) << "ClientController::route_request_outside_dialog - there are " << nPossibles << 
            " possible clients, we are starting with offset " << nOffset  ;

        m_map_of_request_type_offsets.erase( itOffset ) ;
        m_map_of_request_type_offsets.insert(map_of_request_type_offsets::value_type(method_name, nOffset + 1)) ;

        unsigned int nTries = 0 ;
        do {
            map_of_request_types::iterator it = pair.first ;
            std::advance( it, nOffset) ;
            RequestSpecifier& spec = it->second ;
            client = spec.client() ;
            if( !client ) {
                DR_LOG(log_debug) << "Removing disconnected client while iterating"  ;
                m_request_types.erase( it ) ;
                pair = m_request_types.equal_range( method_name ) ;
                if( nOffset >= m_request_types.size() ) {
                    nOffset = m_request_types.size() - 1 ;
                }
                DR_LOG(log_debug) << "Offset has been set to " << nOffset << " size of range is " << m_request_types.size()  ;
            }
            else {
                DR_LOG(log_debug) << "Selected client at offset " << nOffset  ;                
            }
        } while( !client && ++nTries < nPossibles ) ;

        if( !client ) {
            DR_LOG(log_info) << "No clients found to handle incoming " << method_name << " request"  ;
            return client ;
        }
 
        return client ;
    }
	void SipDialog::doSessionTimerHandling() {
		bool bWeAreRefresher = areWeRefresher()  ;
		
		if( bWeAreRefresher ) {
			//TODO: send a refreshing reINVITE, and notify the client
			DR_LOG(log_debug) << "SipDialog::doSessionTimerHandling - sending refreshing re-INVITE with call-id " << getCallId()  ; 
			theOneAndOnlyController->getDialogController()->notifyRefreshDialog( shared_from_this() ) ;
		}
		else {
			//TODO: tear down the leg, and notify the client
			DR_LOG(log_debug) << "SipDialog::doSessionTimerHandling - tearing down sip dialog with call-id " << getCallId() 
				<< " because remote peer did not refresh the session within the specified interval"  ; 
			theOneAndOnlyController->getDialogController()->notifyTerminateStaleDialog( shared_from_this() ) ;
		}

		assert( m_ppSelf ) ;
		delete m_ppSelf ; m_ppSelf = NULL ; m_timerSessionRefresh = NULL ; m_refresher = no_refresher ; m_nSessionExpiresSecs = 0 ;

	}
 bool ClientController::route_api_response( const string& clientMsgId, const string& responseText, const string& additionalResponseData ) {
    client_ptr client = this->findClientForApiRequest( clientMsgId );
     if( !client ) {
         DR_LOG(log_warning) << "ClientController::route_api_response - client that has sent the request has disconnected: " << clientMsgId  ;
         return false ;             
     }
     if( string::npos == additionalResponseData.find("|continue") ) removeApiRequest( clientMsgId ) ;
     m_ioservice.post( boost::bind(&Client::sendApiResponseToClient, client, clientMsgId, responseText, additionalResponseData) ) ;
     return true ;                
 }
 int DrachtioController::validateSipMessage( sip_t const *sip ) {
     if( sip_method_invite == sip->sip_request->rq_method  && (!sip->sip_contact || !sip->sip_contact->m_url[0].url_host ) ) {
         DR_LOG(log_error) << "Invalid or missing contact header" << endl ;
         return 400 ;
     }
     if( !sip->sip_call_id || !sip->sip_call_id->i_id ) {
         DR_LOG(log_error) << "Invalid or missing call-id header" << endl ;
         return 400 ;
     }
     if( sip_method_invite == sip->sip_request->rq_method  && (!sip->sip_to || !sip->sip_to->a_url[0].url_user ) ) {
         DR_LOG(log_error) << "Invalid or missing to header or dialed number information" << endl ;
         return 400 ;            
     }
     if( sip_method_invite == sip->sip_request->rq_method  && (!sip->sip_from || !sip->sip_from->a_tag ) )  {
         DR_LOG(log_error) << "Missing tag on From header on invite" << endl ;
         return 400 ;            
     }
     return 0 ;
 }
    bool ClientController::route_ack_request_inside_dialog( const string& rawSipMsg, const SipMsgData_t& meta, nta_incoming_t* prack, 
        sip_t const *sip, const string& transactionId, const string& inviteTransactionId, const string& dialogId ) {
        client_ptr client = this->findClientForDialog( dialogId );
        if( !client ) {
            client = this->findClientForNetTransaction( inviteTransactionId );
            if( !client ) {
               DR_LOG(log_warning) << "ClientController::route_ack_request_inside_dialog - client managing dialog has disconnected: " << dialogId  ;            
                //TODO: try to find another client providing the same service
                return false ;
            }
        }

        m_ioservice.post( boost::bind(&Client::sendSipMessageToClient, client, transactionId, dialogId, rawSipMsg, meta) ) ;

        this->removeNetTransaction( inviteTransactionId ) ;
        DR_LOG(log_debug) << "ClientController::route_ack_request_inside_dialog - removed incoming invite transaction, map size is now: " << m_mapNetTransactions.size() << " request"  ;
 
        return true ;

    }
 void ClientController::threadFunc() {
     
     DR_LOG(log_debug) << "Client controller thread id: " << boost::this_thread::get_id()  ;
      
     /* to make sure the event loop doesn't terminate when there is no work to do */
     boost::asio::io_service::work work(m_ioservice);
     
     for(;;) {
         
         try {
             DR_LOG(log_notice) << "ClientController: io_service run loop started"  ;
             m_ioservice.run() ;
             DR_LOG(log_notice) << "ClientController: io_service run loop ended normally"  ;
             break ;
         }
         catch( std::exception& e) {
             DR_LOG(log_error) << "Error in event thread: " << string( e.what() )  ;
             break ;
         }
     }
 }
    bool ClientController::wants_requests( client_ptr client, const string& verb ) {
        RequestSpecifier spec( client ) ;
        boost::lock_guard<boost::mutex> l( m_lock ) ;
        m_request_types.insert( map_of_request_types::value_type(verb, spec)) ;  
        DR_LOG(log_debug) << "Added client for " << verb << " requests"  ;

        //initialize the offset if this is the first client registering for that verb
        map_of_request_type_offsets::iterator it = m_map_of_request_type_offsets.find( verb ) ;
        if( m_map_of_request_type_offsets.end() == it ) m_map_of_request_type_offsets.insert(map_of_request_type_offsets::value_type(verb,0)) ;

        //TODO: validate the verb is supported
        return true ;  
    }
    client_ptr ClientController::findClientForDialog_nolock( const string& dialogId ) {
        client_ptr client ;

        mapId2Client::iterator it = m_mapDialogs.find( dialogId ) ;
        if( m_mapDialogs.end() != it ) client = it->second.lock() ;

        // if that client is no longer connected, randomly select another client that is running that app 
        if( !client ) {
            mapDialogId2Appname::iterator it = m_mapDialogId2Appname.find( dialogId ) ;
            if( m_mapDialogId2Appname.end() != it ) {
                string appName = it->second ;
                DR_LOG(log_info) << "Attempting to find another client for app " << appName  ;

                pair<map_of_services::iterator,map_of_services::iterator> pair = m_services.equal_range( appName ) ;
                unsigned int nPossibles = std::distance( pair.first, pair.second ) ;
                if( 0 == nPossibles ) {
                   DR_LOG(log_warning) << "No other clients found for app " << appName  ;
                   return client ;
                }
                unsigned int nOffset = rand() % nPossibles ;
                unsigned int nTries = 0 ;
                do {
                    map_of_services::iterator itTemp = pair.first ;
                    std::advance( itTemp, nOffset) ;
                    client = itTemp->second.lock() ;
                    if( !client ) {
                        if( ++nOffset == nPossibles ) nOffset = 0 ;
                    }
                } while( !client && ++nTries < nPossibles ) ;

                if( !client ) DR_LOG(log_warning) << "No other connected clients found for app " << appName  ;
                else DR_LOG(log_info) << "Found alternative client for app " << appName << " " << nOffset << ":" << nPossibles  ;
            }
        }
        return client ;
    }
Exemple #13
0
	void SipDialog::setSessionTimer( unsigned long nSecs, SessionRefresher_t whoIsResponsible ) {
		assert( NULL == m_timerSessionRefresh ) ;
		m_refresher = whoIsResponsible ;
		su_duration_t nMilliseconds = nSecs * 1000  ;
		m_nSessionExpiresSecs = nSecs ;

		DR_LOG(log_debug) << "Session expires has been set to " << nSecs << " seconds and refresher is " << (areWeRefresher() ? "us" : "them")  ;

		/* if we are the refresher, then we want the timer to go off halfway through the interval */
		if( areWeRefresher() ) nMilliseconds /= 2 ;
		m_timerSessionRefresh = su_timer_create( su_root_task(theOneAndOnlyController->getRoot()), nMilliseconds ) ;

		m_ppSelf = new boost::weak_ptr<SipDialog>( shared_from_this() ) ;
		su_timer_set(m_timerSessionRefresh, session_timer_handler, (su_timer_arg_t *) m_ppSelf );
	}
Exemple #14
0
bool Pdb::Tip(const String& exp, CodeEditor::MouseTip& mt)
{
/*	mt.display = &StdDisplay();
	mt.value = exp;
	mt.sz = Size(100, 20);
	return true;*/
	DR_LOG("Pdb::Tip");
	Visual r;
	try {
		CParser p(exp);
		Val v = Exp(p);
		Visualise(r, v, 2);
		if(r.part.GetCount()) {
			mt.sz = r.GetSize() + Size(4, 4);
			mt.value = RawPickToValue(r);
			mt.display = &Single<VisualDisplay>();
			DR_LOG("Pdb::Tip true");
			return true;
		}
	}
	catch(CParser::Error) {}
	DR_LOG("Pdb::Tip false");
	return false;
}
    int DrachtioController::processRequestInsideDialog( nta_leg_t* leg, nta_incoming_t* irq, sip_t const *sip) {
        DR_LOG(log_debug) << "DrachtioController::processRequestInsideDialog" << endl ;

        int rc = validateSipMessage( sip ) ;
        if( 0 != rc ) {
            return rc ;
        }
         
        boost::shared_ptr<SipDialog> dlg ;
        if( m_pDialogController->findDialogByLeg( leg, dlg ) ) {
            return m_pDialogController->processRequestInsideDialog( leg, irq, sip ) ;
        }
        assert(false) ;

        return 0 ;
    }
Exemple #16
0
void Pdb::AddThread(dword dwThreadId, HANDLE hThread)
{
	if(threads.Find(dwThreadId) >= 0)
		return;
	DR_LOG("AddThread");
	Thread& f = threads.GetAdd(dwThreadId);
	// Retrive "base-level" stack-pointer, to have limit for stackwalks:
	Context c = ReadContext(hThread);
#ifdef CPU_64
	f.sp = win64 ? c.context64.Rsp : c.context32.Esp;
#else
	f.sp = c.context32.Esp;
#endif
	f.hThread = hThread;
	LLOG("Adding thread " << dwThreadId << ", Thread SP: " << Hex(f.sp) << ", handle: " << FormatIntHex((dword)(hThread)));
}
Exemple #17
0
	SipDialog::~SipDialog() {
		DR_LOG(log_debug) << "SipDialog::~SipDialog - destroying sip dialog with call-id " << getCallId() ;
		if( NULL != m_timerSessionRefresh ) {
			cancelSessionTimer() ;
			assert( m_ppSelf ) ;
		}
		if( m_ppSelf ) {
			delete m_ppSelf ;
		}

		nta_leg_t *leg = nta_leg_by_call_id( theOneAndOnlyController->getAgent(), getCallId().c_str() );
		assert( leg ) ;
		if( leg ) {
			nta_leg_destroy( leg ) ;
		}
	}
    int DrachtioController::sendRequestInsideDialog( boost::shared_ptr<JsonMsg> pMsg, const string& rid ) {
        boost::shared_ptr<SipDialog> dlg ;
        const char *dialogId=NULL ;
        json_error_t err ;
        
        if( 0 > json_unpack_ex(pMsg->value(), &err, 0, "{s:{s:s}}", "data", "dialogId", &dialogId) ) {
            DR_LOG(log_error) << "DrachtioController::sendRequestInsideDialog - failed parsing message: " << err.text << endl ;
            return -1 ;
        }
        if( !m_pDialogController->findDialogById( dialogId, dlg ) ) {
            //DO I need to look in dialog maker also ?  What about an UPDATE sent during an INVITE transaction?
            return -1;
        }
        m_pDialogController->sendRequestInsideDialog( pMsg, rid, dlg ) ;

        return 0 ;
    }
    bool ClientController::route_request_inside_dialog( const string& rawSipMsg, const SipMsgData_t& meta, nta_incoming_t* irq, sip_t const *sip, 
        const string& transactionId, const string& dialogId ) {
        client_ptr client = this->findClientForDialog( dialogId );
        if( !client ) {
            DR_LOG(log_warning) << "ClientController::route_request_inside_dialog - client managing dialog has disconnected: " << dialogId  ;
            
            //TODO: try to find another client providing the same service
            return false ;
        }
        this->addNetTransaction( client, transactionId ) ;
 
        m_ioservice.post( boost::bind(&Client::sendSipMessageToClient, client, transactionId, dialogId, rawSipMsg, meta) ) ;

        // if this is a BYE from the network, it ends the dialog 
        string method_name = sip->sip_request->rq_method_name ;
        if( 0 == method_name.compare("BYE") ) {
            removeDialog( dialogId ) ;
        }

        return true ;
    }
    bool ClientController::route_response_inside_transaction( const string& rawSipMsg, const SipMsgData_t& meta, nta_outgoing_t* orq, sip_t const *sip, 
        const string& transactionId, const string& dialogId ) {
        
        client_ptr client = this->findClientForAppTransaction( transactionId );
        if( !client ) {
            DR_LOG(log_warning) << "ClientController::route_response_inside_transaction - client managing transaction has disconnected: " << transactionId  ;
            return false ;
        }

        m_ioservice.post( boost::bind(&Client::sendSipMessageToClient, client, transactionId, dialogId, rawSipMsg, meta) ) ;

        string method_name = sip->sip_cseq->cs_method_name ;

        if( sip->sip_status->st_status >= 200 ) {
            removeAppTransaction( transactionId ) ;
        }

        if( 0 == method_name.compare("BYE") ) {
            removeDialog( dialogId ) ;
        }

        return true ;
    }
 void DrachtioController::generateOutgoingContact( sip_contact_t* const incomingContact, string& strContact ) {
     ostringstream o ;
     
     if( incomingContact->m_display && *incomingContact->m_display ) {
         o << incomingContact->m_display ;
     }
     o << "<sip:" ;
     
     if( incomingContact->m_url[0].url_user ) {
         o << incomingContact->m_url[0].url_user ;
         o << "@" ;
     }
     sip_contact_t* contact = nta_agent_contact( m_nta ) ;
     o << contact->m_url[0].url_host ;
     if( contact->m_url[0].url_port && *contact->m_url[0].url_port ) {
         o << ":" ;
         o << contact->m_url[0].url_port ;
     }
     o << ">" ;
     
     DR_LOG(log_debug) << "generated Contact: " << o.str() << endl ;
     
     strContact = o.str() ;
 }
    void ClientController::addDialogForTransaction( const string& transactionId, const string& dialogId ) {
        boost::lock_guard<boost::mutex> l( m_lock ) ;
        mapId2Client::iterator it = m_mapNetTransactions.find( transactionId ) ;
        if( m_mapNetTransactions.end() != it ) {
            m_mapDialogs.insert( mapId2Client::value_type(dialogId, it->second ) ) ;
            DR_LOG(log_warning) << "ClientController::addDialogForTransaction - added dialog (uas), now tracking: " << 
                m_mapDialogs.size() << " dialogs and " << m_mapNetTransactions.size() << " net transactions"  ;
         }
        else {
            /* dialog will already exist if we received a reliable provisional response */
            mapId2Client::iterator itDialog = m_mapDialogs.find( dialogId ) ;
            if( m_mapDialogs.end() == itDialog ) {
                mapId2Client::iterator itApp = m_mapAppTransactions.find( transactionId ) ;
                if( m_mapAppTransactions.end() != itApp ) {
                    m_mapDialogs.insert( mapId2Client::value_type(dialogId, itApp->second ) ) ;
                    DR_LOG(log_warning) << "ClientController::addDialogForTransaction - added dialog (uac), now tracking: " << 
                        m_mapDialogs.size() << " dialogs and " << m_mapAppTransactions.size() << " app transactions"  ;
                }
                else {
                   DR_LOG(log_error) << "ClientController::addDialogForTransaction - transaction id " << transactionId << " not found"  ;
                    assert(false) ;                           
                }
            }
        }
        DR_LOG(log_debug) << "ClientController::addDialogForTransaction - transaction id " << transactionId << 
            " has associated dialog " << dialogId  ;

        client_ptr client = this->findClientForDialog_nolock( dialogId );
        if( !client ) {
            m_mapDialogs.erase( dialogId ) ;
            DR_LOG(log_warning) << "ClientController::addDialogForTransaction - client managing dialog has disconnected: " << dialogId  ;
            return  ;
        }
        else {
            string strAppName ;
            if( client->getAppName( strAppName ) ) {
                m_mapDialogId2Appname.insert( mapDialogId2Appname::value_type( dialogId, strAppName ) ) ;
                
                DR_LOG(log_debug) << "ClientController::addDialogForTransaction - dialog id " << dialogId << 
                    " has been established for client app " << strAppName << "; count of tracked dialogs is " << m_mapDialogId2Appname.size()  ;
            }
        }
    } 
 void DrachtioConfig::Log() const {
     DR_LOG(log_notice) << "Configuration:" << endl ;
 }
 void DrachtioController::processWatchdogTimer() {
     DR_LOG(log_debug) << "DrachtioController::processWatchdogTimer" << endl ;
     this->printStats() ;
     m_pDialogController->logStorageCount() ;
     m_pClientController->logStorageCount() ;
 }
Exemple #25
0
bool Pdb::RunToException()
{
	DR_LOG("RunToException");
	LLOG("RUN TO EXCEPTION");
	TimeStop ts;
	bool disasfocus = disas.HasFocus();
	bool locked = false;
	bool frestored = false;
	invalidpage.Clear();
	mempage.Clear();
	int opn = 0;
	for(;;) {
		if(terminated) {
			if(locked)
				Unlock();
			return false;
		}
		opn++;
		DR_LOG("WaitForDebugEvent");
		if(WaitForDebugEvent(&event, 0)) {
			DR_LOG("WaitForDebugEvent ended");
			debug_threadid = event.dwThreadId;
			opn = 0;
			running = false;
			switch(event.dwDebugEventCode) {
			case EXCEPTION_DEBUG_EVENT: {
				DR_LOG("EXCEPTION_DEBUG_EVENT");
				LLOG("Exception: " << FormatIntHex(event.u.Exception.ExceptionRecord.ExceptionCode) <<
				     " at: " << FormatIntHex(event.u.Exception.ExceptionRecord.ExceptionAddress) <<
				     " first: " << event.u.Exception.dwFirstChance);
				SaveForeground();
				const EXCEPTION_RECORD& x = event.u.Exception.ExceptionRecord;
				if(findarg(x.ExceptionCode, EXCEPTION_BREAKPOINT, EXCEPTION_SINGLE_STEP,
				                            STATUS_WX86_BREAKPOINT, STATUS_WX86_SINGLE_STEP) < 0)
				{
					LLOG("Non-debug EXCEPTION");
					if(event.u.Exception.dwFirstChance) {
						LLOG("First chance " << FormatIntHex(x.ExceptionCode));
						break;
					}
					String desc = Format("Exception: [* %lX] at [* %16llX]&",
					                     (int64)x.ExceptionCode, (int64)x.ExceptionAddress);
					for(int i = 0; i < __countof(ex_desc); i++)
						if(ex_desc[i].code == x.ExceptionCode)
							desc << "[* " << DeQtf(ex_desc[i].text) << "]&";
					if(x.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
						desc << (x.ExceptionInformation[0] ? "[*@3 writing]" : "[*@4 reading]");
						desc << Format(" at [* %08llX]", (int64)x.ExceptionInformation[1]);
					}
					ToForeground();
					PromptOK(desc);
				}
#ifdef CPU_64
				if(!win64 && x.ExceptionCode == EXCEPTION_BREAKPOINT && !break_running) // Ignore x64 breakpoint in wow64
					break;
#endif
				if(break_running)
					debug_threadid = mainThreadId;
				break_running = false;
				ToForeground();
				if(disasfocus)
					disas.SetFocus();
				if(locked)
					Unlock();
				if(refreshmodules)
					LoadModuleInfo();
				LLOG("event.dwThreadId = " << event.dwThreadId);
				bool isbreakpoint = findarg(x.ExceptionCode, EXCEPTION_BREAKPOINT, STATUS_WX86_BREAKPOINT) >= 0;
				for(int i = 0; i < threads.GetCount(); i++) {
					Thread& t = threads[i];
					(Context&)t = ReadContext(threads[i].hThread);
					if(event.dwThreadId == threads.GetKey(i)) {
						LLOG("Setting current context");
						if(isbreakpoint
#ifdef CPU_64
						   && bp_set.Find((win64 ? t.context64.Rip : t.context32.Eip) - 1) >= 0
#else
						   && bp_set.Find(t.context32.Eip - 1) >= 0
#endif
						) // We have stopped at breakpoint, need to move address back
					#ifdef CPU_64
							if(win64)
								t.context64.Rip--;
							else
					#endif
								t.context32.Eip--;
						context = t;
					}
				}
				RemoveBp();
				return true;
			}
			case CREATE_THREAD_DEBUG_EVENT:
				DR_LOG("CREATE_THREAD_DEBUG_EVENT");
				LLOG("Create thread: " << event.dwThreadId);
				AddThread(event.dwThreadId, event.u.CreateThread.hThread);
				break;
			case EXIT_THREAD_DEBUG_EVENT:
				DR_LOG("EXIT_THREAD_DEBUG_EVENT");
				LLOG("Exit thread: " << event.dwThreadId);
				RemoveThread(event.dwThreadId);
				break;
			case CREATE_PROCESS_DEBUG_EVENT:
				DR_LOG("CREATE_PROCESS_DEBUG_EVENT");
				LLOG("Create process: " << event.dwProcessId);
				processid = event.dwProcessId;
				AddThread(event.dwThreadId, event.u.CreateProcessInfo.hThread);
				CloseHandle(event.u.CreateProcessInfo.hFile);
				CloseHandle(event.u.CreateProcessInfo.hProcess);
				break;
			case EXIT_PROCESS_DEBUG_EVENT:
				DR_LOG("EXIT_PROCESS_DEBUG_EVENT");
				LLOG("Exit process: " << event.dwProcessId);
				if(locked)
					Unlock();
				terminated = true;
				return false;
			case LOAD_DLL_DEBUG_EVENT: {
				DR_LOG("LOAD_DLL_DEBUG_EVENT");
				LLOG("Load dll: " << event.u.LoadDll.lpBaseOfDll);
				CloseHandle(event.u.LoadDll.hFile);
				refreshmodules = true;
				break;
			}
			case UNLOAD_DLL_DEBUG_EVENT:
				DR_LOG("UNLOAD_DLL_DEBUG_EVENT");
				LLOG("UnLoad dll: " << event.u.UnloadDll.lpBaseOfDll);
				refreshmodules = true;
				break;
			case RIP_EVENT:
				DR_LOG("RIP_EVENT");
				LLOG("RIP!");
				Exclamation("Process being debugged died unexpectedly!");
				terminated = true;
				if(locked)
					Unlock();
				return false;
			}
			DR_LOG("ContinueDebugEvent");
			ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
			running = true;
		}
		if(ts.Elapsed() > 200) {
			DR_LOG("ts.Elpsed() > 200");
			if(!lock) {
				Lock();
				locked = true;
			}
			if(!frestored) {
				RestoreForeground();
				frestored = true;
			}
		}
		if(lock) {
			DR_LOG("GuiSleep");
			GuiSleep(opn < 1000 ? 0 : 100);
			Ctrl::ProcessEvents();
		}
		else {
			DR_LOG("Sleep");
			Sleep(opn < 1000 ? 0 : 100);
		}
	}
}
 void ClientController::leave( client_ptr client ) {
     m_clients.erase( client ) ;
     DR_LOG(log_debug) << "Removed client, count of connected clients is now: " << m_clients.size()  ;
 }
 void ClientController::join( client_ptr client ) {
     m_clients.insert( client ) ;
     client_weak_ptr p( client ) ;
     DR_LOG(log_debug) << "Added client, count of connected clients is now: " << m_clients.size()  ;       
 }
 void ClientController::removeNetTransaction( const string& transactionId ) {
     boost::lock_guard<boost::mutex> l( m_lock ) ;
     m_mapNetTransactions.erase( transactionId ) ;        
     DR_LOG(log_debug) << "removeNetTransaction: transactionId " << transactionId << "; size: " << m_mapNetTransactions.size()  ;
 }
    void ClientController::logStorageCount() {
        boost::lock_guard<boost::mutex> lock(m_lock) ;

        DR_LOG(log_debug) << "ClientController storage counts"  ;
        DR_LOG(log_debug) << "----------------------------------"  ;
        DR_LOG(log_debug) << "m_clients size:                                                  " << m_clients.size()  ;
        DR_LOG(log_debug) << "m_services size:                                                 " << m_services.size()  ;
        DR_LOG(log_debug) << "m_request_types size:                                            " << m_request_types.size()  ;
        DR_LOG(log_debug) << "m_map_of_request_type_offsets size:                              " << m_map_of_request_type_offsets.size()  ;
        DR_LOG(log_debug) << "m_mapDialogs size:                                               " << m_mapDialogs.size()  ;
        DR_LOG(log_debug) << "m_mapNetTransactions size:                                       " << m_mapNetTransactions.size()  ;
        DR_LOG(log_debug) << "m_mapAppTransactions size:                                       " << m_mapAppTransactions.size()  ;
        DR_LOG(log_debug) << "m_mapApiRequests size:                                           " << m_mapApiRequests.size()  ;
        DR_LOG(log_debug) << "m_mapDialogId2Appname size:                                      " << m_mapDialogId2Appname.size()  ;


    }
 void ClientController::addNetTransaction( client_ptr client, const string& transactionId ) {
     boost::lock_guard<boost::mutex> l( m_lock ) ;
     m_mapNetTransactions.insert( make_pair( transactionId, client ) ) ;        
     DR_LOG(log_debug) << "addNetTransaction: transactionId " << transactionId << "; size: " << m_mapNetTransactions.size()  ;
 }