]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Adopt new DNS-SD API for cupsd sharing (Issue #931)
authorMichael R Sweet <msweet@msweet.org>
Thu, 18 Apr 2024 18:14:28 +0000 (14:14 -0400)
committerMichael R Sweet <msweet@msweet.org>
Thu, 18 Apr 2024 18:14:28 +0000 (14:14 -0400)
Note: Still needs more testing.

cups/dnssd.c
cups/dnssd.h
scheduler/cupsd.h
scheduler/dirsvc.c
scheduler/dirsvc.h
scheduler/printers.h

index c097f83786fe293d59cbd047cd0b3058c1c81d74..a68b8a68d49006c58c642507dd03d0e3ade194ae 100644 (file)
 #include "debug-internal.h"
 #include "dnssd.h"
 
+#ifdef __APPLE__
+#  include <nameser.h>
+#  include <CoreFoundation/CoreFoundation.h>
+#  include <SystemConfiguration/SystemConfiguration.h>
+#endif // __APPLE__
 #ifdef HAVE_MDNSRESPONDER
 #  include <dns_sd.h>
 #  if _WIN32
@@ -197,6 +202,67 @@ cupsDNSSDAssembleFullName(
 }
 
 
+//
+// 'cupsDNSSDCopyComputerName()' - Copy the current human-readable name for the system.
+//
+// This function copies the current human-readable name ("My Computer") to the
+// provided buffer.  The "dnssd" parameter is a DNS-SD context created with
+// @link cupsDNSSDNew@.  The "buffer" parameter points to a character array of
+// at least 128 bytes and the "bufsize" parameter specifies the actual size of
+// the array.
+//
+
+char *                                 // O - Computer name or `NULL` on error
+cupsDNSSDCopyComputerName(
+    cups_dnssd_t *dnssd,               // I - DNS-SD context
+    char         *buffer,              // I - Computer name buffer
+    size_t       bufsize)              // I - Size of computer name buffer (at least 128 bytes)
+{
+  // Range check input...
+  if (buffer)
+    *buffer = '\0';
+
+  if (!dnssd || !buffer || bufsize < 128)
+    return (NULL);
+
+  // Copy the current computer name...
+#ifdef __APPLE__
+  SCDynamicStoreRef sc;                        // Context for dynamic store
+  CFStringEncoding nameEncoding;       // Encoding of computer name
+  CFStringRef  nameRef;                // Computer name CFString
+
+  if ((sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("libcups"), NULL, NULL)) != NULL)
+  {
+    // Get the computer name from the dynamic store...
+    if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL)
+    {
+      if (!CFStringGetCString(nameRef, buffer, (CFIndex)bufsize, kCFStringEncodingUTF8))
+        *buffer = '\0';
+
+      CFRelease(nameRef);
+    }
+
+    CFRelease(sc);
+  }
+
+#elif defined(HAVE_MDNSRESPONDER)
+  char *bufptr;                        // Pointer into name
+
+  cupsMutexLock(&dnssd->mutex);
+  cupsCopyString(buffer, dnssd->hostname, bufsize);
+  cupsMutexUnlock(&dnssd->mutex);
+
+  if ((bufptr = strchr(buffer, '.')) != NULL)
+    *bufptr = '\0';
+
+#else // HAVE_AVAHI
+  cupsCopyString(buffer, avahi_client_get_host_name(dnssd->client), bufsize);
+#endif // __APPLE__
+
+  return (buffer);
+}
+
+
 //
 // 'cupsDNSSDCopyHostName()' - Copy the current mDNS hostname for the system.
 //
index 9f0d41e20e6b5f28dee9a81de3a03c5884e7258a..f3388bc8bffd3f6d49c7b89adc8b999d077977a3 100644 (file)
@@ -88,6 +88,7 @@ typedef void (*cups_dnssd_service_cb_t)(cups_dnssd_service_t *service, void *cb_
 // Functions...
 //
 
+extern char            *cupsDNSSDCopyComputerName(cups_dnssd_t *dnssd, char *buffer, size_t bufsize) _CUPS_PUBLIC;
 extern char            *cupsDNSSDCopyHostName(cups_dnssd_t *dnssd, char *buffer, size_t bufsize) _CUPS_PUBLIC;
 extern void            cupsDNSSDDelete(cups_dnssd_t *dnssd) _CUPS_PUBLIC;
 extern size_t          cupsDNSSDGetConfigChanges(cups_dnssd_t *dnssd) _CUPS_PUBLIC;
index 689b88b49b2528f618d8a7f7847a9ac6ee5c6c9d..2f161d809dbaf545a77a52054e22a56c304ea23b 100644 (file)
@@ -12,6 +12,7 @@
 #include <cups/cups-private.h>
 #include <cups/file-private.h>
 #include <cups/ppd-private.h>
+#include <cups/dnssd.h>
 
 #include <limits.h>
 #include <time.h>
index e36a5e54aaeb4217ed16d84593b9711fdc7b9eae..850a99abfe8482546ae7759e34a9ba1651af0ac7 100644 (file)
@@ -9,10 +9,6 @@
  * information.
  */
 
-/*
- * Include necessary headers...
- */
-
 #include "cupsd.h"
 #include <grp.h>
 
 #endif /* HAVE_MDNSRESPONDER && __APPLE__ */
 
 
-/*
- * Local globals...
- */
-
-#ifdef HAVE_AVAHI
-static int     avahi_running = 0;
-#endif /* HAVE_AVAHI */
-
-
 /*
  * Local functions...
  */
 
-static char            *get_auth_info_required(cupsd_printer_t *p,
-                                               char *buffer, size_t bufsize);
-#  ifdef __APPLE__
-static void            dnssdAddAlias(const void *key, const void *value,
-                                     void *context);
-#  endif /* __APPLE__ */
-static cupsd_txt_t     dnssdBuildTxtRecord(cupsd_printer_t *p);
-#  ifdef HAVE_AVAHI
-static void            dnssdClientCallback(AvahiClient *c, AvahiClientState state, void *userdata);
-#  endif /* HAVE_AVAHI */
-static void            dnssdDeregisterAllPrinters(int from_callback);
-static void            dnssdDeregisterInstance(cupsd_srv_t *srv, int from_callback);
-static void            dnssdDeregisterPrinter(cupsd_printer_t *p, int clear_name, int from_callback);
-static const char      *dnssdErrorString(int error);
-static void            dnssdFreeTxtRecord(cupsd_txt_t *txt);
-static void            dnssdRegisterAllPrinters(int from_callback);
-#  ifdef HAVE_MDNSRESPONDER
-static void            dnssdRegisterCallback(DNSServiceRef sdRef,
-                                             DNSServiceFlags flags,
-                                             DNSServiceErrorType errorCode,
-                                             const char *name,
-                                             const char *regtype,
-                                             const char *domain,
-                                             void *context);
-#  else
-static void            dnssdRegisterCallback(AvahiEntryGroup *p,
-                                             AvahiEntryGroupState state,
-                                             void *context);
-#  endif /* HAVE_MDNSRESPONDER */
-static int             dnssdRegisterInstance(cupsd_srv_t *srv, cupsd_printer_t *p, char *name, const char *type, const char *subtypes, int port, cupsd_txt_t *txt, int commit, int from_callback);
-static void            dnssdRegisterPrinter(cupsd_printer_t *p, int from_callback);
+static char            *get_auth_info_required(cupsd_printer_t *p, char *buffer, size_t bufsize);
+static int             dnssdBuildTxtRecord(cupsd_printer_t *p, cups_option_t **txt);
+static void            dnssdErrorCB(void *cb_data, const char *message);
+static void            dnssdRegisterCallback(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags);
+static void            dnssdRegisterPrinter(cupsd_printer_t *p);
 static void            dnssdStop(void);
-#  ifdef HAVE_MDNSRESPONDER
-static void            dnssdUpdate(void);
-#  endif /* HAVE_MDNSRESPONDER */
-static void            dnssdUpdateDNSSDName(int from_callback);
 
 
 /*
@@ -89,20 +46,20 @@ cupsdDeregisterPrinter(
   * Only deregister if browsing is enabled and it's a local printer...
   */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG,
-                  "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", (void *)p, p->name,
-                 removeit);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdDeregisterPrinter(p=%p(%s), removeit=%d)", (void *)p, p->name, removeit);
 
-  if (!Browsing || !p->shared ||
-      (p->type & (CUPS_PTYPE_REMOTE | CUPS_PTYPE_SCANNER)))
+  if (!Browsing || !p->shared || (p->type & (CUPS_PTYPE_REMOTE | CUPS_PTYPE_SCANNER)))
     return;
 
  /*
   * Announce the deletion...
   */
 
