Fugu
view release on metacpan or search on metacpan
lib/Fugu/Mdnsd.pm view on Meta::CPAN
# $self->publish(%args):
# Connect if necessary, then publish. This is the whole startup
# path of a daemon that advertises one service: one call, one
# error to report. The arguments are those of publish_service.
# The method returns 1, or undef with the reason in ->error.
sub publish ( $self, %args )
{
if ( !$self->{imsg} ) {
$self->connect or return;
}
return $self->publish_service(%args);
}
# $self->publish_service(%args):
# name => $instance service instance name, also the group
# name. mdnsd requires them equal
# [MDNS-Control §7].
# app => $app application protocol, no underscore
# proto => $proto 'tcp' or 'udp'
# port => $port port number
# txt => $string formatted TXT string [MDNS-Control §5]
# timeout => $secs overrides the object default
# Send the ADD/ADD_SERVICE/COMMIT sequence. Wait for
# GROUP_PUBLISHED. The method returns 1 when the service is
# published. It returns undef on invalid arguments, no
# connection, an error reply, EOF, or timeout. The reason is in
# ->error.
sub publish_service ( $self, %args )
{
my $service = $self->_check_service(%args) or return;
# To republish on a held connection, use update_txt. mdnsd
# silently ignores the duplicate GROUP_ADD, drops the
# ADD_SERVICE, and answers the COMMIT with a success-looking
# reply sequence for the old records [MDNS-Control §8]
if ( $self->{published} ) {
$self->{error} = 'already published';
return;
}
if ( !$self->{imsg} ) {
$self->{error} = 'not connected';
return;
}
$self->{service} = $service;
return $self->_publish( $args{timeout} // $self->{timeout} );
}
# $self->update_txt(%args):
# txt => $string replacement TXT string
# timeout => $secs overrides the object default
# Re-advertise with a new TXT record. Same-socket replacement
# does not work [MDNS-Control §8]. Thus the method withdraws and
# republishes over a fresh connection. It reuses the service
# parameters from publish_service. While unpublished, it is a
# no-op that returns 1. This mirrors the old mdnsctl wrapper.
sub update_txt ( $self, %args )
{
return 1 unless $self->{published};
my $txt = $args{txt} // '';
if ( length($txt) > TXT_MAX ) {
$self->{error} = 'txt too long';
return;
}
$self->withdraw;
$self->{service}{txt} = $txt;
$self->connect or return;
return $self->_publish( $args{timeout} // $self->{timeout} );
}
# $self->withdraw:
# Close the control socket. That is the entire operation. mdnsd
# kills the connection's groups and sends goodbyes
# [MDNS-Control §6].
sub withdraw ($self)
{
if ( $self->{imsg} ) {
$self->{imsg}->close;
$self->{imsg} = undef;
}
$self->{published} = 0;
return 1;
}
# The held socket is the lifetime of the advertisement
# [MDNS-Control §6]. Thus the object going away must withdraw the
# service, whether the caller remembered to or not.
sub DESTROY ($self)
{
$self->withdraw;
}
# $self->is_published:
# The method returns true while the service is published on a
# held connection.
sub is_published ($self)
{
return $self->{published};
}
# $self->error: the most recent failure.
sub error ($self)
{
return $self->{error};
}
# $self->_check_service(%args):
# Validate the lengths against the wire field limits.
# Over-length input is an error, never a silent truncation
# [MDNS-Control §4]. Return the parameter set that publish and
# update reuse.
sub _check_service ( $self, %args )
{
( run in 0.829 second using v1.01-cache-2.11-cpan-4ef0a570458 )