diff options
-rw-r--r-- | Ivy.pm | 258 |
1 files changed, 133 insertions, 125 deletions
@@ -4,16 +4,16 @@ # Copyright 1997-2000 # Centre d'Études de la Navigation Aérienne # -# Authors: Alexandre Bustico <bustico@tls.cena.fr> -# Stéphane Chatty <chatty@tls.cena.fr> -# Hervé Damiano <damiano@tls.cena.fr> +# Authors: Alexandre Bustico <bustico@cena.fr> +# Stéphane Chatty <chatty@cena.fr> +# Hervé Damiano <damiano@cena.fr> # # All functions # # $Id$ # -# Please refer to the debian/copyright file for the -# copyright notice regarding this software +# Please refer to the debian/copyright file for the +# copyright notice regarding this software # package Ivy ; @@ -25,7 +25,7 @@ use Time::Gettimeofday ; use vars qw($VERSION); -$VERSION = '4.3'; +$VERSION = '4.4'; ############################################################################# #### PROTOTYPES ##### @@ -263,7 +263,7 @@ use constant appName => $constantIndexer++; use constant messWhenReady => $constantIndexer++; ############################################################################# -#### METHODES PUBLIQUES ##### +#### METHODES PUBLIQUES ##### ############################################################################# sub init ($%) { @@ -271,9 +271,11 @@ sub init ($%) # valeurs par defaut pour le parametre : variable d'environnement # ou valeur cablee, a defaut - my $default_ivyBus = defined $ENV{"IVYBUS"} ? $ENV{"IVYBUS"} : ""; + my $default_ivyBus = defined $ENV{"IVYBUS"} ? + $ENV{"IVYBUS"} : + BROADCAST_ADDRS.':'.BROADCAST_PORT; - my %defaultOptions = ( #PARAMETRES OBLIGATOIRES + my %optionsAndDefaults = ( #PARAMETRES OBLIGATOIRES -loopMode => undef, # TK ou LOCAL @@ -308,49 +310,51 @@ sub init ($%) # ces sujets sont eliminees. ) ; - - foreach my $opt (keys %defaultOptions) { - # si un parametre n'a pas ete defini + # on examine toutes les options possibles + foreach my $opt (keys %optionsAndDefaults) { + # si un parametre a ete fourni, ignorer les valeurs par defaut next if defined $options{$opt} ; - # est-il facultatif - if (defined $defaultOptions{$opt}) { - $options{$opt} = $defaultOptions{$opt} ; - } - else { - # parametre obligatoire - die "ERREUR Ivy::init vous devez specifier ". - "l'option $opt\n"; + # sinon, prendre la valeur par defaut si elle existe + if (defined $optionsAndDefaults{$opt}) { + $options{$opt} = $optionsAndDefaults{$opt} ; + # sinon, on jette l'eponge + } else { + die "Error in Ivy::init: option $opt is mandatory\n"; } } - foreach my $opt (keys %options) { - die "ERREUR Ivy::init option $opt inconnue\n" unless - exists ($defaultOptions{$opt}); + # on examine toutes les options fournies, pour detecter les inutiles + foreach my $opt (keys %options) { + unless (exists ($optionsAndDefaults{$opt})) { + warn "Warning in Ivy::init: option $opt is unknown\n"; + } } - my $loopMode = $options{-loopMode}; - $ivyBus = $options{-ivyBus} ne "" ? $options{-ivyBus} : undef; - $appName = $options{-appName} ; - $messWhenReady = - $options{-messWhenReady} eq "_APP NAME READY" ? - "$appName READY" : $options{-messWhenReady}; - - $onDieFunc = $options{-onDieFunc} ; + my $loopMode = $options{-loopMode}; + $ivyBus = $options{-ivyBus}; + $appName = $options{-appName} ; + $onDieFunc = $options{-onDieFunc} ; @topicRegexps = @{$options{-pruneRegexp}}; + $messWhenReady = $options{-messWhenReady} eq "_APP NAME READY" ? + "$appName READY" : + $options{-messWhenReady}; + if ($loopMode =~ /local/i) { # mode boucle d'evenement locale use IO::Select; $fileEventFunc = \&fileEvent ; $localLoopSel = IO::Select->new (); + } elsif ($loopMode =~ /tk/i) { # mode boucle d'evenement de TK $fileEventFunc = \&_tkFileEvent ; + } else { - die "l'argument \"mainloop mode\" doit etre TK ou LOCAL\n"; + die "Error in Ivy::init, argument loopMode must be either TK or LOCAL\n"; } - $SIG{'PIPE'} = 'IGNORE' ; + $SIG{'PIPE'} = 'IGNORE' ; } ############# METHODE DE CLASSE NEW @@ -363,7 +367,7 @@ sub new ($%) # on verifie que la methode de classe init ait ete appelee unless ((defined $appName) && ($appName ne '')) { - die "ERREUR Ivy::new vous devez initialiser le module via Ivy->init ()"; + die "Error in Ivy::new, you should have called Ivy->init () first."; } # No de port tcp du serveur @@ -432,7 +436,7 @@ sub new ($%) $self->[buffByConn] = {}; - my %defaultOptions = ( + my %optionsAndDefaults = ( -appName => $appName, # nom de l'appli @@ -477,24 +481,25 @@ sub new ($%) ) ; - foreach my $opt (keys %defaultOptions) { - # si un parametre n'a pas ete defini + # on examine toutes les options possibles + foreach my $opt (keys %optionsAndDefaults) { + # si un parametre a ete fourni, ignorer les valeurs par defaut next if defined $options{$opt} ; - # est-il facultatif - if (defined $defaultOptions{$opt}) { - $options{$opt} = $defaultOptions{$opt} ; + # sinon, prendre la valeur par defaut si elle existe + if (defined $optionsAndDefaults{$opt}) { + $options{$opt} = $optionsAndDefaults{$opt} ; + # sinon, on jette l'eponge } else { - # parametre obligatoire - die "ERREUR Ivy::new vous devez specifier ". - "l'option $opt\n"; + die "Error in Ivy::new: option $opt is mandatory\n"; } } - foreach my $opt (keys %options) { - die "ERREUR Ivy::start option $opt inconnue\n" unless - exists ($defaultOptions{$opt}); + # on examine toutes les options fournies, pour detecter les inutiles + foreach my $opt (keys %options) { + unless (exists ($optionsAndDefaults{$opt})) { + warn "Warning in Ivy::new, option $opt is unknown\n"; + } } - $self->[appName] = $options{-appName} ; @@ -505,7 +510,7 @@ sub new ($%) $allBuses{$self} = $self; ($self->[broadcastPort], $self->[broadcastBuses]) = - _parseIvyBusParam ($options{-ivyBus}); + _parseIvyBusParam ($options{-ivyBus}); return ($self); @@ -529,12 +534,12 @@ sub DESTROY ($) } } - # on clos la socket de signalisation (UDP) + # on clot la socket de signalisation (UDP) # print "DBG> fermeture de supSock\n"; $self->[supSock]->close() if $self->[supSock]; delete $allBuses{$self}; - # on clos la socket de connection + # on clot la socket de connection # print "DBG> fermeture de connSock\n"; $self->[connSock]->close() if $self->[connSock]; undef (@$self); @@ -595,8 +600,8 @@ sub start ($) foreach my $netBroadcastAddr (@{$self->[broadcastBuses]}) { send ($self->[supSock], $bonjourMsg, 0, $netBroadcastAddr) or - warn "Ivy::start envoi du bonjour a echoue sur : $!\n"; - } + warn "Warning in Ivy::start, broadcast of Hello message failed: $!\n"; + } # callback pour traiter la reception des bonjours &$fileEventFunc ($self->[supSock], [\&_getBonjour, $self]) ; @@ -744,7 +749,7 @@ sub sendDirectMsgs ($$$@) } return 1; } else { - warn "Ivy::sendDirectMsgs appli $to inconnue\n"; + warn "Warning in Ivy::sendDirectMsgs, application $to unknown\n"; return 0; } } @@ -769,7 +774,7 @@ sub sendDieTo ($$) return 1; } else { - warn "Ivy::sendDieTo appli $to inconnue\n" if $^W; + warn "Warning in Ivy::sendDieTo, application $to is unknown\n" if $^W; return 0; } } @@ -797,8 +802,8 @@ sub ping ($$$) ############### METHODE MAINLOOP sub mainLoop () { - die "Erreur Ivy->mainLoop, Ivy doit etre initialise en mode". - " loopMode local\n" unless defined $localLoopSel; + die "Error in Ivy::mainLoop, Ivy should have been initialised with LOCAL loop mode \n" + unless defined $localLoopSel; my ($fd, @ready, @allDesc); @@ -895,8 +900,7 @@ sub fileEvent ($$;$) unless (defined $localLoopSel) { - die ("Erreur Ivy::fileEvent : Ivy::fileEvent n'est utilisable qu'en ". - "mode mainLoop LOCALE\n"); + die ("Error in Ivy::fileEvent, Ivy should have been initialised in LOCAL loop mode\n"); } if ($cb) { @@ -927,7 +931,7 @@ sub _getBonjour ($) my $inetAddr = $self->[supSock]->recv ($bonjourMsg, 1024, 0); unless (length $inetAddr) { - warn "Attention : Ivy::_getBonjour recv error, bonjour non traite\n"; + warn "Warning in Ivy::_getBonjour, recv error, Hello message discarded\n"; return; } @@ -939,14 +943,14 @@ sub _getBonjour ($) my ($version, $peerPort) = $bonjourMsg =~ /^(\d+)\s+(\d+)/; unless (defined ($version) && defined ($peerPort)) { - warn "Attention : Ivy::_getBonjour format du message bonjour incorrect\n". - "message = $bonjourMsg\n" ; + warn "Warning in Ivy::_getBonjour, ill-formed Hello message \"$bonjourMsg\"\n" ; return; } if ($version != IVY_PROTOCOLE_VERSION) { - warn "Attention : Ivy::_getBonjour VERSION: demande de connexion de ". - "$peerName\n version courrante : " . IVY_PROTOCOLE_VERSION . ", recue : $version\n" ; + warn "Warning in Ivy::_getBonjour, connection request from ". + "$peerName with protocol version $version,\ncurrent version is " . + IVY_PROTOCOLE_VERSION . "\n" ; return; } @@ -977,7 +981,8 @@ sub _getBonjour ($) } if ($addrInIvyBus == 0) { - warn "bonjour de $peerName ignore, ne fait pas partie des ivyBus\n" if $^W; + warn "Warning: Hello message from $peerName ignored,\n". + "this guy is outside our emission zone\n" if $^W; return; } @@ -998,8 +1003,8 @@ sub _getBonjour ($) $self->_sendWantedRegexp ($appSock); } else { - warn "Attention Ivy::_getBonjour impossible de se connecter au serveur" . - "$peerName:$peerPort\n" ; + warn "Warning in Ivy::_getBonjour, connection to " . + "$peerName:$peerPort is impossible\n" ; } } @@ -1012,12 +1017,12 @@ sub _getConnections ($) my $appSock = $self->[connSock]->accept(); unless (defined $appSock) { - warn "Attention Ivy::_getConnections, \$appSock not defined\n"; + warn "Warning in Ivy::_getConnections, \$appSock not defined\n"; return; } else { - printf "accepting connection from %s:%d\n", - (gethostbyaddr ($appSock->peeraddr(),AF_INET))[0], +# printf "accepting connection from %s:%d\n", +# (gethostbyaddr ($appSock->peeraddr(),AF_INET))[0], $appSock->peerport() if $^W; } @@ -1084,7 +1089,7 @@ sub _getMessages ($$) (.*)/x ; # si ca a chie on rale - (warn "Attention Ivy::_getMessages malformated message $mess\n" and return) unless defined $type ; + (warn "Warning in Ivy::_getMessages, ill-formated message $mess\n" and return) unless defined $type ; # sinon on fait en fonction du type de message if ($type == MSG) { # M S G @@ -1105,8 +1110,8 @@ sub _getMessages ($$) } else { #_sendErrorTo ($appSock, "REEGXP ID $id inconnue"); - warn ("Attention Ivy::_getMessages reception d'un message ". - "MSG : id $id inconnu de $senderName :\n«$mess»"); + warn ("Warning in Ivy::_getMessages, received an unknown message ". + "with id $id from $senderName :\n\"$mess\""); } } elsif ($type == BYE) { @@ -1146,8 +1151,8 @@ _EOL_ } } elsif ($type == ERROR) { # E R R O R - warn ("Attention Ivy::_getMessages ERREUR recue de ". - "$senderName : «$valeurs»\n"); + warn ("Warning in Ivy::_getMessages, error message received from ". + "$senderName : \"$valeurs\"\n"); } elsif ($type == DELREGEXP) { # D E L R E G E X P # on vire la regexp des regexps vefifier @@ -1174,8 +1179,8 @@ _EOL_ elsif ($type == APP_NAME) { # etat Connecte if (($self->[appName] eq $valeurs) && $^W) { - warn "\033[1mATTENTION : Ivy::_getMessages une instance de ". - "$self->[appName] existe deja\033[m\n" ; + warn "\033[1mWarning in Ivy::_getMessages, there is already an instance of ". + "$self->[appName] \033[m\n" ; } $senderName = $valeurs; @@ -1197,8 +1202,8 @@ _EOL_ } else { $self->_sendErrorTo ($appSock, "DIRECT ID $id inconnue"); - warn "Attention Ivy::_getMessages reception d'un message ". - "DIRECT d'id $id inconnue de $senderName :\n«$mess»"; + warn "Warning in Ivy::_getMessages, received a DIRECT message with ". + "unknown id $id from $senderName :\n\"$mess\""; } } elsif ($type == DIE) { # il faut quitter @@ -1215,8 +1220,8 @@ _EOL_ } # on avertit les autres qu'on se barre my $adr = $self->_inetAdrByName ($senderName) ; - warn "Attention Ivy::_getMessages reception d'un ordre " . - "de suicide de $senderName ($adr) ... exiting\n" if $^W; + warn "Notice in Ivy::_getMessages, received a suicide request from " . + "$senderName ($adr) ... exiting\n" if $^W; # adios Ivy::exit (); @@ -1230,8 +1235,8 @@ _EOL_ } else { _$self->sendErrorTo ($appSock, "TYPE DE MESS $type inconnu"); - warn ("reception d'un message de type $type inconnu de " . - "$senderName :\n«$mess»"); + warn ("Warning in Ivy::_getMessages, received a message of unknown ". + " type $type from $senderName :\n\"$mess\""); } } return 0; @@ -1326,7 +1331,7 @@ sub _removeFileDescriptor ($$) } unless (defined $diedAppName) { - warn "Ivy::__removeFileDescriptor : deconnection de NONAME\n" if $^W; + warn "Ivy::__removeFileDescriptor : disconnection of NONAME\n" if $^W; return; } @@ -1334,7 +1339,7 @@ sub _removeFileDescriptor ($$) keys %{$self->[cnnxion]}))[0]; unless (defined $addrInet) { - die "ERREUR _removeFileDescriptor deconnection de $diedAppName ". + die "Error in Ivy::_removeFileDescriptor, disconnection of $diedAppName with ". "addrInet not defined\n"; return; } @@ -1500,8 +1505,7 @@ sub _parseIvyBusParam ($) my ($ivyNetworks, $ivyPort) = $ivyBus =~ /^(.*):(.*)/; - die ("Erreur Ivy::_parseIvyBusParam format de l'adresse ou ". - "no de port incorrect : $ivyBus\n") + die ("Error in Ivy::_parseIvyBusParam, illegal bus address format: $ivyBus\n") unless $ivyPort =~ /^\d+$/; my @ivyAddrInet = (); @@ -1527,7 +1531,7 @@ sub _parseIvyBusParam ($) # chaque 0 qui sort a gauche est remplace par un 255 a droite. my $networkAddr = getnetbyname ($netAddr); unless (defined $networkAddr) { - warn ("Ivy::_parseIvyBusParam reseau inconnu : $netAddr\n"); + warn ("Warning in Ivy::_parseIvyBusParam, network $netAddr is unknown\n"); next; } @@ -1541,7 +1545,7 @@ sub _parseIvyBusParam ($) $netAddrInet = pack ("CCCC", @dummyNetAddr); } else { # on a deja une adresse ip, on rajoute les .255 - # a la fin s'ils ont etes omis. + # a la fin s'ils ont ete omis. ($netAddr .= ".255.255.255") =~ s/^((\d+\.){3}\d+).*/$1/; $netAddrInet = inet_aton ($netAddr); } @@ -1580,8 +1584,8 @@ use Ivy; =head1 DESCRIPTION -The Ivy perl module implements a software bus to provide with an easy -communication between applications. Messages are broadcasted as ASCII strings +The Ivy perl module implements a software bus that provides easy +communication between applications. Messages are broadcast as ASCII strings over a network defined by a list of domains and a port. Messages are received if they match a regular expressions and if your application is on the same network as remote ones. @@ -1612,7 +1616,7 @@ Name of your application used to identify on ivy bus. =item B<-ivyBus =E<gt> 'domain 1,...,domain n:port number'> A list of domains, followed by port number where to broadcast messages. -Default is 127.255.255.255:2010 +Default is 127:2010 =item B<-messWhenReady =E<gt> 'your message when ready'> @@ -1623,10 +1627,10 @@ messages. =item B<-onDieFunc =E<gt> [$an_object, \&a_method, @parameters]> -A callback or method to call when application receive die message. -Don't make an exit in callback, ivy we'll do it for you. +A callback or method to call when your application receive a suicide request. +Do not call exit() in the callback, Ivy will do it for you. -Prototype of your callback must be : +The prototype of your callback must be as follows: sub MyCallback { my @parameters = @_; @@ -1634,7 +1638,7 @@ sub MyCallback { ... } -Prototype of your method must be : +The prototype of your method must be as follows: sub MyMethod { my ($self, @parameters) = @_; @@ -1644,7 +1648,8 @@ sub MyMethod { =item B<-pruneRegexp =E<gt> ['subject 1', ..., 'subject n']> -Optimize communication using this option. Regexps which don't match these subjects are removed. +Optimize communication using this option. Regexps +which don't match these subjects are removed. Example : @@ -1656,41 +1661,42 @@ Example : =head2 Ivy->new(...); -Check parameters, and create an ivy bus object. You must call Ivy->init before -this one. +Check parameters, and create an Ivy bus object. You must call +Ivy->init before creating a bus. Parameters are : =over 4 -=item B<-appName =E<gt> 'your app ivy name'> +=item B<-appName =E<gt> 'your application name'> -Name of your application used to identify on ivy bus. +Name of your application used to identify it with other applications +connected on the same bus. =item B<-ivyBus =E<gt> 'domain 1,...,domain n:port number'> A list of domains, followed by port number where to broadcast messages. -Default is 127.255.255.255:2010 +Default is 127:2010 =item B<-messWhenReady =E<gt> 'your message when ready'> -Synchronisation message sent when application is ready to receive and send +Synchronisation message sent when your application is ready to receive and send messages. =item B<-onDieFunc =E<gt> [\&yourdiefunc, @parameters]> =item B<-onDieFunc =E<gt> [$an_object, \&a_method, @parameters]> -A callback or method to call when application receive die message. -Don't make an exit in callback, ivy we'll do it for you. -Prototype of your callback must be : +A callback or method called when your application receives a suicide request. +Do not call exit() in the callback, Ivy will do it for you. +The prototype of your callback must be as follows: sub MyCallback { my @parameters = @_; ... } -Prototype of your method must be : +The prototype of your method must be as follows: sub MyMethod { my ($self, @parameters) = @_; @@ -1703,13 +1709,14 @@ Optimize communication using this option. Regexps which don't match these subjec =item B<-neededApp =E<gt> ['app 1', ..., 'app n']> -A list of application your own one needs to correctly run. +A list of applications that your application needs present on the bus +before running. =item B<-statusFunc =E<gt> sub {}> -A callback which will be called until every needed app is present on bus. +A callback which will be called until every needed app is present on the bus. -Your callback could be : +Your callback could be: sub MyCallback { my ($present, $absent, %present) = @_; @@ -1720,9 +1727,9 @@ Your callback could be : } } -Example : +Example: - Ivy->new(-ivyBus => '156.255.255.255,157.255.255.255:2204', + Ivy->new(-ivyBus => '156,157:2204', -onDieFunc => [\&restorecontext], -neededApp => ["DataServer", "HMI"], -statusFunc => \&startwhenpresents); @@ -1731,7 +1738,7 @@ Example : =head2 Ivy->mainLoop; -Local main events loop. Use it if you don't use Tk library. +Local main events loop. Use it if you don't use the Tk library. =head2 $ivyobj->stop; @@ -1739,7 +1746,7 @@ Local main events loop. Use it if you don't use Tk library. =head2 $ivyobj->start; -You must call it after you are ready to communicate through ivy bus +You must call this after you are ready to communicate through an Ivy bus and before you really communicate. =head2 $ivyobj->sendMsgs(@messages); @@ -1752,21 +1759,22 @@ Example : =head2 $ivyobj->sendAppNameMsgs(@messages); -Send a list of messages precedeed by ivy application name. +Send a list of messages preceded by your application's name. Example : $ivyobj->sendMsgs("Hello World"); - # it will send "$appName Hello World" over ivy bus + # it will send "$appName Hello World" over the Ivy bus =head2 $ivyobject->bindRegexp($regexp, [\&callback, @cb_parameters]); =head2 $ivyobject->bindRegexp($regexp, [$an_obj, \&method, @cb_parameters]); -Allow one to associate a message which matches a regular expression and a -callback or method. See perlre(1), to find how to write regexps. -Use the bracketing construct ( ... ), so that ivy perl will call -callback with matched patterns as parameters. +This allows you to bind a regular expression to a +callback or method. The callback or method will be called for every +message that matches the regexp. See perlre(1) to find how to write regexps. +Use the bracketing construct ( ... ) so that your callback is +called with the captured bits of text as parameters. Example : @@ -1774,7 +1782,7 @@ Example : # You callback will be called with one more parameter which will be # a number precedeed by a word, because of bracketed regexp. -Your callback and method protos must be : +Your callback and method must be like: sub cb { my ($sendername, @cb_parameters, @@ -1800,19 +1808,19 @@ Same as bindRegexp method but Ask Alex to find what is $id. =head2 $ivyobj->sendDieTo($to) -send a die message to $to application name. +Send a suicide to the application named $to. =head2 $ivyobj->ping($to, $timeout); -send a ping message and wait until timeout to receive a pong. +Send a ping message and wait until timeout to receive a pong. =head2 $after_id = $ivyobj->after($timeAfter, \@callbacks_list); -Call a list of callbacks after $timeAfter mseconds. +Call a list of callbacks after $timeAfter milliseconds. =head2 $repeat_id = $ivyobj->repeat($timeAfter, \@callbacks_list); -Repeat calls of a list of callbacks after $timeAfter mseconds. +Have a list of callbacks repeatedly called every $timeAfter milliseconds. =head2 $ivyobj->afterCancel($after_or_repeat_id); @@ -1834,7 +1842,7 @@ perl(1), perlre(1) =head1 AUTHORS -Alexandre Bustico <bustico@tls.cena.fr>, Herve Damiano <damiano@tls.cena.fr> +Alexandre Bustico <bustico@cena.fr>, Herve Damiano <damiano@cena.fr> =head1 COPYRIGHT |