-  if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
-    dnssdDeregisterPrinter(p, 1, 0);
+  if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDContext)
+  {
+    cupsDNSSDServiceDelete(p->dnssd);
+    p->dnssd = NULL;
+  }
 }
 
 
@@ -114,15 +71,13 @@ cupsdDeregisterPrinter(
 void
 cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
 {
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", (void *)p,
-                  p->name);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRegisterPrinter(p=%p(%s))", (void *)p, p->name);
 
-  if (!Browsing || !BrowseLocalProtocols ||
-      (p->type & (CUPS_PTYPE_REMOTE | CUPS_PTYPE_SCANNER)))
+  if (!Browsing || !BrowseLocalProtocols || (p->type & (CUPS_PTYPE_REMOTE | CUPS_PTYPE_SCANNER)))
     return;
 
-  if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
-    dnssdRegisterPrinter(p, 0);
+  if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDContext)
+    dnssdRegisterPrinter(p);
 }
 
 
@@ -133,38 +88,20 @@ cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
 void
 cupsdStartBrowsing(void)
 {
+  cupsd_printer_t      *p;             /* Current printer */
+
+
   if (!Browsing || !BrowseLocalProtocols)
     return;
 
   if (BrowseLocalProtocols & BROWSE_DNSSD)
   {
-#  ifdef HAVE_MDNSRESPONDER
-    DNSServiceErrorType error;         /* Error from service creation */
-
-   /*
-    * First create a "master" connection for all registrations...
-    */
-
-    if ((error = DNSServiceCreateConnection(&DNSSDMaster))
-           != kDNSServiceErr_NoError)
+    if ((DNSSDContext = cupsDNSSDNew(dnssdErrorCB, /*cb_data*/NULL)) == NULL)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "Unable to create master DNS-SD reference: %d", error);
-
       if (FatalErrors & CUPSD_FATAL_BROWSE)
        cupsdEndProcess(getpid(), 0);
-    }
-    else
-    {
-     /*
-      * Add the master connection to the select list...
-      */
-
-      int fd = DNSServiceRefSockFD(DNSSDMaster);
 
-      fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
-
-      cupsdAddSelect(fd, (cupsd_selfunc_t)dnssdUpdate, NULL, NULL);
+      return;
     }
 
    /*
@@ -174,43 +111,16 @@ cupsdStartBrowsing(void)
     DNSSDPort = 0;
     cupsdUpdateDNSSDName();
 
-#  else /* HAVE_AVAHI */
-    if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create DNS-SD thread.");
+   /*
+    * Register the individual printers
+    */
 
-      if (FatalErrors & CUPSD_FATAL_BROWSE)
-       cupsdEndProcess(getpid(), 0);
-    }
-    else
+    for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers))
     {
-      int error;                       /* Error code, if any */
-
-      DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
-
-      if (DNSSDClient == NULL)
-      {
-        cupsdLogMessage(CUPSD_LOG_ERROR,
-                        "Unable to communicate with avahi-daemon: %s",
-                        dnssdErrorString(error));
-
-        if (FatalErrors & CUPSD_FATAL_BROWSE)
-         cupsdEndProcess(getpid(), 0);
-
-        avahi_threaded_poll_free(DNSSDMaster);
-        DNSSDMaster = NULL;
-      }
-      else
-       avahi_threaded_poll_start(DNSSDMaster);
+      if (!(p->type & (CUPS_PTYPE_REMOTE | CUPS_PTYPE_SCANNER)))
+       dnssdRegisterPrinter(p);
     }
-#  endif /* HAVE_MDNSRESPONDER */
   }
-
- /*
-  * Register the individual printers
-  */
-
-  dnssdRegisterAllPrinters(0);
 }
 
 
@@ -224,17 +134,11 @@ cupsdStopBrowsing(void)
   if (!Browsing || !BrowseLocalProtocols)
     return;
 
- /*
-  * De-register the individual printers
-  */
-
-  dnssdDeregisterAllPrinters(0);
-
  /*
   * Shut down browsing sockets...
   */
 
-  if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
+  if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDContext)
     dnssdStop();
 }
 
@@ -246,92 +150,127 @@ cupsdStopBrowsing(void)
 void
 cupsdUpdateDNSSDName(void)
 {
-  dnssdUpdateDNSSDName(0);
-}
+  char name[1024];                     /* Computer/host name */
 
 
-#  ifdef __APPLE__
-/*
* 'dnssdAddAlias()' - Add a DNS-SD alias name.
- */
+ /*
+  * Only share the web interface and printers when non-local listening is
 * enabled...
 */
 
-static void
-dnssdAddAlias(const void *key,         /* I - Key */
-              const void *value,       /* I - Value (domain) */
-             void       *context)      /* I - Unused */
-{
-  char valueStr[1024],                 /* Domain string */
-       hostname[1024],                 /* Complete hostname */
-       *hostptr;                       /* Pointer into hostname */
+  if (!DNSSDPort)
+  {
+   /*
+    * Get the port we use for registrations.  If we are not listening on any
+    * non-local ports, there is no sense sharing local printers via Bonjour...
+    */
+
+    cupsd_listener_t   *lis;           /* Current listening socket */
+
+    for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners); lis; lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+    {
+      if (httpAddrLocalhost(&(lis->address)))
+       continue;
+
+      DNSSDPort = httpAddrPort(&(lis->address));
+      break;
+    }
+  }
+
+  if (!DNSSDPort)
+    return;
 
+ /*
+  * Get the computer name...
+  */
 
-  (void)key;
-  (void)context;
+  if (cupsDNSSDCopyComputerName(DNSSDContext, name, sizeof(name)) && name[0])
+    cupsdSetString(&DNSSDComputerName, name);
 
-  if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
-      CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
-                         kCFStringEncodingUTF8))
+  if (!DNSSDComputerName)
   {
-    snprintf(hostname, sizeof(hostname), "%s.%s", DNSSDHostName, valueStr);
-    hostptr = hostname + strlen(hostname) - 1;
-    if (*hostptr == '.')
-      *hostptr = '\0';                 /* Strip trailing dot */
+   /*
+    * Use the ServerName instead...
+    */
+
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "Using ServerName \"%s\" as computer name.", ServerName);
+    cupsdSetString(&DNSSDComputerName, ServerName);
+  }
 
-    if (!DNSSDAlias)
-      DNSSDAlias = cupsArrayNew(NULL, NULL);
+ /*
+  * Get the hostname...
+  */
+
+  if (cupsDNSSDCopyHostName(DNSSDContext, name, sizeof(name)))
+    cupsdSetString(&DNSSDHostName, name);
+
+  if (!DNSSDHostName)
+  {
+    if (strchr(ServerName, '.'))
+      cupsdSetString(&DNSSDHostName, ServerName);
+    else
+      cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);
 
-    cupsdAddAlias(DNSSDAlias, hostname);
-    cupsdLogMessage(CUPSD_LOG_DEBUG, "Added Back to My Mac ServerAlias %s",
-                   hostname);
+    cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
+  }
+
+ /*
+  * Then (re)register the web interface if enabled...
+  */
+
+  cupsDNSSDServiceDelete(DNSSDWebIF);
+  DNSSDWebIF = NULL;
+
+  if (BrowseWebIF)
+  {
+    char       webif[1024];            /* Web interface share name */
+
+    if (DNSSDComputerName)
+      snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName);
+    else
+      cupsCopyString(webif, "CUPS", sizeof(webif));
+
+    DNSSDWebIF = cupsDNSSDServiceNew(DNSSDContext, CUPS_DNSSD_IF_INDEX_ANY, webif, /*cb*/NULL, /*cb_data*/NULL);
+    cupsDNSSDServiceAdd(DNSSDWebIF, "_http._tcp", /*domain*/NULL, DNSSDHostName, (uint16_t)DNSSDPort, /*num_txt*/0, /*txt*/NULL);
+    cupsDNSSDServicePublish(DNSSDWebIF);
   }
-  else
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "Bad Back to My Mac domain in dynamic store!");
 }
-#  endif /* __APPLE__ */
 
 
 /*
  * 'dnssdBuildTxtRecord()' - Build a TXT record from printer info.
  */
 
