summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormertz2002-06-20 15:06:27 +0000
committermertz2002-06-20 15:06:27 +0000
commit793615e3565a64b1578cc90c3d6dc8dba33a4bff (patch)
tree6ad2aa8d4f4c5ef9b6e7c6504b5bda4c83a26548
parentf305fd799b654ecf615a9c146b4493f3e75034b4 (diff)
downloadivy-perl-793615e3565a64b1578cc90c3d6dc8dba33a4bff.zip
ivy-perl-793615e3565a64b1578cc90c3d6dc8dba33a4bff.tar.gz
ivy-perl-793615e3565a64b1578cc90c3d6dc8dba33a4bff.tar.bz2
ivy-perl-793615e3565a64b1578cc90c3d6dc8dba33a4bff.tar.xz
multicast is now possible on with address such as 235.0.1.2:7654
-rw-r--r--Ivy.pm147
1 files changed, 96 insertions, 51 deletions
diff --git a/Ivy.pm b/Ivy.pm
index 823f775..4b535e8 100644
--- a/Ivy.pm
+++ b/Ivy.pm
@@ -39,6 +39,7 @@ use IO::Socket;
use strict;
use Time::Gettimeofday;
use Carp;
+use IO::Socket::Multicast;
use vars qw($VERSION);
@@ -290,6 +291,7 @@ use constant cnnxion => $constantIndexer++;
use constant buffByConn => $constantIndexer++;
use constant broadcastPort => $constantIndexer++;
use constant broadcastBuses => $constantIndexer++;
+use constant useMulticast => $constantIndexer++;
use constant appName => $constantIndexer++;
use constant messWhenReady => $constantIndexer++;
@@ -546,7 +548,7 @@ sub new ($%)
$self->[topicRegexps] = $options{-pruneRegexp} ;
$allBuses{$self} = $self;
- ($self->[broadcastPort], $self->[broadcastBuses]) =
+ ($self->[useMulticast], $self->[broadcastPort], $self->[broadcastBuses]) =
_parseIvyBusParam ($options{-ivyBus});
@@ -558,7 +560,7 @@ sub DESTROY ($)
{
my $self = shift;
return unless exists $allBuses{$self};
- # print ("DBG DESTROY appele sur l'objet $self\n");
+ # print ("DBG> DESTROY appele sur l'objet $self\n");
# pour toutes les connections
foreach my $fd (values %{$self->[sockList]}) {
@@ -614,20 +616,20 @@ sub exit ()
############### PROCEDURE BUS START
sub start
{
- my $self;
+ my $self;
- # compatibility for version 3 interface, ie. no objects manipulated by programmer
- if (not @_ or ref ($_[0]) ne __PACKAGE__) {
- init (@_);
- $self = $globalIvy = new Ivy;
- } else {
- $self = shift;
- }
+ # compatibility for version 3 interface, ie. no objects manipulated by programmer
+ if (not @_ or ref ($_[0]) ne __PACKAGE__) {
+ init (@_);
+ $self = $globalIvy = new Ivy;
+ } else {
+ $self = shift;
+ }
- if ($self->[connSock]) {
- print "*** the Ivy bus is already started\n";
- return;
- }
+ if ($self->[connSock]) {
+ print "*** the Ivy bus is already started\n";
+ return;
+ }
# cree la socket de connexion, recupere le no de port
my $connSock = $self->[connSock] = IO::Socket::INET->new(Listen => 128,
Proto => 'tcp',
@@ -640,22 +642,46 @@ sub start
$self->[cnnxion]->{"$hostAddr:". $connSock->sockport} = "\004";
$self->[cnnxion]->{"$localhostAddr:". $connSock->sockport} = "\004";
- # cree la socket de broadcast
- $self->[supSock] = IO::Socket::INET->new
- (LocalPort => $self->[broadcastPort],
- Proto => 'udp',
- Type => SOCK_DGRAM,
- Reuse => 1);
-
- $self->[supSock]->sockopt (SO_BROADCAST, 1);
-
-
- # et on envoie envoie le bonjour : "no de version no de port"
+ # le message de bonjour à envoyer: "no de version no de port"
my $bonjourMsg = sprintf ("%d %d\n", IVY_PROTOCOLE_VERSION, $connSock->sockport());
- foreach my $netBroadcastAddr (@{$self->[broadcastBuses]}) {
- send ($self->[supSock], $bonjourMsg, 0, $netBroadcastAddr) or
- carp "Warning in Ivy::start, broadcast of Hello message failed: $!";
+ if (!$self->[useMulticast]) {
+ # cree la socket de broadcast
+ $self->[supSock] = IO::Socket::INET->new
+ (LocalPort => $self->[broadcastPort],
+ Proto => 'udp',
+ Type => SOCK_DGRAM,
+ Reuse => 1);
+ $self->[supSock]->sockopt (SO_BROADCAST, 1);
+ foreach my $netBroadcastAddr (@{$self->[broadcastBuses]}) {
+ print "BroadcastBus: --", $netBroadcastAddr, "--\n";
+ send ($self->[supSock], $bonjourMsg, 0, $netBroadcastAddr) or
+ carp "Warning in Ivy::start, broadcast of Hello message failed: $!";
+ }
+ }
+ else {
+ # creating the multicast socket
+ $self->[supSock] = IO::Socket::Multicast->new
+ (LocalPort => $self->[broadcastPort],
+ ReuseAddr => 1);
+
+ # Multicast datagrams with initial TTL 0 are restricted to the same host.
+ # Multicast datagrams with initial TTL 1 are restricted to the same subnet.
+ # Multicast datagrams with initial TTL 32 are restricted to the same site.
+ # Multicast datagrams with initial TTL 64 are restricted to the same region.
+ # Multicast datagrams with initial TTL 128 are restricted to the same continent.
+ # Multicast datagrams with initial TTL 255 are unrestricted in scope.
+ $self->[supSock]->mcast_ttl(64);
+ # $self->[supSock]->mcast_loopback(1); must be 1, which is the default
+
+ foreach my $netMulticastAddr (@{$self->[broadcastBuses]}) {
+ my ($port,$multicastGroupI) = sockaddr_in ($netMulticastAddr);
+ my $multicastGroup = inet_ntoa($multicastGroupI);
+ # print "DBG> MulticastBus: --", $multicastGroup,":$port", "--\n";
+ $self->[supSock]->mcast_add($multicastGroup);
+ $self->[supSock]->mcast_send($bonjourMsg, $multicastGroup.":".$port) or
+ carp "Warning in Ivy::start, multicast of Hello message failed: $!";
+ }
}
# callback pour traiter la reception des bonjours
&$fileEventFunc ($self->[supSock], [\&_getBonjour, $self]) ;
@@ -688,7 +714,7 @@ sub bindRegexp
|xge;
$regexp = _substituteEscapedChar ('outside', $regexp);
- # print ("DBG regexp = $regexp\n");
+ # print ("DBG> regexp = $regexp\n");
eval {my $test = "a" =~ /$regexp/ } ; # testing the regexp for avoiding
if ($@) { carp "Warning in Ivy::bindRegexp, ill-formed regexp: '$original_regexp'" ; return };
@@ -1004,7 +1030,7 @@ sub fileEvent ($$;$)
} else {
# deleting the handler
delete $localBindByHandle{$fd};
-# print ("DBG: Ivy::fileEvent : removing fd from the select\n");
+# print ("DBG> Ivy::fileEvent : removing fd from the select\n");
$localLoopSel->remove ($fd);
}
} # end fileEvent
@@ -1051,11 +1077,11 @@ sub _getBonjour ($)
# on verifie qu'on ne se repond pas et qu'on ne
# se reconnecte pas a un process deja connecte
if (exists ($self->[cnnxion]{"$addr:$peerPort"})) {
- #print "DBG> : bonjour de $peerName:$peerPort : DEJA CONNECTE\n" ;
+ #print "DBG> bonjour de $peerName:$peerPort : DEJA CONNECTE\n" ;
return ;
}
else {
- #print "DBG> : reception de $peerName : bonjour $peerPort\n" ;
+ #print "DBG> reception de $peerName : bonjour $peerPort\n" ;
}
# on verifie que l'adresse fasse partie de l'ensemble de reseau
@@ -1147,7 +1173,7 @@ sub _getMessages ($$)
unless (length $buffer) {
# message null : broken pipe, ça s'est deconnecte a l'autre bout
# on vire ce fd de la boucle d'evenements
- # print ("DBG : _getMessages, recv err, calling removeFileDesc.\n");
+ # print ("DBG> _getMessages, recv err, calling removeFileDesc.\n");
# Bon la il faudra un jour clarifier ce bordel, lister toutes
# les facons dont un couple d'applis connectee peuevent sortir et
# eviter les dead lock qui doivent subsister.
@@ -1176,7 +1202,7 @@ sub _getMessages ($$)
$senderName = "NONAME" unless $senderName;
foreach my $mess (@messages) {
-# print "DBG>mess from $senderName '$mess'\n";
+# print "DBG> mess from $senderName '$mess'\n";
# on recupere les 3 champs : le type, le numero de regexp, les valeurs
my ($type, $id, $valeurs) = $mess =~ /^(\d+)
@@ -1186,7 +1212,7 @@ sub _getMessages ($$)
(.*)/x ;
# si ca a chie on rale
- (carp "Warning in Ivy::_getMessages, ill-formated message $mess" and return) unless defined $type ;
+ (carp "Warning in Ivy::_getMessages, ill-formated message \'$mess\'" and return) unless defined $type ;
# sinon on fait en fonction du type de message
if ($type == MSG) { # M S G
@@ -1224,7 +1250,7 @@ sub _getMessages ($$)
# ca permet de compiler les regexp avec 'once' donc une
# fois pour toute, et ainsi optimiser la vitesse de
# filtrage des messages a envoyer
-# print "DBG>REGEXP from $senderName '$id' '$valeurs'\n";
+# print "DBG> REGEXP from $senderName '$id' '$valeurs'\n";
next if $self->_toBePruned ($senderName, $valeurs);
unless (defined $self->[sendRegList]{$appSock}->[$id]) {
# si l'id de regexp n'etait pas utilisee c'est tout bon
@@ -1239,7 +1265,7 @@ sub _getMessages ($$)
send ($appSock, sprintf (MSG_FMT,
MSG, $id, join ("\003",@args)), 0)
or $self->_removeFileDescriptor ($appSock) ;
- #print join (' ', "DBG > J'envoie MSG", $id, @args, "\n");
+ #print join (' ', "DBG> J'envoie MSG", $id, @args, "\n");
return 1;
}
};
@@ -1366,7 +1392,7 @@ sub _sendWantedRegexp ($$)
send ($appSock,
sprintf (MSG_FMT, REGEXP, $id, $self->[recCbList][$id]->[0]),
0) or $self->_removeFileDescriptor ($appSock) ;
- # print sprintf ("DBG > %s %d %s\n",
+ # print sprintf ("DBG> %s %d %s\n",
# 'REGEXP', $id, $self->[recCbList][$id]->[0]);
}
# on envoie le message de fin d'envoi de regexps
@@ -1626,12 +1652,14 @@ sub _toBePruned ($$$)
############### PROCEDURE PARSE IVY BUS PARAM
-sub _parseIvyBusParam ($)
+sub _parseIvyBusParam ($)
{
my $ivyBus = shift;
my ($ivyNetworks, $ivyPort) = $ivyBus =~ /^(.*):(.*)/;
+ my $useMulticast = 0;
+
croak ("Error in Ivy::_parseIvyBusParam, illegal bus address format: $ivyBus\n")
unless $ivyPort =~ /^\d+$/;
@@ -1642,20 +1670,23 @@ sub _parseIvyBusParam ($)
foreach my $netAddr (@broadcastAddrs) {
$netAddr = BROADCAST_ADDRS if
- (($netAddr eq '') || ($netAddr =~ /^127/) ||
- ($netAddr =~ /^loopback/));
+ (($netAddr eq '') || ($netAddr =~ /^127/) || ($netAddr =~ /^loopback/));
# deux cas de figure : on a un nom de sous reseau, ou
# une adresse ip de la forme \d+.\d+....
my $netAddrInet;
- if ($netAddr !~ /^(\d+\.)+\d+/) {
+ if ($netAddr !~ /^\d+(.\d+)+/) {
# on a un nom de reseau, il faut trouver son adresse ip
# on contourne un bug : Si les adresses sont incompletes
# dans la map network : 143.196.53 au lieu de 143.196.53.255
# getbyname renvoie une adresse de type 0.143.196.53.
# on doit donc faire un decalage des octets vers la gauche,
# chaque 0 qui sort a gauche est remplace par un 255 a droite.
+ if ($useMulticast) {
+ carp "Warning in Ivy::_parseIvyBusParam, cannot mix broadcast and multicast.\n\tSkipping broadcast address $netAddr";
+ next;
+ }
my $networkAddr = getnetbyname ($netAddr);
unless (defined $networkAddr) {
warn ("Warning in Ivy::_parseIvyBusParam, network $netAddr is unknown\n");
@@ -1674,12 +1705,24 @@ sub _parseIvyBusParam ($)
# on a deja une adresse ip, on rajoute les .255
# a la fin s'ils ont ete omis.
($netAddr .= ".255.255.255") =~ s/^((\d+\.){3}\d+).*/$1/;
+ my ($dClass) = $netAddr =~ /^(\d*)/ ;
+ if ($dClass >= 224 and $dClass <= 239) { # this adress is for multicast
+ if (!$useMulticast) { # removing all broadcast addresses
+ carp "Warning in Ivy::_parseIvyBusParam, cannot mix broadcast and multicast.\n\tSkipping previous broadcast address" if (scalar @ivyAddrInet);
+ @ivyAddrInet = ();
+ $useMulticast = 1;
+ }
+ }
+ else { # this adress is for broadcast
+ if ($useMulticast) { # we are already in multicast, forget this new address
+ carp "Warning in Ivy::_parseIvyBusParam, cannot mix broadcast and multicast.\n\tSkipping broadcast address $netAddr";
+ next;
+ }
+ }
$netAddrInet = inet_aton ($netAddr);
- }
-
- push (@ivyAddrInet, pack_sockaddr_in ($ivyPort, $netAddrInet));
+ push (@ivyAddrInet, pack_sockaddr_in ($ivyPort, $netAddrInet));
}
-
+}
unless (scalar @ivyAddrInet) {
push (@ivyAddrInet, pack_sockaddr_in ($ivyPort, inet_aton(BROADCAST_ADDRS)));
}
@@ -1687,12 +1730,13 @@ sub _parseIvyBusParam ($)
foreach my $ivyAddr (@ivyAddrInet) {
my ($port, $iaddr) = unpack_sockaddr_in($ivyAddr);
my $iaddrH = unpack ("H8",$iaddr);
- my $iaddrInt = join (".", unpack ("C4", $iaddr));
-
- print "Broadcasting on network $iaddrInt ($iaddrH) on port $ivyPort\n";
+ my $iaddrInt = inet_ntoa($iaddr);
+ if ($useMulticast) {print "Multicasting"}
+ else {print "Broadcasting"}
+ print " on network $iaddrInt ($iaddrH) on port $ivyPort\n";
}
- return ($ivyPort, \@ivyAddrInet);
+ return ($useMulticast, $ivyPort, \@ivyAddrInet);
} # end _parseIvyBusParam
############# Procedure _SUBSTITUTE ESCAPED CHAR
@@ -1765,6 +1809,7 @@ If the domain list is empty (i.e. parameter is ':port number'), broadcast will b
on localhost (i.e. '127:port number'). Default is the value of the environment variable
IVYBUS and if it is not defined the default is 127:2010.
+Since V4.12, it is possible to use multicast (ie. with a domain between 224.0.0.0 and 239.255.255.255). You must be aware than when multicast is used, udp broadcast (defined in the B<-ivyBus> paramter) are skipped. You should also probably avoid using the 244.x.x.x domain often used for networking management.
=item B<-messWhenReady =E<gt> 'your message when ready'>
@@ -2084,7 +2129,7 @@ The stop method does not work!
In the statusFunc, an agent is identified by its name which is not garantted as unique
-A message to be sent should contain no '\n' char, because the '\n' is the message separator.
+A message to be sent should not contain '\n' char, because the '\n' is the message separator. Ivy.pm will detect and skip such messages.
No other known bugs at this time. If you find one, please report them to the authors.