// IvyApplication.cpp : implementation file // #include "IvyStdAfx.h" #include "IvyApplication.h" //#define IVY_DEBUG #define ARG_START "\002" #define ARG_END "\003" 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 ) { static char *start = NULL; static char *end = NULL; if ( s ) { end = s; } start = end; while ( *end && *end != *separator ) end++; if ( *end == *separator ) *end++ = '\0'; if ( end == start ) return NULL; 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 ( unsigned int i = 0; i < regexp_in.size(); i++) #ifdef USE_PCRE pcre_free( regexp_in[i] ); #else delete regexp_in[i]; #endif regexp_in.clear(); if ( m_hSocket != INVALID_SOCKET ) Close(); } ///////////////////////////////////////////////////////////////////////////// // IvyApplication member functions void IvyApplication::Create(const char* host, UINT & port) { // 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; #ifdef USE_PCRE pcre *exp; const char *argv[max_subexp]; const char *errmsg; int erroffset; #else Regexp *exp; const char *argv[Regexp::NSUBEXP]; #endif #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 ( !bus->CheckRegexp( arg ) ) { #ifdef IVY_DEBUG TRACE("Warning exp='%s' can't match removing from %s\n",arg,appname.c_str()); #endif //IVY_DEBUG return; } #ifdef USE_PCRE exp = pcre_compile( arg, PCRE_CASELESS, &errmsg, &erroffset, NULL ); if ( !exp ) { ivy::string err( "Error can't compile regexp '" ); err += arg; err += "' error "; err += errmsg; SendMsg( Error, Error, err.c_str() ); TRACE("IvyApplication %s\n",err.c_str()); return; } #else exp = new Regexp( arg ); if ( !exp->CompiledOK() ) { ivy::string err( "Error can't compile regexp '" ); err += arg; err += "' error "; err += exp->GetErrorString(); SendMsg( Error, Error, err.c_str() ); TRACE("IvyApplication %s\n",err.c_str()); return; } #endif if ( regexp_in.size() < (id + 1) ) regexp_in.resize( id + 1 ); regexp_in[ id ] = exp; #ifdef IVY_DEBUG TRACE("Adding regexp[%d]='%s' size: %d\n",id,arg,regexp_in.size()); #endif //IVY_DEBUG break; case DelRegexp: #ifdef IVY_DEBUG TRACE("Regexp Delete id=%d\n", id); #endif //IVY_DEBUG if ( regexp_in[id] ) { exp = regexp_in[ id ]; #ifdef USE_PCRE pcre_free( exp ); #else delete exp; #endif 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 = nextArg( arg, ARG_END); while ( arg ) { argv[argc++] = arg; arg = nextArg( NULL, 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; 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" ARG_START "%s\n", msg, id, arg ); else sprintf_s( buffer,sizeof( buffer ), "%d %d" ARG_START "\n", msg, id ); #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 ( unsigned int i = 0; i < regexp_in.size(); i++) #ifdef USE_PCRE pcre_free( regexp_in[i] ); #else delete regexp_in[i]; #endif regexp_in.clear(); Close(); // bus->RemoveApplication( this ); } int IvyApplication::SendMsg(const char *message) { int count = 0; #ifdef USE_PCRE pcre *exp; int ovector[max_subexp*3]; #else Regexp *exp; #endif /* send to already connected */ for ( unsigned int i = 0; i < regexp_in.size(); i++ ) { exp = regexp_in[i]; #ifdef USE_PCRE int match_count = pcre_exec( exp, NULL, message, (int) strlen( message ), 0, 0, ovector, max_subexp ); if ( match_count > 0 ) { ivy::string buffer; const char **substring; int err = pcre_get_substring_list(message,ovector, match_count, &substring); if ( err != 0 ) { SendMsg( Error, Error, "Memory Alloc Error" ); } else { for ( int j = 1; j < match_count; j++ ) { buffer += substring[j]; buffer += ARG_END; } pcre_free_substring_list(substring); SendMsg( Msg, i, buffer.c_str() ); count++; } } #else if ( exp && exp->Match( message ) ) { ivy::string buffer; for ( int j = 1; j < exp->SubStrings()+1; j++ ) { buffer += (*exp)[j]; buffer += ARG_END; } SendMsg( Msg, i, buffer.c_str() ); count++; } #endif } 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; }