-static cupsd_txt_t                     /* O - TXT record */
+static int                             /* O - Number of TXT key/value pairs */
 dnssdBuildTxtRecord(
-    cupsd_printer_t *p)                        /* I - Printer information */
+    cupsd_printer_t *p,                        /* I - Printer information */
+    cups_option_t   **txt)             /* O - TXT key/value pairs */
 {
   int          i,                      /* Looping var */
-               count;                  /* Count of key/value pairs */
+               num_txt;                /* Number of TXT key/value pairs */
   char         admin_hostname[256],    /* Hostname for admin page */
-               adminurl_str[256],      /* URL for the admin page */
-               type_str[32],           /* Type to string buffer */
-               rp_str[256],            /* Queue name string buffer */
-               air_str[256],           /* auth-info-required string buffer */
-               urf_str[256],           /* URF string buffer */
-               *keyvalue[32][2],       /* Table of key/value pairs */
+               rp[256],                /* RP value */
+               value[256],             /* TXT value */
                 *ptr;                   /* Pointer in string */
-  cupsd_txt_t  txt;                    /* TXT record */
   cupsd_listener_t *lis;                /* Current listener */
   const char    *admin_scheme = "http"; /* Admin page URL scheme */
   ipp_attribute_t *urf_supported;      /* urf-supported attribute */
 
+
  /*
   * Load up the key value pairs...
   */
 
-  count = 0;
+  num_txt = 0;
+  *txt    = NULL;
 
-  keyvalue[count  ][0] = "txtvers";
-  keyvalue[count++][1] = "1";
+  num_txt = cupsAddOption("txtvers", "1", num_txt, txt);
+  num_txt = cupsAddOption("qtotal", "1", num_txt, txt);
 
-  keyvalue[count  ][0] = "qtotal";
-  keyvalue[count++][1] = "1";
+  snprintf(rp, sizeof(rp), "%s/%s", (p->type & CUPS_PTYPE_CLASS) ? "classes" : "printers", p->name);
+  num_txt = cupsAddOption("rp", rp, num_txt, txt);
 
-  keyvalue[count  ][0] = "rp";
-  keyvalue[count++][1] = rp_str;
-  snprintf(rp_str, sizeof(rp_str), "%s/%s", (p->type & CUPS_PTYPE_CLASS) ? "classes" : "printers", p->name);
-
-  keyvalue[count  ][0] = "ty";
-  keyvalue[count++][1] = p->make_model ? p->make_model : "Unknown";
+  num_txt = cupsAddOption("ty", p->make_model ? p->make_model : "Unknown", num_txt, txt);
 
  /*
   * Get the hostname for the admin page...
@@ -370,769 +309,140 @@ dnssdBuildTxtRecord(
     }
   }
 
-  httpAssembleURIf(HTTP_URI_CODING_ALL, adminurl_str, sizeof(adminurl_str), admin_scheme,  NULL, admin_hostname, DNSSDPort, "/%s/%s", (p->type & CUPS_PTYPE_CLASS) ? "classes" : "printers", p->name);
-  keyvalue[count  ][0] = "adminurl";
-  keyvalue[count++][1] = adminurl_str;
+  httpAssembleURIf(HTTP_URI_CODING_ALL, value, sizeof(value), admin_scheme,  NULL, admin_hostname, DNSSDPort, "/%s/%s", (p->type & CUPS_PTYPE_CLASS) ? "classes" : "printers", p->name);
+
+  num_txt = cupsAddOption("adminurl", value, num_txt, txt);
 
   if (p->location)
-  {
-    keyvalue[count  ][0] = "note";
-    keyvalue[count++][1] = p->location;
-  }
+    num_txt = cupsAddOption("note", p->location, num_txt, txt);
 
-  keyvalue[count  ][0] = "priority";
-  keyvalue[count++][1] = "0";
+  num_txt = cupsAddOption("priority", "0", num_txt, txt);
 
-  keyvalue[count  ][0] = "product";
-  keyvalue[count++][1] = p->pc && p->pc->product ? p->pc->product : "Unknown";
+  num_txt = cupsAddOption("product", p->pc && p->pc->product ? p->pc->product : "Unknown", num_txt, txt);
 
-  keyvalue[count  ][0] = "pdl";
-  keyvalue[count++][1] = p->pdl ? p->pdl : "application/postscript";
+  num_txt = cupsAddOption("pdl", p->pdl ? p->pdl : "application/postscript", num_txt, txt);
 
-  if (get_auth_info_required(p, air_str, sizeof(air_str)))
-  {
-    keyvalue[count  ][0] = "air";
-    keyvalue[count++][1] = air_str;
-  }
+  if (get_auth_info_required(p, value, sizeof(value)))
+    num_txt = cupsAddOption("air", value, num_txt, txt);
 
-  keyvalue[count  ][0] = "UUID";
-  keyvalue[count++][1] = p->uuid + 9;
+  num_txt = cupsAddOption("UUID", p->uuid + 9, num_txt, txt);
 
-  keyvalue[count  ][0] = "TLS";
-  keyvalue[count++][1] = "1.3";
+  num_txt = cupsAddOption("TLS", "1.3", num_txt, txt);
 
   if ((urf_supported = ippFindAttribute(p->ppd_attrs, "urf-supported", IPP_TAG_KEYWORD)) != NULL)
   {
     int urf_count = ippGetCount(urf_supported);
                                        // Number of URF values
 
-    urf_str[0] = '\0';
-    for (i = 0, ptr = urf_str; i < urf_count; i ++)
+    value[0] = '\0';
+    for (i = 0, ptr = value; i < urf_count; i ++)
     {
-      const char *value = ippGetString(urf_supported, i, NULL);
+      const char *keyword = ippGetString(urf_supported, i, NULL);
 
-      if (ptr > urf_str && ptr < (urf_str + sizeof(urf_str) - 1))
+      if (ptr > value && ptr < (value + sizeof(value) - 1))
        *ptr++ = ',';
 
-      cupsCopyString(ptr, value, sizeof(urf_str) - (size_t)(ptr - urf_str));
+      cupsCopyString(ptr, keyword, sizeof(value) - (size_t)(ptr - value));
       ptr += strlen(ptr);
 
-      if (ptr >= (urf_str + sizeof(urf_str) - 1))
+      if (ptr >= (value + sizeof(value) - 1))
        break;
     }
 
-    keyvalue[count  ][0] = "URF";
-    keyvalue[count++][1] = urf_str;
+    num_txt = cupsAddOption("URF", value, num_txt, txt);
   }
 
-  keyvalue[count  ][0] = "mopria-certified";
-  keyvalue[count++][1] = "1.3";
+  num_txt = cupsAddOption("mopria-certified", "1.3", num_txt, txt);
 
   if (p->type & CUPS_PTYPE_FAX)
   {
-    keyvalue[count  ][0] = "Fax";
-    keyvalue[count++][1] = "T";
-    keyvalue[count  ][0] = "rfo";
-    keyvalue[count++][1] = rp_str;
+    num_txt = cupsAddOption("Fax", "T", num_txt, txt);
+    num_txt = cupsAddOption("rfo", rp, num_txt, txt);
   }
 
   if (p->type & CUPS_PTYPE_COLOR)
-  {
-    keyvalue[count  ][0] = "Color";
-    keyvalue[count++][1] = (p->type & CUPS_PTYPE_COLOR) ? "T" : "F";
-  }
+    num_txt = cupsAddOption("Color", (p->type & CUPS_PTYPE_COLOR) ? "T" : "F", num_txt, txt);
 
   if (p->type & CUPS_PTYPE_DUPLEX)
-  {
-    keyvalue[count  ][0] = "Duplex";
-    keyvalue[count++][1] = (p->type & CUPS_PTYPE_DUPLEX) ? "T" : "F";
-  }
+    num_txt = cupsAddOption("Duplex", (p->type & CUPS_PTYPE_DUPLEX) ? "T" : "F", num_txt, txt);
 
   if (p->type & CUPS_PTYPE_STAPLE)
-  {
-    keyvalue[count  ][0] = "Staple";
-    keyvalue[count++][1] = (p->type & CUPS_PTYPE_STAPLE) ? "T" : "F";
-  }
+    num_txt = cupsAddOption("Staple", (p->type & CUPS_PTYPE_STAPLE) ? "T" : "F", num_txt, txt);
 
   if (p->type & CUPS_PTYPE_COPIES)
-  {
-    keyvalue[count  ][0] = "Copies";
-    keyvalue[count++][1] = (p->type & CUPS_PTYPE_COPIES) ? "T" : "F";
-  }
+    num_txt = cupsAddOption("Copies", (p->type & CUPS_PTYPE_COPIES) ? "T" : "F", num_txt, txt);
 
   if (p->type & CUPS_PTYPE_COLLATE)
-  {
-    keyvalue[count  ][0] = "Collate";
-    keyvalue[count++][1] = (p->type & CUPS_PTYPE_COLLATE) ? "T" : "F";
-  }
+    num_txt = cupsAddOption("Collate", (p->type & CUPS_PTYPE_COLLATE) ? "T" : "F", num_txt, txt);
 
   if (p->type & CUPS_PTYPE_PUNCH)
-  {
-    keyvalue[count  ][0] = "Punch";
-    keyvalue[count++][1] = (p->type & CUPS_PTYPE_PUNCH) ? "T" : "F";
-  }
+    num_txt = cupsAddOption("Punch", (p->type & CUPS_PTYPE_PUNCH) ? "T" : "F", num_txt, txt);
 
   if (p->type & CUPS_PTYPE_BIND)
-  {
-    keyvalue[count  ][0] = "Bind";
-    keyvalue[count++][1] = (p->type & CUPS_PTYPE_BIND) ? "T" : "F";
-  }
+    num_txt = cupsAddOption("Bind", (p->type & CUPS_PTYPE_BIND) ? "T" : "F", num_txt, txt);
 
   if (p->type & CUPS_PTYPE_SORT)
-  {
-    keyvalue[count  ][0] = "Sort";
-    keyvalue[count++][1] = (p->type & CUPS_PTYPE_SORT) ? "T" : "F";
-  }
+    num_txt = cupsAddOption("Sort", (p->type & CUPS_PTYPE_SORT) ? "T" : "F", num_txt, txt);
 
   if (p->type & CUPS_PTYPE_MFP)
-  {
-    keyvalue[count  ][0] = "Scan";
-    keyvalue[count++][1] = (p->type & CUPS_PTYPE_MFP) ? "T" : "F";
-  }
+    num_txt = cupsAddOption("Scan", (p->type & CUPS_PTYPE_MFP) ? "T" : "F", num_txt, txt);
 
-  snprintf(type_str, sizeof(type_str), "0x%X", p->type | CUPS_PTYPE_REMOTE);
+  snprintf(value, sizeof(value), "0x%X", p->type | CUPS_PTYPE_REMOTE);
+  num_txt = cupsAddOption("printer-type", value, num_txt, txt);
 
-  keyvalue[count  ][0] = "printer-type";
-  keyvalue[count++][1] = type_str;
-
- /*
-  * Then pack them into a proper txt record...
-  */
-
-#  ifdef HAVE_MDNSRESPONDER
-  TXTRecordCreate(&txt, 0, NULL);
-
-  for (i = 0; i < count; i ++)
-  {
-    size_t len = strlen(keyvalue[i][1]);
-
-    if (len < 256)
-      TXTRecordSetValue(&txt, keyvalue[i][0], (uint8_t)len, keyvalue[i][1]);
-  }
-
-#  else
-  for (i = 0, txt = NULL; i < count; i ++)
-    txt = avahi_string_list_add_printf(txt, "%s=%s", keyvalue[i][0],
-                                       keyvalue[i][1]);
-#  endif /* HAVE_MDNSRESPONDER */
-
-  return (txt);
+  return (num_txt);
 }
 
 
