>From 5a821b0288b919163af84911ed45370ddc870a52 Mon Sep 17 00:00:00 2001
From: Mathias Hasselmann <mathias@openismus.com>
Date: Tue, 27 Nov 2007 11:07:57 +0100
Subject: [PATCH] Announce protocol revisions and DBMS revision as DNS-SD subtypes.

DNS-SD allows announcement of sub-types for efficient service selection. The
prime example DNS-SD experts give, are FTP servers that announce their support
for anonymous sessions. Anonymous clients using that information don't have to
bother with contacting FTP servers not announcing that feature. Other examples
are Bittorrent clients announcing the hashes of the files they offer, and
distcc servers announcing the compiler versions they support.

This patch introduces subtypes describing the protocol revisions supported and
the DBMS revision itself, assuming this information would be useful for clients
to find Postgresql servers with an adequate feature set.

The subtypes describing the protocol version look like this:

	_protocol-2._sub._postgresql._tcp
	_protocol-1._sub._postgresql._tcp

The DBMS revision types look like this:

	_version-8-3._sub._postgresql._tcp
	_version-8._sub._postgresql._tcp

In my opinion it is save to provide that information when announcing Postgresql
via DNS-SD: The server admin already decided to announce the server's existance,
so finding the server and getting that information by fingerprinting is easy.
already. Announcing this capabilities to just increases convenience and
reduces traffic the Postgresql server must handle.

Signed-off-by: Mathias Hasselmann <mathias@openismus.com>
---
 src/backend/postmaster/postmaster.c |   53 ++++++++++++++++++++++++++++++++++-
 1 files changed, 52 insertions(+), 1 deletions(-)

diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 7482dc0..9170223 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -217,6 +217,8 @@ char		*zeroconf_name;
 #if USE_AVAHI
 
 #define PM_SERVICE_TYPE				"_postgresql._tcp"
+#define PM_SERVICE_SUBTYPE_PROTOCOL(REV)	"_protocol-" #REV "._sub._postgresql._tcp"
+#define PM_SERVICE_SUBTYPE_VERSION(VER)		"_version-" #VER "._sub._postgresql._tcp"
 
 typedef struct
 {
@@ -4641,6 +4643,22 @@ HandleServiceCollision(ServiceState *service, bool local)
 }
 
 static void
+PublishSubtype(ServiceState *service, AvahiProtocol protocol, const char *subtype)
+{
+	int rc;
+
+	rc = avahi_entry_group_add_service_subtype (service->group, AVAHI_IF_UNSPEC, 
+						    protocol, 0, service->name,
+						    PM_SERVICE_TYPE, NULL,
+						    subtype);
+
+	if (AVAHI_OK != rc)
+		ereport(WARNING,
+				(errmsg("could not announce subtype %s: %s",
+				 subtype, avahi_strerror(rc))));
+}
+
+static void
 PublishServices(ServiceState *service)
 {
 	int socket_index = (service - pmServices);
@@ -4652,7 +4670,7 @@ PublishServices(ServiceState *service)
 	char host[NI_MAXHOST];
 	const char *fqdn = NULL;
 	int port = PostPortNumber;
-	int rc;
+	int rc, j;
 
 	/* Find the host name the socket is associated with. */
 
@@ -4715,10 +4733,43 @@ PublishServices(ServiceState *service)
 					   NULL, fqdn, port, NULL);
 
 	if (AVAHI_OK == rc)
+	{
+		char subtype[64];
+
 		ereport(LOG,
 				(errmsg("announcing %s socket %s:%d as \"%s\"",
 					avahi_proto_to_string (protocol),
 					host, port, service->name)));
+
+		/* Announce sub-services for each protocol version supported. */
+
+		for (j = PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST);
+		     j < PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST); ++j)
+		{
+			snprintf (subtype, sizeof subtype,
+				  PM_SERVICE_SUBTYPE_PROTOCOL(%d),
+				  j);
+
+			PublishSubtype(service, protocol, subtype);
+		}
+
+		/* Announce sub-service for major.minor part of the version number. */
+
+		snprintf (subtype, sizeof subtype,
+			  PM_SERVICE_SUBTYPE_VERSION(%d-%d),
+			  PG_VERSION_NUM / 10000,
+			  PG_VERSION_NUM / 100 % 100);
+
+		PublishSubtype(service, protocol, subtype);
+
+		/* Announce sub-service for the major version number. */
+
+		snprintf (subtype, sizeof subtype,
+			  PM_SERVICE_SUBTYPE_VERSION(%d),
+			  PG_VERSION_NUM / 10000);
+
+		PublishSubtype(service, protocol, subtype);
+	}
 	else if (AVAHI_ERR_COLLISION == rc)
 		/* Find another service name, if the choosen name is already in use. */
 		HandleServiceCollision(service, true);
-- 
1.5.2.5

