summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordamiano1998-04-09 13:55:38 +0000
committerdamiano1998-04-09 13:55:38 +0000
commit6d4a1d57836737d2e7ac8b4e3f19b0ba736e3981 (patch)
tree8c36fa43b5e19ce4332a3ee4c7408e89d04e8970 /src
parent6143ab5fb9ee7f32f6f779c06c176957fac8c3f2 (diff)
downloadivy-c-6d4a1d57836737d2e7ac8b4e3f19b0ba736e3981.zip
ivy-c-6d4a1d57836737d2e7ac8b4e3f19b0ba736e3981.tar.gz
ivy-c-6d4a1d57836737d2e7ac8b4e3f19b0ba736e3981.tar.bz2
ivy-c-6d4a1d57836737d2e7ac8b4e3f19b0ba736e3981.tar.xz
Move des fichiers dans src
Diffstat (limited to 'src')
-rw-r--r--src/Makefile27
-rw-r--r--src/bus.c693
-rw-r--r--src/bus.h75
-rw-r--r--src/list.h55
-rw-r--r--src/socket.c667
-rw-r--r--src/socket.h87
-rw-r--r--src/testbus.c190
-rw-r--r--src/timer.c160
-rw-r--r--src/timer.h18
9 files changed, 1972 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..c4e6a73
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,27 @@
+XTINC =
+CC=gcc
+OBJ = timer.o socket.o bus.o
+GOBJ = timer.o socket.o gbus.o
+XTOBJ = timer.o xtsocket.o bus.o
+
+all: libbus.a libgbus.a libxtbus.a testbus
+
+gbus.o: bus.c
+ $(CC) -DGNU_REGEXP -c $(CFLAGS) -o gbus.o bus.c
+
+xtsocket.o: socket.c
+ $(CC) -DXTMAINLOOP $(XTINC) -c $(CFLAGS) -o xtsocket.o socket.c
+
+testbus: testbus.o $(OBJ)
+ $(CC) -o testbus testbus.o $(OBJ)
+
+libbus.a: $(OBJ)
+ ar q libbus.a $(OBJ)
+
+libgbus.a: $(GOBJ)
+ ar q libgbus.a $(GOBJ)
+
+libxtbus.a: $(XTOBJ)
+ ar q libxtbus.a $(XTOBJ)
+
+
diff --git a/src/bus.c b/src/bus.c
new file mode 100644
index 0000000..18a5a67
--- /dev/null
+++ b/src/bus.c
@@ -0,0 +1,693 @@
+/*
+ *
+ * $Id$
+ */
+#include <stdlib.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <regex.h>
+
+#include <fcntl.h>
+
+
+#include "socket.h"
+#include "list.h"
+#include "bus.h"
+
+#define VERSION 3
+
+#define MAX_MATCHING_ARGS 20
+
+#define ARG_START "\002"
+#define ARG_END "\003"
+
+
+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 */
+ StartRegexp, /* debut des expressions */
+ DirectMsg, /* message direct a destination de l'appli */
+ Die /* demande de terminaison de l'appli */
+
+}MsgType;
+
+
+typedef struct _msg_snd *MsgSndPtr;
+
+struct _msg_rcv { /* requete d'emission d'un client */
+ MsgRcvPtr next;
+ int id;
+ const char *regexp; /* regexp du message a recevoir */
+ MsgCallback callback; /* callback a declanche a la reception */
+ void *user_data; /* stokage d'info client */
+};
+
+
+struct _msg_snd { /* requete de reception d'un client */
+ MsgSndPtr next;
+ int id;
+ char *str_regexp; /* la regexp sous forme inhumaine */
+ regex_t regexp; /* la regexp sous forme machine */
+};
+
+struct _clnt_lst {
+ BusClientPtr next;
+ Client client; /* la socket client */
+ MsgSndPtr msg_send; /* liste des requetes recues */
+ char *app_name; /* nom de l'application */
+ unsigned short app_port; /* port de l'application */
+ };
+
+/* numero de port TCP en mode serveur */
+static unsigned short ApplicationPort;
+
+/* numero de port UDP */
+static unsigned short SupervisionPort;
+
+/* client pour la socket supervision */
+static Client broadcast;
+
+static const char *ApplicationName = NULL;
+
+/* classes de messages emis par l'application utilise pour le filtrage */
+static int messages_classes_count = 0;
+static char **messages_classes = NULL;
+
+/* callback appele sur reception d'un message direct */
+static MsgDirectCallback direct_callback = NULL;
+static *direct_user_data = NULL;
+
+/* callback appele sur changement d'etat d'application */
+static BusApplicationCallback application_callback;
+static *application_user_data = NULL;
+
+/* callback appele sur demande de terminaison d'application */
+static BusDieCallback application_die_callback;
+static *application_die_user_data = NULL;
+
+/* liste des messages a recevoir */
+static MsgRcvPtr msg_recv = NULL;
+
+
+/* liste des clients connectes */
+static BusClientPtr clients = NULL;
+
+static const char *ready_message = NULL;
+
+static void MsgSendTo( Client client,MsgType msgtype, int id, const char *message )
+{
+SocketSend( client, "%d %d" ARG_START "%s\n",msgtype,id,message);
+}
+static void BusCleanup()
+{
+BusClientPtr clnt;
+
+ /* destruction des connexion clients */
+ LIST_EACH( clients, clnt )
+ {
+ /* on dit au revoir */
+ MsgSendTo( clnt->client, Bye, 0, "" );
+ SocketClose( clnt->client );
+ LIST_EMPTY( clnt->msg_send );
+ }
+ LIST_EMPTY( clients );
+
+}
+static int MsgCall( const char *message, MsgSndPtr msg, Client client )
+{
+ regmatch_t match[MAX_MATCHING_ARGS+1];
+#ifdef GNU_REGEXP
+ regmatch_t* p;
+#else
+ unsigned int i;
+#endif
+
+ if (regexec(&msg->regexp, message, MAX_MATCHING_ARGS, match, 0)==0) {
+#ifdef DEBUG
+ printf( "Sending message id=%d '%s'\n",msg->id,message);
+#endif
+ SocketSend( client, "%d %d" ARG_START ,Msg, msg->id);
+
+#ifdef DEBUG
+ printf( "Send matching args count %d\n",msg->regexp.re_nsub);
+#endif //DEBUG
+
+#ifdef GNU_REGEXP
+ p = &match[1];
+ while ( p->rm_so != -1 ) {
+ SocketSend( client, "%.*s" ARG_END , p->rm_eo - p->rm_so,
+ message + p->rm_so);
+ ++p;
+ }
+#else
+ for ( i = 1; i < msg->regexp.re_nsub+1; i ++ )
+ {
+ if ( match[i].rm_so != -1 )
+ {
+#ifdef DEBUG
+ printf( "Send matching arg%d %d %d\n",i,match[i].rm_so , match[i].rm_eo);
+ printf( "Send matching arg%d %.*s\n",i,match[i].rm_eo - match[i].rm_so,
+ message + match[i].rm_so);
+#endif
+ SocketSend( client, "%.*s" ARG_END ,match[i].rm_eo - match[i].rm_so,
+ message + match[i].rm_so);
+ }
+ else
+ {
+ SocketSend( client, ARG_END );
+#ifdef DEBUG
+ printf( "Send matching arg%d VIDE\n",i);
+#endif //DEBUG
+ }
+ }
+#endif
+
+ SocketSend( client, "\n");
+ return 1;
+ }
+ return 0;
+}
+
+int ClientCall( BusClientPtr clnt, const char *message )
+{
+MsgSndPtr msg;
+int match_count = 0;
+ /* recherche dans la liste des requetes recues de ce client */
+ LIST_EACH( clnt->msg_send, msg )
+ {
+ match_count+= MsgCall( message, msg, clnt->client );
+ }
+ return match_count;
+}
+static int CheckRegexp(char *exp)
+{
+ /* accepte tout par default */
+ int i;
+ int regexp_ok = 1;
+ if ( *exp =='^' && messages_classes_count !=0 )
+ {
+ regexp_ok = 0;
+ for ( i = 0 ; i < messages_classes_count; i++ )
+ {
+ if (strncmp( messages_classes[i], exp+1, strlen( messages_classes[i] )) == 0)
+ return 1;
+ }
+ }
+ return regexp_ok;
+}
+static int CheckConnected( BusClientPtr clnt )
+{
+BusClientPtr client;
+struct in_addr *addr1;
+struct in_addr *addr2;
+ if ( clnt->app_port == 0 )
+ return 0;
+ /* recherche dans la liste des clients de la presence de clnt */
+ LIST_EACH( clients, client )
+ {
+ /* client different mais port identique */
+ if ( (client != clnt) && (clnt->app_port == client->app_port) )
+ {
+ /* et meme machine */
+ addr1 = SocketGetRemoteAddr( client->client );
+ addr2 = SocketGetRemoteAddr( clnt->client );
+ if ( addr1->s_addr == addr2->s_addr )
+ return 1;
+ }
+
+ }
+ return 0;
+}
+static void Receive( Client client, void *data, char *line )
+{
+ BusClientPtr clnt;
+ int err,id,reg;
+ MsgSndPtr snd;
+ MsgRcvPtr rcv;
+ int argc = 0;
+ char *argv[MAX_MATCHING_ARGS];
+ char *arg;
+ int kind_of_msg = Bye;
+ regex_t regexp;
+
+ err = sscanf( line ,"%d %d", &kind_of_msg, &id );
+ arg = strstr( line , ARG_START );
+ if ( (err != 2) || (arg == NULL) )
+ {
+ 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 = (BusClientPtr)data;
+ switch( kind_of_msg )
+ {
+ case Bye:
+
+#ifdef DEBUG
+ printf("Quitting %s\n", line);
+#endif //DEBUG
+
+ SocketClose( client );
+ break;
+ case Error:
+ printf("Receive error %d %s\n", id, arg);
+ break;
+ case AddRegexp:
+
+#ifdef DEBUG
+ printf("Regexp id=%d exp='%s'\n", id, arg);
+#endif //DEBUG
+ if ( !CheckRegexp( arg ) )
+ {
+#ifdef DEBUG
+ printf("Warning exp='%s' can't match removing from %s\n",arg,ApplicationName);
+#endif //DEBUG
+ return;
+ }
+ reg = regcomp(&regexp, arg, REG_ICASE|REG_EXTENDED);
+ if ( reg == 0 )
+ {
+ LIST_ADD( clnt->msg_send, snd )
+ if ( snd )
+ {
+ snd->id = id;
+ snd->str_regexp = strdup( arg );
+ snd->regexp = regexp;
+ }
+ }
+ else
+ {
+ char errbuf[4096];
+ regerror (reg, &regexp, errbuf, 4096);
+ printf("Error compiling '%s', %s\n",arg,errbuf);
+ MsgSendTo( client, Error, reg, errbuf );
+ }
+ break;
+ case DelRegexp:
+
+#ifdef DEBUG
+ printf("Regexp Delete id=%d\n", id);
+#endif //DEBUG
+
+ LIST_ITER( clnt->msg_send, snd, ( id != snd->id ));
+ if ( snd )
+ {
+ free( snd->str_regexp );
+ LIST_REMOVE( clnt->msg_send, snd );
+ }
+ break;
+ case StartRegexp:
+
+#ifdef DEBUG
+ printf("Regexp Start id=%d App='%s'\n", id, arg);
+#endif //DEBUG
+ clnt->app_name = strdup( arg );
+ clnt->app_port = id;
+ if ( CheckConnected( clnt ) )
+ {
+#ifdef DEBUG
+ printf("Quitting already connected %s\n", line);
+#endif //DEBUG
+ SendError( clnt, 0, "Application already connected" );
+ SocketClose( client );
+ }
+ break;
+ case EndRegexp:
+
+#ifdef DEBUG
+ printf("Regexp End id=%d\n", id);
+#endif //DEBUG
+ if ( application_callback )
+ {
+ (*application_callback)( clnt, application_user_data, BusApplicationConnected );
+ }
+ if ( ready_message )
+ {
+ int count;
+ count = ClientCall( clnt, ready_message );
+
+#ifdef DEBUG
+ printf(" Sendind ready message %d\n", count);
+#endif //DEBUG
+
+ }
+ break;
+ case Msg:
+
+#ifdef DEBUG
+ printf("Message id=%d msg='%s'\n", id, arg);
+#endif //DEBUG
+
+ LIST_EACH( msg_recv, rcv )
+ {
+ if ( id == rcv->id )
+ {
+ arg = strtok( arg, ARG_END);
+ while ( arg )
+ {
+ argv[argc++] = arg;
+ arg = strtok( NULL, ARG_END );
+ }
+#ifdef DEBUG
+ printf("Calling id=%d argc=%d for %s\n", id, argc,rcv->regexp);
+#endif
+ if ( rcv->callback ) (*rcv->callback)( clnt, rcv->user_data, argc, argv );
+ return;
+ }
+ }
+ printf("Callback Message id=%d not found!!!'\n", id);
+ break;
+ case DirectMsg:
+
+#ifdef DEBUG
+ printf("Direct Message id=%d msg='%s'\n", id, arg);
+#endif //DEBUG
+
+ if ( direct_callback)
+ (*direct_callback)( clnt, direct_user_data, id, arg );
+ break;
+
+ case Die:
+
+#ifdef DEBUG
+ printf("Die Message\n",);
+#endif //DEBUG
+
+ if ( application_die_callback)
+ (*application_die_callback)( clnt, application_die_user_data, id );
+ BusCleanup();
+ exit(0);
+ break;
+
+ default:
+ printf("Receive unhandled message %s\n", line);
+ break;
+ }
+
+}
+
+static BusClientPtr SendService( Client client )
+{
+ BusClientPtr clnt;
+ MsgRcvPtr msg;
+ LIST_ADD( clients, clnt )
+ if ( clnt )
+ {
+ clnt->msg_send = NULL;
+ clnt->client = client;
+ clnt->app_name = strdup("Unknown");
+ clnt->app_port = 0;
+ MsgSendTo( client, StartRegexp, ApplicationPort, ApplicationName);
+ LIST_EACH(msg_recv, msg )
+ {
+ MsgSendTo( client, AddRegexp,msg->id,msg->regexp);
+ }
+ MsgSendTo( client, EndRegexp, 0, "");
+ }
+ return clnt;
+}
+
+static void ClientDelete( Client client, void *data )
+{
+ BusClientPtr clnt;
+ MsgSndPtr msg;
+ char *remotehost;
+ unsigned short remoteport;
+ clnt = (BusClientPtr)data;
+ if ( application_callback )
+ {
+ (*application_callback)( clnt, application_user_data, BusApplicationDisconnected );
+ }
+ SocketGetRemote( client, &remotehost, &remoteport );
+
+#ifdef DEBUG
+ printf("Deconnexion de %s:%hu\n", remotehost, remoteport );
+#endif //DEBUG
+
+ if ( clnt->app_name ) free( clnt->app_name );
+ LIST_EACH( clnt->msg_send, msg)
+ {
+ /*regfree(msg->regexp);*/
+ free( msg->str_regexp);
+ }
+ LIST_EMPTY( clnt->msg_send );
+ LIST_REMOVE( clients, clnt );
+}
+
+static void *ClientCreate( Client client )
+{
+ char *remotehost;
+ unsigned short remoteport;
+ SocketGetRemote( client, &remotehost, &remoteport );
+
+#ifdef DEBUG
+ printf("Connexion de %s:%hu\n", remotehost, remoteport );
+#endif //DEBUG
+
+ return SendService( client );
+}
+
+static void BroadcastReceive( Client client, void *data, char *line )
+{
+ Client app;
+ char *remotehost;
+ int err;
+ int version;
+ unsigned short remoteport;
+ unsigned short serviceport;
+ SocketGetRemote( client, &remotehost, &remoteport );
+
+ err = sscanf(line,"%d %hu",&version, &serviceport);
+ if ( err != 2 )
+ {
+ /* ignore the message */
+ printf(" Bad Supervision message expected 'version port' from %s:%d\n",remotehost, remoteport);
+ return;
+ }
+ if ( version != VERSION )
+ {
+ /* ignore the message */
+ printf(" Bad Bus verion number expected %d receive %d from %s:%d\n", VERSION,version,remotehost, remoteport);
+ return;
+ }
+ /* check if we receive our own message
+ should test also the host */
+ if ( serviceport == ApplicationPort ) return;
+
+#ifdef DEBUG
+ printf(" Broadcast de %s:%hu port %hu\n", remotehost, remoteport, serviceport );
+#endif //DEBUG
+
+ /* connect to the service and send the regexp */
+ app = SocketConnectAddr(SocketGetRemoteAddr(client), serviceport, NULL, Receive, ClientDelete );
+ if ( app )
+ {
+ BusClientPtr clnt;
+ clnt = SendService( app );
+ SocketSetData( app, clnt);
+ }
+}
+void BusInit(const char *AppName, unsigned short busnumber, const char *ready,
+ BusApplicationCallback callback, void *data,
+ BusDieCallback die_callback, void *die_data
+ )
+{
+ ChannelInit();
+
+ ApplicationName = AppName;
+ SupervisionPort = busnumber;
+ application_callback = callback;
+ application_user_data = data;
+ application_die_callback = die_callback;
+ application_die_user_data = die_data;
+ ready_message = ready;
+ ApplicationPort = SocketServer( ANYPORT, ClientCreate, ClientDelete, Receive );
+ broadcast = SocketBroadcastCreate( SupervisionPort, NULL, BroadcastReceive );
+
+}
+
+void BusClasses( int argc, char **argv)
+{
+ messages_classes_count = argc;
+ messages_classes = argv;
+}
+
+void BusStart()
+{
+
+ SocketSendBroadcast( broadcast, 143 << 24 | 196 << 16 | 1 << 8 | 255, SupervisionPort, "%d %hu\n", VERSION, ApplicationPort);
+ SocketSendBroadcast( broadcast, 143 << 24 | 196 << 16 | 2 << 8 | 255, SupervisionPort, "%d %hu\n", VERSION, ApplicationPort);
+
+ fprintf(stderr,"Server Ready TCP:%hu\n",ApplicationPort);
+}
+void BusLoop()
+{
+ ChannelMainLoop(NULL);
+}
+/* desabonnements */
+void UnbindMsg( MsgRcvPtr msg )
+{
+BusClientPtr clnt;
+ /* Send to already connected clients */
+ LIST_EACH( clients, clnt )
+ {
+ MsgSendTo( clnt->client, DelRegexp,msg->id, "");
+ }
+}
+
+/* demande de reception d'un message */
+static MsgRcvPtr _BindMsg( MsgCallback callback, void *user_data, const char *regexp )
+{
+ static int recv_id = 0;
+ BusClientPtr clnt;
+ MsgRcvPtr msg;
+ /* add Msg to the query list */
+ LIST_ADD( msg_recv, msg );
+ if ( msg )
+ {
+ msg->id = recv_id++;
+ msg->regexp = strdup(regexp);
+ msg->callback = callback;
+ msg->user_data = user_data;
+ }
+ /* Send to already connected clients */
+ /* recherche dans la liste des requetes recues de mes clients */
+ LIST_EACH( clients, clnt )
+ {
+ MsgSendTo( clnt->client, AddRegexp,msg->id,msg->regexp);
+ }
+ return msg;
+}
+MsgRcvPtr BindMsg( MsgCallback callback, void *user_data, const char *fmt_regex, ... )
+{
+ char buffer[4096];
+ va_list ap;
+
+ va_start( ap, fmt_regex );
+ vsprintf( buffer, fmt_regex, ap );
+ va_end ( ap );
+ return _BindMsg( callback, user_data, buffer );
+}
+static int _SendMsg( const char *message )
+{
+BusClientPtr clnt;
+int match_count = 0;
+
+ /* recherche dans la liste des requetes recues de mes clients */
+ LIST_EACH( clients, clnt )
+ {
+ match_count+= ClientCall( clnt, message );
+ }
+#ifdef DEBUG
+ if ( match_count == 0 ) printf( "Warning no recipient for %s\n",message);
+#endif
+ return match_count;
+}
+int SendMsg(const char *fmt, ...)
+{
+ char buffer[4096];
+ va_list ap;
+
+ va_start( ap, fmt );
+ vsprintf( buffer, fmt, ap );
+ va_end ( ap );
+ return _SendMsg( buffer );
+}
+void SendError( BusClientPtr app, int id, const char *fmt, ... )
+{
+ char buffer[4096];
+ va_list ap;
+
+ va_start( ap, fmt );
+ vsprintf( buffer, fmt, ap );
+ va_end ( ap );
+ MsgSendTo( app->client, Error, id, buffer);
+}
+void BindDirectMsg( MsgDirectCallback callback, void *user_data)
+{
+direct_callback = callback;
+direct_user_data = user_data;
+}
+void SendDirectMsg( BusClientPtr app, int id, char *msg )
+{
+ MsgSendTo( app->client, DirectMsg, id, msg);
+}
+
+void SendDieMsg( BusClientPtr app )
+{
+ MsgSendTo( app->client, Die, 0, "" );
+}
+
+char *GetApplicationName( BusClientPtr app )
+{
+ if ( app && app->app_name )
+ return app->app_name;
+ else return "Unknown";
+}
+
+char *GetApplicationHost( BusClientPtr app )
+{
+ if ( app && app->client )
+ return SocketGetPeerHost( app->client );
+ else return NULL;
+}
+
+void BusDefaultApplicationCallback( BusClientPtr app, void *user_data, BusApplicationEvent event)
+{
+ switch ( event ) {
+ case BusApplicationConnected:
+ printf("Application: %s ready on %s\n",GetApplicationName( app ), GetApplicationHost(app));
+ break;
+ case BusApplicationDisconnected:
+ printf("Application: %s bye on %s\n",GetApplicationName( app ), GetApplicationHost(app));
+ break;
+ default:
+ printf("Application: %s unkown event %d\n",GetApplicationName( app ), event);
+ break;
+ }
+}
+
+BusClientPtr GetApplication( char *name )
+{
+ BusClientPtr app = NULL;
+ LIST_ITER( clients, app, strcmp(name, app->app_name) != 0 );
+ return app;
+}
+
+char *GetApplicationList()
+{
+ static char applist[4096];
+ BusClientPtr app;
+ applist[0] = '\0';
+ LIST_EACH( clients, app )
+ {
+ strcat( applist, app->app_name );
+ strcat( applist, " " );
+ }
+ return applist;
+}
+
+char **GetApplicationMessages( BusClientPtr app )
+{
+ static char *messagelist[200];
+ MsgSndPtr msg;
+ int msgCount= 0;
+ memset( messagelist, 0 , sizeof( messagelist ));
+ /* recherche dans la liste des requetes recues de ce client */
+ LIST_EACH( app->msg_send, msg )
+ {
+ messagelist[msgCount++]= msg->str_regexp;
+ }
+ return messagelist;
+}
diff --git a/src/bus.h b/src/bus.h
new file mode 100644
index 0000000..b0971a3
--- /dev/null
+++ b/src/bus.h
@@ -0,0 +1,75 @@
+#ifndef _BUS_H
+#define _BUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* numero par default du bus */
+
+#define DEFAULT_BUS 2010
+
+typedef struct _clnt_lst *BusClientPtr;
+
+typedef enum { BusApplicationConnected, BusApplicationDisconnected } BusApplicationEvent;
+
+extern void BusDefaultApplicationCallback( BusClientPtr app, void *user_data, BusApplicationEvent event ) ;
+/* callback callback appele sur connection deconnection d'une appli */
+typedef void (*BusApplicationCallback)( BusClientPtr app, void *user_data, BusApplicationEvent event ) ;
+/* callback appele sur reception de die */
+typedef void (*BusDieCallback)( BusClientPtr app, void *user_data, int id ) ;
+
+/* callback appele sur reception de messages normaux */
+typedef void (*MsgCallback)( BusClientPtr app, void *user_data, int argc, char **argv ) ;
+/* callback appele sur reception de messages directs */
+typedef void (*MsgDirectCallback)( BusClientPtr app, void *user_data, int id, char *msg ) ;
+
+/* identifiant d'une expression reguliere ( Bind/Unbind ) */
+typedef struct _msg_rcv *MsgRcvPtr;
+
+/* filtrage des regexps */
+void BusClasses( int argc, char **argv);
+
+void BusInit(
+ const char *AppName, /* nom de l'application */
+ unsigned short busnumber, /* numero de bus ( port UDP ) */
+ const char *ready, /* ready Message peut etre NULL */
+ BusApplicationCallback callback, /* callback appele sur connection deconnection d'une appli */
+ void *data, /* user data passe au callback */
+ BusDieCallback die_callback, /* last change callback before die */
+ void *die_data ); /* user data */
+
+void BusStart(); /* emission du bonjour */
+void BusLoop(); /* boucle principale */
+
+/* query sur les applications connectees */
+char *GetApplicationName( BusClientPtr app );
+char *GetApplicationHost( BusClientPtr app );
+BusClientPtr GetApplication( char *name );
+char *GetApplicationList();
+char **GetApplicationMessages( BusClientPtr app);
+/* demande de reception d'un message */
+
+MsgRcvPtr BindMsg( MsgCallback callback, void *user_data, const char *fmt_regexp, ... ); /* avec sprintf prealable */
+void UnbindMsg( MsgRcvPtr id );
+
+/* emmission d'un message d'erreur */
+void SendError( BusClientPtr app, int id, const char *fmt, ... );
+
+/* emmission d'un message die pour terminer l'application */
+void SendDieMsg( BusClientPtr app );
+
+/* emmission d'un message retourne le nb effectivement emis */
+
+int SendMsg( const char *fmt_message, ... ); /* avec sprintf prealable */
+
+/* Message Direct Inter-application */
+
+void BindDirectMsg( MsgDirectCallback callback, void *user_data);
+void SendDirectMsg( BusClientPtr app, int id, char *msg );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..4a6fe26
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,55 @@
+#define LIST_ITER( list, p, cond ) \
+ p = list; \
+ while ( p && (cond) ) p = p->next
+
+#define LIST_REMOVE( list, p ) \
+ { \
+ void *toRemove; \
+ if ( list == p ) \
+ { \
+ list = p->next; \
+ free(p);\
+ } \
+ else \
+ {\
+ toRemove = p;\
+ LIST_ITER( list, p, ( p->next != toRemove ));\
+ if ( p )\
+ {\
+ /* somme tricky swapping to use a untyped variable */\
+ void *suiv; \
+ void *prec = p;\
+ p = toRemove;\
+ suiv = p->next;\
+ p = prec;\
+ p->next = suiv;\
+ free(toRemove);\
+ }\
+ } \
+ }
+
+#define LIST_ADD(list, p ) \
+ if ((p = malloc( sizeof( *p ))))\
+ { \
+ memset( p, 0 , sizeof( *p ));\
+ p->next = list; \
+ list = p; \
+ }
+
+#define LIST_EACH( list, p ) \
+ for ( p = list ; p ; p = p -> next )
+
+#define LIST_EACH_SAFE( list, p, next )\
+for ( p = list ; (next = p ? p->next: p ),p ; p = next )
+
+
+#define LIST_EMPTY( list ) \
+ { \
+ void *p; \
+ while( list ) \
+ { \
+ p = list;\
+ list = list->next; \
+ free(p);\
+ } \
+ }
diff --git a/src/socket.c b/src/socket.c
new file mode 100644
index 0000000..17d0fe1
--- /dev/null
+++ b/src/socket.c
@@ -0,0 +1,667 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#ifdef WIN32
+#include <windows.h>
+#define close closesocket
+#define perror( a ) printf(a" error=%d\n",WSAGetLastError());
+#else
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <signal.h>
+#endif
+#ifdef XTMAINLOOP
+#include <X11/Intrinsic.h>
+#endif
+#include "list.h"
+#include "socket.h"
+#include "timer.h"
+
+#define MAX_BUFFER 2048
+
+struct _channel {
+ Channel next;
+ HANDLE fd;
+#ifdef XTMAINLOOP
+ XtInputId id;
+#endif
+ void *data;
+ int tobedeleted;
+ void (*handle_delete)( void *data );
+ void (*handle_read)( Channel channel, HANDLE fd, void *data);
+ };
+
+typedef struct _server *Server;
+
+struct _server {
+ Server next;
+ Channel channel;
+ void *(*create)(Client client);
+ void (*handle_delete)(Client client, void *data);
+ SocketInterpretation interpretation;
+ };
+
+struct _client {
+ Client next;
+ Channel channel;
+ unsigned short port;
+ struct sockaddr_in from;
+ SocketInterpretation interpretation;
+ void (*handle_delete)(Client client, void *data);
+ char buffer[MAX_BUFFER+2];
+ char *ptr;
+ void *data;
+ };
+
+static Channel channels_list = NULL;
+static Server servers_list = NULL;
+static Client clients_list = NULL;
+static int channel_initialized = 0;
+
+#ifdef XTMAINLOOP
+static XtAppContext app;
+#else
+static fd_set open_fds;
+static int MainLoop = 1;
+#endif
+
+
+
+#ifdef WIN32
+WSADATA WsaData;
+#endif
+
+void ChannelClose( Channel channel )
+{
+#ifdef XTMAINLOOP
+ if ( channel->handle_delete )
+ (*channel->handle_delete)( channel->data );
+ close(channel->fd);
+ XtRemoveInput( channel->id );
+ LIST_REMOVE( channels_list, channel );
+#else
+ channel->tobedeleted = 1;
+#endif
+}
+#ifdef XTMAINLOOP
+static void HandleChannel( XtPointer closure, int* source, XtInputId* id )
+{
+ Channel channel = (Channel)closure;
+#ifdef DEBUG
+ printf("Handle Channel read %d\n",*source );
+#endif
+ (*channel->handle_read)(channel,channel->fd,channel->data);
+}
+#else
+static void ChannelDelete( Channel channel )
+{
+ if ( channel->handle_delete )
+ (*channel->handle_delete)( channel->data );
+ close(channel->fd);
+
+ FD_CLR(channel->fd, &open_fds);
+ LIST_REMOVE( channels_list, channel );
+}
+static void ChannelDefferedDelete()
+{
+ Channel channel,next;
+ LIST_EACH_SAFE( channels_list, channel,next)
+ {
+ if ( channel->tobedeleted )
+ {
+ ChannelDelete( channel );
+ }
+ }
+}
+#endif
+Channel ChannelSetUp(HANDLE fd, void *data,
+ void (*handle_delete)( void *data ),
+ void (*handle_read)( Channel channel, HANDLE fd, void *data)
+ )
+{
+ Channel channel;
+
+ LIST_ADD( channels_list, channel );
+ if ( !channel )
+ {
+ fprintf(stderr,"NOK Memory Alloc Error\n");
+ close( fd );
+ exit(0);
+ }
+ channel->fd = fd;
+ channel->tobedeleted = 0;
+ channel->handle_delete = handle_delete;
+ channel->handle_read = handle_read;
+ channel->data = data;
+#ifdef XTMAINLOOP
+ channel->id = XtAppAddInput( app, fd, (XtPointer)XtInputReadMask, HandleChannel, channel);
+#else
+ FD_SET( channel->fd, &open_fds );
+#endif
+ return channel;
+}
+#ifndef XTMAINLOOP
+static void ChannelHandleRead(fd_set *current)
+{
+ Channel channel,next;
+
+ LIST_EACH_SAFE( channels_list, channel, next )
+ {
+ if ( FD_ISSET( channel->fd, current ) )
+ {
+ (*channel->handle_read)(channel,channel->fd,channel->data);
+ }
+ }
+}
+static void ChannelHandleExcpt(fd_set *current)
+{
+ Channel channel,next;
+ LIST_EACH_SAFE( channels_list, channel, next )
+ {
+ if (FD_ISSET( channel->fd, current ) )
+ {
+ ChannelClose( channel );
+ }
+ }
+}
+#endif
+static void DeleteSocket(void *data)
+{
+ Client client = ( Client )data;
+ if ( client->handle_delete )
+ (*client->handle_delete)( client, client->data );
+ shutdown( client->channel->fd, 2 );
+ LIST_REMOVE( clients_list, client );
+}
+static void HandleSocket( Channel channel, HANDLE fd, void *data)
+{
+ Client client = (Client)data;
+ char *ptr;
+ char *ptr_nl;
+ long nb_to_read = 0;
+ long nb;
+ int len;
+
+ /* limitation taille buffer */
+ nb_to_read = MAX_BUFFER - ( client->ptr - client->buffer );
+ if( nb_to_read == 0 ) {
+ fprintf(stderr, "Erreur message trop long sans LF\n");
+ client->ptr = client->buffer;
+ return;
+ };
+ len = sizeof( client->from );
+ nb = recvfrom( fd, client->ptr, nb_to_read,0,(struct sockaddr *)&client->from,&len);
+ if (nb < 0) {
+ perror(" Read Socket ");
+ ChannelClose( client->channel );
+ return;
+ };
+ if ( nb == 0 )
+ {
+ ChannelClose( client->channel );
+ return;
+ }
+
+ client->ptr += nb;
+ *(client->ptr) = '\0';
+ ptr = client->buffer;
+ while( (ptr_nl = strchr( ptr, '\n' )))
+ {
+ *ptr_nl = '\0';
+ if ( client->interpretation )
+ (*client->interpretation)( client, client->data, ptr );
+ else fprintf( stderr,"Socket No interpretation function ???!\n");
+ ptr = ++ptr_nl;
+ }
+ if ( *ptr != '\0' )
+ { /* recopie ligne incomplete au debut du buffer */
+ strcpy( client->buffer, ptr );
+ client->ptr = client->buffer + strlen(client->buffer);
+ }
+ else
+ {
+ client->ptr = client->buffer;
+ }
+}
+static void HandleServer(Channel channel, HANDLE fd, void *data)
+{
+ Server server = ( Server ) data;
+ Client client;
+ HANDLE ns;
+ int addrlen;
+ struct sockaddr_in remote2;
+
+ addrlen = sizeof( remote2 );
+ if ((ns = accept( fd, (struct sockaddr *)&remote2, &addrlen)) <0)
+ {
+ perror ( "*** accept ***");
+ return;
+ };
+ LIST_ADD( clients_list, client );
+ if ( !client )
+ {
+ fprintf(stderr,"NOK Memory Alloc Error\n");
+ close( fd );
+ exit(0);
+ }
+ client->from = remote2;
+ client->channel = ChannelSetUp( ns, client, DeleteSocket, HandleSocket );
+ client->interpretation = server->interpretation;
+ client->ptr = client->buffer;
+ client->handle_delete = server->handle_delete;
+ client->data = (*server->create)( client );
+
+}
+int SocketServer(unsigned short port,
+ void*(*create)(Client client),
+ void(*handle_delete)(Client client, void *data),
+ void(*interpretation)( Client client, void *data, char *ligne))
+{
+ Server server;
+ HANDLE fd;
+ int one=1;
+ struct sockaddr_in local;
+ int addrlen;
+
+
+ if ((fd = socket( AF_INET, SOCK_STREAM, 0)) < 0){
+ perror( "***open socket ***");
+ exit(0);
+ };
+
+
+ local.sin_family = AF_INET;
+ local.sin_addr.s_addr = INADDR_ANY;
+ local.sin_port = htons (port);
+
+ if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&one,sizeof(one)) < 0)
+ {
+ perror( "*** set socket option SO_REUSEADDR ***");
+ exit(0);
+ }
+
+#ifdef SO_REUSEPORT
+
+ if (setsockopt( fd, SOL_SOCKET, SO_REUSEPORT, (char *)&one, sizeof( one)) < 0)
+ {
+ perror( "*** set socket option REUSEPORT ***");
+ exit(0);
+ }
+#endif
+
+ if (bind(fd, (struct sockaddr *)&local, sizeof(local)) < 0)
+ {
+ perror( "*** bind ***");
+ exit(0);
+ }
+
+ addrlen = sizeof( local );
+ if (getsockname(fd,(struct sockaddr *)&local, &addrlen) < 0)
+ {
+ perror( "***get socket name ***");
+ exit(0);
+ }
+
+ if (listen( fd, 128) < 0){
+ perror( "*** listen ***");
+ exit(0);
+ };
+
+
+ LIST_ADD( servers_list, server );
+ if ( !server )
+ {
+ fprintf(stderr,"NOK Memory Alloc Error\n");
+ exit(0);
+ }
+ server->channel = ChannelSetUp( fd, server, DeleteSocket, HandleServer );
+ server->create = create;
+ server->handle_delete = handle_delete;
+ server->interpretation = interpretation;
+ return ntohs(local.sin_port);
+}
+char *SocketGetPeerHost( Client client )
+{
+ int err;
+ struct sockaddr_in name;
+ struct hostent *host;
+ int len = sizeof(name);
+ err = getpeername( client->channel->fd, (struct sockaddr *)&name, &len );
+ if ( err < 0 ) return "can't get peer";
+ host = gethostbyaddr( (char *)&name.sin_addr.s_addr,sizeof(name.sin_addr.s_addr),name.sin_family);
+ if ( host == NULL ) return "can't translate addr";
+ return host->h_name;
+}
+struct in_addr * SocketGetRemoteAddr( Client client )
+{
+ return &client->from.sin_addr;
+}
+void SocketGetRemote( Client client, char **host, unsigned short *port )
+{
+ struct hostent *hostp;
+ /* extract hostname and port from last message received */
+ hostp = gethostbyaddr( (char *)&client->from.sin_addr.s_addr,
+ sizeof(client->from.sin_addr.s_addr),client->from.sin_family);
+ if ( hostp == NULL ) *host = "unknown";
+ else *host = hostp->h_name;
+ *port = ntohs( client->from.sin_port );
+}
+void SocketClose( Client client )
+{
+ ChannelClose( client->channel );
+}
+
+void SocketSendRaw( Client client, char *buffer, int len )
+{
+ int err;
+ err = send( client->channel->fd, buffer, len, 0 );
+ if ( err != len )
+ perror( "*** send ***");
+}
+void SocketSetData( Client client, void *data )
+{
+ client->data = data;
+}
+void SocketSend( Client client, char *fmt, ... )
+{
+ char buffer[4096];
+ va_list ap;
+ int len;
+ va_start( ap, fmt );
+ len = vsprintf( buffer, fmt, ap );
+ SocketSendRaw( client, buffer, len );
+ va_end ( ap );
+}
+void *SocketGetData( Client client )
+{
+ return client->data;
+}
+void SocketBroadcast( char *fmt, ... )
+{
+ Client client;
+ char buffer[4096];
+ va_list ap;
+ int len;
+
+ va_start( ap, fmt );
+ len = vsprintf( buffer, fmt, ap );
+ va_end ( ap );
+ LIST_EACH( clients_list, client )
+ {
+ SocketSendRaw( client, buffer, len );
+ }
+}
+/*
+Ouverture d'un canal TCP/IP en mode client
+*/
+Client SocketConnect( char * host, unsigned short port,
+ void *data,
+ SocketInterpretation interpretation,
+ void (*handle_delete)(Client client, void *data)
+ )
+{
+struct hostent *rhost;
+
+
+if ((rhost = gethostbyname( host )) == NULL){
+ fprintf(stderr, "Erreur %s Calculateur inconnu !\n",host);
+ return NULL;
+ };
+return SocketConnectAddr( (struct in_addr*)(rhost->h_addr), port, data, interpretation, handle_delete);
+}
+Client SocketConnectAddr( struct in_addr * addr, unsigned short port,
+ void *data,
+ SocketInterpretation interpretation,
+ void (*handle_delete)(Client client, void *data)
+ )
+{
+HANDLE handle;
+Client client;
+struct sockaddr_in remote;
+
+remote.sin_family = AF_INET;
+remote.sin_addr = *addr;
+remote.sin_port = htons (port);
+
+if ((handle = socket( AF_INET, SOCK_STREAM, 0)) < 0){
+ perror( "*** client socket ***");
+ return NULL;
+ };
+
+if ( connect( handle, (struct sockaddr *)&remote, sizeof(remote) ) < 0){
+ perror( "*** client connect ***");
+ return NULL;
+ };
+
+LIST_ADD( clients_list, client );
+if ( !client )
+ {
+ fprintf(stderr,"NOK Memory Alloc Error\n");
+ close( handle );
+ exit(0);
+ }
+
+
+client->channel = ChannelSetUp( handle, client, DeleteSocket, HandleSocket );
+client->interpretation = interpretation;
+client->ptr = client->buffer;
+client->data = data;
+client->handle_delete = handle_delete;
+client->from.sin_family = AF_INET;
+client->from.sin_addr = *addr;
+client->from.sin_port = htons (port);
+
+return client;
+}
+int SocketWaitForReply( Client client, char *buffer, int size, int delai)
+{
+ fd_set rdset;
+ struct timeval timeout;
+ struct timeval *timeoutptr = &timeout;
+ int ready;
+ char *ptr;
+ char *ptr_nl;
+ long nb_to_read = 0;
+ long nb;
+ HANDLE fd;
+
+ fd = client->channel->fd;
+ ptr = buffer;
+ timeout.tv_sec = delai;
+ timeout.tv_usec = 0;
+ do {
+ /* limitation taille buffer */
+ nb_to_read = size - ( ptr - buffer );
+ if( nb_to_read == 0 )
+ {
+ fprintf(stderr, "Erreur message trop long sans LF\n");
+ ptr = buffer;
+ return -1;
+ }
+ FD_ZERO( &rdset );
+ FD_SET( fd, &rdset );
+ ready = select(fd+1, &rdset, 0, 0, timeoutptr);
+ if ( ready < 0 )
+ {
+ perror("select");
+ return -1;
+ }
+ if ( ready == 0 )
+ {
+ return -2;
+ }
+ if ((nb = recv( fd , ptr, nb_to_read, 0 )) < 0)
+ {
+ perror(" Read Socket ");
+ return -1;
+ }
+ if ( nb == 0 )
+ return 0;
+
+ ptr += nb;
+ *ptr = '\0';
+ ptr_nl = strchr( buffer, '\n' );
+ } while ( !ptr_nl );
+ *ptr_nl = '\0';
+ return (ptr_nl - buffer);
+}
+void ChannelInit(void)
+{
+#ifdef WIN32
+ int error;
+#else
+ signal( SIGPIPE, SIG_IGN);
+#endif
+ if ( channel_initialized ) return;
+#ifndef XTMAINLOOP
+ FD_ZERO( &open_fds );
+#endif
+#ifdef WIN32
+ error = WSAStartup( 0x0101, &WsaData );
+ if ( error == SOCKET_ERROR ) {
+ printf( "WSAStartup failed.\n" );
+ }
+#endif
+ channel_initialized = 1;
+}
+
+#ifdef XTMAINLOOP
+
+void SetSocketAppContext( XtAppContext cntx )
+{
+ app = cntx;
+}
+
+void ChannelMainLoop(void(*hook)(void))
+{
+ printf("Compiled for Use of XtMainLoop not ChannelMainLoop\n");
+ exit(-1);
+}
+#else
+void ChannelStop(void)
+{
+ MainLoop = 0;
+}
+void ChannelMainLoop(void(*hook)(void))
+{
+
+fd_set rdset;
+fd_set exset;
+int ready;
+
+
+
+ while (MainLoop) {
+ ChannelDefferedDelete();
+ if ( hook ) (*hook)();
+ rdset = open_fds;
+ exset = open_fds;
+ ready = select(64, &rdset, 0, &exset, TimerGetSmallestTimeout());
+ if ( ready < 0 && ( errno != EINTR ))
+ {
+ perror("select");
+ return;
+ }
+ TimerScan();
+ if ( ready > 0 )
+ {
+ ChannelHandleExcpt(&exset);
+ ChannelHandleRead(&rdset);
+ continue;
+ }
+ }
+}
+#endif
+/* Socket UDP */
+
+Client SocketBroadcastCreate( unsigned short port,
+ void *data,
+ SocketInterpretation interpretation
+ )
+{
+HANDLE handle;
+Client client;
+struct sockaddr_in local;
+int on = 1;
+
+local.sin_family = AF_INET;
+local.sin_addr.s_addr = INADDR_ANY;
+local.sin_port = htons (port);
+
+if ((handle = socket( AF_INET, SOCK_DGRAM, 0)) < 0){
+ perror( "*** dgram socket ***");
+ return NULL;
+ };
+
+/* wee need to used multiple client on the same host */
+if (setsockopt( handle, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof( on)) < 0)
+ {
+ perror( "*** set socket option REUSEADDR ***");
+ return NULL;
+ };
+#ifdef SO_REUSEPORT
+
+if (setsockopt( fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof( on)) < 0)
+ {
+ perror( "*** set socket option REUSEPORT ***");
+ return NULL;
+ }
+#endif
+/* wee need to broadcast */
+if (setsockopt( handle, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof( on)) < 0)
+ {
+ perror( "*** BROADCAST ***");
+ return NULL;
+ };
+
+if (bind(handle, (struct sockaddr *)&local, sizeof(local)) < 0)
+ {
+ perror( "*** test BIND ***");
+ return NULL;
+ };
+
+LIST_ADD( clients_list, client );
+if ( !client )
+ {
+ fprintf(stderr,"NOK Memory Alloc Error\n");
+ close( handle );
+ exit(0);
+ }
+
+
+client->channel = ChannelSetUp( handle, client, DeleteSocket, HandleSocket );
+client->interpretation = interpretation;
+client->ptr = client->buffer;
+client->data = data;
+
+return client;
+}
+
+void SocketSendBroadcast( Client client, unsigned long host, unsigned short port, char *fmt, ... )
+{
+ struct sockaddr_in remote;
+ char buffer[4096];
+ va_list ap;
+ int err,len;
+
+ va_start( ap, fmt );
+ len = vsprintf( buffer, fmt, ap );
+ /* Send UDP packet to the dest */
+ remote.sin_family = AF_INET;
+ remote.sin_addr.s_addr = htonl( host );
+ remote.sin_port = htons(port);
+ err = sendto( client->channel->fd,
+ buffer, len,0,
+ (struct sockaddr *)&remote,sizeof(remote));
+ if ( err != len )
+ {
+ perror( "*** send ***");
+ } va_end ( ap );
+}
diff --git a/src/socket.h b/src/socket.h
new file mode 100644
index 0000000..99b9abd
--- /dev/null
+++ b/src/socket.h
@@ -0,0 +1,87 @@
+#ifndef _SOCKET_H
+#define _SOCKET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* general Handle */
+
+#define ANYPORT 0
+
+#ifdef WIN32
+#include <windows.h>
+#define HANDLE SOCKET
+#else
+#define HANDLE int
+#include <netinet/in.h>
+#endif
+
+typedef struct _channel *Channel;
+
+extern void ChannelInit(void);
+extern void ChannelStop(void);
+extern void ChannelMainLoop(void(*hook)(void) );
+extern Channel ChannelSetUp(
+ HANDLE fd,
+ void *data,
+ void (*handle_delete)( void *data ),
+ void (*handle_read)( Channel channel, HANDLE fd, void *data)
+ );
+
+extern void ChannelClose( Channel channel );
+
+/* Server Part */
+typedef struct _client *Client;
+typedef void (*SocketInterpretation)( Client client, void *data, char *ligne);
+
+extern void SocketClose( Client client );
+extern void SocketSend( Client client, char *fmt, ... );
+extern void SocketSendRaw( Client client, char *buffer, int len );
+extern char *SocketGetPeerHost( Client client );
+extern void SocketSetData( Client client, void *data );
+extern void *SocketGetData( Client client );
+extern void SocketBroadcast( char *fmt, ... );
+
+extern int SocketServer(unsigned short port,
+ void*(*create)(Client client),
+ void(*handle_delete)(Client client, void *data),
+ SocketInterpretation interpretation);
+
+/* Client Part */
+
+extern Client SocketConnect( char * host, unsigned short port,
+ void *data,
+ SocketInterpretation interpretation,
+ void (*handle_delete)(Client client, void *data)
+ );
+extern Client SocketConnectAddr( struct in_addr * addr, unsigned short port,
+ void *data,
+ SocketInterpretation interpretation,
+ void (*handle_delete)(Client client, void *data)
+ );
+extern int SocketWaitForReply( Client client, char *buffer, int size, int delai);
+
+/* Socket UDP */
+/* Creation d'une socket en mode non connecte */
+/* et ecoute des messages */
+extern Client SocketBroadcastCreate(
+ unsigned short port,
+ void *data,
+ SocketInterpretation interpretation
+ );
+/* recuperation de l'emetteur du message */
+extern struct in_addr * SocketGetRemoteAddr( Client client );
+extern void SocketGetRemote( Client client, char **host, unsigned short *port );
+/* emmission d'un broadcast UDP */
+extern void SocketSendBroadcast( Client client, unsigned long host, unsigned short port, char *fmt, ... );
+
+#ifdef XTMAINLOOP
+extern void SetSocketAppContext( XtAppContext cntx );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/testbus.c b/src/testbus.c
new file mode 100644
index 0000000..39d55b5
--- /dev/null
+++ b/src/testbus.c
@@ -0,0 +1,190 @@
+#include <stdio.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include "socket.h"
+#include "bus.h"
+#include "timer.h"
+#ifdef XTMAINLOOP
+#include <X11/Intrinsic.h>
+#endif
+
+int app_count = 0;
+int wait_count = 0;
+
+void Callback( BusClientPtr app, void *user_data, int argc, char *argv[])
+{
+ int i;
+ printf(" %s Called function %d args:",GetApplicationName(app),argc);
+ for ( i = 0; i < argc; i++ )
+ printf(" '%s'",argv[i]);
+ printf("\n");
+}
+void HandleStdin( Channel channel, int fd, void *data)
+{
+ char buf[4096];
+ char *line;
+ char *cmd;
+ char *arg;
+ int id;
+ BusClientPtr app;
+ int err;
+ line = gets( buf);
+ if ( !line )
+ {
+ ChannelClose( channel );
+ ChannelStop();
+ return;
+ }
+ if ( *line == '.' )
+ {
+ cmd = strtok( line, ".: ");
+ if ( strcmp(cmd, "die" ) == 0 )
+ {
+ arg = strtok( NULL, " " );
+ if ( arg )
+ {
+ app = GetApplication( arg );
+ if ( app )
+ SendDieMsg( app );
+ else printf( "No Application %s!!!\n",arg);
+ }
+ }
+ if ( strcmp(cmd, "bind" ) == 0 )
+ {
+ arg = strtok( NULL, "'" );
+ if ( arg )
+ {
+ BindMsg( Callback, NULL, arg );
+ }
+ }
+ if ( strcmp(cmd, "where" ) == 0 )
+ {
+ arg = strtok( NULL, " " );
+ if ( arg )
+ {
+ app = GetApplication( arg );
+ if ( app )
+ printf( "Application %s on %s\n",arg, GetApplicationHost( app ));
+ else printf( "No Application %s!!!\n",arg);
+ }
+ }
+ if ( strcmp(cmd, "direct" ) == 0 )
+ {
+ arg = strtok( NULL, " " );
+ if ( arg )
+ {
+ app = GetApplication( arg );
+ if ( app )
+ {
+ arg = strtok( NULL, " " );
+ id = atoi( arg ) ;
+ arg = strtok( NULL, "'" );
+ SendDirectMsg( app, id, arg );
+ }
+ else printf( "No Application %s!!!\n",arg);
+ }
+
+ }
+ if ( strcmp(cmd, "who") == 0 )
+ {
+ printf("Apps: %s\n", GetApplicationList());
+ }
+ if ( strcmp(cmd, "help") == 0 )
+ {
+ printf("Commands list:\n");
+ printf(" .help - this help\n");
+ printf(" .quit - terminate this application\n");
+ printf(" .die appname - send die msg to appname\n");
+ printf(" .direct appname id 'arg' - send direct msg to appname\n");
+ printf(" .where appname - on which host is appname\n");
+ printf(" .bind 'regexp' - add a msg to receive\n");
+ printf(" .who - who is on the bus\n");
+ }
+ if ( strcmp(cmd, "quit") == 0 )
+ {
+ exit(0);
+ }
+ }
+ else
+ {
+ err = SendMsg( buf );
+ printf("Sent:%d\n",err);
+ }
+}
+
+void ApplicationCallback( BusClientPtr app, void *user_data, BusApplicationEvent event)
+{
+ char *appname;
+ char *host;
+ char **msgList;
+ appname = GetApplicationName( app );
+ host = GetApplicationHost( app );
+ switch ( event ) {
+ case BusApplicationConnected:
+ app_count++;
+ printf("Application(%d): %s ready on %s\n",app_count, appname, host);
+ printf("Application(%s): Begin Messages\n", appname);
+ msgList = GetApplicationMessages( app );
+ while( *msgList )
+ printf("Application(%s): Receive '%s'\n",appname,*msgList++);
+ printf("Application(%s): End Messages\n",appname);
+ if ( app_count == wait_count )
+ ChannelSetUp( 0, NULL, NULL, HandleStdin);
+ break;
+ case BusApplicationDisconnected:
+ app_count--;
+ printf("Application(%d): %s bye on %s\n",app_count, appname, host);
+ break;
+ default:
+ printf("Application(%d): %s unkown event %d\n", app_count, appname, event);
+ break;
+ }
+
+}
+void TimerCall(TimerId id, void *user_data, unsigned long delta)
+{
+ printf("Timer callback: %d delta %lu ms\n", (int)user_data, delta );
+ SendMsg( "TEST TIMER %d", (int)user_data);
+ /*if ( (int)user_data == 5 ) TimerModify( id, 2000 );*/
+}
+int main(int argc, char *argv[])
+{
+
+ unsigned short bport = DEFAULT_BUS;
+ int c;
+ int timer_test = 0;
+ while ((c = getopt(argc, argv, "b:w:t")) != EOF)
+ switch (c)
+ {
+ case 'b':
+ bport = atoi(optarg) ;
+ break;
+ case 'w':
+ wait_count = atoi(optarg) ;
+ break;
+ case 't':
+ timer_test = 1;
+ break;
+ }
+#ifdef XTMAINLOOP
+ XtToolkitInitialize();
+
+#endif
+ BusInit("TEST",bport,"TEST READY",ApplicationCallback,NULL,NULL,NULL);
+ for ( ; optind < argc; optind++ )
+ BindMsg( Callback, NULL, argv[optind] );
+ if ( wait_count == 0 )
+ ChannelSetUp( 0, NULL, NULL, HandleStdin);
+ BusStart( );
+ if ( timer_test )
+ {
+ TimerRepeatAfter( TIMER_LOOP, 1000, TimerCall, (void*)1 );
+ TimerRepeatAfter( 5, 5000, TimerCall, (void*)5 );
+ }
+#ifdef XTMAINLOOP
+ XtMainLoop();
+#else
+ BusLoop();
+#endif
+ return 0;
+}
diff --git a/src/timer.c b/src/timer.c
new file mode 100644
index 0000000..a1fb791
--- /dev/null
+++ b/src/timer.c
@@ -0,0 +1,160 @@
+/* Module de gestion des timers autour d'un select */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <stdlib.h>
+#include <time.h>
+#include <memory.h>
+#ifdef WIN32
+#include <windows.h>
+#endif
+#include "list.h"
+#include "timer.h"
+
+#define BIGVALUE 2147483647
+#define MILLISEC 1000
+
+static struct timeval *timeoutptr = NULL;
+static struct timeval selectTimeout = { BIGVALUE, 0 };
+/* la prochaine echeance */
+static unsigned long nextTimeout = BIGVALUE;
+
+struct _timer {
+ struct _timer *next;
+ int repeat;
+ unsigned long period;
+ unsigned long when;
+ TimerCb callback;
+ void *user_data;
+ }Timer;
+
+/* liste des timers */
+TimerId timers = NULL;
+
+static long currentTime()
+{
+ struct timeval tv;
+ unsigned long current;
+ gettimeofday (&tv, 0);
+ current = 1000 * tv.tv_sec + tv.tv_usec / 1000;
+ return current;
+
+#if 0
+ unsigned long current;
+ current = clock();
+ return current;
+#endif
+}
+static void SetNewTimeout( unsigned long current, unsigned long when )
+{
+ unsigned long time;
+ time = when - current;
+ nextTimeout = when;
+ selectTimeout.tv_sec = time / MILLISEC;
+ selectTimeout.tv_usec = (time - selectTimeout.tv_sec* MILLISEC) * MILLISEC;
+ if ( timeoutptr == NULL )
+ timeoutptr = &selectTimeout;
+ /*printf("New timeout %lu\n", time );*/
+}
+static void AdjTimeout(unsigned long current)
+{
+ unsigned long newTimeout;
+ TimerId timer;
+ if ( timers )
+ {
+ /* recherche de la plus courte echeance dans la liste */
+ newTimeout = timers->when ; /* remise a la premiere valeur */
+ LIST_EACH( timers , timer )
+ {
+ if ( timer->when < newTimeout )
+ newTimeout = timer->when;
+
+ }
+ SetNewTimeout( current, newTimeout );
+ }
+ else
+ {
+ timeoutptr = NULL;
+ }
+}
+
+/* API */
+
+TimerId TimerRepeatAfter( int count, long time, TimerCb cb, void *user_data )
+{
+ unsigned long stamp;
+ TimerId timer;
+
+ /* si y a rien a faire et ben on fait rien */
+ if ( cb == NULL ) return NULL;
+
+ LIST_ADD( timers, timer )
+ if ( timer )
+ {
+ timer->repeat = count;
+ timer->callback = cb;
+ timer->user_data = user_data;
+ stamp = currentTime();
+ timer->period = time;
+ timer->when = stamp + time;
+ if ( (timer->when < nextTimeout) || (timeoutptr == NULL))
+ SetNewTimeout( stamp, timer->when );
+ }
+ return timer;
+}
+void TimerRemove( TimerId timer )
+{
+ unsigned long stamp;
+ if ( !timer ) return;
+ LIST_REMOVE( timers, timer );
+ stamp = currentTime();
+ AdjTimeout(stamp);
+}
+void TimerModify( TimerId timer, long time )
+{
+ unsigned long stamp;
+ if ( !timer ) return;
+
+ stamp = currentTime();
+ timer->period = time;
+ timer->when = stamp + time;
+ AdjTimeout(stamp);
+}
+/* Interface avec select */
+
+struct timeval *TimerGetSmallestTimeout()
+{
+ return timeoutptr;
+}
+
+void TimerScan()
+{
+ unsigned long stamp;
+ TimerId timer;
+ TimerId next;
+ unsigned long delta;
+ int timer_echu = 0;
+
+ stamp = currentTime();
+ /* recherche des timers echu dans la liste */
+ LIST_EACH_SAFE( timers , timer, next )
+ {
+ if ( timer->when <= stamp )
+ {
+ timer_echu++;
+ delta = stamp - timer->when;
+ /* call callback */
+ (*timer->callback)( timer, timer->user_data, delta );
+ if ( timer->repeat == TIMER_LOOP || --(timer->repeat) )
+ {
+ timer->when = stamp + timer->period;
+ }
+ else
+ {
+ LIST_REMOVE( timers, timer );
+ }
+ }
+ }
+ /* recalcul du prochain timeout */
+ AdjTimeout( stamp );
+}
diff --git a/src/timer.h b/src/timer.h
new file mode 100644
index 0000000..7aa425f
--- /dev/null
+++ b/src/timer.h
@@ -0,0 +1,18 @@
+/* Module de gestion des timers autour d'un select */
+
+typedef struct _timer *TimerId;
+typedef void (*TimerCb)( TimerId id , void *user_data, unsigned long delta );
+
+/* API le temp est en milli secondes */
+#define TIMER_LOOP -1 /* timer en boucle infinie */
+TimerId TimerRepeatAfter( int count, long time, TimerCb cb, void *user_data );
+
+void TimerModify( TimerId id, long time );
+
+void TimerRemove( TimerId id );
+
+/* Interface avec select */
+
+struct timeval *TimerGetSmallestTimeout();
+
+void TimerScan();