-#  ifdef HAVE_AVAHI
-/*
- * 'dnssdClientCallback()' - Client callback for Avahi.
- *
- * Called whenever the client or server state changes...
- */
+//
+// 'dnssdErrorCB()' - DNS-SD error callback.
+//
 
 static void
-dnssdClientCallback(
-    AvahiClient      *c,               /* I - Client */
-    AvahiClientState state,            /* I - Current state */
-    void             *userdata)                /* I - User data (unused) */
+dnssdErrorCB(void       *cb_data,      // I - Callback data (unused)
+             const char *message)      // I - Error message
 {
-  int  error;                          /* Error code, if any */
-
-
-  (void)userdata;
-
-  if (!c)
-    return;
-
- /*
-  * Make sure DNSSDClient is already set also if this callback function is
-  * already running before avahi_client_new() in dnssdStartBrowsing()
-  * finishes.
-  */
-
-  if (!DNSSDClient)
-    DNSSDClient = c;
-
-  switch (state)
-  {
-    case AVAHI_CLIENT_S_REGISTERING:
-    case AVAHI_CLIENT_S_RUNNING:
-    case AVAHI_CLIENT_S_COLLISION:
-       cupsdLogMessage(CUPSD_LOG_DEBUG, "Avahi server connection now available, registering printers for Bonjour broadcasting.");
-
-       /*
-       * Mark that Avahi server is running...
-       */
-
-       avahi_running = 1;
-
-       /*
-       * Set the computer name and register the web interface...
-       */
-
-       DNSSDPort = 0;
-       dnssdUpdateDNSSDName(1);
-
-       /*
-       * Register the individual printers
-       */
-
-       dnssdRegisterAllPrinters(1);
-       break;
-
-    case AVAHI_CLIENT_FAILURE:
-       if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED)
-       {
-         cupsdLogMessage(CUPSD_LOG_DEBUG, "Avahi server disappeared, unregistering printers for Bonjour broadcasting.");
-
-        /*
-         * Unregister everything and close the client...
-         */
-
-         dnssdDeregisterAllPrinters(1);
-         dnssdDeregisterInstance(&WebIFSrv, 1);
-         avahi_client_free(DNSSDClient);
-         DNSSDClient = NULL;
-
-        /*
-         * Mark that Avahi server is not running...
-         */
-
-         avahi_running = 0;
-
-        /*
-         * Renew Avahi client...
-         */
-
-         DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssdClientCallback, NULL, &error);
-
-         if (!DNSSDClient)
-         {
-           cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to communicate with avahi-daemon: %s", dnssdErrorString(error));
-           if (FatalErrors & CUPSD_FATAL_BROWSE)
-             cupsdEndProcess(getpid(), 0);
-         }
-       }
-       else
-       {
-         cupsdLogMessage(CUPSD_LOG_ERROR, "Communication with avahi-daemon has failed: %s", avahi_strerror(avahi_client_errno(c)));
-         if (FatalErrors & CUPSD_FATAL_BROWSE)
-           cupsdEndProcess(getpid(), 0);
-       }
-       break;
+  (void)cb_data;
 
-    default:
-        break;
-  }
+  cupsdLogMessage(CUPSD_LOG_ERROR, "[DNS-SD] %s", message);
 }
-#  endif /* HAVE_AVAHI */
 
 
 /*
- * 'dnssdDeregisterAllPrinters()' - Deregister all printers.
+ * 'dnssdRegisterCallback()' - Service registration callback.
  */
 
 static void
-dnssdDeregisterAllPrinters(
-    int             from_callback)     /* I - Deregistering because of callback? */
+dnssdRegisterCallback(
+    cups_dnssd_service_t *service,     // I - Service
+    void                 *cb_data,     // I - Callback data (printer)
+    cups_dnssd_flags_t   flags)                // I - Registration flags
 {
-  cupsd_printer_t      *p;             /* Current printer */
+  cupsd_printer_t *p = (cupsd_printer_t *)cb_data;
+                                       // Current printer
+  const char   *reg_name;              // Updated service name
 
 
-  if (!DNSSDMaster)
+  if (flags & CUPS_DNSSD_FLAGS_ERROR)
     return;
 
-  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
-       p;
-       p = (cupsd_printer_t *)cupsArrayNext(Printers))
-    if (!(p->type & (CUPS_PTYPE_REMOTE | CUPS_PTYPE_SCANNER)))
-      dnssdDeregisterPrinter(p, 1, from_callback);
-}
-
-
-/*
- * 'dnssdDeregisterInstance()' - Deregister a DNS-SD service instance.
- */
-
-static void
-dnssdDeregisterInstance(
-    cupsd_srv_t     *srv,              /* I - Service */
-    int             from_callback)     /* I - Called from callback? */
-{
-  if (!srv || !*srv)
+  if (!p)
     return;
 
-#  ifdef HAVE_MDNSRESPONDER
-  (void)from_callback;
-
-  DNSServiceRefDeallocate(*srv);
-
-  *srv = NULL;
-
-#  else /* HAVE_AVAHI */
-  if (!from_callback)
-    avahi_threaded_poll_lock(DNSSDMaster);
-
-  if (*srv)
-  {
-    avahi_entry_group_free(*srv);
-    *srv = NULL;
-  }
-
-  if (!from_callback)
-    avahi_threaded_poll_unlock(DNSSDMaster);
-#  endif /* HAVE_MDNSRESPONDER */
-}
-
-
-/*
- * 'dnssdDeregisterPrinter()' - Deregister all services for a printer.
- */
-
-static void
-dnssdDeregisterPrinter(
-    cupsd_printer_t *p,                        /* I - Printer */
-    int             clear_name,                /* I - Clear the name? */
-    int             from_callback)     /* I - Called from callback? */
-
-{
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "dnssdDeregisterPrinter(p=%p(%s), clear_name=%d)", (void *)p, p->name,
-                  clear_name);
-
-  if (p->ipp_srv)
-  {
-    dnssdDeregisterInstance(&p->ipp_srv, from_callback);
-
-#  ifdef HAVE_MDNSRESPONDER
-    dnssdDeregisterInstance(&p->ipps_srv, from_callback);
-    dnssdDeregisterInstance(&p->printer_srv, from_callback);
-#  endif /* HAVE_MDNSRESPONDER */
-  }
-
- /*
-  * Remove the printer from the array of DNS-SD printers but keep the
-  * registered name...
-  */
-
-  cupsArrayRemove(DNSSDPrinters, p);
-
- /*
-  * Optionally clear the service name...
-  */
-
-  if (clear_name)
-    cupsdClearString(&p->reg_name);
-}
-
-
-/*
- * 'dnssdErrorString()' - Return an error string for an error code.
- */
+  reg_name = cupsDNSSDServiceGetName(service);
 
