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 )