summaryrefslogtreecommitdiff
path: root/Ivy/IvyApplication.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Ivy/IvyApplication.cxx')
-rw-r--r--Ivy/IvyApplication.cxx375
1 files changed, 375 insertions, 0 deletions
diff --git a/Ivy/IvyApplication.cxx b/Ivy/IvyApplication.cxx
new file mode 100644
index 0000000..07f37be
--- /dev/null
+++ b/Ivy/IvyApplication.cxx
@@ -0,0 +1,375 @@
+// IvyApplication.cpp : implementation file
+//
+
+#include "IvyStdAfx.h"
+
+#include "IvyApplication.h"
+#include "IvyBinding.h"
+
+
+//#define IVY_DEBUG
+
+#define ARG_START 2
+#define ARG_END 3
+
+static char * firstArg( char *s, const char separator )
+{
+ char *ptr = s;
+
+ while ( *ptr && *ptr != separator )
+ ptr++;
+ if ( *ptr == separator )
+ return ptr++ ;
+ else return NULL;
+}
+/*
+function like strok but do not eat consecutive separator
+*/
+static char * nextArg( char **s, const char separator )
+{
+ char *start = *s;
+ char *end = *s;
+
+ while ( *end && *end != separator )
+ end++;
+ if ( *end == separator ) *end++ = '\0';
+ if ( end == start ) return NULL;
+ *s = end;
+ return start;
+}
+/////////////////////////////////////////////////////////////////////////////
+// IvyApplication
+
+IvyApplication::IvyApplication(Ivy * bus)
+{
+ this->bus = bus;
+ remoteService = 0; /* unknown or unconnected application */
+ appname = "Unknown";
+ AppConnectedCallbackCalled = false;
+}
+
+IvyApplication::~IvyApplication()
+{
+// bus->RemoveApplication( this );
+ for ( Bindings::iterator iter = regexp_in.begin( ); iter != regexp_in.end( ); iter++ )
+ delete iter->second;
+ regexp_in.clear();
+ if ( m_hSocket != INVALID_SOCKET )
+ Close();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// IvyApplication member functions
+
+
+void IvyApplication::Create(const char* host, UINT & port, const char* name)
+{
+ appname = name;
+ // Exception to catch
+ CBufferedSocket::Create();
+ Connect(host, port);
+}
+
+
+
+UINT IvyApplication::Create()
+{
+ ivy::string host;
+ UINT port;
+ CBufferedSocket::Create();
+ // Max Listen Connexion
+ Listen( SOMAXCONN );
+ GetSockName( host, port );
+ TRACE(" TCP %s:%d\n", host.c_str(), port );
+#ifdef IVY_DEBUG
+ TRACE( "IvyApplication::Create server socket %d\n", m_hSocket );
+#endif
+ return port;
+}
+
+void IvyApplication::OnReceive(char * line)
+{
+ int err;
+ unsigned int id;
+ int kind_of_msg = Bye;
+ char *arg;
+ int argc = 0;
+ char *arg_ptr;
+ static const int max_subexp = 200;
+ const char *argv[max_subexp];
+
+ IvyBinding *exp;
+ int erroffset;
+ const char *errmsg;
+
+#ifdef IVY_DEBUG
+ TRACE("Receive %s\n",line);
+#endif //IVY_DEBUG
+
+ err = sscanf_s( line ,"%d %d", &kind_of_msg, &id);
+ arg = firstArg( line , ARG_START );
+ if ( (err != 2) || (arg == NULL) )
+ {
+ TRACE("Quitting bad format %s\n", line);
+ SendMsg(Error, Error, "bad format request expected 'type id ...'");
+// bus->RemoveApplication( this );
+ Close();
+ return;
+ }
+ arg++;
+ switch( kind_of_msg )
+ {
+ case Bye:
+
+#ifdef IVY_DEBUG
+ TRACE("Quitting %s\n", line);
+#endif //IVY_DEBUG
+
+// bus->RemoveApplication( this );
+ OnClose(0);
+ //Close();
+ break;
+ case Error:
+
+#ifdef IVY_DEBUG
+ TRACE("Receive error %d %s\n", id, arg);
+#endif //IVY_DEBUG
+
+ break;
+ case AddRegexp:
+
+#ifdef IVY_DEBUG
+ TRACE("Regexp id=%d exp='%s'\n", id, arg);
+#endif //IVY_DEBUG
+
+ if ( !IvyBinding::Filter( arg ) )
+ {
+#ifdef IVY_DEBUG
+ TRACE("Warning exp='%s' can't match removing from %s\n",arg,appname.c_str());
+#endif //IVY_DEBUG
+ bus->CallBindingFilterCallback( this, id, arg );
+ return;
+ }
+ exp = new IvyBinding();
+ if ( !exp->Compile(arg, &erroffset, &errmsg ) )
+ {
+ ivy::string errstr( "Error can't compile regexp '" );
+ errstr += arg;
+ errstr += "' error ";
+ errstr += errmsg;
+ SendMsg( Error, Error, errstr.c_str() );
+ TRACE("IvyApplication %s\n",errstr.c_str());
+ delete exp;
+ return;
+ }
+
+ /*if ( regexp_in.size() < (id + 1) )
+ {
+ regexp_in.resize( id + 1 );
+ regexp_str_in.resize( id + 1 );
+ }*/
+ regexp_in[ id ] = exp;
+ regexp_str_in[ id ] = arg;
+#ifdef IVY_DEBUG
+ TRACE("Adding regexp[%d]='%s' size: %d\n",id,arg,regexp_in.size());
+#endif //IVY_DEBUG
+ bus->CallBindingAddCallback( this, id, arg );
+ break;
+ case DelRegexp:
+
+#ifdef IVY_DEBUG
+ TRACE("Regexp Delete id=%d\n", id);
+#endif //IVY_DEBUG
+ if ( regexp_in[id] )
+ {
+ exp = regexp_in[ id ];
+ bus->CallBindingRemoveCallback( this, id, regexp_str_in[id].c_str() );
+
+ delete exp;
+ regexp_in[ id ] = NULL;
+ }
+ break;
+ case StartRegexp:
+
+#ifdef IVY_DEBUG
+ TRACE("Regexp Start id=%d\n", id);
+#endif //IVY_DEBUG
+
+ appname = arg;
+ /* remote socket port */
+ remoteService = id;
+ if ( bus->CheckConnected( this ) )
+ {
+ TRACE("Quitting already connected %s\n", appname.c_str());
+ SendMsg( Error, Error, "already connected" );
+// bus->RemoveApplication( this );
+ Close();
+ }
+ break;
+ case EndRegexp:
+
+#ifdef IVY_DEBUG
+ TRACE("Regexp End id=%d\n", id);
+#endif //IVY_DEBUG
+
+ bus->CallApplicationConnectedCallback( this );
+ AppConnectedCallbackCalled = true;
+ if ( !bus->ready_message.empty() )
+ SendMsg( bus->ready_message.c_str() );
+ break;
+ case Msg:
+
+#ifdef IVY_DEBUG
+ TRACE("Message id=%d msg='%s'\n", id, arg);
+#endif //IVY_DEBUG
+
+ arg_ptr = arg;
+ arg = nextArg( &arg_ptr, ARG_END);
+ while ( arg )
+ {
+ argv[argc++] = arg;
+ arg = nextArg( &arg_ptr, ARG_END );
+ }
+ bus->CallMessageCallback( this, id, argc, argv );
+ break;
+ case DirectMsg:
+
+#ifdef IVY_DEBUG
+ TRACE("Direct Message id=%d msg='%s'\n", id, arg);
+#endif //IVY_DEBUG
+
+ bus->CallDirectMessageCallback( this, id, arg );
+ break;
+ case Die:
+
+#ifdef IVY_DEBUG
+ TRACE("Die Message id=%d msg='%s'\n", id, arg);
+#endif //IVY_DEBUG
+
+ if ( bus->CallDieCallback( this, id, arg ) )
+ {
+ PostMessage( NULL, WM_CLOSE, 0, 0);
+ exit(-1);
+ }
+ break;
+ case Ping:
+#ifdef IVY_DEBUG
+ TRACE("Ping Message\n");
+#endif //IVY_DEBUG
+ this->SendMsg( Pong, 0, "beurk" );
+ break;
+
+ case Pong:
+#ifdef IVY_DEBUG
+ TRACE("Pong Message\n");
+#endif //IVY_DEBUG
+ TRACE("Receive unhandled Pong message (ivy-c++ not able to send ping)\n");
+ break;
+
+ default:
+ TRACE("Receive unhandled message %s\n", line);
+ break;
+ }
+}
+
+
+void IvyApplication::SendMsg(MsgType msg, int id, const char * arg)
+{
+ char buffer[1024];
+ if ( arg )
+ _snprintf_s( buffer, sizeof( buffer ),sizeof( buffer )-1, "%d %d%c%s\n", msg, id, ARG_START, arg );
+ else sprintf_s( buffer,sizeof( buffer ), "%d %d%c\n", msg, id, ARG_START);
+
+#ifdef IVY_DEBUG
+ TRACE("SendMsg %s\n",buffer);
+#endif //IVY_DEBUG
+ Send( buffer );
+}
+
+void IvyApplication::OnAccept(int nErrorCode)
+{
+ ivy::string remotehost;
+ UINT remoteport;
+
+ // construct a new, empty socket
+
+ IvyApplication *newapp = new IvyApplication(bus);
+
+ // accept connection
+
+ Accept( *newapp );
+ newapp->GetPeerName( remotehost, remoteport );
+ TRACE("Connexion de %s:%u\n", remotehost.c_str(), remoteport );
+ bus->AddApplication( newapp );
+}
+
+void IvyApplication::OnClose(int nErrorCode)
+{
+ ivy::string remotehost;
+ UINT remoteport;
+ GetPeerName( remotehost, remoteport );
+ TRACE("Deconnexion de %s:%u\n", remotehost.c_str(), remoteport );
+ if ( AppConnectedCallbackCalled )
+ bus->CallApplicationDisconnectedCallback( this );
+
+ for ( Bindings::iterator iter = regexp_in.begin( ); iter != regexp_in.end( ); iter++)
+ delete iter->second;
+ regexp_in.clear();
+ Close();
+ //bus->RemoveApplication( this );
+}
+
+int IvyApplication::SendMsg(const char *message)
+{
+ int count = 0;
+ IvyBinding *exp;
+
+ /* send to already connected */
+ for ( Bindings::iterator iter = regexp_in.begin( ); iter != regexp_in.end( ); iter++ )
+ {
+ exp = iter->second;
+ if ( !exp )
+ continue;
+ int match_count = exp->Exec( message );
+ if ( match_count > 0 )
+ {
+ ivy::string buffer;
+ int arglen;
+ const char *arg;
+
+ for ( int j = 1; j < match_count; j++ )
+ {
+ exp->Match(message, j, &arglen, &arg);
+ buffer += ivy::string(arg,arglen );
+ buffer += ARG_END;
+ }
+ SendMsg( Msg, iter->first, buffer.c_str() );
+ count++;
+ }
+
+ }
+ return count;
+}
+
+const char *IvyApplication::GetName(void)
+{
+return appname.c_str();
+}
+
+
+BOOL IvyApplication::SameApplication(IvyApplication * app)
+{
+ ivy::string host1;
+ UINT port1;
+ ivy::string host2;
+ UINT port2;
+ if ( (remoteService != 0) && (remoteService == app->remoteService) )
+ {
+ GetPeerName( host1, port1 );
+ app->GetPeerName( host2, port2 );
+ TRACE( "IvyApplication::SameApplication %s:%d %s:%d\n", host1.c_str(),port1, host2.c_str(),port2);
+ return ( host1 == host2 );
+ }
+ return false;
+}