-static const char *                    /* O - Error message */
-dnssdErrorString(int error)            /* I - Error number */
-{
-#  ifdef HAVE_MDNSRESPONDER
-  switch (error)
+  if ((!p->reg_name || _cups_strcasecmp(reg_name, p->reg_name)))
   {
-    case kDNSServiceErr_NoError :
-        return ("OK.");
-
-    default :
-    case kDNSServiceErr_Unknown :
-        return ("Unknown error.");
-
-    case kDNSServiceErr_NoSuchName :
-        return ("Service not found.");
-
-    case kDNSServiceErr_NoMemory :
-        return ("Out of memory.");
-
-    case kDNSServiceErr_BadParam :
-        return ("Bad parameter.");
-
-    case kDNSServiceErr_BadReference :
-        return ("Bad service reference.");
-
-    case kDNSServiceErr_BadState :
-        return ("Bad state.");
-
-    case kDNSServiceErr_BadFlags :
-        return ("Bad flags.");
-
-    case kDNSServiceErr_Unsupported :
-        return ("Unsupported.");
-
-    case kDNSServiceErr_NotInitialized :
-        return ("Not initialized.");
-
-    case kDNSServiceErr_AlreadyRegistered :
-        return ("Already registered.");
-
-    case kDNSServiceErr_NameConflict :
-        return ("Name conflict.");
-
-    case kDNSServiceErr_Invalid :
-        return ("Invalid name.");
-
-    case kDNSServiceErr_Firewall :
-        return ("Firewall prevents registration.");
-
-    case kDNSServiceErr_Incompatible :
-        return ("Client library incompatible.");
-
-    case kDNSServiceErr_BadInterfaceIndex :
-        return ("Bad interface index.");
-
-    case kDNSServiceErr_Refused :
-        return ("Server prevents registration.");
-
-    case kDNSServiceErr_NoSuchRecord :
-        return ("Record not found.");
-
-    case kDNSServiceErr_NoAuth :
-        return ("Authentication required.");
-
-    case kDNSServiceErr_NoSuchKey :
-        return ("Encryption key not found.");
-
-    case kDNSServiceErr_NATTraversal :
-        return ("Unable to traverse NAT boundary.");
-
-    case kDNSServiceErr_DoubleNAT :
-        return ("Unable to traverse double-NAT boundary.");
-
-    case kDNSServiceErr_BadTime :
-        return ("Bad system time.");
-
-    case kDNSServiceErr_BadSig :
-        return ("Bad signature.");
-
-    case kDNSServiceErr_BadKey :
-        return ("Bad encryption key.");
-
-    case kDNSServiceErr_Transient :
-        return ("Transient error occurred - please try again.");
-
-    case kDNSServiceErr_ServiceNotRunning :
-        return ("Server not running.");
-
-    case kDNSServiceErr_NATPortMappingUnsupported :
-        return ("NAT doesn't support NAT-PMP or UPnP.");
-
-    case kDNSServiceErr_NATPortMappingDisabled :
-        return ("NAT supports NAT-PNP or UPnP but it is disabled.");
-
-    case kDNSServiceErr_NoRouter :
-        return ("No Internet/default router configured.");
-
-    case kDNSServiceErr_PollingMode :
-        return ("Service polling mode error.");
-
-    case kDNSServiceErr_Timeout :
-        return ("Service timeout.");
-  }
-
-#  else /* HAVE_AVAHI */
-  return (avahi_strerror(error));
-#  endif /* HAVE_MDNSRESPONDER */
-}
-
-
-/*
- * 'dnssdRegisterCallback()' - Free a TXT record.
- */
-
-static void
-dnssdFreeTxtRecord(cupsd_txt_t *txt)   /* I - TXT record */
-{
-#  ifdef HAVE_MDNSRESPONDER
-  TXTRecordDeallocate(txt);
-
-#  else /* HAVE_AVAHI */
-  avahi_string_list_free(*txt);
-  *txt = NULL;
-#  endif /* HAVE_MDNSRESPONDER */
-}
-
-
-/*
- * 'dnssdRegisterAllPrinters()' - Register all printers.
- */
-
-static void
-dnssdRegisterAllPrinters(int from_callback)    /* I - Called from callback? */
-{
-  cupsd_printer_t      *p;                     /* Current printer */
-
-
-  if (!DNSSDMaster)
-    return;
-
-  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
-       p;
-       p = (cupsd_printer_t *)cupsArrayNext(Printers))
-    if (!(p->type & (CUPS_PTYPE_REMOTE | CUPS_PTYPE_SCANNER)))
-      dnssdRegisterPrinter(p, from_callback);
-}
-
-
-/*
- * 'dnssdRegisterCallback()' - DNSServiceRegister callback.
- */
-
-#  ifdef HAVE_MDNSRESPONDER
-static void
-dnssdRegisterCallback(
-    DNSServiceRef      sdRef,          /* I - DNS Service reference */
-    DNSServiceFlags    flags,          /* I - Reserved for future use */
-    DNSServiceErrorType        errorCode,      /* I - Error code */
-    const char         *name,          /* I - Service name */
-    const char         *regtype,       /* I - Service type */
-    const char         *domain,        /* I - Domain. ".local" for now */
-    void               *context)       /* I - Printer */
-{
-  cupsd_printer_t *p = (cupsd_printer_t *)context;
-                                       /* Current printer */
-
-
-  (void)sdRef;
-  (void)flags;
-  (void)domain;
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterCallback(%s, %s) for %s (%s)",
-                  name, regtype, p ? p->name : "Web Interface",
-                 p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
-
-  if (errorCode)
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                   "DNSServiceRegister failed with error %d", (int)errorCode);
-    return;
-  }
-  else if (p && (!p->reg_name || _cups_strcasecmp(name, p->reg_name)))
-  {
-    cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\"",
-                    name, p->name);
+    cupsdLogMessage(CUPSD_LOG_INFO, "Using service name \"%s\" for \"%s\".", reg_name, p->name);
 
     cupsArrayRemove(DNSSDPrinters, p);
-    cupsdSetString(&p->reg_name, name);
+    cupsdSetString(&p->reg_name, reg_name);
     cupsArrayAdd(DNSSDPrinters, p);
 
     LastEvent |= CUPSD_EVENT_PRINTER_MODIFIED;
   }
 }
 
