From 6d4a1d57836737d2e7ac8b4e3f19b0ba736e3981 Mon Sep 17 00:00:00 2001 From: damiano Date: Thu, 9 Apr 1998 13:55:38 +0000 Subject: Move des fichiers dans src --- src/Makefile | 27 +++ src/bus.c | 693 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/bus.h | 75 +++++++ src/list.h | 55 +++++ src/socket.c | 667 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/socket.h | 87 ++++++++ src/testbus.c | 190 ++++++++++++++++ src/timer.c | 160 ++++++++++++++ src/timer.h | 18 ++ 9 files changed, 1972 insertions(+) create mode 100644 src/Makefile create mode 100644 src/bus.c create mode 100644 src/bus.h create mode 100644 src/list.h create mode 100644 src/socket.c create mode 100644 src/socket.h create mode 100644 src/testbus.c create mode 100644 src/timer.c create mode 100644 src/timer.h (limited to 'src') 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 + +#include +#include +#include + +#include + +#include + + +#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(®exp, 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, ®exp, 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 +#include +#include +#include +#include +#ifdef WIN32 +#include +#define close closesocket +#define perror( a ) printf(a" error=%d\n",WSAGetLastError()); +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#ifdef XTMAINLOOP +#include +#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 +#define HANDLE SOCKET +#else +#define HANDLE int +#include +#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 +#include +#include +#include "socket.h" +#include "bus.h" +#include "timer.h" +#ifdef XTMAINLOOP +#include +#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 +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#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(); -- cgit v1.1