diff options
Diffstat (limited to 'src/ivy.c')
-rw-r--r-- | src/ivy.c | 1045 |
1 files changed, 419 insertions, 626 deletions
@@ -7,8 +7,7 @@ * * Main functions * - * Authors: Francois-Regis Colin <fcolin@cena.fr> - * Stephane Chatty <chatty@cena.fr> + * Authors: Francois-Regis Colin,Stephane Chatty * * $Id$ * @@ -16,31 +15,37 @@ * copyright notice regarding this software */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <ctype.h> -#include <fcntl.h> +#include <stdlib.h> #ifdef WIN32 -#include <crtdbg.h> #include <windows.h> #else -#include <arpa/inet.h> #include <sys/time.h> -#include <unistd.h> -#include <netdb.h> +#include <arpa/inet.h> #endif +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> +#include <fcntl.h> + +#include "intervalRegexp.h" #include "ivychannel.h" -#include "ivybind.h" #include "ivysocket.h" #include "list.h" -#include "hash.h" +#include "ivybuffer.h" +#include "ivydebug.h" +#include "ivybind.h" #include "ivy.h" -#define VERSION 4 +#define VERSION 3 + +#define MAX_MATCHING_ARGS 40 + +#define ARG_START "\002" +#define ARG_END "\003" + #define DEFAULT_DOMAIN 127.255.255.255 /* stringification et concatenation du domaine et du port en 2 temps : @@ -50,37 +55,28 @@ #define GenerateIvyBus(domain,bus) str(domain)":"str(bus) static char* DefaultIvyBus = GenerateIvyBus(DEFAULT_DOMAIN,DEFAULT_BUS); -/* syntaxe des messages */ -#define MSGTYPE 0 -#define MSGID 1 -#define ARG_0 2 - typedef enum { - Bye, /* l'application emettrice se termine */ - AddRegexp, /* expression reguliere d'un client */ - Msg, /* message reel */ - Error, /* error message */ - DelRegexp, /* Remove expression reguliere */ - EndRegexp, /* end of the regexp list */ + Bye, /* l'application emettrice se termine */ + AddRegexp, /* expression reguliere d'un client */ + Msg, /* message reel */ + Error, /* error message */ + DelRegexp, /* Remove expression reguliere */ + EndRegexp, /* end of the regexp list */ StartRegexp, /* debut des expressions */ - DirectMsg, /* message direct a destination de l'appli */ - Die, /* demande de terminaison de l'appli */ - Ping = 9, /* checks the presence of the other */ - Pong = 10, /* checks the presence of the other */ - AddBinding = 11, /* other methods for binding message based on hash table */ - DelBinding = 12, /* other methods for binding message based on hash table */ - ApplicationId = 13, /* on start send my ID and priority */ - + DirectMsg, /* message direct a destination de l'appli */ + Die, /* demande de terminaison de l'appli */ + Ping, /* message de controle ivy */ + Pong /* ivy doit renvoyer ce message à la reception d'un ping */ } MsgType; typedef struct _msg_snd *MsgSndPtr; struct _msg_rcv { /* requete d'emission d'un client */ - IvyBindingType type; + MsgRcvPtr next; int id; - char *regexp; /* regexp du message a recevoir */ - MsgCallback callback; /* callback a declanche a la reception */ + const char *regexp; /* regexp du message a recevoir */ + MsgCallback callback; /* callback a declanche a la reception */ void *user_data; /* stokage d'info client */ }; @@ -88,7 +84,7 @@ struct _msg_snd { /* requete de reception d'un client */ MsgSndPtr next; int id; char *str_regexp; /* la regexp sous forme inhumaine */ - IvyBinding bind; + IvyBinding binding; /* la regexp sous forme machine */ }; struct _clnt_lst { @@ -96,11 +92,12 @@ struct _clnt_lst { Client client; /* la socket client */ MsgSndPtr msg_send; /* liste des requetes recues */ char *app_name; /* nom de l'application */ - char *app_id; /* identificateur unique de l'application (time-ip-port) */ - int priority; /* client priority */ unsigned short app_port; /* port de l'application */ }; +/* flag pour le debug en cas de Filter de regexp */ +int debug_filter = 0; + /* server pour la socket application */ static Server server; @@ -114,17 +111,19 @@ static unsigned short SupervisionPort; static Client broadcast; static const char *ApplicationName = 0; +static const char *ApplicationID = 0; + /* callback appele sur reception d'un message direct */ static MsgDirectCallback direct_callback = 0; static void *direct_user_data = 0; /* callback appele sur changement d'etat d'application */ -static IvyApplicationCallback application_callback = 0; +static IvyApplicationCallback application_callback; static void *application_user_data = 0; /* callback appele sur ajout suppression de regexp */ -static IvyBindCallback application_bind_callback = 0; +static IvyBindCallback application_bind_callback; static void *application_bind_data = 0; /* callback appele sur demande de terminaison d'application */ @@ -132,241 +131,114 @@ static IvyDieCallback application_die_callback; static void *application_die_user_data = 0; /* liste des messages a recevoir */ -//static MsgRcvPtr msg_recv = 0; -static HASHTABLE msg_recv= NULL; - +static MsgRcvPtr msg_recv = 0; /* liste des clients connectes */ static IvyClientPtr clients = 0; static const char *ready_message = 0; +static void substituteInterval (IvyBuffer *src); -static char *applicationUniqueId = 0; -static int applicationPriority = DEFAULT_PRIORITY; - -/* get Current Time in milliseconds */ -static long currentTime() -{ - unsigned long current; -#ifdef WIN32 - current = GetTickCount(); -#else - struct timeval stamp; - gettimeofday( &stamp, NULL ); - current = stamp.tv_sec * 1000 + stamp.tv_usec/1000; -#endif - return current; -} - - -// fonction de formtage a la printf d'un buffer avec reallocation dynamique -#define MESSAGE_SIZE 4096 /* taille buffer initiale on multiple pas deux a chaque realloc */ - -static int make_message(char ** buffer, int *size, int offset, const char *fmt, va_list ap) -{ - /* Guess we need no more than BUFFER_INIT_SIZE bytes. */ - long n; - if ( *size == 0 || *buffer == NULL ) - { - *size = MESSAGE_SIZE; - *buffer = malloc (MESSAGE_SIZE); - if ( *buffer == NULL ) - return -1; - } - while (1) { - /* Try to print in the allocated space. */ -#ifdef WIN32 - n = _vsnprintf (*buffer + offset, *size - offset, fmt, ap); -#else - n = vsnprintf (*buffer + offset, *size - offset, fmt, ap); -#endif - /* If that worked, return the string size. */ - if (n > -1 && n < *size) - return n; - /* Else try again with more space. */ - if (n > -1) /* glibc 2.1 */ - *size = n+1; /* precisely what is needed */ - else /* glibc 2.0 */ - *size *= 2; /* twice the old size */ - if ((*buffer = realloc (*buffer, *size)) == NULL) - return -1; - } -} - -static char *DupArg( int len, void *s) -{ - char *ptr; - ptr = malloc( len+1 ); - if (!ptr ) - { - fprintf(stderr,"DupArg Buffer Memory Alloc Error\n"); - exit(-1); - } - memcpy( ptr, s, len ); - ptr[len] = '\0'; - return ptr; -} -/* returns < 0 if *p sorts lower than *q */ -static int keycmp (IvyClientPtr p, IvyClientPtr q) -{ - return p->priority - q->priority; -} - -/* merge 2 lists under dummy head item */ -static IvyClientPtr lmerge (IvyClientPtr p, IvyClientPtr q) -{ - IvyClientPtr r; - struct _clnt_lst head; - - for ( r = &head; p && q; ) - { - if ( keycmp(p, q) < 0 ) - { - r = r->next = p; - p = p->next; - } - else - { - r = r->next = q; - q = q->next; - } - } - r->next = (p ? p : q); - return head.next; -} - -/* split list into 2 parts, sort each recursively, merge */ -static IvyClientPtr lsort (IvyClientPtr p) -{ - IvyClientPtr q, r; - - if ( p ) - { - q = p; - for ( r = q->next; r && (r = r->next) != NULL; r = r->next ) - q = q->next; - r = q->next; - q->next = NULL; - if ( r ) - p = lmerge(lsort(r), lsort(p)); - } - return p; -} - - -static void SortClients() -{ - // sort client list again priority! - lsort( clients ); -} -static void MsgSendTo( Client client, MsgType msgtype, int id, int len_arg, const void *arg ) +/* + * function like strok but do not eat consecutive separator + * */ +static char * nextArg( char *s, const char *separator ) { - unsigned short header[3]; - -#ifdef DEBUG - printf( "Sending message type=%d id=%d '%.*s'\n",msgtype,id,len_arg,(char*)arg); -#endif - header[0] = htons( (unsigned short)msgtype ); - header[1] = htons( (unsigned short)id ); - header[2] = htons( (unsigned short)len_arg ); - SocketSend( client, (char *)header, sizeof(header) ); - if ( len_arg ) + static char *start = NULL; + static char *end = NULL; + if ( s ) { - SocketSend( client, arg, len_arg ); + end = s; } - SocketFlush( client ); -} - -static int MsgSendCallTo (Client client, const char *message, MsgSndPtr msg ) -{ - void * buffer = NULL; - int buf_len = 0; - int len; - IvyArgument args; - - - int rc = IvyBindingExec( msg->bind, message ); - - if (rc<1) return 0; /* no match */ -#ifdef DEBUG - printf( "Sending message id=%d '%s'\n",msg->id,message); -#endif - // il faut essayer d'envoyer le message en une seule fois sur la socket - // pour eviter au maximun de passer dans le select plusieur fois par message du protocole Ivy - // pour eviter la latence ( PB de perfo detecte par ivyperf ping roudtrip ) + start = end; -#ifdef DEBUG - printf( "Send matching args count %d\n",rc); -#endif - args = IvyBindingMatch( msg->bind, message ); - /* serialize into buffer */ - len = IvyArgumentSerialize(args, &buf_len, &buffer, 0); - - MsgSendTo( client, Msg, msg->id, len, buffer ); - IvyArgumentFree( args ); /* TODO supress malloc /free */ - free( buffer ); - return 1; + while ( *end && *end != *separator ) + end++; + if ( *end == *separator ) *end++ = '\0'; + if ( end == start ) return NULL; + return start; } -static BOOL RemoveBinding(HASHKEYTYPE key, void *data, va_list args) +static int MsgSendTo( Client client, MsgType msgtype, int id, const char *message ) { - MsgRcvPtr msg = (MsgRcvPtr)data; - free( msg->regexp ); - free ( msg ); - return FALSE; /* iter throught all hash table */ + return SocketSend( client, "%d %d" ARG_START "%s\n", msgtype, id, message); } + static void IvyCleanup() { IvyClientPtr clnt,next; - MsgSndPtr msg,msg_next; + /* destruction des connexions clients */ IVY_LIST_EACH_SAFE( clients, clnt, next ) { /* on dit au revoir */ - MsgSendTo( clnt->client, Bye, 0, 0, "" ); + MsgSendTo( clnt->client, Bye, 0, "" ); SocketClose( clnt->client ); - IVY_LIST_EACH_SAFE( clnt->msg_send, msg, msg_next ) - { - free( msg->str_regexp ); - IvyBindingFree( msg->bind ); - } IVY_LIST_EMPTY( clnt->msg_send ); } IVY_LIST_EMPTY( clients ); - /* destruction de mes bindings */ - hash_search( msg_recv, RemoveBinding); - hash_destroy( msg_recv ); - free( applicationUniqueId ); + /* destruction des sockets serveur et supervision */ SocketServerClose( server ); SocketClose( broadcast ); } -static int ClientCall (IvyClientPtr clnt, const char *message) +static int MsgCall (const char *message, MsgSndPtr msg, IvyClientPtr client) +{ + int waiting = 0; + static IvyBuffer buffer = { NULL, 0, 0 }; /* Use satic mem to eliminate multiple call to malloc /free */ + int err; + int index; + int arglen; + const char *arg; + + int rc= IvyBindingExec( msg->binding, message ); + + if (rc<1) return 0; /* no match */ + + TRACE( "Sending message id=%d '%s'\n",msg->id,message); + + buffer.offset = 0; + // il faut essayer d'envoyer le message en une seule fois sur la socket + // pour eviter au maximun de passer dans le select plusieur fois par message du protocole Ivy + // pour eviter la latence ( PB de perfo detecte par ivyperf ping roudtrip ) + err = make_message_var( &buffer, "%d %d" ARG_START ,Msg, msg->id); + + TRACE( "Send matching args count %d\n",rc); + + for( index=1; index < rc ; index++ ) + { + IvyBindingMatch( msg->binding, message, index, &arglen, & arg ); + err = make_message_var( &buffer, "%.*s" ARG_END , arglen, arg ); + } + err = make_message_var( &buffer, "\n"); + waiting = SocketSendRaw(client->client, buffer.data , buffer.offset); + if ( waiting ) + fprintf(stderr, "Ivy: Slow client : %s\n", client->app_name ); + return 1; +} + + +static int +ClientCall (IvyClientPtr clnt, const char *message) { MsgSndPtr msg; int match_count = 0; - /* for simple binding message syntax msg arg1=val1 arg2=val2 ... argn=valn */ - IvyBindingParseMessage( message ); /* recherche dans la liste des requetes recues de ce client */ IVY_LIST_EACH (clnt->msg_send, msg) { - match_count+= MsgSendCallTo (clnt->client, message, msg ); + match_count+= MsgCall (message, msg, clnt); } return match_count; } - static int CheckConnected( IvyClientPtr clnt ) { IvyClientPtr client; struct in_addr *addr1; struct in_addr *addr2; - /* TODO check multiple instance of the same application name */ - if ( clnt->app_port == 0 ) /* Old Ivy Protocol Dont check */ return 0; /* recherche dans la liste des clients de la presence de clnt */ - /* TODO check based on appid not on the copule host:port */ IVY_LIST_EACH( clients, client ) { /* client different mais port identique */ @@ -378,193 +250,140 @@ static int CheckConnected( IvyClientPtr clnt ) if ( addr1->s_addr == addr2->s_addr ) return 1; } + /* client different mais applicationID identique */ + /* TODO est-ce utile ??? verif dans UDP + if ( (client != clnt) && (clnt->app_id == client->app_id) ) + { + return 1; + } + */ } return 0; } -static char* Receive( Client client, void *data, char *message, unsigned int len ) +static void Receive( Client client, void *data, char *line ) { IvyClientPtr clnt; - int id; - unsigned short len_args; + int err,id; MsgSndPtr snd; MsgRcvPtr rcv; - IvyArgument arguments; + int argc = 0; + char *argv[MAX_MATCHING_ARGS]; + char *arg; int kind_of_msg = Bye; IvyBinding bind; - char *ptr_end; - void *args =NULL; - char *str_regexp; - int adv_buffer; - - ptr_end = message; - - if ( len < 6 ) return NULL; /* incomplete message */ - kind_of_msg = ntohs( *((unsigned short *) ptr_end)++ ); - id = ntohs( *((unsigned short *) ptr_end)++ ); - len_args = ntohs( *((unsigned short *) ptr_end)++ ); - - if ( len_args ) - { - if ( len < (6 + len_args) ) return NULL; /* incomplete message */ - args = ptr_end; - ptr_end += len_args; - } -#ifdef DEBUG - printf("Receive Message type=%d id=%d arg=%.*s\n", kind_of_msg, id, len_args, (char*)args); -#endif //DEBUG + const char *errbuf; + int erroffset; + err = sscanf( line ,"%d %d", &kind_of_msg, &id ); + arg = strstr( line , ARG_START ); + if ( (err != 2) || (arg == 0) ) + { + printf("Quitting bad format %s\n", line); + MsgSendTo( client, Error, Error, "bad format request expected 'type id ...'" ); + MsgSendTo( client, Bye, 0, "" ); + SocketClose( client ); + return; + } + arg++; clnt = (IvyClientPtr)data; switch( kind_of_msg ) { case Bye: -#ifdef DEBUG - printf("Quitting Bye %.*s\n", len_args, (char*)args); -#endif //DEBUG + TRACE("Quitting %s\n", line); SocketClose( client ); break; case Error: - /*TODO Callback */ - fprintf (stderr, "Received error %d %.*s from %s\n", id, len_args, (char*)args, clnt->app_name); + printf ("Received error %d %s\n", id, arg); break; case AddRegexp: -#ifdef DEBUG - printf("AddRegexp id=%d exp='%.*s'\n", id, len_args, (char*)args); -#endif //DEBUG - if ( !IvyBindingFilter( IvyBindRegexp, len_args, args ) ) - { -#ifdef DEBUG - printf("Warning: regexp '%.*s' illegal, removing from %s\n",len_args,(char*)args,ApplicationName); -#endif //DEBUG - return ptr_end; - } - str_regexp = DupArg( len_args, args ); - - bind = IvyBindingCompile( IvyBindRegexp, str_regexp ); - if ( bind != NULL ) - { - IVY_LIST_ADD( clnt->msg_send, snd ) - if ( snd ) - { - snd->id = id; - snd->str_regexp = str_regexp; /* should be Freeed on remove */ - snd->bind = bind; - if ( application_bind_callback ) - { - (*application_bind_callback)( clnt, application_bind_data, IvyAddBind, snd->str_regexp ); - } - } - } - else - { - int offset; - const char *errbuf; - IvyBindingGetCompileError( &offset, &errbuf ); - MsgSendTo( client, Error, offset, strlen(errbuf), errbuf ); - free( str_regexp ); /* not used so Free it */ - } - - break; - case DelRegexp: -#ifdef DEBUG - printf("DelRegexp id=%d\n", id); -#endif //DEBUG - IVY_LIST_ITER( clnt->msg_send, snd, ( id != snd->id )); - if ( snd ) + TRACE("Regexp id=%d exp='%s'\n", id, arg); + + if ( !IvyBindingFilter( arg ) ) { - if ( application_bind_callback ) - { - (*application_bind_callback)( clnt, application_bind_data, IvyRemoveBind, snd->str_regexp ); - } - free( snd->str_regexp ); - IvyBindingFree( snd->bind ); - IVY_LIST_REMOVE( clnt->msg_send, snd ); - } - break; - case AddBinding: + TRACE("Warning: regexp '%s' illegal, removing from %s\n",arg,ApplicationName); -#ifdef DEBUG - printf("AddBinding id=%d exp='%.*s'\n", id, len_args, (char*)args); -#endif //DEBUG - if ( !IvyBindingFilter( IvyBindSimple, len_args, args ) ) - { -#ifdef DEBUG - printf("Warning: regexp '%.*s' illegal, removing from %s\n",len_args,(char*)args,ApplicationName); -#endif //DEBUG - return ptr_end; - } - str_regexp = DupArg( len_args, args ); - - bind = IvyBindingCompile( IvyBindSimple, str_regexp ); - if ( bind != NULL ) - { - IVY_LIST_ADD( clnt->msg_send, snd ) - if ( snd ) - { - snd->id = id; - snd->str_regexp = str_regexp; - snd->bind = bind; - if ( application_bind_callback ) + if ( application_bind_callback ) { - (*application_bind_callback)( clnt, application_bind_data, IvyAddBind, snd->str_regexp ); + (*application_bind_callback)( clnt, application_bind_data, id, arg, IvyFilterBind ); } - } + return; } - else + + bind = IvyBindingCompile( arg, & erroffset, & errbuf ); + if ( bind != NULL ) { - int offset; - const char *errbuf; - IvyBindingGetCompileError( &offset, &errbuf ); - MsgSendTo( client, Error, offset, strlen(errbuf), errbuf ); - free( str_regexp ); + // On teste si c'est un change regexp : changement de regexp d'une id existante + IVY_LIST_ITER( clnt->msg_send, snd, ( id != snd->id )); + if ( snd ) { + free (snd->str_regexp); + snd->str_regexp = strdup( arg ); + snd->binding = bind; + if ( application_bind_callback ) + { + (*application_bind_callback)( clnt, application_bind_data, id, snd->str_regexp, IvyChangeBind ); + } + } else { + IVY_LIST_ADD_START( clnt->msg_send, snd ) + snd->id = id; + snd->str_regexp = strdup( arg ); + snd->binding = bind; + if ( application_bind_callback ) + { + (*application_bind_callback)( clnt, application_bind_data, id, snd->str_regexp, IvyAddBind ); + } + IVY_LIST_ADD_END( clnt->msg_send, snd ) + + } } - + else + { + printf("Error compiling '%s', %s\n", arg, errbuf); + MsgSendTo( client, Error, erroffset, errbuf ); + } + break; - case DelBinding: -#ifdef DEBUG - printf("DelBinding id=%d\n", id); -#endif //DEBUG + case DelRegexp: + + TRACE("Regexp Delete id=%d\n", id); IVY_LIST_ITER( clnt->msg_send, snd, ( id != snd->id )); if ( snd ) { if ( application_bind_callback ) { - (*application_bind_callback)( clnt, application_bind_data, IvyRemoveBind, snd->str_regexp ); + (*application_bind_callback)( clnt, application_bind_data, id, snd->str_regexp, IvyRemoveBind ); } - free( snd->str_regexp ); - IvyBindingFree( snd->bind ); - + IvyBindingFree( snd->binding ); IVY_LIST_REMOVE( clnt->msg_send, snd ); } break; case StartRegexp: -#ifdef DEBUG - printf("Regexp Start id=%d Application='%.*s'\n", id, len_args, (char*)args); -#endif //DEBUG - clnt->app_name = DupArg( len_args, args ); + + TRACE("Regexp Start id=%d Application='%s'\n", id, arg); + + clnt->app_name = strdup( arg ); clnt->app_port = id; if ( CheckConnected( clnt ) ) { -#ifdef DEBUG - printf("Quitting already connected %.*s\n", len_args, (char*)args); -#endif //DEBUG + + TRACE("Quitting already connected %s\n", line); + IvySendError( clnt, 0, "Application already connected" ); SocketClose( client ); } break; case EndRegexp: -#ifdef DEBUG - printf("Regexp End id=%d\n", id); -#endif //DEBUG + TRACE("Regexp End id=%d\n", id); + if ( application_callback ) { (*application_callback)( clnt, application_user_data, IvyApplicationConnected ); @@ -574,94 +393,85 @@ static char* Receive( Client client, void *data, char *message, unsigned int len int count; count = ClientCall( clnt, ready_message ); -#ifdef DEBUG - printf(" Sendind ready message %d\n", count); -#endif //DEBUG - + TRACE(" Sendind ready message %d\n", count); } break; case Msg: -#ifdef DEBUG - printf("Message id=%d msg='%.*s'\n", id, len_args, (char*)args); -#endif //DEBUG - rcv = hash_lookup( msg_recv, id ); - if ( rcv && rcv->callback ) + TRACE("Message id=%d msg='%s'\n", id, arg); + + IVY_LIST_EACH( msg_recv, rcv ) + { + if ( id == rcv->id ) { - arguments = IvyArgumentDeserialize( len_args, args, &adv_buffer ); - -#ifdef DEBUG - printf("Calling id=%d for %s\n", id, rcv->regexp); -#endif - (*rcv->callback)( clnt, rcv->user_data, arguments ); - IvyArgumentFree( arguments ); /* TODO evy , suppress malloc/free on each callback */ - return ptr_end; + arg = nextArg( arg, ARG_END); + while ( arg ) + { + argv[argc++] = arg; + arg = nextArg( 0, ARG_END ); + } + TRACE("Calling id=%d argc=%d for %s\n", id, argc,rcv->regexp); + if ( rcv->callback ) (*rcv->callback)( clnt, rcv->user_data, argc, argv ); + return; } - else - printf("Callback Message id=%d not found!!!'\n", id); + } + printf("Callback Message id=%d not found!!!'\n", id); break; case DirectMsg: -#ifdef DEBUG - printf("Direct Message id=%d msg='%.*s'\n", id, len_args, (char*)args); -#endif //DEBUG + TRACE("Direct Message id=%d msg='%s'\n", id, arg); if ( direct_callback) - (*direct_callback)( clnt, direct_user_data, id, len_args, args ); + (*direct_callback)( clnt, direct_user_data, id, arg ); break; case Die: -#ifdef DEBUG - printf("Die Message\n"); -#endif //DEBUG + TRACE("Die Message\n"); if ( application_die_callback) (*application_die_callback)( clnt, application_die_user_data, id ); IvyCleanup(); exit(0); break; - case ApplicationId: -#ifdef DEBUG - printf("ApplicationId priority=%d appid='%.*s'\n", id, len_args, (char*)args); -#endif //DEBUG - clnt->app_id = DupArg( len_args, args ); - if ( id != clnt->priority ) - { - clnt->priority = id; - SortClients(); - } + + case Ping: + + TRACE("Ping Message\n"); + MsgSendTo( client, Pong, id, "" ); + break; + + case Pong: + + TRACE("Pong Message\n"); + printf("Receive unhandled Pong message (ivy-c not able to send ping)\n"); break; + default: - printf("Receive unhandled message %d\n", kind_of_msg); + printf("Receive unhandled message %s\n", line); break; } - return ptr_end; -} -static BOOL SendRegexp(HASHKEYTYPE key, void *data, va_list args) -{ - Client client = va_arg( args, Client); - MsgRcvPtr msg = (MsgRcvPtr)data; - MsgSendTo( client, msg->type == IvyBindRegexp ? AddRegexp : AddBinding, msg->id, strlen(msg->regexp), msg->regexp); - return FALSE; /* iter throught all hash table */ + } -static IvyClientPtr SendService( Client client ) + +static IvyClientPtr SendService( Client client, const char *appname ) { IvyClientPtr clnt; - IVY_LIST_ADD( clients, clnt ) - if ( clnt ) - { - SocketKeepAlive ( client, 1 ); + MsgRcvPtr msg; + IVY_LIST_ADD_START( clients, clnt ) + clnt->msg_send = 0; clnt->client = client; - clnt->app_name = strdup("Unknown"); + clnt->app_name = strdup(appname); clnt->app_port = 0; - clnt->priority = DEFAULT_PRIORITY; - MsgSendTo( client, ApplicationId, applicationPriority, strlen(applicationUniqueId), applicationUniqueId ); - MsgSendTo( client, StartRegexp, ApplicationPort, strlen(ApplicationName), ApplicationName ); - hash_search( msg_recv, SendRegexp, client); - MsgSendTo( client, EndRegexp, 0, 0,""); - } + MsgSendTo( client, StartRegexp, ApplicationPort, ApplicationName); + IVY_LIST_EACH(msg_recv, msg ) + { + MsgSendTo( client, AddRegexp,msg->id,msg->regexp); + } + MsgSendTo( client, EndRegexp, 0, ""); + + IVY_LIST_ADD_END( clients, clnt ) return clnt; } @@ -682,14 +492,13 @@ static void ClientDelete( Client client, void *data ) #ifdef DEBUG /* probably bogus call, but this is for debug only anyway */ SocketGetRemoteHost( client, &remotehost, &remoteport ); - printf("Deconnexion de %s:%hu\n", remotehost, remoteport ); + TRACE("Deconnexion de %s:%hu\n", remotehost, remoteport ); #endif //DEBUG if ( clnt->app_name ) free( clnt->app_name ); - if ( clnt->app_id ) free( clnt->app_id ); IVY_LIST_EACH( clnt->msg_send, msg) { - IvyBindingFree( msg->bind ); + /*regfree(msg->regexp);*/ free( msg->str_regexp); } IVY_LIST_EMPTY( clnt->msg_send ); @@ -703,69 +512,36 @@ static void *ClientCreate( Client client ) char *remotehost; unsigned short remoteport; SocketGetRemoteHost( client, &remotehost, &remoteport ); - printf("Connexion de %s:%hu\n", remotehost, remoteport ); + TRACE("Connexion de %s:%hu\n", remotehost, remoteport ); #endif //DEBUG - return SendService (client); -} -/* Hello packet Send */ -static void IvySendHello(unsigned long mask) -{ - char *packet; - char *ptr; - int lenAppId; - int lenAppName; - int len; - lenAppId = strlen( applicationUniqueId ); - lenAppName = strlen( ApplicationName ); - len = 4*sizeof(unsigned short) + lenAppId + lenAppName; - packet = malloc( len ); - ptr = packet; - *((unsigned short *) ptr)++ = htons( VERSION ); - *((unsigned short *) ptr)++ = htons( ApplicationPort ); - *((unsigned short *) ptr)++ = htons( lenAppId ); - strncpy( ptr, applicationUniqueId , lenAppId); - ptr += lenAppId; - *((unsigned short *) ptr)++ = htons( lenAppName ); - strncpy( ptr, ApplicationName , lenAppName); - - SocketSendBroadcast(broadcast, mask, SupervisionPort, packet,len ); - free( packet ); + + return SendService (client, "Unknown"); } -/* Hello packet Receive */ -static char* BroadcastReceive( Client client, void *data, char *message, unsigned int len) + +static void BroadcastReceive( Client client, void *data, char *line ) { Client app; - unsigned short version; + int err; + int version; unsigned short serviceport; - char appname[1024]; - char appid[1024]; - unsigned short len_appid; - unsigned short len_appname; + char appid[2048]; + char appname[2048]; #ifdef DEBUG unsigned short remoteport; char *remotehost = 0; #endif - - char *ptr_end; - ptr_end = message; - - if ( len < 6 ) return NULL; /* incomplete message */ - - version = ntohs( *((unsigned short *) ptr_end)++ ); - serviceport = ntohs( *((unsigned short *) ptr_end)++ ); - len_appid = ntohs( *((unsigned short *) ptr_end)++ ); - if ( len < (6 +len_appid) ) return NULL; /* incomplete message */ - - strncpy( appid , ptr_end, len_appid ); - appid[ len_appid ] = '\0'; - ptr_end += len_appid; - len_appname = ntohs( *((unsigned short *) ptr_end)++ ); - if ( len < (6 +len_appid + len_appname) ) return NULL; /* incomplete message */ - - strncpy( appname , ptr_end, len_appname ); - appname[ len_appname ] = '\0'; - ptr_end += len_appname; - + memset( appid, 0, sizeof( appid ) ); + memset( appname, 0, sizeof( appname ) ); + err = sscanf (line,"%d %hu %s %[^\n]", &version, &serviceport, appid, appname); + if ( err < 2 ) { + /* ignore the message */ + unsigned short remoteport; + char *remotehost; + SocketGetRemoteHost (client, &remotehost, &remoteport ); + printf (" Bad supervision message, expected 'version port' from %s:%d\n", + remotehost, remoteport); + return; + } if ( version != VERSION ) { /* ignore the message */ unsigned short remoteport; @@ -773,116 +549,82 @@ static char* BroadcastReceive( Client client, void *data, char *message, unsigne SocketGetRemoteHost (client, &remotehost, &remoteport ); fprintf (stderr, "Bad Ivy version, expected %d and got %d from %s:%d\n", VERSION, version, remotehost, remoteport); - return ptr_end; + return; } - /* check if we received our own message */ - if (strcmp( appid,applicationUniqueId )== 0) - return ptr_end; + /* check if we received our own message. SHOULD ALSO TEST THE HOST */ + if ( strcmp( appid , ApplicationID) ==0 ) return; + if (serviceport == ApplicationPort) return; #ifdef DEBUG SocketGetRemoteHost (client, &remotehost, &remoteport ); - printf(" Broadcast de %s:%hu port %hu %s %s\n", remotehost, remoteport, serviceport, appname, appid ); + TRACE(" Broadcast de %s:%hu port %hu\n", remotehost, remoteport, serviceport ); #endif //DEBUG - /* check if already the same name on the bus */ - if ( strcmp( appname,ApplicationName )== 0) - { - /* TODO rize some callback ? */ - fprintf(stderr,"!!! Warning a another instance of %s is arriving on the Bus !!!\n", ApplicationName ); - } /* connect to the service and send the regexp */ app = SocketConnectAddr(SocketGetRemoteAddr(client), serviceport, 0, Receive, ClientDelete ); if (app) { IvyClientPtr clnt; - clnt = SendService( app ); + clnt = SendService( app, appname ); SocketSetData( app, clnt); } - return ptr_end; +} +static unsigned long currentTime() +{ +#define MILLISEC 1000 + unsigned long current; +#ifdef WIN32 + current = GetTickCount(); +#else + struct timeval stamp; + gettimeofday( &stamp, NULL ); + current = stamp.tv_sec * MILLISEC + stamp.tv_usec/MILLISEC; +#endif + return current; } +static const char * GenApplicationUniqueIdentifier() +{ + static char appid[2048]; + unsigned long curtime; + curtime = currentTime(); + srand( curtime ); + sprintf(appid,"%d:%lu:%d",rand(),curtime,ApplicationPort); + return appid; +} void IvyInit (const char *appname, const char *ready, IvyApplicationCallback callback, void *data, IvyDieCallback die_callback, void *die_data ) { - char hostname[1024]; - struct hostent *host; - IvyChannelInit(); + SocketInit(); - msg_recv = hash_create( 1024, FALSE ); - if ( ! msg_recv ) - { - fprintf(stderr,"IvyInit can't create Binding hash Table\n"); - exit(-1); - } ApplicationName = appname; application_callback = callback; application_user_data = data; application_die_callback = die_callback; application_die_user_data = die_data; ready_message = ready; - /* - * Initialize TCP port - */ - server = SocketServer (ANYPORT, ClientCreate, ClientDelete, Receive); - ApplicationPort = SocketServerGetPort (server); - /* get Host Ip address */ - if ( gethostname(hostname,sizeof(hostname)) < 0 ) - { - perror("gethostname"); - exit(-1); - } - host = gethostbyname( hostname ); - if ( ! host ) - { - perror("gethostbyname"); - exit(-1); - } - /* generate application UniqueID (timeStamp-Ipaddress-port*/ - /* TODO bug if multiple interface */ - applicationUniqueId = malloc(1024); - sprintf( applicationUniqueId , "%lu-%u%u%u%u-%d", - currentTime(), - (unsigned char)host->h_addr[0], - (unsigned char)host->h_addr[1], - (unsigned char)host->h_addr[2], - (unsigned char)host->h_addr[3], - ApplicationPort); - } -void IvyStop() +void IvySetBindCallback( IvyBindCallback bind_callback, void *bind_data ) { - IvyCleanup(); - IvyChannelStop(); + application_bind_callback=bind_callback; + application_bind_data=bind_data; } -void IvySetApplicationPriority( int priority ) +void IvySetFilter( int argc, const char **argv) { - int len; - IvyClientPtr clnt; - applicationPriority = priority; - if ( clients ) - { - /* Send to already connected clients */ - len = strlen(applicationUniqueId); - IVY_LIST_EACH (clients, clnt ) { - MsgSendTo( clnt->client, ApplicationId, applicationPriority, len, applicationUniqueId); - } - } -} + IvyBindingSetFilter( argc, argv ); + if ( getenv( "IVY_DEBUG_FILTER" )) debug_filter = 1; -void IvySetBindCallback(IvyBindCallback bind_callback, void *bind_data) -{ - application_bind_callback=bind_callback; - application_bind_data=bind_data; } -void IvySetMyMessagesStart( int argc, const char **argv) +void IvyStop (void) { - IvyBindingSetFilter( argc, argv ); + IvyChannelStop(); } + void IvyStart (const char* bus) { @@ -898,6 +640,13 @@ void IvyStart (const char* bus) /* + * Initialize TCP port + */ + server = SocketServer (ANYPORT, ClientCreate, ClientDelete, Receive); + ApplicationPort = SocketServerGetPort (server); + ApplicationID = GenApplicationUniqueIdentifier(); + + /* * Find network list as well as broadcast port * (we accept things like 123.231,123.123:2000 or 123.231 or :2000), * Initialize UDP port @@ -956,7 +705,7 @@ void IvyStart (const char* bus) if ( IN_MULTICAST( mask ) ) SocketAddMember (broadcast , mask ); - IvySendHello( mask ); + SocketSendBroadcast (broadcast, mask, SupervisionPort, "%d %hu %s %s\n", VERSION, ApplicationPort, ApplicationID, ApplicationName); numelem = 0; mask = 0xffffffff; } @@ -986,123 +735,117 @@ void IvyStart (const char* bus) ++p; } -#ifdef DEBUG - fprintf (stderr,"Listening on TCP:%hu\n",ApplicationPort); -#endif + TRACE ("Listening on TCP:%hu\n",ApplicationPort); } /* desabonnements */ -void IvyUnbindMsg (MsgRcvPtr msg) +void +IvyUnbindMsg (MsgRcvPtr msg) { IvyClientPtr clnt; /* Send to already connected clients */ IVY_LIST_EACH (clients, clnt ) { - MsgSendTo( clnt->client, DelRegexp,msg->id, 0, ""); + MsgSendTo( clnt->client, DelRegexp,msg->id, ""); } - hash_remove( msg_recv, msg->id ); + IVY_LIST_REMOVE( msg_recv, msg ); } /* demande de reception d'un message */ -static MsgRcvPtr IvyBind ( IvyBindingType typ, MsgCallback callback, void *user_data, const char *fmt_regex, va_list ap ) + +MsgRcvPtr +IvyBindMsg (MsgCallback callback, void *user_data, const char *fmt_regex, ... ) { - char *buffer = NULL; - int size = 0; + static IvyBuffer buffer = { NULL, 0, 0}; + va_list ap; static int recv_id = 0; IvyClientPtr clnt; MsgRcvPtr msg; - int len; - int MsgType = typ == IvyBindRegexp ? AddRegexp : AddBinding; - make_message( &buffer, &size, 0, fmt_regex, ap ); - + va_start (ap, fmt_regex ); + buffer.offset = 0; + make_message( &buffer, fmt_regex, ap ); + va_end (ap ); + + substituteInterval (&buffer); + /* add Msg to the query list */ - msg = malloc(sizeof(struct _msg_rcv)); - if (msg) { - msg->type = typ; + IVY_LIST_ADD_START( msg_recv, msg ) msg->id = recv_id++; - msg->regexp = buffer; + msg->regexp = strdup(buffer.data); msg->callback = callback; msg->user_data = user_data; - if ( !hash_add(msg_recv, msg->id, msg) ) - { - perror("IvyBindMsg can't hash_add Entry already exists!"); - exit(-1); - } - } - else - { - perror("IvyBindMsg can't allocate Binding"); - free ( buffer ); - exit(-1); - } - len = strlen(msg->regexp); + IVY_LIST_ADD_END( msg_recv, msg ) /* Send to already connected clients */ /* recherche dans la liste des requetes recues de mes clients */ IVY_LIST_EACH( clients, clnt ) { - MsgSendTo( clnt->client, MsgType,msg->id, len, msg->regexp); + MsgSendTo( clnt->client, AddRegexp,msg->id,msg->regexp); } return msg; } - -MsgRcvPtr IvyBindMsg (MsgCallback callback, void *user_data, const char *fmt_regex, ... ) +/* changement de regexp d'un bind existant precedement fait avec IvyBindMsg */ +MsgRcvPtr +IvyChangeMsg (MsgRcvPtr msg, const char *fmt_regex, ... ) { + static IvyBuffer buffer = { NULL, 0, 0}; va_list ap; - MsgRcvPtr msg; + IvyClientPtr clnt; va_start (ap, fmt_regex ); - msg = IvyBind ( IvyBindRegexp, callback, user_data, fmt_regex, ap ); + buffer.offset = 0; + make_message( &buffer, fmt_regex, ap ); va_end (ap ); - return msg; - -} -MsgRcvPtr IvyBindSimpleMsg( MsgCallback callback, void *user_data, const char *fmt_regex, ... ) -{ - va_list ap; - MsgRcvPtr msg; + substituteInterval (&buffer); - va_start (ap, fmt_regex ); - msg = IvyBind ( IvyBindSimple, callback, user_data, fmt_regex, ap ); - va_end (ap ); - return msg; + /* change Msg in the query list */ + msg->regexp = strdup(buffer.data); + /* Send to already connected clients */ + /* recherche dans la liste des requetes recues de mes clients */ + IVY_LIST_EACH( clients, clnt ) { + MsgSendTo( clnt->client, AddRegexp,msg->id,msg->regexp); + } + return msg; } +/* emmission d'un message avec formatage a la printf */ int IvySendMsg(const char *fmt, ...) { IvyClientPtr clnt; int match_count = 0; - char *buffer = NULL; /* Use satic mem to eliminate multiple call to malloc /free */ - int size = 0; /* donc non reentrant !!!! */ + static IvyBuffer buffer = { NULL, 0, 0}; /* Use satic mem to eliminate multiple call to malloc /free */ va_list ap; + if( fmt == 0 || strlen(fmt) == 0 ) return 0; va_start( ap, fmt ); - make_message( &buffer, &size, 0, fmt, ap ); + buffer.offset = 0; + make_message( &buffer, fmt, ap ); va_end ( ap ); /* recherche dans la liste des requetes recues de mes clients */ IVY_LIST_EACH (clients, clnt) { - match_count += ClientCall (clnt, buffer); + match_count += ClientCall (clnt, buffer.data); + } + TRACE_IF( match_count == 0, "Warning no recipient for %s\n",buffer.data); + /* si le message n'est pas emit et qu'il y a des filtres alors WARNING */ + if ( match_count == 0 && debug_filter ) + { + IvyBindindFilterCheck( buffer.data ); } -#ifdef DEBUG - if ( match_count == 0 ) printf( "Warning no recipient for %s\n",buffer); -#endif - free(buffer); return match_count; } void IvySendError( IvyClientPtr app, int id, const char *fmt, ... ) { - char *buffer = NULL; /* Use satic mem to eliminate multiple call to malloc /free */ - int size = 0; /* donc non reentrant !!!! */ + static IvyBuffer buffer = { NULL, 0, 0}; /* Use satic mem to eliminate multiple call to malloc /free */ va_list ap; va_start( ap, fmt ); - make_message( &buffer, &size, 0, fmt, ap ); + buffer.offset = 0; + make_message( &buffer, fmt, ap ); va_end ( ap ); - MsgSendTo( app->client, Error, id, strlen(buffer), buffer); - free(buffer); + MsgSendTo( app->client, Error, id, buffer.data); } void IvyBindDirectMsg( MsgDirectCallback callback, void *user_data) @@ -1111,14 +854,14 @@ void IvyBindDirectMsg( MsgDirectCallback callback, void *user_data) direct_user_data = user_data; } -void IvySendDirectMsg( IvyClientPtr app, int id, int len, void *msg ) +void IvySendDirectMsg( IvyClientPtr app, int id, char *msg ) { - MsgSendTo( app->client, DirectMsg, id, len, msg); + MsgSendTo( app->client, DirectMsg, id, msg); } void IvySendDieMsg( IvyClientPtr app ) { - MsgSendTo( app->client, Die, 0, 0, "" ); + MsgSendTo( app->client, Die, 0, "" ); } char *IvyGetApplicationName( IvyClientPtr app ) @@ -1134,12 +877,7 @@ char *IvyGetApplicationHost( IvyClientPtr app ) return SocketGetPeerHost (app->client ); else return 0; } -char *IvyGetApplicationId( IvyClientPtr app ) -{ - if ( app && app->app_id ) - return app->app_id; - else return 0; -} + void IvyDefaultApplicationCallback( IvyClientPtr app, void *user_data, IvyApplicationEvent event) { switch ( event ) { @@ -1154,14 +892,21 @@ void IvyDefaultApplicationCallback( IvyClientPtr app, void *user_data, IvyApplic break; } } -void IvyDefaultBindCallback( IvyClientPtr app, void *user_data, IvyBindEvent event, char* regexp ) +void IvyDefaultBindCallback( IvyClientPtr app, void *user_data, int id, char* regexp, IvyBindEvent event) { switch ( event ) { case IvyAddBind: - printf("Application: %s on %s add regexp %s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), regexp); + printf("Application: %s on %s add regexp %d : %s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), id, regexp); break; case IvyRemoveBind: - printf("Application: %s on %s remove regexp %s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), regexp); + printf("Application: %s on %s remove regexp %d :%s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), id, regexp); + break; + case IvyFilterBind: + printf("Application: %s on %s as been filtred regexp %d :%s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), id, regexp); + break; + case IvyChangeBind: + printf("Application: %s on %s change regexp %d : %s\n", IvyGetApplicationName( app ), IvyGetApplicationHost(app), id, regexp); + break; break; default: printf("Application: %s unkown event %d\n",IvyGetApplicationName( app ), event); @@ -1176,22 +921,23 @@ IvyClientPtr IvyGetApplication( char *name ) return app; } -char **IvyGetApplicationList() +char *IvyGetApplicationList(const char *sep) { - static char* applist[500]; + static char applist[4096]; /* TODO remove that ugly Thing */ IvyClientPtr app; - int appCount= 0; - memset( applist, 0 , sizeof( applist )); + applist[0] = '\0'; IVY_LIST_EACH( clients, app ) { - applist[appCount++]= app->app_name; + strcat( applist, app->app_name ); + strcat( applist, sep ); } return applist; } char **IvyGetApplicationMessages( IvyClientPtr app ) { - static char *messagelist[200]; +#define MAX_REGEXP 4096 + static char *messagelist[MAX_REGEXP+1];/* TODO remove that ugly Thing */ MsgSndPtr msg; int msgCount= 0; memset( messagelist, 0 , sizeof( messagelist )); @@ -1199,6 +945,53 @@ char **IvyGetApplicationMessages( IvyClientPtr app ) IVY_LIST_EACH( app->msg_send, msg ) { messagelist[msgCount++]= msg->str_regexp; + if ( msgCount >= MAX_REGEXP ) + { + fprintf(stderr,"Too Much expression(%d) for buffer\n",msgCount); + break; + } } return messagelist; } + +static void substituteInterval (IvyBuffer *src) +{ + // pas de traitement couteux s'il n'y a rien à interpoler + if (strstr (src->data, "(?I") == NULL) { + return; + } else { + char *curPos; + char *itvPos; + IvyBuffer dst = {NULL, 0, 0}; + dst.size = 8192; + dst.data = malloc (dst.size); + + curPos = src->data; + while ((itvPos = strstr (curPos, "(?I")) != NULL) { + // copie depuis la position courante jusqu'à l'intervalle + int lenCp, min,max; + char withDecimal; + lenCp = itvPos-curPos; + memcpy (&(dst.data[dst.offset]), curPos, lenCp); + curPos=itvPos; + dst.offset += 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 (&(dst.data[dst.offset]), dst.size-dst.offset, min, max, (withDecimal != 'i')); + dst.offset = strlen (dst.data); + + // consommation des caractères décrivant intervalle dans la chaine source + curPos = strstr (curPos, ")"); + curPos++; + } + strncat (dst.data, curPos, dst.size-dst.offset); + free (src->data); + src->data = dst.data; + } +} |