-#  else /* HAVE_AVAHI */
-static void
-dnssdRegisterCallback(
-    AvahiEntryGroup      *srv,         /* I - Service */
-    AvahiEntryGroupState state,                /* I - Registration state */
-    void                 *context)     /* I - Printer */
-{
-  cupsd_printer_t *p = (cupsd_printer_t *)context;
-                                       /* Current printer */
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "dnssdRegisterCallback(srv=%p, state=%d, context=%p) "
-                  "for %s (%s)", srv, state, context,
-                  p ? p->name : "Web Interface",
-                 p ? (p->reg_name ? p->reg_name : "(null)") : "NA");
-
-  /* TODO: Handle collisions with avahi_alternate_service_name(p->reg_name)? */
-}
-#  endif /* HAVE_MDNSRESPONDER */
-
-
-/*
- * 'dnssdRegisterInstance()' - Register an instance of a printer service.
- */
-
-static int                             /* O - 1 on success, 0 on failure */
-dnssdRegisterInstance(
-    cupsd_srv_t     *srv,              /* O - Service */
-    cupsd_printer_t *p,                        /* I - Printer */
-    char            *name,             /* I - DNS-SD service name */
-    const char      *type,             /* I - DNS-SD service type */
-    const char      *subtypes,         /* I - Subtypes to register or NULL */
-    int             port,              /* I - Port number or 0 */
-    cupsd_txt_t     *txt,              /* I - TXT record */
-    int             commit,            /* I - Commit registration? */
-    int             from_callback)     /* I - Called from callback? */
-{
-  char temp[256],                      /* Temporary string */
-       *ptr;                           /* Pointer into string */
-  int  error;                          /* Any error */
-
-
-#  ifdef HAVE_MDNSRESPONDER
-  (void)from_callback;
-#  endif /* HAVE_MDNSRESPONDER */
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "Registering \"%s\" with DNS-SD type \"%s\".", name, type);
-
-  if (p && !srv)
-  {
-   /*
-    * Assign the correct pointer for "srv"...
-    */
-
-#  ifdef HAVE_MDNSRESPONDER
-    if (!strcmp(type, "_printer._tcp"))
-      srv = &p->printer_srv;           /* Target LPD service */
-    else if (!strcmp(type, "_ipps._tcp"))
-      srv = &p->ipps_srv;              /* Target IPPS service */
-    else
-      srv = &p->ipp_srv;               /* Target IPP service */
-
-#  else /* HAVE_AVAHI */
-    srv = &p->ipp_srv;                 /* Target service group */
-#  endif /* HAVE_MDNSRESPONDER */
-  }
-
-#  ifdef HAVE_MDNSRESPONDER
-  (void)commit;
-
-#  else /* HAVE_AVAHI */
-  if (!from_callback)
-    avahi_threaded_poll_lock(DNSSDMaster);
-
-  if (!*srv)
-    *srv = avahi_entry_group_new(DNSSDClient, dnssdRegisterCallback, NULL);
-  if (!*srv)
-  {
-    if (!from_callback)
-      avahi_threaded_poll_unlock(DNSSDMaster);
-
-    cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s",
-                    name, dnssdErrorString(avahi_client_errno(DNSSDClient)));
-    return (0);
-  }
-#  endif /* HAVE_MDNSRESPONDER */
-
- /*
-  * Make sure the name is <= 63 octets, and when we truncate be sure to
-  * properly truncate any UTF-8 characters...
-  */
-
-  ptr = name + strlen(name);
-  while ((ptr - name) > 63)
-  {
-    do
-    {
-      ptr --;
-    }
-    while (ptr > name && (*ptr & 0xc0) == 0x80);
-
-    if (ptr > name)
-      *ptr = '\0';
-  }
-
- /*
-  * Register the service...
-  */
-
-#  ifdef HAVE_MDNSRESPONDER
-  if (subtypes)
-    snprintf(temp, sizeof(temp), "%s,%s", type, subtypes);
-  else
-    cupsCopyString(temp, type, sizeof(temp));
-
-  *srv  = DNSSDMaster;
-  error = DNSServiceRegister(srv, kDNSServiceFlagsShareConnection,
-                            0, name, temp, NULL, DNSSDHostName, htons(port),
-                            txt ? TXTRecordGetLength(txt) : 0,
-                            txt ? TXTRecordGetBytesPtr(txt) : NULL,
-                            dnssdRegisterCallback, p);
-
-#  else /* HAVE_AVAHI */
-  if (txt)
-  {
-    AvahiStringList *temptxt;
-    for (temptxt = *txt; temptxt; temptxt = temptxt->next)
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS_SD \"%s\" %s", name, temptxt->text);
-  }
-
-  error = avahi_entry_group_add_service_strlst(*srv, AVAHI_IF_UNSPEC,
-                                               AVAHI_PROTO_UNSPEC, 0, name,
-                                               type, NULL, DNSSDHostName, port,
-                                               txt ? *txt : NULL);
-  if (error)
-    cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD service add for \"%s\" failed.",
-                    name);
-
-  if (!error && subtypes)
-  {
-   /*
-    * Register all of the subtypes...
-    */
-
-    char       *start,                 /* Start of subtype */
-               subtype[256];           /* Subtype string */
-
-    cupsCopyString(temp, subtypes, sizeof(temp));
-
-    for (start = temp; *start; start = ptr)
-    {
-     /*
-      * Skip leading whitespace...
-      */
-
-      while (*start && isspace(*start & 255))
-        start ++;
-
-     /*
-      * Grab everything up to the next comma or the end of the string...
-      */
-
-      for (ptr = start; *ptr && *ptr != ','; ptr ++);
-
-      if (*ptr)
-        *ptr++ = '\0';
-
-      if (!*start)
-        break;
-
-     /*
-      * Register the subtype...
-      */
-
-      snprintf(subtype, sizeof(subtype), "%s._sub.%s", start, type);
-
-      error = avahi_entry_group_add_service_subtype(*srv, AVAHI_IF_UNSPEC,
-                                                    AVAHI_PROTO_UNSPEC, 0,
-                                                    name, type, NULL, subtype);
-      if (error)
-      {
-        cupsdLogMessage(CUPSD_LOG_DEBUG,
-                        "DNS-SD subtype %s registration for \"%s\" failed." ,
-                        subtype, name);
-        break;
-      }
-    }
-  }
-
-  if (!error && commit)
-  {
-    if ((error = avahi_entry_group_commit(*srv)) != 0)
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD commit of \"%s\" failed.",
-                      name);
-  }
-
-  if (!from_callback)
-    avahi_threaded_poll_unlock(DNSSDMaster);
-#  endif /* HAVE_MDNSRESPONDER */
-
-  if (error)
-  {
-    cupsdLogMessage(CUPSD_LOG_WARN, "DNS-SD registration of \"%s\" failed: %s",
-                    name, dnssdErrorString(error));
-    cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD type: %s", type);
-    if (subtypes)
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "DNS-SD sub-types: %s", subtypes);
-  }
-
-  return (!error);
-}
-
 
 /*
  * 'dnssdRegisterPrinter()' - Start sending broadcast information for a printer
@@ -1141,28 +451,24 @@ dnssdRegisterInstance(
 
 static void
 dnssdRegisterPrinter(
-    cupsd_printer_t *p,                        /* I - Printer */
-    int             from_callback)     /* I - Called from callback? */
+    cupsd_printer_t *p)                        /* I - Printer */
 {
-  char         name[256];              /* Service name */
-  int          status;                 /* Registration status */
-  cupsd_txt_t  ipp_txt;                /* IPP(S) TXT record */
+  char         name[256],              /* Service name */
+               regtype[256];           /* Registration type(s) */
+  int          num_txt;                /* Number of IPP(S) TXT key/value pairs */
+  cups_option_t        *txt;                   /* IPP(S) TXT key/value pairs */
+  bool         status;                 /* Registration status */
 
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s) %s", p->name,
-                  !p->ipp_srv ? "new" : "update");
-
-#  ifdef HAVE_AVAHI
-  if (!avahi_running)
-    return;
-#  endif /* HAVE_AVAHI */
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "dnssdRegisterPrinter(%s)", p->name);
 
  /*
   * Remove the current registrations if we have them and then return if
   * per-printer sharing was just disabled...
   */
 
-  dnssdDeregisterPrinter(p, 0, from_callback);
+  cupsDNSSDServiceDelete(p->dnssd);
+  p->dnssd = NULL;
 
   if (!p->shared)
     return;
@@ -1182,12 +488,18 @@ dnssdRegisterPrinter(
        cupsCopyString(name, p->info, sizeof(name));
     }
     else if (DNSSDComputerName)
+    {
       snprintf(name, sizeof(name), "%s @ %s", p->name, DNSSDComputerName);
+    }
     else
+    {
       cupsCopyString(name, p->name, sizeof(name));
+    }
   }
   else
+  {
     cupsCopyString(name, p->reg_name, sizeof(name));
+  }
 
  /*
   * Register IPP and LPD...
@@ -1196,49 +508,54 @@ dnssdRegisterPrinter(
   * our name, but use port number 0 so that we don't have clients using LPD...
   */
 
-  ipp_txt = dnssdBuildTxtRecord(p);
+  p->dnssd = cupsDNSSDServiceNew(DNSSDContext, CUPS_DNSSD_IF_INDEX_ANY, name, dnssdRegisterCallback, p);
+  status   = p->dnssd != NULL;
 
-  status = dnssdRegisterInstance(NULL, p, name, "_printer._tcp", NULL, 0, NULL, 0, from_callback);
+  // LPD placeholder
+  status &= cupsDNSSDServiceAdd(p->dnssd, "_printer._tcp", /*domain*/NULL, DNSSDHostName, /*port*/0, /*num_txt*/0, /*txt*/NULL);
 
