From f477dcbb7da7f518d1175953c668545d21970c2d Mon Sep 17 00:00:00 2001 From: bustico Date: Wed, 19 Jun 2013 12:39:15 +0000 Subject: complete implementation of ping/pong protocol message --- src/Makefile | 2 +- src/ivy.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/ivy.h | 16 +++++++++++++++ src/version.h | 2 +- 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/Makefile b/src/Makefile index 4501aa6..98e1b8c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -17,7 +17,7 @@ # change this in version.h too !!!! MAJOR=3 -MINOR=13 +MINOR=14 PERHAPS64 := $(shell getconf LONG_BIT | perl -ne "print /64/ ? '64' : '';") LIB = /lib$(PERHAPS64) diff --git a/src/ivy.c b/src/ivy.c index a87d24e..607c679 100644 --- a/src/ivy.c +++ b/src/ivy.c @@ -73,6 +73,8 @@ extern int WSAAPI inet_pton(int af, const char *src, void *dst); * effectuée si on stringifie directement dans la macro GenerateIvyBus */ #define str(bus) #bus #define GenerateIvyBus(domain,bus) str(domain)":"str(bus) +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + static const char* DefaultIvyBus = GenerateIvyBus(DEFAULT_DOMAIN,IVY_DEFAULT_BUS); typedef enum { @@ -122,6 +124,12 @@ struct _msg_snd_dict { /* requete de reception d'un client */ /* liste de clients, champ de la struct _msg_snd_dict qui est valeur du dictionnaire */ /* typedef IvyClientPtr */ + +struct _ping_timestamp { + struct timeval ts; + int id; +}; + struct _clnt_lst_dict { RWIvyClientPtr next; Client client; /* la socket client */ @@ -135,9 +143,11 @@ struct _clnt_lst_dict { #ifdef OPENMP int endRegexpReceived; #endif // OPENMP - int readyToSend; /* comptage des endRegexps recu et emis */ - int ignore_subsequent_msg; /* pour ignore les messages venant - d'une socket ferme, mais donc les donnees sont deja en buffer */ + int readyToSend; /* comptage des endRegexps recu et emis */ + int ignore_subsequent_msg; /* pour ignorer les messages venant + d'une socket ferme, mais donc les donnees sont deja en buffer */ + struct _ping_timestamp ping_timestamp; /* on enregistre le timestamp du ping pour envoyer le roundtrip à + la reception du pong */ }; /* flag pour le debug en cas de Filter de regexp */ @@ -181,6 +191,10 @@ static void *application_bind_data = NULL; static IvyDieCallback application_die_callback; static void *application_die_user_data = NULL; +/* callback appele sur reception d'une trame PONG */ +static IvyPongCallback application_pong_callback = NULL; + + /* liste des messages a recevoir */ static MsgRcvPtr msg_recv = NULL; @@ -713,9 +727,28 @@ static void Receive( Client client, const void *data, char *line ) case Pong: TRACE("Pong Message\n"); - printf("Receive unhandled Pong message (ivy-c not able to send ping)\n"); + if (application_pong_callback != NULL) { + if (timerisset (&(clnt->ping_timestamp.ts))) { + struct timeval now, diff; + int roundTripOrTimout; + gettimeofday (&now, NULL); + timersub (&now, &(clnt->ping_timestamp.ts), &diff); + roundTripOrTimout = (MIN(diff.tv_sec, 2000) *1000000) + (diff.tv_usec); + timerclear (&(clnt->ping_timestamp.ts)); + + // if received id is not the last sent id, it means that whe have not + // received the pong of previous ping, so we send negative value which mean + // this value is a timout + if (id != clnt->ping_timestamp.id) { + roundTripOrTimout *= -1; + } + (*application_pong_callback)( clnt, roundTripOrTimout); + } + } else { + fprintf(stderr, "Receive unhandled Pong message (no registered pong callback defined)\n"); + } break; - + default: printf("Receive unhandled message %s\n", line); break; @@ -733,6 +766,8 @@ static RWIvyClientPtr SendService( Client client, const char *appname ) clnt->app_port = 0; clnt->readyToSend = 0; clnt->ignore_subsequent_msg =0; + clnt->ping_timestamp.ts.tv_sec = clnt->ping_timestamp.ts.tv_usec = 0; + clnt->ping_timestamp.id=0; MsgSendTo(clnt, StartRegexp, ApplicationPort, ApplicationName); IVY_LIST_EACH(msg_recv, msg ) { @@ -932,6 +967,11 @@ void IvySetBindCallback( IvyBindCallback bind_callback, void *bind_data ) application_bind_data=bind_data; } +void IvySetPongCallback( IvyPongCallback pong_callback ) +{ + application_pong_callback = pong_callback; +} + void IvySetFilter( int argc, const char **argv) { IvyBindingSetFilter( argc, argv ); @@ -1326,6 +1366,19 @@ void IvySendDirectMsg(IvyClientPtr app, int id, char *msg ) MsgSendTo( app, DirectMsg, id, msg); } +void IvySendPing( IvyClientPtr app) +{ + if (application_pong_callback != NULL) { + RWIvyClientPtr clnt = (RWIvyClientPtr) app; + + gettimeofday (&(clnt->ping_timestamp.ts), NULL); + MsgSendTo( clnt, Ping, ++clnt->ping_timestamp.id, ""); + } else { + fprintf(stderr,"Application: %s useless IvySendPing issued since no pong callback defined\n", + IvyGetApplicationName( app )); + } +} + void IvySendDieMsg(IvyClientPtr app ) { MsgSendTo(app, Die, 0, "" ); diff --git a/src/ivy.h b/src/ivy.h index 50bc301..df6fcc2 100644 --- a/src/ivy.h +++ b/src/ivy.h @@ -15,6 +15,7 @@ * copyright notice regarding this software */ + #ifndef IVY_H #define IVY_H @@ -50,6 +51,9 @@ typedef void (*IvyBindCallback)( IvyClientPtr app, void *user_data, int id, cons /* callback appele sur reception de die */ typedef void (*IvyDieCallback)( IvyClientPtr app, void *user_data, int id ) ; +/* callback appele sur reception de pong */ +typedef void (*IvyPongCallback)( IvyClientPtr app, int round_trip_delay) ; + /* callback appele sur reception de messages normaux */ typedef void (*MsgCallback)( IvyClientPtr app, void *user_data, int argc, char **argv ) ; @@ -77,6 +81,8 @@ void IvyTerminate(void); void IvySetBindCallback( IvyBindCallback bind_callback, void *bind_data ); +void IvySetPongCallback( + IvyPongCallback pong_callback ); void IvyStart (const char*); void IvyStop (void); @@ -113,6 +119,16 @@ __attribute__((format(printf,1,2))); /* avec sprintf prealable */ void IvyBindDirectMsg( MsgDirectCallback callback, void *user_data); void IvySendDirectMsg( IvyClientPtr app, int id, char *msg ); + /* to use ping protocol, you need to bind a callback to pong with IvySetPongCallback + prior to sending ping + When pong is received, your supplied callback will be called with an int argument which is : + ° if positive value : the round trip time in micro seconds + ° if negative value : the timout of the previous ping (for the same application) + which has not yet been answered + see ivyprobe.c to see a simple example of usage +*/ +void IvySendPing( IvyClientPtr app); + #ifdef __cplusplus } #endif diff --git a/src/version.h b/src/version.h index 8288a6b..a75a7fa 100644 --- a/src/version.h +++ b/src/version.h @@ -26,4 +26,4 @@ * */ #define IVYMAJOR_VERSION 3 -#define IVYMINOR_VERSION 13 +#define IVYMINOR_VERSION 14 -- cgit v1.1