summaryrefslogtreecommitdiff
path: root/Ivy/Ivy.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Ivy/Ivy.cxx')
-rw-r--r--Ivy/Ivy.cxx437
1 files changed, 437 insertions, 0 deletions
diff --git a/Ivy/Ivy.cxx b/Ivy/Ivy.cxx
new file mode 100644
index 0000000..4564c6f
--- /dev/null
+++ b/Ivy/Ivy.cxx
@@ -0,0 +1,437 @@
+// 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));
+ }
+
+}
+