-  if (status)
-    dnssdRegisterInstance(NULL, p, name, "_ipps._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 0, from_callback);
+  // IPP service
+  num_txt = dnssdBuildTxtRecord(p, &txt);
 
-  if (status)
+  if (p->type & CUPS_PTYPE_FAX)
   {
-   /*
-    * Use the "_fax-ipp" service type for fax queues, otherwise use "_ipp"...
-    */
-
-    if (p->type & CUPS_PTYPE_FAX)
-      status = dnssdRegisterInstance(NULL, p, name, "_fax-ipp._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 1, from_callback);
+    if (DNSSDSubTypes)
+      snprintf(regtype, sizeof(regtype), "_fax-ipp._tcp,%s", DNSSDSubTypes);
+    else
+      cupsCopyString(regtype, "_fax-ipp._tcp", sizeof(regtype));
+  }
+  else
+  {
+    if (DNSSDSubTypes)
+      snprintf(regtype, sizeof(regtype), "_ipp._tcp,%s", DNSSDSubTypes);
     else
-      status = dnssdRegisterInstance(NULL, p, name, "_ipp._tcp", DNSSDSubTypes, DNSSDPort, &ipp_txt, 1, from_callback);
+      cupsCopyString(regtype, "_ipp._tcp", sizeof(regtype));
   }
 
-  dnssdFreeTxtRecord(&ipp_txt);
+  status &= cupsDNSSDServiceAdd(p->dnssd, regtype, /*domain*/NULL, DNSSDHostName, (uint16_t)DNSSDPort, num_txt, txt);
+
+  // IPPS service
+  if (DNSSDSubTypes)
+    snprintf(regtype, sizeof(regtype), "_ipps._tcp,%s", DNSSDSubTypes);
+  else
+    cupsCopyString(regtype, "_ipps._tcp", sizeof(regtype));
+
+  status &= cupsDNSSDServiceAdd(p->dnssd, regtype, /*domain*/NULL, DNSSDHostName, (uint16_t)DNSSDPort, num_txt, txt);
+
+  cupsFreeOptions(num_txt, txt);
 
   if (status)
   {
-   /*
-    * Save the registered name and add the printer to the array of DNS-SD
-    * printers...
-    */
-
+    // Save the registered name and add the printer to the array of DNS-SD
+    // printers...
     cupsdSetString(&p->reg_name, name);
     cupsArrayAdd(DNSSDPrinters, p);
   }
   else
   {
-   /*
-    * Registration failed for this printer...
-    */
-
-    dnssdDeregisterInstance(&p->ipp_srv, from_callback);
-
-#  ifdef HAVE_MDNSRESPONDER
-    dnssdDeregisterInstance(&p->ipps_srv, from_callback);
-    dnssdDeregisterInstance(&p->printer_srv, from_callback);
-#  endif /* HAVE_MDNSRESPONDER */
+    // Registration failed for this printer...
+    cupsDNSSDServiceDelete(p->dnssd);
+    p->dnssd = NULL;
   }
 }
 
@@ -1257,39 +574,21 @@ dnssdStop(void)
   * De-register the individual printers
   */
 
-  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
-       p;
-       p = (cupsd_printer_t *)cupsArrayNext(Printers))
-    dnssdDeregisterPrinter(p, 1, 0);
+  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers))
+  {
+    cupsDNSSDServiceDelete(p->dnssd);
+    p->dnssd = NULL;
+  }
 
  /*
   * Shutdown the rest of the service refs...
   */
 
-  dnssdDeregisterInstance(&WebIFSrv, 0);
-
-#  ifdef HAVE_MDNSRESPONDER
-  cupsdRemoveSelect(DNSServiceRefSockFD(DNSSDMaster));
-
-  DNSServiceRefDeallocate(DNSSDMaster);
-  DNSSDMaster = NULL;
-
-#  else /* HAVE_AVAHI */
-  if (DNSSDMaster)
-    avahi_threaded_poll_stop(DNSSDMaster);
-
-  if (DNSSDClient)
-  {
-    avahi_client_free(DNSSDClient);
-    DNSSDClient = NULL;
-  }
+  cupsDNSSDServiceDelete(DNSSDWebIF);
+  DNSSDWebIF = NULL;
 
-  if (DNSSDMaster)
-  {
-    avahi_threaded_poll_free(DNSSDMaster);
-    DNSSDMaster = NULL;
-  }
-#  endif /* HAVE_MDNSRESPONDER */
+  cupsDNSSDDelete(DNSSDContext);
+  DNSSDContext = NULL;
 
   cupsArrayDelete(DNSSDPrinters);
   DNSSDPrinters = NULL;
@@ -1298,231 +597,6 @@ dnssdStop(void)
 }
 
 
-#  ifdef HAVE_MDNSRESPONDER
-/*
- * 'dnssdUpdate()' - Handle DNS-SD queries.
- */
-
-static void
-dnssdUpdate(void)
-{
-  DNSServiceErrorType  sdErr;          /* Service discovery error */
-
-
-  if ((sdErr = DNSServiceProcessResult(DNSSDMaster)) != kDNSServiceErr_NoError)
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "DNS Service Discovery registration error %d!",
-                   sdErr);
-    dnssdStop();
-  }
-}
-#  endif /* HAVE_MDNSRESPONDER */
-
-
-/*
- * 'dnssdUpdateDNSSDName()' - Update the listen port, computer name, and web interface registration.
- */
-
-static void
-dnssdUpdateDNSSDName(int from_callback)        /* I - Called from callback? */
-{
-  char         webif[1024];            /* Web interface share name */
-#  ifdef __APPLE__
-  SCDynamicStoreRef sc;                        /* Context for dynamic store */
-  CFDictionaryRef btmm;                        /* Back-to-My-Mac domains */
-  CFStringEncoding nameEncoding;       /* Encoding of computer name */
-  CFStringRef  nameRef;                /* Host name CFString */
-  char         nameBuffer[1024];       /* C-string buffer */
-#  endif /* __APPLE__ */
-
-
- /*
-  * Only share the web interface and printers when non-local listening is
-  * enabled...
-  */
-
-  if (!DNSSDPort)
-  {
-   /*
-    * Get the port we use for registrations.  If we are not listening on any
-    * non-local ports, there is no sense sharing local printers via Bonjour...
-    */
-
-    cupsd_listener_t   *lis;           /* Current listening socket */
-
-    for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
-        lis;
-        lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
-    {
-      if (httpAddrLocalhost(&(lis->address)))
-       continue;
-
-      DNSSDPort = httpAddrPort(&(lis->address));
-      break;
-    }
-  }
-
-  if (!DNSSDPort)
-    return;
-
- /*
-  * Get the computer name as a c-string...
-  */
-
-#  ifdef __APPLE__
-  sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);
-
-  if (sc)
-  {
-   /*
-    * Get the computer name from the dynamic store...
-    */
-
-    cupsdClearString(&DNSSDComputerName);
-
-    if ((nameRef = SCDynamicStoreCopyComputerName(sc, &nameEncoding)) != NULL)
-    {
-      if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
-                            kCFStringEncodingUTF8))
-      {
-        cupsdLogMessage(CUPSD_LOG_DEBUG,
-                       "Dynamic store computer name is \"%s\".", nameBuffer);
-       cupsdSetString(&DNSSDComputerName, nameBuffer);
-      }
-
-      CFRelease(nameRef);
-    }
-
-    if (!DNSSDComputerName)
-    {
-     /*
-      * Use the ServerName instead...
-      */
-
-      cupsdLogMessage(CUPSD_LOG_DEBUG,
-                      "Using ServerName \"%s\" as computer name.", ServerName);
-      cupsdSetString(&DNSSDComputerName, ServerName);
-    }
-
-    if (!DNSSDHostName)
-    {
-     /*
-      * Get the local hostname from the dynamic store...
-      */
-
-      if ((nameRef = SCDynamicStoreCopyLocalHostName(sc)) != NULL)
-      {
-       if (CFStringGetCString(nameRef, nameBuffer, sizeof(nameBuffer),
-                              kCFStringEncodingUTF8))
-       {
-         cupsdLogMessage(CUPSD_LOG_DEBUG, "Dynamic store host name is \"%s\".", nameBuffer);
-
-         if (strchr(nameBuffer, '.'))
-           cupsdSetString(&DNSSDHostName, nameBuffer);
-         else
-           cupsdSetStringf(&DNSSDHostName, "%s.local", nameBuffer);
-
-         cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
-       }
-
-       CFRelease(nameRef);
-      }
-    }
-
-    if (!DNSSDHostName)
-    {
-     /*
-      * Use the ServerName instead...
-      */
-
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "Using ServerName \"%s\" as host name.", ServerName);
-      cupsdSetString(&DNSSDHostName, ServerName);
-
-      cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
-    }
-
-   /*
-    * Get any Back-to-My-Mac domains and add them as aliases...
-    */
-
-    cupsdFreeAliases(DNSSDAlias);
-    DNSSDAlias = NULL;
-
-    btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
-    if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "%d Back to My Mac aliases to add.",
-                     (int)CFDictionaryGetCount(btmm));
-      CFDictionaryApplyFunction(btmm, dnssdAddAlias, NULL);
-    }
-    else if (btmm)
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "Bad Back to My Mac data in dynamic store!");
-    else
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "No Back to My Mac aliases to add.");
-
-    if (btmm)
-      CFRelease(btmm);
-
-    CFRelease(sc);
-  }
-  else
-#  endif /* __APPLE__ */
-#  ifdef HAVE_AVAHI
-  if (DNSSDClient)
-  {
-    const char *host_name = avahi_client_get_host_name(DNSSDClient);
-
-    cupsdSetString(&DNSSDComputerName, host_name ? host_name : ServerName);
-
-    if (!DNSSDHostName)
-    {
-      const char *host_fqdn = avahi_client_get_host_name_fqdn(DNSSDClient);
-
-      if (host_fqdn)
-       cupsdSetString(&DNSSDHostName, host_fqdn);
-      else if (strchr(ServerName, '.'))
-       cupsdSetString(&DNSSDHostName, ServerName);
-      else
-       cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);
-
-      cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
-    }
-  }
-  else
-#  endif /* HAVE_AVAHI */
-  {
-    cupsdSetString(&DNSSDComputerName, ServerName);
-
-    if (!DNSSDHostName)
-    {
-      if (strchr(ServerName, '.'))
-       cupsdSetString(&DNSSDHostName, ServerName);
-      else
-       cupsdSetStringf(&DNSSDHostName, "%s.local", ServerName);
-
-      cupsdLogMessage(CUPSD_LOG_INFO, "Defaulting to \"DNSSDHostName %s\".", DNSSDHostName);
-    }
-  }
-
- /*
-  * Then (re)register the web interface if enabled...
-  */
-
-  if (BrowseWebIF)
-  {
-    if (DNSSDComputerName)
-      snprintf(webif, sizeof(webif), "CUPS @ %s", DNSSDComputerName);
-    else
-      cupsCopyString(webif, "CUPS", sizeof(webif));
-
-    dnssdDeregisterInstance(&WebIFSrv, from_callback);
-    dnssdRegisterInstance(&WebIFSrv, NULL, webif, "_http._tcp", "_printer", DNSSDPort, NULL, 1, from_callback);
-  }
-}
-
-
 /*
  * 'get_auth_info_required()' - Get the auth-info-required value to advertise.
  */
