// Ivy.cpp: implementation of the Ivy class. // ////////////////////////////////////////////////////////////////////// #include "IvyStdAfx.h" #include "Ivy.h" #include "IvyWatcher.h" #include "IvyApplication.h" #include "IvySynchroWnd.h" #include "IvyBinding.h" #include "intervalRegexp.h" #define DEFAULT_ADDR "127.255.255.255" #define SEPARATOR ":" #define DEFAULT_PORT "2010" #define DEFAULT_DOMAIN DEFAULT_ADDR/**/SEPARATOR/**/DEFAULT_PORT ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// Ivy::~Ivy() { // remove all app and stop watcher stop(); regexp_out.clear(); if ( synchronous ) { for ( unsigned int i = 0; i < callbacks.size(); i ++) { delete callbacks[i]; } } callbacks.clear(); // if ( direct_callback ) delete direct_callback; // if ( application_callback ) delete application_callback; delete watcher; // server->Close(); delete server; if ( synchronous ) { delete IvySynchronousCallback::m_synchro; delete application_callback; } } Ivy::Ivy(const char* name, const char * ready, IvyApplicationCallback *callback, bool Synchronous) { InitializeCriticalSection( &m_application_cs ); regexp_id = 0; synchronous = Synchronous; if ( synchronous ) IvySynchronousCallback::m_synchro = new IvySynchroWnd(); ready_message = ready; ApplicationName = name; binding_callback = NULL; application_callback = synchronous ? new IvySynchronousApplicationCallback(callback) : callback; direct_callback = NULL; die_callback = NULL; server = new IvyApplication(this); applicationPort = server->Create(); if ( !applicationPort ) { TRACE( " Can't Create server %d\n", server->GetLastError( ) ); return; } ApplicationID = GenApplicationUniqueIdentifier(); watcher = new IvyWatcher(this); } const char *Ivy::GenApplicationUniqueIdentifier() { static char appid[2048]; unsigned long curtime; curtime = GetTickCount(); srand( curtime ); sprintf(appid,"%d:%lu:%d",rand(),curtime,applicationPort); return appid; } const char * Ivy::GetDomain(const char *domainlist) { // determine domain to use // the syntax of domain is "IpBroadcastAddr1,IpBroadcastAddr2,IpBroadcastAddr2:port" if ( domainlist ) { domain = domainlist; } if ( domain.empty() ) { #ifndef UNDER_CE size_t requiredSize; getenv_s( &requiredSize, NULL, 0, "IVYBUS"); if ( requiredSize ) { char *env = (char*)malloc( requiredSize * sizeof(char)); getenv_s( &requiredSize, env, requiredSize, "IVYBUS"); domain = env; free( env ); } #endif if ( domain.empty() ) domain = DEFAULT_DOMAIN; } // first find our UDP port size_t sep_index = domain.rfind( ':' ); if ( sep_index == -1 ) { domain = DEFAULT_DOMAIN; TRACE(" Missing ':' in domain list using default domain %s\n", domain ); } if ( sep_index == 0 ) { /* missing addr using localhost */ domain.insert(0,DEFAULT_ADDR); } return domain.c_str(); } void Ivy::start(const char *domain) { watcher->start(domain); } void Ivy::stop() { watcher->stop(); IvyApplicationList::iterator iter; for ( iter = applications.begin() ; iter != applications.end() ; ++iter ) { IvyApplication *app = *iter; app->Close(); delete app; } applications.clear(); } int Ivy::BindMsg(const char *regexp, IvyMessageCallback *cb) { char buffer[8192]; SubstituteInterval( regexp, buffer, sizeof( buffer ) ); regexp_out.push_back( buffer ); callbacks.push_back( synchronous ? new IvySynchronousMessageCallback(cb) : cb ); /* send to already connected */ IvyApplicationList::iterator iter; for ( iter = applications.begin() ; iter != applications.end() ; ++iter ) { IvyApplication *app = *iter; app->SendMsg(IvyApplication::AddRegexp, regexp_id, buffer ); } return regexp_id++; } int Ivy::BindMsg( IvyMessageCallback *cb, const char *regexp, ... ) { char buffer[4096]; char buffer2[8192]; va_list args; va_start( args, regexp ); /* Initialize variable arguments. */ _vsnprintf_s( buffer, sizeof(buffer), sizeof(buffer)-1, regexp, args ); va_end( args); SubstituteInterval( buffer, buffer2, sizeof( buffer2 ) ); regexp_out.push_back( buffer2 ); callbacks.push_back( synchronous ? new IvySynchronousMessageCallback(cb) : cb ); /* send to already connected */ IvyApplicationList::iterator iter; for ( iter = applications.begin() ; iter != applications.end() ; ++iter ) { IvyApplication *app = *iter; app->SendMsg(IvyApplication::AddRegexp, regexp_id, buffer2 ); } return regexp_id++; } void Ivy::UnbindMsg(int id) { regexp_out[ id ] = ""; callbacks[ id ] = NULL; /* send to already connected */ IvyApplicationList::iterator iter; for ( iter = applications.begin() ; iter != applications.end() ; ++iter ) { IvyApplication *app = *iter; app->SendMsg(IvyApplication::DelRegexp, id, "" ); } } void Ivy::BindDirectMsg(IvyDirectMessageCallback *callback) { direct_callback = callback; } unsigned int Ivy::GetApplicationPort() { return applicationPort; } void Ivy::AddApplication(IvyApplication *app) { EnterCriticalSection( &m_application_cs ); // Check for disconnected Application IvyApplicationList::iterator iter; for ( iter = applications.begin() ; iter != applications.end() ; ) { IvyApplication *disc_app = *iter++; if ( disc_app->m_hSocket == INVALID_SOCKET ) { applications.remove( disc_app ); delete disc_app; } } applications.push_back( app ); LeaveCriticalSection( &m_application_cs ); SendSubscriptions( app ); } void Ivy::RemoveApplication(IvyApplication * app) { /// OLD NOT called because of deallocation PB // the real remove is done at arrival of a new Application // or at the bus Stop TRACE( "Ivy::RemoveApplication %lu\n", app ); if ( app ) { EnterCriticalSection( &m_application_cs ); applications.remove( app ); LeaveCriticalSection( &m_application_cs ); delete app; } } void Ivy::SendSubscriptions(IvyApplication *app) { app->SendMsg( IvyApplication::StartRegexp, GetApplicationPort(), ApplicationName.c_str()); for ( unsigned int id = 0 ; id < regexp_out.size(); id++ ) { const ivy::string& regexp = regexp_out[id]; if ( !regexp.empty() ) app->SendMsg( IvyApplication::AddRegexp, id, regexp.c_str()); } app->SendMsg( IvyApplication::EndRegexp, 0); } int Ivy::SendMsg(const char * message, ... ) { int count = 0; char buffer[4096]; va_list args; va_start( args, message ); /* Initialize variable arguments. */ _vsnprintf_s( buffer, sizeof(buffer), sizeof(buffer)-1, message, args ); va_end( args); /* send to already connected */ IvyApplicationList::iterator iter; for ( iter = applications.begin() ; iter != applications.end() ; ++iter ) { IvyApplication *app = *iter; count += app->SendMsg( buffer ); } return count; } void Ivy::SendDieMsg( IvyApplication *app ) { app->SendMsg( IvyApplication::Die, 0 ); } IvyApplication * Ivy::GetApplication(const char *name) { IvyApplication *app = NULL; EnterCriticalSection( &m_application_cs ); IvyApplicationList::iterator iter; for ( iter = applications.begin() ; iter != applications.end() ; ) { IvyApplication *ap = *iter++; if ( (ap->m_hSocket != INVALID_SOCKET) && ap->appname == name ) { app = ap; break; // dont return because of LeaveCriticalSection !!! } } LeaveCriticalSection( &m_application_cs ); return app; } void Ivy::CallMessageCallback(IvyApplication *app, int id, int argc, const char ** argv) { IvyMessageCallback *callback; callback = callbacks[ id ]; if ( callback ) { callback->OnMessage( app, argc, argv ); } } void Ivy::CallDirectMessageCallback(IvyApplication *app, int id, const char *arg) { if ( direct_callback ) { direct_callback->OnDirectMessage( app, id, arg ); } } bool Ivy::CallDieCallback(IvyApplication *app, int id, const char *arg) { if ( die_callback ) { return die_callback->OnDie( app, id, arg ); } return TRUE; } void Ivy::CallApplicationConnectedCallback(IvyApplication * app) { if ( application_callback ) { application_callback->OnApplicationConnected( app ); } } void Ivy::CallApplicationDisconnectedCallback(IvyApplication * app) { if ( application_callback ) { application_callback->OnApplicationDisconnected( app ); } } void Ivy::CallBindingAddCallback(IvyApplication * app, int id, const char * regexp) { if ( binding_callback ) { binding_callback->OnAddBind( app, id, regexp ); } } void Ivy::CallBindingRemoveCallback(IvyApplication * app, int id, const char * regexp) { if ( binding_callback ) { binding_callback->OnRemoveBind( app, id, regexp ); } } void Ivy::CallBindingFilterCallback(IvyApplication * app, int id, const char * regexp) { if ( binding_callback ) { binding_callback->OnFilterBind( app, id, regexp ); } } void Ivy::SendDirectMsg(IvyApplication * app, int id, const char *message) { app->SendMsg( IvyApplication::DirectMsg, id, message ); } void Ivy::SetBindCallback( IvyBindingCallback* bind_callback ) { binding_callback = synchronous ? new IvySynchronousBindingCallback(bind_callback) : bind_callback; } void Ivy::SetFilter(int argc, const char **argv ) { IvyBinding::SetFilter(argc, argv ); } bool Ivy::CheckConnected(IvyApplication * app) { if (app->remoteService == 0) /* old application dont check */ return false; /* check to see if app already connected */ IvyApplicationList::iterator iter; for ( iter = applications.begin() ; iter != applications.end() ; ++iter ) { IvyApplication *application = *iter; if ( application != app && application->SameApplication(app)) return true; } return false; } void Ivy::SubstituteInterval (const char *src, char *dst, size_t dst_len) { // pas de traitement couteux s'il n'y a rien à interpoler if (strstr (src, "(?I") == NULL) { strcpy (dst,src); return; } else { char *curPos; char *itvPos; char *dstPos = dst; curPos = (char *)src; while ((itvPos = strstr (curPos, "(?I")) != NULL) { // copie depuis la position courante jusqu'à l'intervalle int lenCp, min,max; char withDecimal; lenCp = itvPos-curPos; memcpy ( dstPos, curPos, lenCp); curPos=itvPos; dstPos += lenCp; // extraction des paramètres de l'intervalle sscanf (itvPos, "(?I%d#%d%c", &min, &max, &withDecimal); // printf ("DBG> substituteInterval min=%d max=%d withDecimal=%d\n", // min, max, (withDecimal != 'i')); // generation et copie de l'intervalle regexpGen (dstPos, dst_len-(dstPos-dst), min, max, (withDecimal != 'i')); dstPos = dst + strlen (dst); // consommation des caractères décrivant intervalle dans la chaine source curPos = strstr (curPos, ")"); curPos++; } strncat (dstPos, curPos, dst_len-(dstPos-dst)); } }