index 91bbf497936266d6f4251baeede4c3be36719fd3..cb978cd4e5ea4d9917238ba73ba97e012a78fb37 100644 (file)
@@ -38,19 +38,12 @@ VAR cups_array_t    *DNSSDAlias     VALUE(NULL);
                                        /* List of dynamic ServerAlias's */
 VAR int                        DNSSDPort       VALUE(0);
                                        /* Port number to register */
+VAR cups_dnssd_t       *DNSSDContext   VALUE(NULL);
+                                       /* DNS-SD context */
 VAR cups_array_t       *DNSSDPrinters  VALUE(NULL);
                                        /* Printers we have registered */
-#  ifdef HAVE_MDNSRESPONDER
-VAR DNSServiceRef      DNSSDMaster     VALUE(NULL);
-                                       /* Master DNS-SD service reference */
-#  else /* HAVE_AVAHI */
-VAR AvahiThreadedPoll  *DNSSDMaster    VALUE(NULL);
-                                       /* Master polling interface for Avahi */
-VAR AvahiClient                *DNSSDClient    VALUE(NULL);
-                                       /* Client information */
-#  endif /* HAVE_MDNSRESPONDER */
-VAR cupsd_srv_t                WebIFSrv        VALUE(NULL);
-                                       /* Service reference for the web interface */
+VAR cups_dnssd_service_t *DNSSDWebIF   VALUE(NULL);
+                                       /* Web interface service */
 
 
 /*
index 3c1b12de41a88c9661d4bb1b2f9afb59af6c28d2..360d8ac7f1fe98e923435c590999ac49092ed1d9 100644 (file)
@@ -8,14 +8,6 @@
  * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
 
-#ifdef HAVE_MDNSRESPONDER
-#  include <dns_sd.h>
-#elif defined(HAVE_AVAHI)
-#  include <avahi-client/client.h>
-#  include <avahi-client/publish.h>
-#  include <avahi-common/error.h>
-#  include <avahi-common/thread-watch.h>
-#endif /* HAVE_MDNSRESPONDER */
 #include <cups/pwg-private.h>
 
 
@@ -32,20 +24,6 @@ typedef struct
 } cupsd_quota_t;
 
 
-/*
- * DNS-SD types to make the code cleaner/clearer...
- */
-
-#ifdef HAVE_MDNSRESPONDER
-typedef DNSServiceRef cupsd_srv_t;     /* Service reference */
-typedef TXTRecordRef cupsd_txt_t;      /* TXT record */
-
-#elif defined(HAVE_AVAHI)
-typedef AvahiEntryGroup *cupsd_srv_t;  /* Service reference */
-typedef AvahiStringList *cupsd_txt_t;  /* TXT record */
-#endif /* HAVE_MDNSRESPONDER */
-
-
 /*
  * Printer/class information structure...
  */
@@ -113,11 +91,7 @@ struct cupsd_printer_s
 
   char         *reg_name,              /* Name used for service registration */
                *pdl;                   /* pdl value for TXT record */
-  cupsd_srv_t  ipp_srv;                /* IPP service(s) */
-#  ifdef HAVE_MDNSRESPONDER
-  cupsd_srv_t  ipps_srv;               /* IPPS service(s) */
-  cupsd_srv_t  printer_srv;            /* LPD service */
-#  endif /* HAVE_MDNSRESPONDER */
+  cups_dnssd_service_t *dnssd;         /* DNS-SD service(s) */
 };
 
 
@@ -153,36 +127,21 @@ extern int                cupsdDeletePrinter(cupsd_printer_t *p, int update);
 extern void             cupsdDeleteTemporaryPrinters(int force);
 extern cupsd_printer_t *cupsdFindDest(const char *name);
 extern cupsd_printer_t *cupsdFindPrinter(const char *name);
-extern cupsd_quota_t   *cupsdFindQuota(cupsd_printer_t *p,
-                                       const char *username);
+extern cupsd_quota_t   *cupsdFindQuota(cupsd_printer_t *p, const char *username);
 extern void            cupsdFreeQuotas(cupsd_printer_t *p);
 extern void            cupsdLoadAllPrinters(void);
-extern void            cupsdRenamePrinter(cupsd_printer_t *p,
-                                          const char *name);
+extern void            cupsdRenamePrinter(cupsd_printer_t *p, const char *name);
 extern void            cupsdSaveAllPrinters(void);
-extern int             cupsdSetAuthInfoRequired(cupsd_printer_t *p,
-                                                const char *values,
-                                                ipp_attribute_t *attr);
+extern int             cupsdSetAuthInfoRequired(cupsd_printer_t *p, const char *values, ipp_attribute_t *attr);
 extern void            cupsdSetDeviceURI(cupsd_printer_t *p, const char *uri);
-extern void            cupsdSetPrinterAttr(cupsd_printer_t *p,
-                                           const char *name,
-                                           const char *value);
+extern void            cupsdSetPrinterAttr(cupsd_printer_t *p, const char *name, const char *value);
 extern void            cupsdSetPrinterAttrs(cupsd_printer_t *p);
-extern int             cupsdSetPrinterReasons(cupsd_printer_t *p,
-                                              const char *s);
-extern void            cupsdSetPrinterState(cupsd_printer_t *p, ipp_pstate_t s,
-                                            int update);
-#define                        cupsdStartPrinter(p,u) cupsdSetPrinterState((p), \
-                                                  IPP_PSTATE_IDLE, (u))
+extern int             cupsdSetPrinterReasons(cupsd_printer_t *p, const char *s);
+extern void            cupsdSetPrinterState(cupsd_printer_t *p, ipp_pstate_t s, int update);
+#define                        cupsdStartPrinter(p,u) cupsdSetPrinterState((p), IPP_PSTATE_IDLE, (u))
 extern void            cupsdStopPrinter(cupsd_printer_t *p, int update);
-extern int             cupsdUpdatePrinterPPD(cupsd_printer_t *p,
-                                             int num_keywords,
-                                             cups_option_t *keywords);
+extern int             cupsdUpdatePrinterPPD(cupsd_printer_t *p, int num_keywords, cups_option_t *keywords);
 extern void            cupsdUpdatePrinters(void);
-extern cupsd_quota_t   *cupsdUpdateQuota(cupsd_printer_t *p,
-                                         const char *username, int pages,
-                                         int k);
-extern const char      *cupsdValidateDest(const char *uri,
-                                          cups_ptype_t *dtype,
-                                          cupsd_printer_t **printer);
+extern cupsd_quota_t   *cupsdUpdateQuota(cupsd_printer_t *p, const char *username, int pages, int k);
+extern const char      *cupsdValidateDest(const char *uri, cups_ptype_t *dtype, cupsd_printer_t **printer);
 extern void            cupsdWritePrintcap(void);