From: Michael R Sweet Date: Tue, 18 Mar 2025 18:43:02 +0000 (-0400) Subject: Mirror Win32 DNS-SD changes from libcups project. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=39398cc570d209e72c16bee8a98c452ab5cca4bf;p=thirdparty%2Fcups.git Mirror Win32 DNS-SD changes from libcups project. --- diff --git a/CHANGES.md b/CHANGES.md index f258270786..72aa7c48a4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -37,6 +37,7 @@ Changes in CUPS v2.5b1 (YYYY-MM-DD) - Added `cups-oauth` and `cups-x509` utilities (Issue #1184) - Updated documentation (Issue #984, Issue #1086, Issue #1182) - Updated the configure script to default to installing to /usr/local. +- Updated CUPS to use the Windows mDNS APIs. - Updated CUPS to require TLS support - OpenSSL, GNUTLS and LibreSSL are supported. - Updated CUPS to require ZLIB. diff --git a/cups/dnssd.c b/cups/dnssd.c index d72f0d1f66..696593e854 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -1,7 +1,7 @@ // // DNS-SD API functions for CUPS. // -// Copyright © 2022-2024 by OpenPrinting. +// Copyright © 2022-2025 by OpenPrinting. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information. @@ -25,6 +25,7 @@ # endif // _WIN32 #elif _WIN32 # include +# pragma comment(lib, "dnsapi.lib") // Link in dnsapi library... #else // HAVE_AVAHI # include # include @@ -39,6 +40,13 @@ #endif // HAVE_MDNSRESPONDER +// +// Constants... +// + +#define _CUPS_DNSSD_MAX 50 // Maximum number of browsers/services/etc. + + // // Private structures... // @@ -46,7 +54,7 @@ struct _cups_dnssd_s // DNS-SD context { cups_rwlock_t rwlock; // R/W lock for context - size_t config_changes; // Number of hostname/network changes + size_t config_changes; // Number of hostname/network changes cups_dnssd_error_cb_t cb; // Error callback function void *cb_data; // Error callback data cups_array_t *browses, // Browse requests @@ -58,19 +66,21 @@ struct _cups_dnssd_s // DNS-SD context DNSServiceRef ref; // Master service reference char hostname[256]; // Current mDNS hostname DNSServiceRef hostname_ref; // Hostname monitoring reference - cups_thread_t monitor; // Monitoring thread + cups_thread_t monitor; // Monitoring thread #elif _WIN32 + char hostname[256]; // Current mDNS hostname #else // HAVE_AVAHI cups_mutex_t mutex; // Avahi poll mutex bool in_callback; // Doing a callback? - AvahiClient *client; // Avahi client connection + AvahiClient *client; // Avahi client connection AvahiSimplePoll *poll; // Avahi poll class - cups_thread_t monitor; // Monitoring thread + cups_thread_t monitor; // Monitoring thread AvahiDomainBrowser *dbrowser; // Domain browser - size_t num_domains; // Number of domains - char domains[32][256];// Domains + size_t num_domains; // Number of domains + char domains[_CUPS_DNSSD_MAX][256]; + // Domains #endif // HAVE_MDNSRESPONDER }; @@ -82,10 +92,20 @@ struct _cups_dnssd_browse_s // DNS-SD browse request #ifdef HAVE_MDNSRESPONDER DNSServiceRef ref; // Browse reference + #elif _WIN32 + size_t num_browsers; // Number of browsers + struct + { // Browsers + WCHAR name[256]; // Browse name as a UTF-16 string + DNS_SERVICE_BROWSE_REQUEST req; // Browse request + DNS_SERVICE_CANCEL cancel; // Cancellation structure + } browsers[_CUPS_DNSSD_MAX]; + #else // HAVE_AVAHI - size_t num_browsers; // Number of browsers - AvahiServiceBrowser *browsers[33]; // Browsers + size_t num_browsers; // Number of browsers + AvahiServiceBrowser *browsers[_CUPS_DNSSD_MAX]; + // Browsers #endif // HAVE_MDNSRESPONDER }; @@ -97,7 +117,13 @@ struct _cups_dnssd_query_s // DNS-SD query request #ifdef HAVE_MDNSRESPONDER DNSServiceRef ref; // Query reference + #elif _WIN32 + WCHAR fullname[256]; // Query full name as a UTF-16 string + MDNS_QUERY_REQUEST req; // Query request + MDNS_QUERY_HANDLE handle; // Query handle + DNS_QUERY_RESULT res; // Query result + #else // HAVE_AVAHI AvahiRecordBrowser *browser; // Browser #endif // HAVE_MDNSRESPONDER @@ -111,12 +137,28 @@ struct _cups_dnssd_resolve_s // DNS-SD resolve request #ifdef HAVE_MDNSRESPONDER DNSServiceRef ref; // Resolve reference + #elif _WIN32 + WCHAR fullname[256]; // Full name as a UTF-16 string + DNS_SERVICE_RESOLVE_REQUEST req; // Resolve request + DNS_SERVICE_CANCEL cancel; // Cancellation structure + #else // HAVE_AVAHI AvahiServiceResolver *resolver; // Resolver #endif // HAVE_MDNSRESPONDER }; +#if _WIN32 +struct _win32_srv_s // Service +{ + DNS_SERVICE_REGISTER_REQUEST req; // Registration request + DNS_SERVICE_CANCEL cancel; // Cancellation structure + WCHAR fullname[256]; // Full service name + WCHAR hostname[256]; // Hostname + WCHAR *txt; // TXT key/value string buffer +}; +#endif // _WIN32 + struct _cups_dnssd_service_s // DNS-SD service registration { cups_dnssd_t *dnssd; // DNS-SD context @@ -129,9 +171,16 @@ struct _cups_dnssd_service_s // DNS-SD service registration #ifdef HAVE_MDNSRESPONDER size_t num_refs; // Number of service references - DNSServiceRef refs[16]; // Service references - DNSRecordRef loc_refs[16]; // Service location records + DNSServiceRef refs[_CUPS_DNSSD_MAX]; + // Service references + DNSRecordRef loc_refs[_CUPS_DNSSD_MAX]; + // Service location records + #elif _WIN32 + size_t num_srvs; // Number of services + struct _win32_srv_s srvs[_CUPS_DNSSD_MAX]; + // Services + #else // HAVE_AVAHI AvahiEntryGroup *group; // Group of services under this name #endif // HAVE_MDNSRESPONDER @@ -159,6 +208,12 @@ static const char *mdns_strerror(DNSServiceErrorType errorCode); static cups_dnssd_flags_t mdns_to_cups(DNSServiceFlags flags, DNSServiceErrorType error); #elif _WIN32 +static void win32_browse_cb(DWORD status, PVOID context, PDNS_RECORD record); +static void win32_query_cb(PVOID context, PMDNS_QUERY_HANDLE handle, PDNS_QUERY_RESULT result); +static void win32_resolve_cb(DWORD status, PVOID context, PDNS_SERVICE_INSTANCE instance); +static void win32_service_cb(DWORD status, PVOID context, PDNS_SERVICE_INSTANCE instance); +static void win32_utf8cpy(char *dst, const WCHAR *src, size_t dstsize); +static void win32_wstrcpy(WCHAR *dst, const char *src, size_t dstsize); #else // HAVE_AVAHI static void avahi_browse_cb(AvahiServiceBrowser *browser, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, cups_dnssd_browse_t *browse); @@ -185,7 +240,7 @@ static void avahi_service_cb(AvahiEntryGroup *srv, AvahiEntryGroupState state, bool // O - `true` on success, `false` on failure cupsDNSSDAssembleFullName( char *fullname, // I - Buffer for full name - size_t fullsize, // I - Size of buffer + size_t fullsize, // I - Size of buffer const char *name, // I - Service instance name const char *type, // I - Registration type const char *domain) // I - Domain @@ -200,7 +255,28 @@ cupsDNSSDAssembleFullName( return (DNSServiceConstructFullName(fullname, name, type, domain) == kDNSServiceErr_NoError); #elif _WIN32 - return (false); + char *fullptr, // Pointer into full name + *fullend; // End of full name + + for (fullptr = fullname, fullend = fullname + fullsize - 1; *name; name ++) + { + if (*name == ' ' || *name == '\\' || (*name & 0x80)) + { + if ((fullend - fullptr) < 4) + return (false); + + snprintf(fullptr, fullend - fullptr + 1, "\\%03d", *name & 255); + fullptr += strlen(fullptr); + } + else + { + *fullptr++ = *name; + } + } + + snprintf(fullptr, fullend - fullptr + 1, ".%s.%s", type, domain ? domain : "local"); + + return (true); #else // HAVE_AVAHI return (!avahi_service_name_join(fullname, fullsize, name, type, domain)); @@ -324,44 +400,140 @@ cupsDNSSDBrowseNew( } #elif _WIN32 + DNS_STATUS status; // DNS request status + size_t i, // Looping var + count; // Number of types + const char *base, // Base query name + *subtype; // Subtype + char typename[256]; // Current query name + cups_array_t *tarray; // Types array -#else // HAVE_AVAHI - if (!dnssd->in_callback) + + if ((tarray = cupsArrayNewStrings(types, ',')) == NULL) { - DEBUG_puts("2cupsDNSSDBrowseNew: Locking mutex."); - cupsMutexLock(&dnssd->mutex); + report_error(dnssd, "Unable to create types array: %s", strerror(errno)); + free(browse); + browse = NULL; + goto done; } - browse->num_browsers = 1; - browse->browsers[0] = avahi_service_browser_new(dnssd->client, avahi_if_index(if_index), AVAHI_PROTO_UNSPEC, types, /*domain*/NULL, /*flags*/0, (AvahiServiceBrowserCallback)avahi_browse_cb, browse); + base = (const char *)cupsArrayGetElement(tarray, 0); + count = cupsArrayGetCount(tarray); + + if (count == 1) + count ++; - if (!browse->browsers[0]) + for (i = 1; i < count; i ++) { - report_error(dnssd, "Unable to create DNS-SD browse request: %s", avahi_strerror(avahi_client_errno(dnssd->client))); - free(browse); - browse = NULL; + subtype = (const char *)cupsArrayGetElement(tarray, i); - if (!dnssd->in_callback) + if (subtype) + snprintf(typename, sizeof(typename), "%s._sub.%s.local", subtype, base); + else + snprintf(typename, sizeof(typename), "%s.local", base); + + browse->browsers[i].req.Version = DNS_QUERY_REQUEST_VERSION1; + browse->browsers[i].req.InterfaceIndex = if_index; + browse->browsers[i].req.pBrowseCallback = win32_browse_cb; + browse->browsers[i].req.pQueryContext = browse; + browse->browsers[i].req.QueryName = browse->browsers[i].name; + + win32_wstrcpy(browse->browsers[i].name, typename, sizeof(browse->browsers[i].name)); + + if ((status = DnsServiceBrowse(&browse->browsers[i].req, &browse->browsers[i].cancel)) != DNS_REQUEST_PENDING) { - DEBUG_puts("2cupsDNSSDBrowseNew: Unlocking mutex."); - cupsMutexUnlock(&dnssd->mutex); + report_error(dnssd, "Unable to create browser: %u", status); + while (i > 0) + { + i --; + DnsServiceBrowseCancel(&browse->browsers[i].cancel); + } + free(browse); + browse = NULL; + cupsArrayDelete(tarray); + goto done; } + } + + cupsArrayDelete(tarray); + +#else // HAVE_AVAHI + size_t i, j, // Looping vars + count; // Number of types + const char *base, // Base query name + *subtype; // Subtype + char typename[256]; // Current query name + cups_array_t *tarray; // Types array + + if ((tarray = cupsArrayNewStrings(types, ',')) == NULL) + { + report_error(dnssd, "Unable to create types array: %s", strerror(errno)); + free(browse); + browse = NULL; goto done; } - if (!domain && dnssd->num_domains > 0) + base = (const char *)cupsArrayGetElement(tarray, 0); + count = cupsArrayGetCount(tarray); + + if (count == 1) + count ++; + + if (!dnssd->in_callback) + { + DEBUG_puts("2cupsDNSSDBrowseNew: Locking mutex."); + cupsMutexLock(&dnssd->mutex); + } + + for (i = 1; i < count && browse->num_browsers < _CUPS_DNSSD_MAX; i ++) { - // Add browsers for all domains... - size_t i; // Looping var + subtype = (const char *)cupsArrayGetElement(tarray, i); - for (i = 0; i < dnssd->num_domains; i ++) + if (subtype) + snprintf(typename, sizeof(typename), "%s._sub.%s.local", subtype, base); + else + snprintf(typename, sizeof(typename), "%s.local", base); + + if ((browse->browsers[browse->num_browsers] = avahi_service_browser_new(dnssd->client, avahi_if_index(if_index), AVAHI_PROTO_UNSPEC, typename, domain, /*flags*/0, (AvahiServiceBrowserCallback)avahi_browse_cb, browse)) != NULL) { - if ((browse->browsers[browse->num_browsers] = avahi_service_browser_new(dnssd->client, avahi_if_index(if_index), AVAHI_PROTO_UNSPEC, types, dnssd->domains[i], /*flags*/0, (AvahiServiceBrowserCallback)avahi_browse_cb, browse)) != NULL) - browse->num_browsers ++; + browse->num_browsers ++; + } + else + { + report_error(dnssd, "Unable to create DNS-SD browse request: %s", avahi_strerror(avahi_client_errno(dnssd->client))); + while (browse->num_browsers > 0) + { + browse->num_browsers --; + avahi_service_browser_free(browse->browsers[browse->num_browsers]); + } + free(browse); + browse = NULL; + + cupsArrayDelete(tarray); + + if (!dnssd->in_callback) + { + DEBUG_puts("2cupsDNSSDBrowseNew: Unlocking mutex."); + cupsMutexUnlock(&dnssd->mutex); + } + + goto done; + } + + if (!domain && dnssd->num_domains > 0) + { + // Add browsers for all domains... + for (j = 0; j < dnssd->num_domains && browse->num_browsers < _CUPS_DNSSD_MAX; j ++) + { + if ((browse->browsers[browse->num_browsers] = avahi_service_browser_new(dnssd->client, avahi_if_index(if_index), AVAHI_PROTO_UNSPEC, typename, dnssd->domains[i], /*flags*/0, (AvahiServiceBrowserCallback)avahi_browse_cb, browse)) != NULL) + browse->num_browsers ++; + } } } + cupsArrayDelete(tarray); + if (!dnssd->in_callback) { DEBUG_puts("2cupsDNSSDBrowseNew: Unlocking mutex."); @@ -441,6 +613,11 @@ cupsDNSSDCopyComputerName( if ((bufptr = strchr(buffer, '.')) != NULL) *bufptr = '\0'; +#elif _WIN32 + DWORD size = (DWORD)bufsize; // Size for GetComputerNameA + + GetComputerNameA(buffer, &size); + #else // HAVE_AVAHI cupsCopyString(buffer, avahi_client_get_host_name(dnssd->client), bufsize); #endif // __APPLE__ @@ -484,6 +661,9 @@ cupsDNSSDCopyHostName( DEBUG_puts("2cupsDNSSDCopyHostName: Unlocking rwlock."); cupsRWUnlock(&dnssd->rwlock); +#elif _WIN32 + cupsCopyString(buffer, dnssd->hostname, bufsize); + #else // HAVE_AVAHI cupsCopyString(buffer, avahi_client_get_host_name_fqdn(dnssd->client), bufsize); #endif // HAVE_MDNSRESPONDER @@ -691,6 +871,12 @@ cupsDNSSDNew( DEBUG_printf("2cupsDNSSDNew: dnssd->monitor=%p", (void *)dnssd->monitor); #elif _WIN32 + char compname[256]; // Computer name + DWORD compsize = sizeof(compname); // Size of computer name buffer + + GetComputerNameA(compname, &compsize); + + snprintf(dnssd->hostname, sizeof(dnssd->hostname), "%s.local", compname); #else // HAVE_AVAHI int error; // Error code @@ -817,7 +1003,7 @@ cupsDNSSDQueryNew( cups_dnssd_query_t *query; // Query request - DEBUG_printf("cupsDNSSDQueryNew(dnssd=%p, if_index=%u, fullname=\"%s\", rrtype=%u, query_cb=%p, cb_data=%p)", (void *)dnssd, if_index, fullname, rrtype, (void *)query_cb, cb_data); + DEBUG_printf("cupsDNSSDQueryNew(dnssd=%p, if_index=%u, fullname=\"%s\", rrtype=%u, query_cb=%p, cb_data=%p)", (void *)dnssd, if_index, fullname, rrtype, query_cb, cb_data); // Range check input... if (!dnssd || !fullname || !query_cb) @@ -860,6 +1046,24 @@ cupsDNSSDQueryNew( } #elif _WIN32 + DNS_STATUS status; // DNS request status + + win32_wstrcpy(query->fullname, fullname, sizeof(query->fullname)); + + query->req.Version = DNS_QUERY_REQUEST_VERSION1; + query->req.InterfaceIndex = if_index; + query->req.Query = query->fullname; + query->req.QueryType = rrtype; + query->req.pQueryCallback = win32_query_cb; + query->req.pQueryContext = query; + + if ((status = DnsStartMulticastQuery(&query->req, &query->handle)) != ERROR_SUCCESS) + { + report_error(dnssd, "Unable to start mDNS query request: %d", status); + free(query); + query = NULL; + goto done; + } #else // HAVE_AVAHI if (!dnssd->in_callback) @@ -954,7 +1158,7 @@ cupsDNSSDResolveGetContext( // const char *fullname, // const char *host, // uint16_t port, -// size_t num_txt, +// int num_txt, // cups_option_t *txt) // { // // Process resolved service @@ -1001,12 +1205,31 @@ cupsDNSSDResolveNew( resolve->ref = dnssd->ref; if ((error = DNSServiceResolve(&resolve->ref, kDNSServiceFlagsShareConnection, if_index, name, type, domain, (DNSServiceResolveReply)mdns_resolve_cb, resolve)) != kDNSServiceErr_NoError) { - report_error(dnssd, "Unable to create DNS-SD query request: %s", mdns_strerror(error)); + report_error(dnssd, "Unable to create DNS-SD resolve request: %s", mdns_strerror(error)); free(resolve); return (NULL); } #elif _WIN32 + DNS_STATUS status; // Status of resolve + char fullname[256]; // Full service name + + snprintf(fullname, sizeof(fullname), "%s.%s.%s", name, type, domain ? domain : "local"); + + win32_wstrcpy(resolve->fullname, fullname, sizeof(resolve->fullname)); + + resolve->req.Version = DNS_QUERY_REQUEST_VERSION1; + resolve->req.InterfaceIndex = if_index; + resolve->req.QueryName = resolve->fullname; + resolve->req.pResolveCompletionCallback = win32_resolve_cb; + resolve->req.pQueryContext = resolve; + + if ((status = DnsServiceResolve(&resolve->req, &resolve->cancel)) != DNS_REQUEST_PENDING) + { + report_error(dnssd, "Unable to create DNS-SD resolve request: %d", status); + free(resolve); + return (NULL); + } #else // HAVE_AVAHI if (!dnssd->in_callback) @@ -1076,9 +1299,9 @@ bool // O - `true` on success, `false` on error cupsDNSSDSeparateFullName( const char *fullname, // I - Full service name char *name, // I - Instance name buffer - size_t namesize, // I - Size of instance name buffer + size_t namesize, // I - Size of instance name buffer char *type, // I - Registration type buffer - size_t typesize, // I - Size of registration type buffer + size_t typesize, // I - Size of registration type buffer char *domain, // I - Domain name buffer size_t domainsize) // I - Size of domain name buffer { @@ -1264,6 +1487,110 @@ cupsDNSSDServiceAdd( service->num_refs ++; #elif _WIN32 + DWORD status; // Status of call + struct _win32_srv_s *srv; // Service + int j, // Looping var + count; // Number of types + size_t length; // Length of TXT key/value pairs + WCHAR *ptr, // Pointer into TXT buffer + *end, // End of TXT buffer + *keys[256], // TXT key strings + *values[256]; // TXT value strings + const char *base; // Base service type + char fullname[256]; // Full service instance name + cups_array_t *tarray; // Types array + + if ((tarray = cupsArrayNewStrings(types, ',')) == NULL) + { + report_error(service->dnssd, "Unable to create types array: %s", strerror(errno)); + ret = false; + goto done; + } + + base = (const char *)cupsArrayGetElement(tarray, 0); + count = cupsArrayGetCount(tarray); + + // TODO: Figure out how WinDNS wants sub-types registered, yields invalid argument error for sub-type + for (i = 0; i < count && i < 1; i ++) + { + // Get the fullname... + if (i) + snprintf(fullname, sizeof(fullname), "%s.%s._sub.%s.%s", service->name, (const char*)cupsArrayGetElement(tarray, i), base, domain ? domain : "local"); + else + snprintf(fullname, sizeof(fullname), "%s.%s.%s", service->name, base, domain ? domain : "local"); + + DEBUG_printf("cupsDNSSDServiceAdd: Adding fullname=\"%s\"", fullname); + + // Get the service... + if (service->num_srvs >= _CUPS_DNSSD_MAX) + { + report_error(service->dnssd, "Too many services for this name."); + ret = false; + cupsArrayDelete(tarray); + goto done; + } + + srv = service->srvs + service->num_srvs; + + // Initialize values... + srv->req.Version = DNS_QUERY_REQUEST_VERSION1; + srv->req.InterfaceIndex = service->if_index; + + win32_wstrcpy(srv->fullname, fullname, sizeof(srv->fullname)); + if (host) + win32_wstrcpy(srv->hostname, host, sizeof(srv->hostname)); + else + win32_wstrcpy(srv->hostname, service->dnssd->hostname, sizeof(srv->hostname)); + + for (j = 0, length = 0; j < num_txt; j ++) + length += strlen(txt[j].name) + strlen(txt[j].value) + 2; + + DEBUG_printf("cupsDNSSDServiceAdd: TXT length=%lu", (unsigned long)length); + + if (length > 0) + { + srv->txt = calloc(length, sizeof(WCHAR)); + + for (j = 0, ptr = srv->txt, end = srv->txt + length; j < num_txt; j ++) + { + win32_wstrcpy(ptr, txt[j].name, (size_t)(end - ptr) * sizeof(WCHAR)); + keys[j] = ptr; + ptr += strlen(txt[j].name) + 1; + + win32_wstrcpy(ptr, txt[j].value, (size_t)(end - ptr) * sizeof(WCHAR)); + values[j] = ptr; + ptr += strlen(txt[j].value) + 1; + } + } + + if ((srv->req.pServiceInstance = DnsServiceConstructInstance(srv->fullname, srv->hostname, /*pIp4*/NULL, /*pIp6*/NULL, port, 0, 0, (DWORD)num_txt, keys, values)) == NULL) + { + report_error(service->dnssd, "Unable to allocate memory for '%s'.", fullname); + ret = false; + cupsArrayDelete(tarray); + goto done; + } + + srv->req.pRegisterCompletionCallback = win32_service_cb; + srv->req.pQueryContext = service; + srv->req.unicastEnabled = domain && strcmp(domain, "local") != 0; + + DEBUG_printf("cupsDNSSDServiceAdd: unicastEnabled=%s", srv->req.unicastEnabled ? "true" : "false"); + + if ((status = DnsServiceRegister(&srv->req, &srv->cancel)) != DNS_REQUEST_PENDING) + { + report_error(service->dnssd, "Unable to register '%s': %d", fullname, status); + ret = false; + DnsServiceFreeInstance(srv->req.pServiceInstance); + cupsArrayDelete(tarray); + goto done; + } + + // Register... + service->num_srvs ++; + } + + cupsArrayDelete(tarray); #else // HAVE_AVAHI int error; // Error code @@ -1622,6 +1949,10 @@ delete_browse( DNSServiceRefDeallocate(browse->ref); #elif _WIN32 + size_t i; // Looping var + + for (i = 0; i < browse->num_browsers; i ++) + DnsServiceBrowseCancel(&browse->browsers[i].cancel); #else // HAVE_AVAHI size_t i; // Looping var @@ -1646,6 +1977,7 @@ delete_query( DNSServiceRefDeallocate(query->ref); #elif _WIN32 + DnsStopMulticastQuery(&query->handle); #else // HAVE_AVAHI avahi_record_browser_free(query->browser); @@ -1665,6 +1997,7 @@ delete_resolve( DNSServiceRefDeallocate(resolve->ref); #elif _WIN32 + DnsServiceResolveCancel(&resolve->cancel); #else // HAVE_AVAHI avahi_service_resolver_free(resolve->resolver); @@ -1690,6 +2023,14 @@ delete_service( DNSServiceRefDeallocate(service->refs[i]); #elif _WIN32 + size_t i; // Looping var + + for (i = 0; i < service->num_srvs; i ++) + { + DnsServiceRegisterCancel(&service->srvs[i].cancel); + DnsServiceFreeInstance(service->srvs[i].req.pServiceInstance); + free(service->srvs[i].txt); + } #else // HAVE_AVAHI avahi_entry_group_free(service->group); @@ -2111,6 +2452,265 @@ mdns_to_cups( #elif _WIN32 +// +// 'win32_browse_cb()' - Handle browse callbacks from WinDNS. +// + +static void +win32_browse_cb( + DWORD status, // I - Status + PVOID context, // I - Browser + PDNS_RECORD records) // I - Record list +{ + cups_dnssd_browse_t *browse = (cups_dnssd_browse_t *)context; + PDNS_RECORD record; // Current DNS record + char fullname[256], // Full service instance name + name[256] = "", // Service name + type[256] = "", // Service type + domain[256] = ""; // Domain name + + + for (record = records; record; record = record->pNext) + { + if (record->wType == DNS_TYPE_PTR) + { + win32_utf8cpy(fullname, record->Data.PTR.pNameHost, sizeof(fullname)); + cupsDNSSDSeparateFullName(fullname, name, sizeof(name), type, sizeof(type), domain, sizeof(domain)); + break; + } + } + + (browse->cb)(browse, browse->cb_data, status == ERROR_SUCCESS ? CUPS_DNSSD_FLAGS_NONE : CUPS_DNSSD_FLAGS_ERROR, /*if_index*/0, name, type, domain); + + DnsRecordListFree(records, DnsFreeRecordList); +} + + +// +// 'win32_query_cb()' - Handle query callbacks from WinDNS. +// + +static void +win32_query_cb( + PVOID context, // I - Pointer to query + PMDNS_QUERY_HANDLE handle, // I - Query handle + PDNS_QUERY_RESULT result) // I - Query result +{ + cups_dnssd_query_t *query = (cups_dnssd_query_t *)context; + // Query + char fullname[256]; // Full instance name of query + + + win32_utf8cpy(fullname, query->fullname, sizeof(fullname)); + + if (result && result->pQueryRecords) + { + PDNS_RECORD record; // Current DNS record + + for (record = result->pQueryRecords; record; record = record->pNext) + (query->cb)(query, query->cb_data, CUPS_DNSSD_FLAGS_NONE, /*if_index*/0, fullname, record->wType, &record->Data, record->wDataLength); + + DnsRecordListFree(result->pQueryRecords, DnsFreeRecordList); + } +} + + +// +// 'win32_resolve_cb()' - Handle resolve callbacks from WinDNS. +// + +static void +win32_resolve_cb( + DWORD status, // I - Status + PVOID context, // I - Resolver + PDNS_SERVICE_INSTANCE instance) // I - Service instance +{ + cups_dnssd_resolve_t *resolve = (cups_dnssd_resolve_t *)context; + // Resolver + + + if (status == ERROR_SUCCESS) + { + char fullname[256], // Full instance name + hostname[256], // Hostname + txtname[256], // TXT name + txtvalue[256]; // TXT value + DWORD i; // Looping var + int num_txt = 0; // Number of TXT values + cups_option_t *txt = NULL; // TXT values + + win32_utf8cpy(fullname, instance->pszInstanceName, sizeof(fullname)); + win32_utf8cpy(hostname, instance->pszHostName, sizeof(hostname)); + + for (i = 0; i < instance->dwPropertyCount; i ++) + { + win32_utf8cpy(txtname, instance->keys[i], sizeof(txtname)); + win32_utf8cpy(txtvalue, instance->values[i], sizeof(txtvalue)); + + num_txt = cupsAddOption(txtname, txtvalue, num_txt, &txt); + } + + (resolve->cb)(resolve, resolve->cb_data, CUPS_DNSSD_FLAGS_NONE, instance->dwInterfaceIndex, fullname, hostname, instance->wPort, num_txt, txt); + + cupsFreeOptions(num_txt, txt); + } + else + { + (resolve->cb)(resolve, resolve->cb_data, CUPS_DNSSD_FLAGS_ERROR, /*if_index*/0, /*fullname*/NULL, /*host*/NULL, /*port*/0, /*num_txt*/0, /*txt*/NULL); + } +} + + +// +// 'win32_service_cb()' - Handle service registration callbacks from WinDNS. +// + +static void +win32_service_cb( + DWORD status, // I - Status + PVOID context, // I - Service + PDNS_SERVICE_INSTANCE instance) // I - New instance +{ + cups_dnssd_service_t *service = (cups_dnssd_service_t *)context; + // Service + + (service->cb)(service, service->cb_data, status == ERROR_SUCCESS ? CUPS_DNSSD_FLAGS_NONE : CUPS_DNSSD_FLAGS_ERROR); + + if (instance) + DnsServiceFreeInstance(instance); +} + + +// +// 'win32_utf8cpy()' - Copy a UTF-16 string to a UTF-8 string. +// + +static void +win32_utf8cpy(char *dst, // I - Destination string + const WCHAR *src, // I - Source string + size_t dstsize) // I - Size of destination string +{ + int ch; // Current character + + + // Loop until we run out of characters or buffer space... + while (*src && dstsize > 4) + { + // Get the current character... + ch = *src++; + + if (ch >= 0xd800 && ch <= 0xdbff && *src >= 0xdc00 && *src <= 0xdfff) + { + // Convert UTF-16 to unicode... + ch = ((ch - 0xd800) << 10) | (*src++ - 0xdc00); + } + + if (ch < 0x80) + { + *dst++ = ch; + } + else if (ch < 0x800) + { + *dst++ = 0xc0 | (ch >> 6); + *dst++ = 0x80 | (ch & 0x3f); + } + else if (ch < 0x10000) + { + *dst++ = 0xe0 | (ch >> 12); + *dst++ = 0x80 | ((ch >> 6) & 0x3f); + *dst++ = 0x80 | (ch & 0x3f); + } + else + { + *dst++ = 0xf0 | (ch >> 18); + *dst++ = 0x80 | ((ch >> 12) & 0x3f); + *dst++ = 0x80 | ((ch >> 6) & 0x3f); + *dst++ = 0x80 | (ch & 0x3f); + } + } + + // Nul-terminate the destination... + *dst = '\0'; +} + + +// +// 'win32_wstrcpy()' - Copy a UTF-8 string to a UTF-16 string. +// + +static void +win32_wstrcpy(WCHAR *dst, // I - Destination string + const char *src, // I - Source string + size_t dstsize) // I - Size of destination +{ + int ch; // Current character + + + // Adjust size from bytes to words... + dstsize /= sizeof(WCHAR); + + // Loop until we run out of characters or buffer space... + while (*src && dstsize > 1) + { + // Get the current character... + if ((*src & 0xe0) == 0xc0) + { + // Two-byte UTF-8... + if ((src[1] & 0xc0) != 0x80) + break; + + ch = ((src[0] & 0x1f) << 6) | (src[1] & 0x3f); + src += 2; + } + else if ((*src & 0xf0) == 0xe0) + { + // Three-byte UTF-8... + if ((src[1] & 0xc0) != 0x80 || (src[2] & 0xc0) != 0x80) + break; + + ch = ((src[0] & 0x1f) << 12) | ((src[1] & 0x3f) << 6) | (src[2] & 0x3f); + src += 3; + } + else if ((*src & 0xf8) == 0xf0) + { + // Four-byte UTF-8... + if ((src[1] & 0xc0) != 0x80 || (src[2] & 0xc0) != 0x80 || (src[3] & 0xc0) != 0x80) + break; + + ch = ((src[0] & 0x1f) << 18) | ((src[1] & 0x3f) << 12) | ((src[2] & 0x3f) << 6) | (src[3] & 0x3f); + src += 4; + } + else + { + // US ASCII... + ch = *src++; + } + + // Map it to UTF-16... + if (ch < 0x10000) + { + // One-word UTF-16... + *dst++ = ch; + dstsize --; + } + else if (dstsize > 2) + { + // Two-word UTF-16... + *dst++ = 0xd800 | ((ch >> 12) & 0x3ff); + *dst++ = 0xdc00 | (ch & 0x3ff); + + dstsize -= 2; + } + else + { + // Terminate early... + break; + } + } + + // Nul-terminate the destination... + *dst = '\0'; +} #else // HAVE_AVAHI @@ -2145,9 +2745,14 @@ avahi_browse_cb( cups_dnssd_flags_t cups_flags; // CUPS DNS-SD flags + DEBUG_printf("3avahi_browse_cb(browser=%p, if_index=%u, protocol=%u, event=%d, name=\"%s\", type=\"%s\", domain=\"%s\", flags=%u, browse=%p)", (void *)browser, (unsigned)if_index, (unsigned)protocol, event, name, type, domain, (unsigned)flags, (void *)browse); + (void)protocol; (void)flags; + if (!name) + return; + switch (event) { case AVAHI_BROWSER_NEW : @@ -2397,7 +3002,7 @@ avahi_resolve_cb( cups_dnssd_resolve_t *resolve) // I - Resolve request { AvahiStringList *txtpair; // Current pair - size_t num_txt = 0; // Number of TXT key/value pairs + int num_txt = 0; // Number of TXT key/value pairs cups_option_t *txt = NULL; // TXT key/value pairs char fullname[1024]; // Full service name @@ -2430,13 +3035,13 @@ avahi_resolve_cb( avahi_string_list_get_pair(txtpair, &key, &value, NULL); - DEBUG_printf("4avahi_resolve_cb: txt[%u].name=\"%s\", .value=\"%s\"", (unsigned)num_txt, key, value); + DEBUG_printf("4avahi_resolve_cb: txt[%d].name=\"%s\", .value=\"%s\"", num_txt, key, value); num_txt = cupsAddOption(key, value, num_txt, &txt); avahi_free(key); avahi_free(value); } - DEBUG_printf("4avahi_resolve_cb: num_txt=%u", (unsigned)num_txt); + DEBUG_printf("4avahi_resolve_cb: num_txt=%d", num_txt); // Create a full name for the service... cupsDNSSDAssembleFullName(fullname, sizeof(fullname), name, type, domain); diff --git a/vcnet/cups.sln b/vcnet/cups.sln index a9045e401e..0556636367 100644 --- a/vcnet/cups.sln +++ b/vcnet/cups.sln @@ -3,41 +3,47 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 15.0.28010.2036 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcups2", "libcups2.vcxproj", "{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testdnssd", "testdnssd.vcxproj", "{CBEFF8C1-C109-4B37-92B9-843DF7EB4FA0}" ProjectSection(ProjectDependencies) = postProject - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} = {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testfile", "testfile.vcxproj", "{CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}" + ProjectSection(ProjectDependencies) = postProject + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testhttp", "testhttp.vcxproj", "{90B0058C-8393-411F-BD3B-E2C831D4E883}" ProjectSection(ProjectDependencies) = postProject - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} = {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cupstestppd", "cupstestppd.vcxproj", "{6BE0CDD3-4ED7-409C-A80F-19DF73664B1F}" ProjectSection(ProjectDependencies) = postProject - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} = {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ipptool", "ipptool.vcxproj", "{B246D91E-61F2-4433-BFD2-6C2A96FBD4D4}" ProjectSection(ProjectDependencies) = postProject - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} = {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regex", "regex.vcxproj", "{18950A1B-D37A-40C7-B2DF-C12986C0526E}" + ProjectSection(ProjectDependencies) = postProject + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ippfind", "ippfind.vcxproj", "{B484DA0C-62C8-4C32-83B6-CCEB58968B85}" ProjectSection(ProjectDependencies) = postProject - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} = {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ippeveprinter", "ippeveprinter.vcxproj", "{82A03BC7-0746-4B85-8908-3C7A3FAA58A9}" ProjectSection(ProjectDependencies) = postProject - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} = {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} = {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dnssdstub", "dnssdstub.vcxproj", "{C0899B3A-43E7-4BC3-A785-659E1FD2EA83}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -48,6 +54,10 @@ Global {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug|x64.Build.0 = Debug|x64 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.ActiveCfg = Release|x64 {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release|x64.Build.0 = Release|x64 + {CBEFF8C1-C109-4B37-92B9-843DF7EB4FA0}.Debug|x64.ActiveCfg = Debug|x64 + {CBEFF8C1-C109-4B37-92B9-843DF7EB4FA0}.Debug|x64.Build.0 = Debug|x64 + {CBEFF8C1-C109-4B37-92B9-843DF7EB4FA0}.Release|x64.ActiveCfg = Release|x64 + {CBEFF8C1-C109-4B37-92B9-843DF7EB4FA0}.Release|x64.Build.0 = Release|x64 {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|x64.ActiveCfg = Debug|x64 {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Debug|x64.Build.0 = Debug|x64 {CE75FC5F-E0CF-45DC-AD27-84666D3FBA30}.Release|x64.ActiveCfg = Release|x64 @@ -76,10 +86,6 @@ Global {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Debug|x64.Build.0 = Debug|x64 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Release|x64.ActiveCfg = Release|x64 {82A03BC7-0746-4B85-8908-3C7A3FAA58A9}.Release|x64.Build.0 = Release|x64 - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83}.Debug|x64.ActiveCfg = Debug|x64 - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83}.Debug|x64.Build.0 = Debug|x64 - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83}.Release|x64.ActiveCfg = Release|x64 - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/vcnet/dns_sd.c b/vcnet/dns_sd.c deleted file mode 100644 index 341fc0964f..0000000000 --- a/vcnet/dns_sd.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Dynamic wrapper for Bonjour SDK for Windows. - * - * Copyright © 2020-2024 by OpenPrinting. - * Copyright 2018 by Apple Inc. - * - * Licensed under Apache License v2.0. See the file "LICENSE" for more - * information. - */ - -//#include -#include -#include "dns_sd.h" - - -/* - * Pointers for functions... - */ - -static int dnssd_initialized = 0; -static cups_mutex_t dnssd_mutex = CUPS_MUTEX_INITIALIZER; -static DNSServiceErrorType (*dnssd_add_record)(DNSServiceRef sdRef, DNSRecordRef *RecordRef, DNSServiceFlags flags, uint16_t rrtype, uint16_t rdlen, const void *rdata, uint32_t ttl); -static DNSServiceErrorType (*dnssd_browse)(DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *regtype, const char *domain, DNSServiceBrowseReply callBack, void *context); -static DNSServiceErrorType (*dnssd_construct_full_name)(char * const fullName, const char * const service, const char * const regtype, const char * const domain); -static DNSServiceErrorType (*dnssd_create_connection)(DNSServiceRef *sdRef); -static DNSServiceErrorType (*dnssd_process_result)(DNSServiceRef sdRef); -static DNSServiceErrorType (*dnssd_query_record)(DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *fullname, uint16_t rrtype, uint16_t rrclass, DNSServiceQueryRecordReply callBack, void *context); -static void (*dnssd_deallocate)(DNSServiceRef sdRef); -static int (*dnssd_sock_fd)(DNSServiceRef sdRef); -static DNSServiceErrorType (*dnssd_register)(DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *name, const char *regtype, const char *domain, const char *host, uint16_t port, uint16_t txtLen, const void *txtRecord, DNSServiceRegisterReply callBack, void *context); -static DNSServiceErrorType (*dnssd_remove_record)(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags); -static DNSServiceErrorType (*dnssd_resolve)(DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *name, const char *regtype, const char *domain, DNSServiceResolveReply callBack, void *context); -static DNSServiceErrorType (*dnssd_update_record)(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, uint16_t rdlen, const void *rdata, uint32_t ttl); - -static void (*dnssd_txt_create)(TXTRecordRef *txtRecord, uint16_t bufferLen, void *buffer); -static void (*dnssd_txt_deallocate)(TXTRecordRef *txtRecord); -static const void *(*dnssd_txt_get_bytes_ptr)(const TXTRecordRef *txtRecord); -static uint16_t (*dnssd_txt_get_count)(uint16_t txtLen, const void *txtRecord); -static uint16_t (*dnssd_txt_get_length)(const TXTRecordRef *txtRecord); -static DNSServiceErrorType (*dnssd_txt_get_item_at_index)(uint16_t txtLen, const void *txtRecord, uint16_t itemIndex, uint16_t keyBufLen, char *key, uint8_t *valueLen, const void **value); -static const void *(*dnssd_txt_get_value_ptr)(uint16_t txtLen, const void *txtRecord, const char *key, uint8_t *valueLen); -static DNSServiceErrorType (*dnssd_txt_set_value)(TXTRecordRef *txtRecord, const char *key, uint8_t valueSize, const void *value); - - -/* - * Function to initialize pointers... - */ - -static void -dnssd_init(void) -{ - cupsMutexLock(&dnssd_mutex); - if (!dnssd_initialized) - { - HINSTANCE dll_handle = LoadLibraryA("dnssd.dll"); - - if (dll_handle) - { - dnssd_add_record = (DNSServiceErrorType (*)(DNSServiceRef, DNSRecordRef *, DNSServiceFlags, uint16_t, uint16_t, const void *, uint32_t))GetProcAddress(dll_handle, "DNSServiceAddRecord"); - dnssd_browse = (DNSServiceErrorType(*)(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, const char *, DNSServiceBrowseReply, void *))GetProcAddress(dll_handle, "DNSServiceBrowse"); - dnssd_construct_full_name = (DNSServiceErrorType(*)(char * const, const char * const, const char * const, const char * const))GetProcAddress(dll_handle, "DNSServiceConstructFullName"); - dnssd_create_connection = (DNSServiceErrorType(*)(DNSServiceRef *))GetProcAddress(dll_handle, "DNSServiceCreateConnection"); - dnssd_deallocate = (DNSServiceErrorType(*)(DNSServiceRef))GetProcAddress(dll_handle, "DNSServiceRefDeallocate"); - dnssd_process_result = (DNSServiceErrorType(*)(DNSServiceRef))GetProcAddress(dll_handle, "DNSServiceProcessResult"); - dnssd_query_record = (DNSServiceErrorType(*)(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, uint16_t, uint16_t, DNSServiceQueryRecordReply, void *))GetProcAddress(dll_handle, "DNSServiceQueryRecord"); - dnssd_register = (DNSServiceErrorType(*)(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, const char *, const char *, const char *, uint16_t, uint16_t, const void *, DNSServiceRegisterReply, void *))GetProcAddress(dll_handle, "DNSServiceRegister"); - dnssd_remove_record = (DNSServiceErrorType(*)(DNSServiceRef, DNSRecordRef, DNSServiceFlags))GetProcAddress(dll_handle, "DNSServiceRemoveRecord"); - dnssd_resolve = (DNSServiceErrorType(*)(DNSServiceRef *, DNSServiceFlags, uint32_t, const char *, const char *, const char *, DNSServiceResolveReply, void *))GetProcAddress(dll_handle, "DNSServiceResolve"); - dnssd_sock_fd = (int(*)(DNSServiceRef))GetProcAddress(dll_handle, "DNSServiceRefSockFD"); - dnssd_update_record = (DNSServiceErrorType(*)(DNSServiceRef, DNSRecordRef, DNSServiceFlags, uint16_t, const void *, uint32_t))GetProcAddress(dll_handle, "DNSServiceUpdateRecord"); - - dnssd_txt_create = (void (*)(TXTRecordRef *, uint16_t, void *))GetProcAddress(dll_handle, "TXTRecordCreate"); - dnssd_txt_deallocate = (void (*)(TXTRecordRef *))GetProcAddress(dll_handle, "TXTRecordDeallocate"); - dnssd_txt_get_bytes_ptr = (const void *(*)(const TXTRecordRef *))GetProcAddress(dll_handle, "TXTRecordGetBytesPtr"); - dnssd_txt_get_count = (uint16_t (*)(uint16_t, const void *))GetProcAddress(dll_handle, "TXTRecordGetCount"); - dnssd_txt_get_item_at_index = (DNSServiceErrorType (*)(uint16_t, const void *, uint16_t, uint16_t, char *, uint8_t *, const void **))GetProcAddress(dll_handle, "TXTRecordGetItemAtIndex"); - dnssd_txt_get_length = (uint16_t (*)(const TXTRecordRef *))GetProcAddress(dll_handle, "TXTRecordGetLength"); - dnssd_txt_get_value_ptr = (const void *(*)(uint16_t, const void *, const char *, uint8_t *))GetProcAddress(dll_handle, "TXTRecordGetValuePtr"); - dnssd_txt_set_value = (DNSServiceErrorType (*)(TXTRecordRef *, const char *, uint8_t, const void *))GetProcAddress(dll_handle, "TXTRecordSetValue"); - } - - dnssd_initialized = 1; - } - cupsMutexUnlock(&dnssd_mutex); -} - - -// DNSServiceAddRecord -DNSServiceErrorType DNSSD_API DNSServiceAddRecord - ( - DNSServiceRef sdRef, - DNSRecordRef *RecordRef, - DNSServiceFlags flags, - uint16_t rrtype, - uint16_t rdlen, - const void *rdata, - uint32_t ttl - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_add_record) - return (*dnssd_add_record)(sdRef, RecordRef, flags, rrtype, rdlen, rdata, ttl); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// DNSServiceBrowse -DNSServiceErrorType DNSSD_API DNSServiceBrowse - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *regtype, - const char *domain, /* may be NULL */ - DNSServiceBrowseReply callBack, - void *context /* may be NULL */ - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_browse) - return (*dnssd_browse)(sdRef, flags, interfaceIndex, regtype, domain, callBack, context); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// DNSServiceConstructFullName -DNSServiceErrorType DNSSD_API DNSServiceConstructFullName - ( - char * const fullName, - const char * const service, /* may be NULL */ - const char * const regtype, - const char * const domain - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_construct_full_name) - return (*dnssd_construct_full_name)(fullName, service, regtype, domain); - else - return (-1); -} - - -// DNSServiceCreateConnection -DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_create_connection) - return (*dnssd_create_connection)(sdRef); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// DNSServiceProcessResult -DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_process_result) - return (*dnssd_process_result)(sdRef); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// DNSServiceQueryRecord -DNSServiceErrorType DNSSD_API DNSServiceQueryRecord - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *fullname, - uint16_t rrtype, - uint16_t rrclass, - DNSServiceQueryRecordReply callBack, - void *context /* may be NULL */ - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_query_record) - return (*dnssd_query_record)(sdRef, flags, interfaceIndex, fullname, rrtype, rrclass, callBack, context); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// DNSServiceRefDeallocate -void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_deallocate) - (*dnssd_deallocate)(sdRef); -} - - -// DNSServiceRefSockFD -int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_sock_fd) - return (*dnssd_sock_fd)(sdRef); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// DNSServiceRegister -DNSServiceErrorType DNSSD_API DNSServiceRegister - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *name, /* may be NULL */ - const char *regtype, - const char *domain, /* may be NULL */ - const char *host, /* may be NULL */ - uint16_t port, /* In network byte order */ - uint16_t txtLen, - const void *txtRecord, /* may be NULL */ - DNSServiceRegisterReply callBack, /* may be NULL */ - void *context /* may be NULL */ - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_register) - return (*dnssd_register)(sdRef, flags, interfaceIndex, name, regtype, domain, host, port, txtLen, txtRecord, callBack, context); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// DNSServiceRemoveRecord -DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord - ( - DNSServiceRef sdRef, - DNSRecordRef RecordRef, - DNSServiceFlags flags - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_remove_record) - return (*dnssd_remove_record)(sdRef, RecordRef, flags); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// DNSServiceResolve -DNSServiceErrorType DNSSD_API DNSServiceResolve - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *name, - const char *regtype, - const char *domain, - DNSServiceResolveReply callBack, - void *context /* may be NULL */ - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_resolve) - return (*dnssd_resolve)(sdRef, flags, interfaceIndex, name, regtype, domain, callBack, context); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// DNSServiceUpdateRecord -DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord - ( - DNSServiceRef sdRef, - DNSRecordRef RecordRef, /* may be NULL */ - DNSServiceFlags flags, - uint16_t rdlen, - const void *rdata, - uint32_t ttl - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_update_record) - return (*dnssd_update_record)(sdRef, RecordRef, flags, rdlen, rdata, ttl); - else - return (kDNSServiceErr_ServiceNotRunning); -} - - -// TXTRecordCreate -void DNSSD_API -TXTRecordCreate( - TXTRecordRef *txtRecord, - uint16_t bufferLen, - void *buffer) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_txt_create) - (*dnssd_txt_create)(txtRecord, bufferLen, buffer); -} - - -// TXTRecordDeallocate -void DNSSD_API TXTRecordDeallocate - ( - TXTRecordRef *txtRecord - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_txt_deallocate) - (*dnssd_txt_deallocate)(txtRecord); -} - - -// TXTRecordGetBytesPtr -const void * DNSSD_API TXTRecordGetBytesPtr - ( - const TXTRecordRef *txtRecord - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_txt_get_bytes_ptr) - return (*dnssd_txt_get_bytes_ptr)(txtRecord); - else - return (NULL); -} - - -// TXTRecordGetLength -uint16_t DNSSD_API TXTRecordGetLength - ( - const TXTRecordRef *txtRecord - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_txt_get_length) - return (*dnssd_txt_get_length)(txtRecord); - else - return (0); -} - - -// TXTRecordSetValue -DNSServiceErrorType DNSSD_API TXTRecordSetValue - ( - TXTRecordRef *txtRecord, - const char *key, - uint8_t valueSize, /* may be zero */ - const void *value /* may be NULL */ - ) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_txt_set_value) - return (*dnssd_txt_set_value)(txtRecord, key, valueSize, value); - else - return (-1); -} - - -// TXTRecordGetCount -uint16_t DNSSD_API -TXTRecordGetCount( - uint16_t txtLen, - const void *txtRecord) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_txt_get_count) - return (*dnssd_txt_get_count)(txtLen, txtRecord); - else - return (0); -} - - -// TXTRecordGetItemAtIndex -DNSServiceErrorType DNSSD_API -TXTRecordGetItemAtIndex( - uint16_t txtLen, - const void *txtRecord, - uint16_t itemIndex, - uint16_t keyBufLen, - char *key, - uint8_t *valueLen, - const void **value) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_txt_get_item_at_index) - return (*dnssd_txt_get_item_at_index)(txtLen, txtRecord, itemIndex, keyBufLen, key, valueLen, value); - else - return (-1); -} - - -// TXTRecordGetValuePtr -const void * DNSSD_API -TXTRecordGetValuePtr( - uint16_t txtLen, - const void *txtRecord, - const char *key, - uint8_t *valueLen) -{ - if (!dnssd_initialized) - dnssd_init(); - - if (dnssd_txt_get_value_ptr) - return (*dnssd_txt_get_value_ptr)(txtLen, txtRecord, key, valueLen); - else - return (NULL); -} diff --git a/vcnet/dns_sd.h b/vcnet/dns_sd.h deleted file mode 100644 index afd6ce7c47..0000000000 --- a/vcnet/dns_sd.h +++ /dev/null @@ -1,2435 +0,0 @@ -/* -*- Mode: C; tab-width: 4 -*- - * - * Copyright © 2020-2024 by OpenPrinting. - * Copyright (c) 2003-2004, Apple Computer, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -/*! @header DNS Service Discovery - * - * @discussion This section describes the functions, callbacks, and data structures - * that make up the DNS Service Discovery API. - * - * The DNS Service Discovery API is part of Bonjour, Apple's implementation - * of zero-configuration networking (ZEROCONF). - * - * Bonjour allows you to register a network service, such as a - * printer or file server, so that it can be found by name or browsed - * for by service type and domain. Using Bonjour, applications can - * discover what services are available on the network, along with - * all the information -- such as name, IP address, and port -- - * necessary to access a particular service. - * - * In effect, Bonjour combines the functions of a local DNS server and - * AppleTalk. Bonjour allows applications to provide user-friendly printer - * and server browsing, among other things, over standard IP networks. - * This behavior is a result of combining protocols such as multicast and - * DNS to add new functionality to the network (such as multicast DNS). - * - * Bonjour gives applications easy access to services over local IP - * networks without requiring the service or the application to support - * an AppleTalk or a Netbeui stack, and without requiring a DNS server - * for the local network. - */ - - -/* _DNS_SD_H contains the mDNSResponder version number for this header file, formatted as follows: - * Major part of the build number * 10000 + - * minor part of the build number * 100 - * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as - * version 1080400. This allows C code to do simple greater-than and less-than comparisons: - * e.g. an application that requires the DNSServiceGetProperty() call (new in mDNSResponder-126) can check: - * - * #if _DNS_SD_H+0 >= 1260000 - * ... some C code that calls DNSServiceGetProperty() ... - * #endif - * - * The version defined in this header file symbol allows for compile-time - * checking, so that C code building with earlier versions of the header file - * can avoid compile errors trying to use functions that aren't even defined - * in those earlier versions. Similar checks may also be performed at run-time: - * => weak linking -- to avoid link failures if run with an earlier - * version of the library that's missing some desired symbol, or - * => DNSServiceGetProperty(DaemonVersion) -- to verify whether the running daemon - * ("system service" on Windows) meets some required minimum functionality level. - */ - -#ifndef _DNS_SD_H -#define _DNS_SD_H 3331000 - -#ifdef __cplusplus - extern "C" { -#endif - -/* Set to 1 if libdispatch is supported - * Note: May also be set by project and/or Makefile - */ -#ifndef _DNS_SD_LIBDISPATCH -#define _DNS_SD_LIBDISPATCH 0 -#endif /* ndef _DNS_SD_LIBDISPATCH */ - -/* standard calling convention under Win32 is __stdcall */ -/* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */ -/* _WIN32 symbol is defined by the compiler even though it's NOT compiling code for Windows32 */ -#if defined(_WIN32) && !defined(EFI32) && !defined(EFI64) -#define DNSSD_API __stdcall -#else -#define DNSSD_API -#endif - -/* stdint.h does not exist on FreeBSD 4.x; its types are defined in sys/types.h instead */ -#if defined(__FreeBSD__) && (__FreeBSD__ < 5) -#include - -/* Likewise, on Sun, standard integer types are in sys/types.h */ -#elif defined(__sun__) -#include - -/* EFI does not have stdint.h, or anything else equivalent */ -#elif defined(EFI32) || defined(EFI64) || defined(EFIX64) -#include "Tiano.h" -#if !defined(_STDINT_H_) -typedef UINT8 uint8_t; -typedef INT8 int8_t; -typedef UINT16 uint16_t; -typedef INT16 int16_t; -typedef UINT32 uint32_t; -typedef INT32 int32_t; -#endif -/* Windows has its own differences */ -#elif defined(_WIN32) -#include -#define _UNUSED -#ifndef _MSL_STDINT_H -typedef UINT8 uint8_t; -typedef INT8 int8_t; -typedef UINT16 uint16_t; -typedef INT16 int16_t; -typedef UINT32 uint32_t; -typedef INT32 int32_t; -#endif - -/* All other Posix platforms use stdint.h */ -#else -#include -#endif - -#if _DNS_SD_LIBDISPATCH -#include -#endif - -/* DNSServiceRef, DNSRecordRef - * - * Opaque internal data types. - * Note: client is responsible for serializing access to these structures if - * they are shared between concurrent threads. - */ - -typedef struct _DNSServiceRef_t *DNSServiceRef; -typedef struct _DNSRecordRef_t *DNSRecordRef; - -struct sockaddr; - -/*! @enum General flags - * Most DNS-SD API functions and callbacks include a DNSServiceFlags parameter. - * As a general rule, any given bit in the 32-bit flags field has a specific fixed meaning, - * regardless of the function or callback being used. For any given function or callback, - * typically only a subset of the possible flags are meaningful, and all others should be zero. - * The discussion section for each API call describes which flags are valid for that call - * and callback. In some cases, for a particular call, it may be that no flags are currently - * defined, in which case the DNSServiceFlags parameter exists purely to allow future expansion. - * In all cases, developers should expect that in future releases, it is possible that new flag - * values will be defined, and write code with this in mind. For example, code that tests - * if (flags == kDNSServiceFlagsAdd) ... - * will fail if, in a future release, another bit in the 32-bit flags field is also set. - * The reliable way to test whether a particular bit is set is not with an equality test, - * but with a bitwise mask: - * if (flags & kDNSServiceFlagsAdd) ... - */ -enum - { - kDNSServiceFlagsMoreComing = 0x1, - /* MoreComing indicates to a callback that at least one more result is - * queued and will be delivered following immediately after this one. - * When the MoreComing flag is set, applications should not immediately - * update their UI, because this can result in a great deal of ugly flickering - * on the screen, and can waste a great deal of CPU time repeatedly updating - * the screen with content that is then immediately erased, over and over. - * Applications should wait until until MoreComing is not set, and then - * update their UI when no more changes are imminent. - * When MoreComing is not set, that doesn't mean there will be no more - * answers EVER, just that there are no more answers immediately - * available right now at this instant. If more answers become available - * in the future they will be delivered as usual. - */ - - kDNSServiceFlagsAdd = 0x2, - kDNSServiceFlagsDefault = 0x4, - /* Flags for domain enumeration and browse/query reply callbacks. - * "Default" applies only to enumeration and is only valid in - * conjunction with "Add". An enumeration callback with the "Add" - * flag NOT set indicates a "Remove", i.e. the domain is no longer - * valid. - */ - - kDNSServiceFlagsNoAutoRename = 0x8, - /* Flag for specifying renaming behavior on name conflict when registering - * non-shared records. By default, name conflicts are automatically handled - * by renaming the service. NoAutoRename overrides this behavior - with this - * flag set, name conflicts will result in a callback. The NoAutorename flag - * is only valid if a name is explicitly specified when registering a service - * (i.e. the default name is not used.) - */ - - kDNSServiceFlagsShared = 0x10, - kDNSServiceFlagsUnique = 0x20, - /* Flag for registering individual records on a connected - * DNSServiceRef. Shared indicates that there may be multiple records - * with this name on the network (e.g. PTR records). Unique indicates that the - * record's name is to be unique on the network (e.g. SRV records). - */ - - kDNSServiceFlagsBrowseDomains = 0x40, - kDNSServiceFlagsRegistrationDomains = 0x80, - /* Flags for specifying domain enumeration type in DNSServiceEnumerateDomains. - * BrowseDomains enumerates domains recommended for browsing, RegistrationDomains - * enumerates domains recommended for registration. - */ - - kDNSServiceFlagsLongLivedQuery = 0x100, - /* Flag for creating a long-lived unicast query for the DNSServiceQueryRecord call. */ - - kDNSServiceFlagsAllowRemoteQuery = 0x200, - /* Flag for creating a record for which we will answer remote queries - * (queries from hosts more than one hop away; hosts not directly connected to the local link). - */ - - kDNSServiceFlagsForceMulticast = 0x400, - /* Flag for signifying that a query or registration should be performed exclusively via multicast - * DNS, even for a name in a domain (e.g. foo.apple.com.) that would normally imply unicast DNS. - */ - - kDNSServiceFlagsForce = 0x800, - /* Flag for signifying a "stronger" variant of an operation. - * Currently defined only for DNSServiceReconfirmRecord(), where it forces a record to - * be removed from the cache immediately, instead of querying for a few seconds before - * concluding that the record is no longer valid and then removing it. This flag should - * be used with caution because if a service browsing PTR record is indeed still valid - * on the network, forcing its removal will result in a user-interface flap -- the - * discovered service instance will disappear, and then re-appear moments later. - */ - - kDNSServiceFlagsReturnIntermediates = 0x1000, - /* Flag for returning intermediate results. - * For example, if a query results in an authoritative NXDomain (name does not exist) - * then that result is returned to the client. However the query is not implicitly - * cancelled -- it remains active and if the answer subsequently changes - * (e.g. because a VPN tunnel is subsequently established) then that positive - * result will still be returned to the client. - * Similarly, if a query results in a CNAME record, then in addition to following - * the CNAME referral, the intermediate CNAME result is also returned to the client. - * When this flag is not set, NXDomain errors are not returned, and CNAME records - * are followed silently without informing the client of the intermediate steps. - * (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME) - */ - - kDNSServiceFlagsNonBrowsable = 0x2000, - /* A service registered with the NonBrowsable flag set can be resolved using - * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse(). - * This is for cases where the name is actually a GUID; it is found by other means; - * there is no end-user benefit to browsing to find a long list of opaque GUIDs. - * Using the NonBrowsable flag creates SRV+TXT without the cost of also advertising - * an associated PTR record. - */ - - kDNSServiceFlagsShareConnection = 0x4000, - /* For efficiency, clients that perform many concurrent operations may want to use a - * single Unix Domain Socket connection with the background daemon, instead of having a - * separate connection for each independent operation. To use this mode, clients first - * call DNSServiceCreateConnection(&MainRef) to initialize the main DNSServiceRef. - * For each subsequent operation that is to share that same connection, the client copies - * the MainRef, and then passes the address of that copy, setting the ShareConnection flag - * to tell the library that this DNSServiceRef is not a typical uninitialized DNSServiceRef; - * it's a copy of an existing DNSServiceRef whose connection information should be reused. - * - * For example: - * - * DNSServiceErrorType error; - * DNSServiceRef MainRef; - * error = DNSServiceCreateConnection(&MainRef); - * if (error) ... - * DNSServiceRef BrowseRef = MainRef; // Important: COPY the primary DNSServiceRef first... - * error = DNSServiceBrowse(&BrowseRef, kDNSServiceFlagsShareConnection, ...); // then use the copy - * if (error) ... - * ... - * DNSServiceRefDeallocate(BrowseRef); // Terminate the browse operation - * DNSServiceRefDeallocate(MainRef); // Terminate the shared connection - * - * Notes: - * - * 1. Collective kDNSServiceFlagsMoreComing flag - * When callbacks are invoked using a shared DNSServiceRef, the - * kDNSServiceFlagsMoreComing flag applies collectively to *all* active - * operations sharing the same parent DNSServiceRef. If the MoreComing flag is - * set it means that there are more results queued on this parent DNSServiceRef, - * but not necessarily more results for this particular callback function. - * The implication of this for client programmers is that when a callback - * is invoked with the MoreComing flag set, the code should update its - * internal data structures with the new result, and set a variable indicating - * that its UI needs to be updated. Then, later when a callback is eventually - * invoked with the MoreComing flag not set, the code should update *all* - * stale UI elements related to that shared parent DNSServiceRef that need - * updating, not just the UI elements related to the particular callback - * that happened to be the last one to be invoked. - * - * 2. Canceling operations and kDNSServiceFlagsMoreComing - * Whenever you cancel any operation for which you had deferred UI updates - * waiting because of a kDNSServiceFlagsMoreComing flag, you should perform - * those deferred UI updates. This is because, after cancelling the operation, - * you can no longer wait for a callback *without* MoreComing set, to tell - * you do perform your deferred UI updates (the operation has been canceled, - * so there will be no more callbacks). An implication of the collective - * kDNSServiceFlagsMoreComing flag for shared connections is that this - * guideline applies more broadly -- any time you cancel an operation on - * a shared connection, you should perform all deferred UI updates for all - * operations sharing that connection. This is because the MoreComing flag - * might have been referring to events coming for the operation you canceled, - * which will now not be coming because the operation has been canceled. - * - * 3. Only share DNSServiceRef's created with DNSServiceCreateConnection - * Calling DNSServiceCreateConnection(&ref) creates a special shareable DNSServiceRef. - * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve() - * cannot be shared by copying them and using kDNSServiceFlagsShareConnection. - * - * 4. Don't Double-Deallocate - * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates - * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef - * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref)) - * automatically terminates the shared connection and all operations that were still using it. - * After doing this, DO NOT then attempt to deallocate any remaining subordinate DNSServiceRef's. - * The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt - * to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses - * to freed memory, leading to crashes or other equally undesirable results. - * - * 5. Thread Safety - * The dns_sd.h API does not presuppose any particular threading model, and consequently - * does no locking of its own (which would require linking some specific threading library). - * If client code calls API routines on the same DNSServiceRef concurrently - * from multiple threads, it is the client's responsibility to use a mutext - * lock or take similar appropriate precautions to serialize those calls. - */ - - kDNSServiceFlagsSuppressUnusable = 0x8000, - /* - * This flag is meaningful only in DNSServiceQueryRecord which suppresses unusable queries on the - * wire. If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name) - * but this host has no routable IPv6 address, then the call will not try to look up IPv6 addresses - * for "hostname", since any addresses it found would be unlikely to be of any use anyway. Similarly, - * if this host has no routable IPv4 address, the call will not try to look up IPv4 addresses for - * "hostname". - */ - - kDNSServiceFlagsTimeout = 0x10000, - /* - * When kDNServiceFlagsTimeout is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo, the query is - * stopped after a certain number of seconds have elapsed. The time at which the query will be stopped - * is determined by the system and cannot be configured by the user. The query will be stopped irrespective - * of whether a response was given earlier or not. When the query is stopped, the callback will be called - * with an error code of kDNSServiceErr_Timeout and a NULL sockaddr will be returned for DNSServiceGetAddrInfo - * and zero length rdata will be returned for DNSServiceQueryRecord. - */ - - kDNSServiceFlagsIncludeP2P = 0x20000, - /* - * Include P2P interfaces when kDNSServiceInterfaceIndexAny is specified. - * By default, specifying kDNSServiceInterfaceIndexAny does not include P2P interfaces. - */ - kDNSServiceFlagsWakeOnResolve = 0x40000 - /* - * This flag is meaningful only in DNSServiceResolve. When set, it tries to send a magic packet - * to wake up the client. - */ - }; - -/* Possible protocols for DNSServiceNATPortMappingCreate(). */ -enum - { - kDNSServiceProtocol_IPv4 = 0x01, - kDNSServiceProtocol_IPv6 = 0x02, - /* 0x04 and 0x08 reserved for future internetwork protocols */ - - kDNSServiceProtocol_UDP = 0x10, - kDNSServiceProtocol_TCP = 0x20 - /* 0x40 and 0x80 reserved for future transport protocols, e.g. SCTP [RFC 2960] - * or DCCP [RFC 4340]. If future NAT gateways are created that support port - * mappings for these protocols, new constants will be defined here. - */ - }; - -/* - * The values for DNS Classes and Types are listed in RFC 1035, and are available - * on every OS in its DNS header file. Unfortunately every OS does not have the - * same header file containing DNS Class and Type constants, and the names of - * the constants are not consistent. For example, BIND 8 uses "T_A", - * BIND 9 uses "ns_t_a", Windows uses "DNS_TYPE_A", etc. - * For this reason, these constants are also listed here, so that code using - * the DNS-SD programming APIs can use these constants, so that the same code - * can compile on all our supported platforms. - */ - -enum - { - kDNSServiceClass_IN = 1 /* Internet */ - }; - -enum - { - kDNSServiceType_A = 1, /* Host address. */ - kDNSServiceType_NS = 2, /* Authoritative server. */ - kDNSServiceType_MD = 3, /* Mail destination. */ - kDNSServiceType_MF = 4, /* Mail forwarder. */ - kDNSServiceType_CNAME = 5, /* Canonical name. */ - kDNSServiceType_SOA = 6, /* Start of authority zone. */ - kDNSServiceType_MB = 7, /* Mailbox domain name. */ - kDNSServiceType_MG = 8, /* Mail group member. */ - kDNSServiceType_MR = 9, /* Mail rename name. */ - kDNSServiceType_NULL = 10, /* Null resource record. */ - kDNSServiceType_WKS = 11, /* Well known service. */ - kDNSServiceType_PTR = 12, /* Domain name pointer. */ - kDNSServiceType_HINFO = 13, /* Host information. */ - kDNSServiceType_MINFO = 14, /* Mailbox information. */ - kDNSServiceType_MX = 15, /* Mail routing information. */ - kDNSServiceType_TXT = 16, /* One or more text strings (NOT "zero or more..."). */ - kDNSServiceType_RP = 17, /* Responsible person. */ - kDNSServiceType_AFSDB = 18, /* AFS cell database. */ - kDNSServiceType_X25 = 19, /* X_25 calling address. */ - kDNSServiceType_ISDN = 20, /* ISDN calling address. */ - kDNSServiceType_RT = 21, /* Router. */ - kDNSServiceType_NSAP = 22, /* NSAP address. */ - kDNSServiceType_NSAP_PTR = 23, /* Reverse NSAP lookup (deprecated). */ - kDNSServiceType_SIG = 24, /* Security signature. */ - kDNSServiceType_KEY = 25, /* Security key. */ - kDNSServiceType_PX = 26, /* X.400 mail mapping. */ - kDNSServiceType_GPOS = 27, /* Geographical position (withdrawn). */ - kDNSServiceType_AAAA = 28, /* IPv6 Address. */ - kDNSServiceType_LOC = 29, /* Location Information. */ - kDNSServiceType_NXT = 30, /* Next domain (security). */ - kDNSServiceType_EID = 31, /* Endpoint identifier. */ - kDNSServiceType_NIMLOC = 32, /* Nimrod Locator. */ - kDNSServiceType_SRV = 33, /* Server Selection. */ - kDNSServiceType_ATMA = 34, /* ATM Address */ - kDNSServiceType_NAPTR = 35, /* Naming Authority PoinTeR */ - kDNSServiceType_KX = 36, /* Key Exchange */ - kDNSServiceType_CERT = 37, /* Certification record */ - kDNSServiceType_A6 = 38, /* IPv6 Address (deprecated) */ - kDNSServiceType_DNAME = 39, /* Non-terminal DNAME (for IPv6) */ - kDNSServiceType_SINK = 40, /* Kitchen sink (experimental) */ - kDNSServiceType_OPT = 41, /* EDNS0 option (meta-RR) */ - kDNSServiceType_APL = 42, /* Address Prefix List */ - kDNSServiceType_DS = 43, /* Delegation Signer */ - kDNSServiceType_SSHFP = 44, /* SSH Key Fingerprint */ - kDNSServiceType_IPSECKEY = 45, /* IPSECKEY */ - kDNSServiceType_RRSIG = 46, /* RRSIG */ - kDNSServiceType_NSEC = 47, /* Denial of Existence */ - kDNSServiceType_DNSKEY = 48, /* DNSKEY */ - kDNSServiceType_DHCID = 49, /* DHCP Client Identifier */ - kDNSServiceType_NSEC3 = 50, /* Hashed Authenticated Denial of Existence */ - kDNSServiceType_NSEC3PARAM = 51, /* Hashed Authenticated Denial of Existence */ - - kDNSServiceType_HIP = 55, /* Host Identity Protocol */ - - kDNSServiceType_SPF = 99, /* Sender Policy Framework for E-Mail */ - kDNSServiceType_UINFO = 100, /* IANA-Reserved */ - kDNSServiceType_UID = 101, /* IANA-Reserved */ - kDNSServiceType_GID = 102, /* IANA-Reserved */ - kDNSServiceType_UNSPEC = 103, /* IANA-Reserved */ - - kDNSServiceType_TKEY = 249, /* Transaction key */ - kDNSServiceType_TSIG = 250, /* Transaction signature. */ - kDNSServiceType_IXFR = 251, /* Incremental zone transfer. */ - kDNSServiceType_AXFR = 252, /* Transfer zone of authority. */ - kDNSServiceType_MAILB = 253, /* Transfer mailbox records. */ - kDNSServiceType_MAILA = 254, /* Transfer mail agent records. */ - kDNSServiceType_ANY = 255 /* Wildcard match. */ - }; - -/* possible error code values */ -enum - { - kDNSServiceErr_NoError = 0, - kDNSServiceErr_Unknown = -65537, /* 0xFFFE FFFF */ - kDNSServiceErr_NoSuchName = -65538, - kDNSServiceErr_NoMemory = -65539, - kDNSServiceErr_BadParam = -65540, - kDNSServiceErr_BadReference = -65541, - kDNSServiceErr_BadState = -65542, - kDNSServiceErr_BadFlags = -65543, - kDNSServiceErr_Unsupported = -65544, - kDNSServiceErr_NotInitialized = -65545, - kDNSServiceErr_AlreadyRegistered = -65547, - kDNSServiceErr_NameConflict = -65548, - kDNSServiceErr_Invalid = -65549, - kDNSServiceErr_Firewall = -65550, - kDNSServiceErr_Incompatible = -65551, /* client library incompatible with daemon */ - kDNSServiceErr_BadInterfaceIndex = -65552, - kDNSServiceErr_Refused = -65553, - kDNSServiceErr_NoSuchRecord = -65554, - kDNSServiceErr_NoAuth = -65555, - kDNSServiceErr_NoSuchKey = -65556, - kDNSServiceErr_NATTraversal = -65557, - kDNSServiceErr_DoubleNAT = -65558, - kDNSServiceErr_BadTime = -65559, /* Codes up to here existed in Tiger */ - kDNSServiceErr_BadSig = -65560, - kDNSServiceErr_BadKey = -65561, - kDNSServiceErr_Transient = -65562, - kDNSServiceErr_ServiceNotRunning = -65563, /* Background daemon not running */ - kDNSServiceErr_NATPortMappingUnsupported = -65564, /* NAT doesn't support NAT-PMP or UPnP */ - kDNSServiceErr_NATPortMappingDisabled = -65565, /* NAT supports NAT-PMP or UPnP but it's disabled by the administrator */ - kDNSServiceErr_NoRouter = -65566, /* No router currently configured (probably no network connectivity) */ - kDNSServiceErr_PollingMode = -65567, - kDNSServiceErr_Timeout = -65568 - - /* mDNS Error codes are in the range - * FFFE FF00 (-65792) to FFFE FFFF (-65537) */ - }; - -/* Maximum length, in bytes, of a service name represented as a */ -/* literal C-String, including the terminating NULL at the end. */ - -#define kDNSServiceMaxServiceName 64 - -/* Maximum length, in bytes, of a domain name represented as an *escaped* C-String */ -/* including the final trailing dot, and the C-String terminating NULL at the end. */ - -#define kDNSServiceMaxDomainName 1009 - -/* - * Notes on DNS Name Escaping - * -- or -- - * "Why is kDNSServiceMaxDomainName 1009, when the maximum legal domain name is 256 bytes?" - * - * All strings used in the DNS-SD APIs are UTF-8 strings. Apart from the exceptions noted below, - * the APIs expect the strings to be properly escaped, using the conventional DNS escaping rules: - * - * '\\' represents a single literal '\' in the name - * '\.' represents a single literal '.' in the name - * '\ddd', where ddd is a three-digit decimal value from 000 to 255, - * represents a single literal byte with that value. - * A bare unescaped '.' is a label separator, marking a boundary between domain and subdomain. - * - * The exceptions, that do not use escaping, are the routines where the full - * DNS name of a resource is broken, for convenience, into servicename/regtype/domain. - * In these routines, the "servicename" is NOT escaped. It does not need to be, since - * it is, by definition, just a single literal string. Any characters in that string - * represent exactly what they are. The "regtype" portion is, technically speaking, - * escaped, but since legal regtypes are only allowed to contain letters, digits, - * and hyphens, there is nothing to escape, so the issue is moot. The "domain" - * portion is also escaped, though most domains in use on the public Internet - * today, like regtypes, don't contain any characters that need to be escaped. - * As DNS-SD becomes more popular, rich-text domains for service discovery will - * become common, so software should be written to cope with domains with escaping. - * - * The servicename may be up to 63 bytes of UTF-8 text (not counting the C-String - * terminating NULL at the end). The regtype is of the form _service._tcp or - * _service._udp, where the "service" part is 1-15 characters, which may be - * letters, digits, or hyphens. The domain part of the three-part name may be - * any legal domain, providing that the resulting servicename+regtype+domain - * name does not exceed 256 bytes. - * - * For most software, these issues are transparent. When browsing, the discovered - * servicenames should simply be displayed as-is. When resolving, the discovered - * servicename/regtype/domain are simply passed unchanged to DNSServiceResolve(). - * When a DNSServiceResolve() succeeds, the returned fullname is already in - * the correct format to pass to standard system DNS APIs such as res_query(). - * For converting from servicename/regtype/domain to a single properly-escaped - * full DNS name, the helper function DNSServiceConstructFullName() is provided. - * - * The following (highly contrived) example illustrates the escaping process. - * Suppose you have an service called "Dr. Smith\Dr. Johnson", of type "_ftp._tcp" - * in subdomain "4th. Floor" of subdomain "Building 2" of domain "apple.com." - * The full (escaped) DNS name of this service's SRV record would be: - * Dr\.\032Smith\\Dr\.\032Johnson._ftp._tcp.4th\.\032Floor.Building\0322.apple.com. - */ - - -/* - * Constants for specifying an interface index - * - * Specific interface indexes are identified via a 32-bit unsigned integer returned - * by the if_nametoindex() family of calls. - * - * If the client passes 0 for interface index, that means "do the right thing", - * which (at present) means, "if the name is in an mDNS local multicast domain - * (e.g. 'local.', '254.169.in-addr.arpa.', '{8,9,A,B}.E.F.ip6.arpa.') then multicast - * on all applicable interfaces, otherwise send via unicast to the appropriate - * DNS server." Normally, most clients will use 0 for interface index to - * automatically get the default sensible behaviour. - * - * If the client passes a positive interface index, then for multicast names that - * indicates to do the operation only on that one interface. For unicast names the - * interface index is ignored unless kDNSServiceFlagsForceMulticast is also set. - * - * If the client passes kDNSServiceInterfaceIndexLocalOnly when registering - * a service, then that service will be found *only* by other local clients - * on the same machine that are browsing using kDNSServiceInterfaceIndexLocalOnly - * or kDNSServiceInterfaceIndexAny. - * If a client has a 'private' service, accessible only to other processes - * running on the same machine, this allows the client to advertise that service - * in a way such that it does not inadvertently appear in service lists on - * all the other machines on the network. - * - * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing - * then it will find *all* records registered on that same local machine. - * Clients explicitly wishing to discover *only* LocalOnly services can - * accomplish this by inspecting the interfaceIndex of each service reported - * to their DNSServiceBrowseReply() callback function, and discarding those - * where the interface index is not kDNSServiceInterfaceIndexLocalOnly. - * - * kDNSServiceInterfaceIndexP2P is meaningful only in Browse, QueryRecord, - * and Resolve operations. It should not be used in other DNSService APIs. - * - * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceBrowse or - * DNSServiceQueryRecord, it restricts the operation to P2P. - * - * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceResolve, it is - * mapped internally to kDNSServiceInterfaceIndexAny, because resolving - * a P2P service may create and/or enable an interface whose index is not - * known a priori. The resolve callback will indicate the index of the - * interface via which the service can be accessed. - * - * If applications pass kDNSServiceInterfaceIndexAny to DNSServiceBrowse - * or DNSServiceQueryRecord, they must set the kDNSServiceFlagsIncludeP2P flag - * to include P2P. In this case, if a service instance or the record being queried - * is found over P2P, the resulting ADD event will indicate kDNSServiceInterfaceIndexP2P - * as the interface index. - */ - -#define kDNSServiceInterfaceIndexAny 0 -#define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1) -#define kDNSServiceInterfaceIndexUnicast ((uint32_t)-2) -#define kDNSServiceInterfaceIndexP2P ((uint32_t)-3) - -typedef uint32_t DNSServiceFlags; -typedef uint32_t DNSServiceProtocol; -typedef int32_t DNSServiceErrorType; - - -/********************************************************************************************* - * - * Version checking - * - *********************************************************************************************/ - -/* DNSServiceGetProperty() Parameters: - * - * property: The requested property. - * Currently the only property defined is kDNSServiceProperty_DaemonVersion. - * - * result: Place to store result. - * For retrieving DaemonVersion, this should be the address of a uint32_t. - * - * size: Pointer to uint32_t containing size of the result location. - * For retrieving DaemonVersion, this should be sizeof(uint32_t). - * On return the uint32_t is updated to the size of the data returned. - * For DaemonVersion, the returned size is always sizeof(uint32_t), but - * future properties could be defined which return variable-sized results. - * - * return value: Returns kDNSServiceErr_NoError on success, or kDNSServiceErr_ServiceNotRunning - * if the daemon (or "system service" on Windows) is not running. - */ - -DNSServiceErrorType DNSSD_API DNSServiceGetProperty - ( - const char *property, /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */ - void *result, /* Pointer to place to store result */ - uint32_t *size /* size of result location */ - ); - -/* - * When requesting kDNSServiceProperty_DaemonVersion, the result pointer must point - * to a 32-bit unsigned integer, and the size parameter must be set to sizeof(uint32_t). - * - * On return, the 32-bit unsigned integer contains the version number, formatted as follows: - * Major part of the build number * 10000 + - * minor part of the build number * 100 - * - * For example, Mac OS X 10.4.9 has mDNSResponder-108.4, which would be represented as - * version 1080400. This allows applications to do simple greater-than and less-than comparisons: - * e.g. an application that requires at least mDNSResponder-108.4 can check: - * - * if (version >= 1080400) ... - * - * Example usage: - * - * uint32_t version; - * uint32_t size = sizeof(version); - * DNSServiceErrorType err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &version, &size); - * if (!err) printf("Bonjour version is %d.%d\n", version / 10000, version / 100 % 100); - */ - -#define kDNSServiceProperty_DaemonVersion "DaemonVersion" - - -/********************************************************************************************* - * - * Unix Domain Socket access, DNSServiceRef deallocation, and data processing functions - * - *********************************************************************************************/ - -/* DNSServiceRefSockFD() - * - * Access underlying Unix domain socket for an initialized DNSServiceRef. - * The DNS Service Discovery implementation uses this socket to communicate between the client and - * the mDNSResponder daemon. The application MUST NOT directly read from or write to this socket. - * Access to the socket is provided so that it can be used as a kqueue event source, a CFRunLoop - * event source, in a select() loop, etc. When the underlying event management subsystem (kqueue/ - * select/CFRunLoop etc.) indicates to the client that data is available for reading on the - * socket, the client should call DNSServiceProcessResult(), which will extract the daemon's - * reply from the socket, and pass it to the appropriate application callback. By using a run - * loop or select(), results from the daemon can be processed asynchronously. Alternatively, - * a client can choose to fork a thread and have it loop calling "DNSServiceProcessResult(ref);" - * If DNSServiceProcessResult() is called when no data is available for reading on the socket, it - * will block until data does become available, and then process the data and return to the caller. - * When data arrives on the socket, the client is responsible for calling DNSServiceProcessResult(ref) - * in a timely fashion -- if the client allows a large backlog of data to build up the daemon - * may terminate the connection. - * - * sdRef: A DNSServiceRef initialized by any of the DNSService calls. - * - * return value: The DNSServiceRef's underlying socket descriptor, or -1 on - * error. - */ - -int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef); - - -/* DNSServiceProcessResult() - * - * Read a reply from the daemon, calling the appropriate application callback. This call will - * block until the daemon's response is received. Use DNSServiceRefSockFD() in - * conjunction with a run loop or select() to determine the presence of a response from the - * server before calling this function to process the reply without blocking. Call this function - * at any point if it is acceptable to block until the daemon's response arrives. Note that the - * client is responsible for ensuring that DNSServiceProcessResult() is called whenever there is - * a reply from the daemon - the daemon may terminate its connection with a client that does not - * process the daemon's responses. - * - * sdRef: A DNSServiceRef initialized by any of the DNSService calls - * that take a callback parameter. - * - * return value: Returns kDNSServiceErr_NoError on success, otherwise returns - * an error code indicating the specific failure that occurred. - */ - -DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef); - - -/* DNSServiceRefDeallocate() - * - * Terminate a connection with the daemon and free memory associated with the DNSServiceRef. - * Any services or records registered with this DNSServiceRef will be deregistered. Any - * Browse, Resolve, or Query operations called with this reference will be terminated. - * - * Note: If the reference's underlying socket is used in a run loop or select() call, it should - * be removed BEFORE DNSServiceRefDeallocate() is called, as this function closes the reference's - * socket. - * - * Note: If the reference was initialized with DNSServiceCreateConnection(), any DNSRecordRefs - * created via this reference will be invalidated by this call - the resource records are - * deregistered, and their DNSRecordRefs may not be used in subsequent functions. Similarly, - * if the reference was initialized with DNSServiceRegister, and an extra resource record was - * added to the service via DNSServiceAddRecord(), the DNSRecordRef created by the Add() call - * is invalidated when this function is called - the DNSRecordRef may not be used in subsequent - * functions. - * - * Note: This call is to be used only with the DNSServiceRef defined by this API. It is - * not compatible with dns_service_discovery_ref objects defined in the legacy Mach-based - * DNSServiceDiscovery.h API. - * - * sdRef: A DNSServiceRef initialized by any of the DNSService calls. - * - */ - -void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef); - - -/********************************************************************************************* - * - * Domain Enumeration - * - *********************************************************************************************/ - -/* DNSServiceEnumerateDomains() - * - * Asynchronously enumerate domains available for browsing and registration. - * - * The enumeration MUST be cancelled via DNSServiceRefDeallocate() when no more domains - * are to be found. - * - * Note that the names returned are (like all of DNS-SD) UTF-8 strings, - * and are escaped using standard DNS escaping rules. - * (See "Notes on DNS Name Escaping" earlier in this file for more details.) - * A graphical browser displaying a hierarchical tree-structured view should cut - * the names at the bare dots to yield individual labels, then de-escape each - * label according to the escaping rules, and then display the resulting UTF-8 text. - * - * DNSServiceDomainEnumReply Callback Parameters: - * - * sdRef: The DNSServiceRef initialized by DNSServiceEnumerateDomains(). - * - * flags: Possible values are: - * kDNSServiceFlagsMoreComing - * kDNSServiceFlagsAdd - * kDNSServiceFlagsDefault - * - * interfaceIndex: Specifies the interface on which the domain exists. (The index for a given - * interface is determined via the if_nametoindex() family of calls.) - * - * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise indicates - * the failure that occurred (other parameters are undefined if errorCode is nonzero). - * - * replyDomain: The name of the domain. - * - * context: The context pointer passed to DNSServiceEnumerateDomains. - * - */ - -typedef void (DNSSD_API *DNSServiceDomainEnumReply) - ( - DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *replyDomain, - void *context - ); - - -/* DNSServiceEnumerateDomains() Parameters: - * - * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds - * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, - * and the enumeration operation will run indefinitely until the client - * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). - * - * flags: Possible values are: - * kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing. - * kDNSServiceFlagsRegistrationDomains to enumerate domains recommended - * for registration. - * - * interfaceIndex: If non-zero, specifies the interface on which to look for domains. - * (the index for a given interface is determined via the if_nametoindex() - * family of calls.) Most applications will pass 0 to enumerate domains on - * all interfaces. See "Constants for specifying an interface index" for more details. - * - * callBack: The function to be called when a domain is found or the call asynchronously - * fails. - * - * context: An application context pointer which is passed to the callback function - * (may be NULL). - * - * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous - * errors are delivered to the callback), otherwise returns an error code indicating - * the error that occurred (the callback is not invoked and the DNSServiceRef - * is not initialized). - */ - -DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceDomainEnumReply callBack, - void *context /* may be NULL */ - ); - - -/********************************************************************************************* - * - * Service Registration - * - *********************************************************************************************/ - -/* Register a service that is discovered via Browse() and Resolve() calls. - * - * DNSServiceRegisterReply() Callback Parameters: - * - * sdRef: The DNSServiceRef initialized by DNSServiceRegister(). - * - * flags: When a name is successfully registered, the callback will be - * invoked with the kDNSServiceFlagsAdd flag set. When Wide-Area - * DNS-SD is in use, it is possible for a single service to get - * more than one success callback (e.g. one in the "local" multicast - * DNS domain, and another in a wide-area unicast DNS domain). - * If a successfully-registered name later suffers a name conflict - * or similar problem and has to be deregistered, the callback will - * be invoked with the kDNSServiceFlagsAdd flag not set. The callback - * is *not* invoked in the case where the caller explicitly terminates - * the service registration by calling DNSServiceRefDeallocate(ref); - * - * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will - * indicate the failure that occurred (including name conflicts, - * if the kDNSServiceFlagsNoAutoRename flag was used when registering.) - * Other parameters are undefined if errorCode is nonzero. - * - * name: The service name registered (if the application did not specify a name in - * DNSServiceRegister(), this indicates what name was automatically chosen). - * - * regtype: The type of service registered, as it was passed to the callout. - * - * domain: The domain on which the service was registered (if the application did not - * specify a domain in DNSServiceRegister(), this indicates the default domain - * on which the service was registered). - * - * context: The context pointer that was passed to the callout. - * - */ - -typedef void (DNSSD_API *DNSServiceRegisterReply) - ( - DNSServiceRef sdRef, - DNSServiceFlags flags, - DNSServiceErrorType errorCode, - const char *name, - const char *regtype, - const char *domain, - void *context - ); - - -/* DNSServiceRegister() Parameters: - * - * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds - * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, - * and the registration will remain active indefinitely until the client - * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). - * - * interfaceIndex: If non-zero, specifies the interface on which to register the service - * (the index for a given interface is determined via the if_nametoindex() - * family of calls.) Most applications will pass 0 to register on all - * available interfaces. See "Constants for specifying an interface index" for more details. - * - * flags: Indicates the renaming behavior on name conflict (most applications - * will pass 0). See flag definitions above for details. - * - * name: If non-NULL, specifies the service name to be registered. - * Most applications will not specify a name, in which case the computer - * name is used (this name is communicated to the client via the callback). - * If a name is specified, it must be 1-63 bytes of UTF-8 text. - * If the name is longer than 63 bytes it will be automatically truncated - * to a legal length, unless the NoAutoRename flag is set, - * in which case kDNSServiceErr_BadParam will be returned. - * - * regtype: The service type followed by the protocol, separated by a dot - * (e.g. "_ftp._tcp"). The service type must be an underscore, followed - * by 1-15 characters, which may be letters, digits, or hyphens. - * The transport protocol must be "_tcp" or "_udp". New service types - * should be registered at . - * - * Additional subtypes of the primary service type (where a service - * type has defined subtypes) follow the primary service type in a - * comma-separated list, with no additional spaces, e.g. - * "_primarytype._tcp,_subtype1,_subtype2,_subtype3" - * Subtypes provide a mechanism for filtered browsing: A client browsing - * for "_primarytype._tcp" will discover all instances of this type; - * a client browsing for "_primarytype._tcp,_subtype2" will discover only - * those instances that were registered with "_subtype2" in their list of - * registered subtypes. - * - * The subtype mechanism can be illustrated with some examples using the - * dns-sd command-line tool: - * - * % dns-sd -R Simple _test._tcp "" 1001 & - * % dns-sd -R Better _test._tcp,HasFeatureA "" 1002 & - * % dns-sd -R Best _test._tcp,HasFeatureA,HasFeatureB "" 1003 & - * - * Now: - * % dns-sd -B _test._tcp # will find all three services - * % dns-sd -B _test._tcp,HasFeatureA # finds "Better" and "Best" - * % dns-sd -B _test._tcp,HasFeatureB # finds only "Best" - * - * Subtype labels may be up to 63 bytes long, and may contain any eight- - * bit byte values, including zero bytes. However, due to the nature of - * using a C-string-based API, conventional DNS escaping must be used for - * dots ('.'), commas (','), backslashes ('\') and zero bytes, as shown below: - * - * % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123 - * - * domain: If non-NULL, specifies the domain on which to advertise the service. - * Most applications will not specify a domain, instead automatically - * registering in the default domain(s). - * - * host: If non-NULL, specifies the SRV target host name. Most applications - * will not specify a host, instead automatically using the machine's - * default host name(s). Note that specifying a non-NULL host does NOT - * create an address record for that host - the application is responsible - * for ensuring that the appropriate address record exists, or creating it - * via DNSServiceRegisterRecord(). - * - * port: The port, in network byte order, on which the service accepts connections. - * Pass 0 for a "placeholder" service (i.e. a service that will not be discovered - * by browsing, but will cause a name conflict if another client tries to - * register that same name). Most clients will not use placeholder services. - * - * txtLen: The length of the txtRecord, in bytes. Must be zero if the txtRecord is NULL. - * - * txtRecord: The TXT record rdata. A non-NULL txtRecord MUST be a properly formatted DNS - * TXT record, i.e. ... - * Passing NULL for the txtRecord is allowed as a synonym for txtLen=1, txtRecord="", - * i.e. it creates a TXT record of length one containing a single empty string. - * RFC 1035 doesn't allow a TXT record to contain *zero* strings, so a single empty - * string is the smallest legal DNS TXT record. - * As with the other parameters, the DNSServiceRegister call copies the txtRecord - * data; e.g. if you allocated the storage for the txtRecord parameter with malloc() - * then you can safely free that memory right after the DNSServiceRegister call returns. - * - * callBack: The function to be called when the registration completes or asynchronously - * fails. The client MAY pass NULL for the callback - The client will NOT be notified - * of the default values picked on its behalf, and the client will NOT be notified of any - * asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration - * of the service. The client may NOT pass the NoAutoRename flag if the callback is NULL. - * The client may still deregister the service at any time via DNSServiceRefDeallocate(). - * - * context: An application context pointer which is passed to the callback function - * (may be NULL). - * - * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous - * errors are delivered to the callback), otherwise returns an error code indicating - * the error that occurred (the callback is never invoked and the DNSServiceRef - * is not initialized). - */ - -DNSServiceErrorType DNSSD_API DNSServiceRegister - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *name, /* may be NULL */ - const char *regtype, - const char *domain, /* may be NULL */ - const char *host, /* may be NULL */ - uint16_t port, /* In network byte order */ - uint16_t txtLen, - const void *txtRecord, /* may be NULL */ - DNSServiceRegisterReply callBack, /* may be NULL */ - void *context /* may be NULL */ - ); - - -/* DNSServiceAddRecord() - * - * Add a record to a registered service. The name of the record will be the same as the - * registered service's name. - * The record can later be updated or deregistered by passing the RecordRef initialized - * by this function to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). - * - * Note that the DNSServiceAddRecord/UpdateRecord/RemoveRecord are *NOT* thread-safe - * with respect to a single DNSServiceRef. If you plan to have multiple threads - * in your program simultaneously add, update, or remove records from the same - * DNSServiceRef, then it's the caller's responsibility to use a mutext lock - * or take similar appropriate precautions to serialize those calls. - * - * Parameters; - * - * sdRef: A DNSServiceRef initialized by DNSServiceRegister(). - * - * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesful completion of this - * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). - * If the above DNSServiceRef is passed to DNSServiceRefDeallocate(), RecordRef is also - * invalidated and may not be used further. - * - * flags: Currently ignored, reserved for future use. - * - * rrtype: The type of the record (e.g. kDNSServiceType_TXT, kDNSServiceType_SRV, etc) - * - * rdlen: The length, in bytes, of the rdata. - * - * rdata: The raw rdata to be contained in the added resource record. - * - * ttl: The time to live of the resource record, in seconds. - * Most clients should pass 0 to indicate that the system should - * select a sensible default value. - * - * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an - * error code indicating the error that occurred (the RecordRef is not initialized). - */ - -DNSServiceErrorType DNSSD_API DNSServiceAddRecord - ( - DNSServiceRef sdRef, - DNSRecordRef *RecordRef, - DNSServiceFlags flags, - uint16_t rrtype, - uint16_t rdlen, - const void *rdata, - uint32_t ttl - ); - - -/* DNSServiceUpdateRecord - * - * Update a registered resource record. The record must either be: - * - The primary txt record of a service registered via DNSServiceRegister() - * - A record added to a registered service via DNSServiceAddRecord() - * - An individual record registered by DNSServiceRegisterRecord() - * - * Parameters: - * - * sdRef: A DNSServiceRef that was initialized by DNSServiceRegister() - * or DNSServiceCreateConnection(). - * - * RecordRef: A DNSRecordRef initialized by DNSServiceAddRecord, or NULL to update the - * service's primary txt record. - * - * flags: Currently ignored, reserved for future use. - * - * rdlen: The length, in bytes, of the new rdata. - * - * rdata: The new rdata to be contained in the updated resource record. - * - * ttl: The time to live of the updated resource record, in seconds. - * Most clients should pass 0 to indicate that the system should - * select a sensible default value. - * - * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an - * error code indicating the error that occurred. - */ - -DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord - ( - DNSServiceRef sdRef, - DNSRecordRef RecordRef, /* may be NULL */ - DNSServiceFlags flags, - uint16_t rdlen, - const void *rdata, - uint32_t ttl - ); - - -/* DNSServiceRemoveRecord - * - * Remove a record previously added to a service record set via DNSServiceAddRecord(), or deregister - * an record registered individually via DNSServiceRegisterRecord(). - * - * Parameters: - * - * sdRef: A DNSServiceRef initialized by DNSServiceRegister() (if the - * record being removed was registered via DNSServiceAddRecord()) or by - * DNSServiceCreateConnection() (if the record being removed was registered via - * DNSServiceRegisterRecord()). - * - * recordRef: A DNSRecordRef initialized by a successful call to DNSServiceAddRecord() - * or DNSServiceRegisterRecord(). - * - * flags: Currently ignored, reserved for future use. - * - * return value: Returns kDNSServiceErr_NoError on success, otherwise returns an - * error code indicating the error that occurred. - */ - -DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord - ( - DNSServiceRef sdRef, - DNSRecordRef RecordRef, - DNSServiceFlags flags - ); - - -/********************************************************************************************* - * - * Service Discovery - * - *********************************************************************************************/ - -/* Browse for instances of a service. - * - * DNSServiceBrowseReply() Parameters: - * - * sdRef: The DNSServiceRef initialized by DNSServiceBrowse(). - * - * flags: Possible values are kDNSServiceFlagsMoreComing and kDNSServiceFlagsAdd. - * See flag definitions for details. - * - * interfaceIndex: The interface on which the service is advertised. This index should - * be passed to DNSServiceResolve() when resolving the service. - * - * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will - * indicate the failure that occurred. Other parameters are undefined if - * the errorCode is nonzero. - * - * serviceName: The discovered service name. This name should be displayed to the user, - * and stored for subsequent use in the DNSServiceResolve() call. - * - * regtype: The service type, which is usually (but not always) the same as was passed - * to DNSServiceBrowse(). One case where the discovered service type may - * not be the same as the requested service type is when using subtypes: - * The client may want to browse for only those ftp servers that allow - * anonymous connections. The client will pass the string "_ftp._tcp,_anon" - * to DNSServiceBrowse(), but the type of the service that's discovered - * is simply "_ftp._tcp". The regtype for each discovered service instance - * should be stored along with the name, so that it can be passed to - * DNSServiceResolve() when the service is later resolved. - * - * domain: The domain of the discovered service instance. This may or may not be the - * same as the domain that was passed to DNSServiceBrowse(). The domain for each - * discovered service instance should be stored along with the name, so that - * it can be passed to DNSServiceResolve() when the service is later resolved. - * - * context: The context pointer that was passed to the callout. - * - */ - -typedef void (DNSSD_API *DNSServiceBrowseReply) - ( - DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *serviceName, - const char *regtype, - const char *replyDomain, - void *context - ); - - -/* DNSServiceBrowse() Parameters: - * - * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds - * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, - * and the browse operation will run indefinitely until the client - * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). - * - * flags: Currently ignored, reserved for future use. - * - * interfaceIndex: If non-zero, specifies the interface on which to browse for services - * (the index for a given interface is determined via the if_nametoindex() - * family of calls.) Most applications will pass 0 to browse on all available - * interfaces. See "Constants for specifying an interface index" for more details. - * - * regtype: The service type being browsed for followed by the protocol, separated by a - * dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp". - * A client may optionally specify a single subtype to perform filtered browsing: - * e.g. browsing for "_primarytype._tcp,_subtype" will discover only those - * instances of "_primarytype._tcp" that were registered specifying "_subtype" - * in their list of registered subtypes. - * - * domain: If non-NULL, specifies the domain on which to browse for services. - * Most applications will not specify a domain, instead browsing on the - * default domain(s). - * - * callBack: The function to be called when an instance of the service being browsed for - * is found, or if the call asynchronously fails. - * - * context: An application context pointer which is passed to the callback function - * (may be NULL). - * - * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous - * errors are delivered to the callback), otherwise returns an error code indicating - * the error that occurred (the callback is not invoked and the DNSServiceRef - * is not initialized). - */ - -DNSServiceErrorType DNSSD_API DNSServiceBrowse - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *regtype, - const char *domain, /* may be NULL */ - DNSServiceBrowseReply callBack, - void *context /* may be NULL */ - ); - - -/* DNSServiceResolve() - * - * Resolve a service name discovered via DNSServiceBrowse() to a target host name, port number, and - * txt record. - * - * Note: Applications should NOT use DNSServiceResolve() solely for txt record monitoring - use - * DNSServiceQueryRecord() instead, as it is more efficient for this task. - * - * Note: When the desired results have been returned, the client MUST terminate the resolve by calling - * DNSServiceRefDeallocate(). - * - * Note: DNSServiceResolve() behaves correctly for typical services that have a single SRV record - * and a single TXT record. To resolve non-standard services with multiple SRV or TXT records, - * DNSServiceQueryRecord() should be used. - * - * DNSServiceResolveReply Callback Parameters: - * - * sdRef: The DNSServiceRef initialized by DNSServiceResolve(). - * - * flags: Possible values: kDNSServiceFlagsMoreComing - * - * interfaceIndex: The interface on which the service was resolved. - * - * errorCode: Will be kDNSServiceErr_NoError (0) on success, otherwise will - * indicate the failure that occurred. Other parameters are undefined if - * the errorCode is nonzero. - * - * fullname: The full service domain name, in the form ... - * (This name is escaped following standard DNS rules, making it suitable for - * passing to standard system DNS APIs such as res_query(), or to the - * special-purpose functions included in this API that take fullname parameters. - * See "Notes on DNS Name Escaping" earlier in this file for more details.) - * - * hosttarget: The target hostname of the machine providing the service. This name can - * be passed to functions like gethostbyname() to identify the host's IP address. - * - * port: The port, in network byte order, on which connections are accepted for this service. - * - * txtLen: The length of the txt record, in bytes. - * - * txtRecord: The service's primary txt record, in standard txt record format. - * - * context: The context pointer that was passed to the callout. - * - * NOTE: In earlier versions of this header file, the txtRecord parameter was declared "const char *" - * This is incorrect, since it contains length bytes which are values in the range 0 to 255, not -128 to +127. - * Depending on your compiler settings, this change may cause signed/unsigned mismatch warnings. - * These should be fixed by updating your own callback function definition to match the corrected - * function signature using "const unsigned char *txtRecord". Making this change may also fix inadvertent - * bugs in your callback function, where it could have incorrectly interpreted a length byte with value 250 - * as being -6 instead, with various bad consequences ranging from incorrect operation to software crashes. - * If you need to maintain portable code that will compile cleanly with both the old and new versions of - * this header file, you should update your callback function definition to use the correct unsigned value, - * and then in the place where you pass your callback function to DNSServiceResolve(), use a cast to eliminate - * the compiler warning, e.g.: - * DNSServiceResolve(sd, flags, index, name, regtype, domain, (DNSServiceResolveReply)MyCallback, context); - * This will ensure that your code compiles cleanly without warnings (and more importantly, works correctly) - * with both the old header and with the new corrected version. - * - */ - -typedef void (DNSSD_API *DNSServiceResolveReply) - ( - DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *fullname, - const char *hosttarget, - uint16_t port, /* In network byte order */ - uint16_t txtLen, - const unsigned char *txtRecord, - void *context - ); - - -/* DNSServiceResolve() Parameters - * - * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds - * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, - * and the resolve operation will run indefinitely until the client - * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). - * - * flags: Specifying kDNSServiceFlagsForceMulticast will cause query to be - * performed with a link-local mDNS query, even if the name is an - * apparently non-local name (i.e. a name not ending in ".local.") - * - * interfaceIndex: The interface on which to resolve the service. If this resolve call is - * as a result of a currently active DNSServiceBrowse() operation, then the - * interfaceIndex should be the index reported in the DNSServiceBrowseReply - * callback. If this resolve call is using information previously saved - * (e.g. in a preference file) for later use, then use interfaceIndex 0, because - * the desired service may now be reachable via a different physical interface. - * See "Constants for specifying an interface index" for more details. - * - * name: The name of the service instance to be resolved, as reported to the - * DNSServiceBrowseReply() callback. - * - * regtype: The type of the service instance to be resolved, as reported to the - * DNSServiceBrowseReply() callback. - * - * domain: The domain of the service instance to be resolved, as reported to the - * DNSServiceBrowseReply() callback. - * - * callBack: The function to be called when a result is found, or if the call - * asynchronously fails. - * - * context: An application context pointer which is passed to the callback function - * (may be NULL). - * - * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous - * errors are delivered to the callback), otherwise returns an error code indicating - * the error that occurred (the callback is never invoked and the DNSServiceRef - * is not initialized). - */ - -DNSServiceErrorType DNSSD_API DNSServiceResolve - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *name, - const char *regtype, - const char *domain, - DNSServiceResolveReply callBack, - void *context /* may be NULL */ - ); - - -/********************************************************************************************* - * - * Querying Individual Specific Records - * - *********************************************************************************************/ - -/* DNSServiceQueryRecord - * - * Query for an arbitrary DNS record. - * - * DNSServiceQueryRecordReply() Callback Parameters: - * - * sdRef: The DNSServiceRef initialized by DNSServiceQueryRecord(). - * - * flags: Possible values are kDNSServiceFlagsMoreComing and - * kDNSServiceFlagsAdd. The Add flag is NOT set for PTR records - * with a ttl of 0, i.e. "Remove" events. - * - * interfaceIndex: The interface on which the query was resolved (the index for a given - * interface is determined via the if_nametoindex() family of calls). - * See "Constants for specifying an interface index" for more details. - * - * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will - * indicate the failure that occurred. Other parameters are undefined if - * errorCode is nonzero. - * - * fullname: The resource record's full domain name. - * - * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) - * - * rrclass: The class of the resource record (usually kDNSServiceClass_IN). - * - * rdlen: The length, in bytes, of the resource record rdata. - * - * rdata: The raw rdata of the resource record. - * - * ttl: If the client wishes to cache the result for performance reasons, - * the TTL indicates how long the client may legitimately hold onto - * this result, in seconds. After the TTL expires, the client should - * consider the result no longer valid, and if it requires this data - * again, it should be re-fetched with a new query. Of course, this - * only applies to clients that cancel the asynchronous operation when - * they get a result. Clients that leave the asynchronous operation - * running can safely assume that the data remains valid until they - * get another callback telling them otherwise. - * - * context: The context pointer that was passed to the callout. - * - */ - -typedef void (DNSSD_API *DNSServiceQueryRecordReply) - ( - DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *fullname, - uint16_t rrtype, - uint16_t rrclass, - uint16_t rdlen, - const void *rdata, - uint32_t ttl, - void *context - ); - - -/* DNSServiceQueryRecord() Parameters: - * - * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds - * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError, - * and the query operation will run indefinitely until the client - * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate(). - * - * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery. - * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast - * query in a non-local domain. Without setting this flag, unicast queries - * will be one-shot - that is, only answers available at the time of the call - * will be returned. By setting this flag, answers (including Add and Remove - * events) that become available after the initial call is made will generate - * callbacks. This flag has no effect on link-local multicast queries. - * - * interfaceIndex: If non-zero, specifies the interface on which to issue the query - * (the index for a given interface is determined via the if_nametoindex() - * family of calls.) Passing 0 causes the name to be queried for on all - * interfaces. See "Constants for specifying an interface index" for more details. - * - * fullname: The full domain name of the resource record to be queried for. - * - * rrtype: The numerical type of the resource record to be queried for - * (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) - * - * rrclass: The class of the resource record (usually kDNSServiceClass_IN). - * - * callBack: The function to be called when a result is found, or if the call - * asynchronously fails. - * - * context: An application context pointer which is passed to the callback function - * (may be NULL). - * - * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous - * errors are delivered to the callback), otherwise returns an error code indicating - * the error that occurred (the callback is never invoked and the DNSServiceRef - * is not initialized). - */ - -DNSServiceErrorType DNSSD_API DNSServiceQueryRecord - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *fullname, - uint16_t rrtype, - uint16_t rrclass, - DNSServiceQueryRecordReply callBack, - void *context /* may be NULL */ - ); - - -/********************************************************************************************* - * - * Unified lookup of both IPv4 and IPv6 addresses for a fully qualified hostname - * - *********************************************************************************************/ - -/* DNSServiceGetAddrInfo - * - * Queries for the IP address of a hostname by using either Multicast or Unicast DNS. - * - * DNSServiceGetAddrInfoReply() parameters: - * - * sdRef: The DNSServiceRef initialized by DNSServiceGetAddrInfo(). - * - * flags: Possible values are kDNSServiceFlagsMoreComing and - * kDNSServiceFlagsAdd. - * - * interfaceIndex: The interface to which the answers pertain. - * - * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will - * indicate the failure that occurred. Other parameters are - * undefined if errorCode is nonzero. - * - * hostname: The fully qualified domain name of the host to be queried for. - * - * address: IPv4 or IPv6 address. - * - * ttl: If the client wishes to cache the result for performance reasons, - * the TTL indicates how long the client may legitimately hold onto - * this result, in seconds. After the TTL expires, the client should - * consider the result no longer valid, and if it requires this data - * again, it should be re-fetched with a new query. Of course, this - * only applies to clients that cancel the asynchronous operation when - * they get a result. Clients that leave the asynchronous operation - * running can safely assume that the data remains valid until they - * get another callback telling them otherwise. - * - * context: The context pointer that was passed to the callout. - * - */ - -typedef void (DNSSD_API *DNSServiceGetAddrInfoReply) - ( - DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - const char *hostname, - const struct sockaddr *address, - uint32_t ttl, - void *context - ); - - -/* DNSServiceGetAddrInfo() Parameters: - * - * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it - * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the query - * begins and will last indefinitely until the client terminates the query - * by passing this DNSServiceRef to DNSServiceRefDeallocate(). - * - * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery. - * Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast - * query in a non-local domain. Without setting this flag, unicast queries - * will be one-shot - that is, only answers available at the time of the call - * will be returned. By setting this flag, answers (including Add and Remove - * events) that become available after the initial call is made will generate - * callbacks. This flag has no effect on link-local multicast queries. - * - * interfaceIndex: The interface on which to issue the query. Passing 0 causes the query to be - * sent on all active interfaces via Multicast or the primary interface via Unicast. - * - * protocol: Pass in kDNSServiceProtocol_IPv4 to look up IPv4 addresses, or kDNSServiceProtocol_IPv6 - * to look up IPv6 addresses, or both to look up both kinds. If neither flag is - * set, the system will apply an intelligent heuristic, which is (currently) - * that it will attempt to look up both, except: - * - * * If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name) - * but this host has no routable IPv6 address, then the call will not try to - * look up IPv6 addresses for "hostname", since any addresses it found would be - * unlikely to be of any use anyway. Similarly, if this host has no routable - * IPv4 address, the call will not try to look up IPv4 addresses for "hostname". - * - * hostname: The fully qualified domain name of the host to be queried for. - * - * callBack: The function to be called when the query succeeds or fails asynchronously. - * - * context: An application context pointer which is passed to the callback function - * (may be NULL). - * - * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous - * errors are delivered to the callback), otherwise returns an error code indicating - * the error that occurred. - */ - -DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceProtocol protocol, - const char *hostname, - DNSServiceGetAddrInfoReply callBack, - void *context /* may be NULL */ - ); - - -/********************************************************************************************* - * - * Special Purpose Calls: - * DNSServiceCreateConnection(), DNSServiceRegisterRecord(), DNSServiceReconfirmRecord() - * (most applications will not use these) - * - *********************************************************************************************/ - -/* DNSServiceCreateConnection() - * - * Create a connection to the daemon allowing efficient registration of - * multiple individual records. - * - * Parameters: - * - * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating - * the reference (via DNSServiceRefDeallocate()) severs the - * connection and deregisters all records registered on this connection. - * - * return value: Returns kDNSServiceErr_NoError on success, otherwise returns - * an error code indicating the specific failure that occurred (in which - * case the DNSServiceRef is not initialized). - */ - -DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef); - - -/* DNSServiceRegisterRecord - * - * Register an individual resource record on a connected DNSServiceRef. - * - * Note that name conflicts occurring for records registered via this call must be handled - * by the client in the callback. - * - * DNSServiceRegisterRecordReply() parameters: - * - * sdRef: The connected DNSServiceRef initialized by - * DNSServiceCreateConnection(). - * - * RecordRef: The DNSRecordRef initialized by DNSServiceRegisterRecord(). If the above - * DNSServiceRef is passed to DNSServiceRefDeallocate(), this DNSRecordRef is - * invalidated, and may not be used further. - * - * flags: Currently unused, reserved for future use. - * - * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will - * indicate the failure that occurred (including name conflicts.) - * Other parameters are undefined if errorCode is nonzero. - * - * context: The context pointer that was passed to the callout. - * - */ - - typedef void (DNSSD_API *DNSServiceRegisterRecordReply) - ( - DNSServiceRef sdRef, - DNSRecordRef RecordRef, - DNSServiceFlags flags, - DNSServiceErrorType errorCode, - void *context - ); - - -/* DNSServiceRegisterRecord() Parameters: - * - * sdRef: A DNSServiceRef initialized by DNSServiceCreateConnection(). - * - * RecordRef: A pointer to an uninitialized DNSRecordRef. Upon succesful completion of this - * call, this ref may be passed to DNSServiceUpdateRecord() or DNSServiceRemoveRecord(). - * (To deregister ALL records registered on a single connected DNSServiceRef - * and deallocate each of their corresponding DNSServiceRecordRefs, call - * DNSServiceRefDeallocate()). - * - * flags: Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique - * (see flag type definitions for details). - * - * interfaceIndex: If non-zero, specifies the interface on which to register the record - * (the index for a given interface is determined via the if_nametoindex() - * family of calls.) Passing 0 causes the record to be registered on all interfaces. - * See "Constants for specifying an interface index" for more details. - * - * fullname: The full domain name of the resource record. - * - * rrtype: The numerical type of the resource record (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) - * - * rrclass: The class of the resource record (usually kDNSServiceClass_IN) - * - * rdlen: Length, in bytes, of the rdata. - * - * rdata: A pointer to the raw rdata, as it is to appear in the DNS record. - * - * ttl: The time to live of the resource record, in seconds. - * Most clients should pass 0 to indicate that the system should - * select a sensible default value. - * - * callBack: The function to be called when a result is found, or if the call - * asynchronously fails (e.g. because of a name conflict.) - * - * context: An application context pointer which is passed to the callback function - * (may be NULL). - * - * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous - * errors are delivered to the callback), otherwise returns an error code indicating - * the error that occurred (the callback is never invoked and the DNSRecordRef is - * not initialized). - */ - -DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord - ( - DNSServiceRef sdRef, - DNSRecordRef *RecordRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *fullname, - uint16_t rrtype, - uint16_t rrclass, - uint16_t rdlen, - const void *rdata, - uint32_t ttl, - DNSServiceRegisterRecordReply callBack, - void *context /* may be NULL */ - ); - - -/* DNSServiceReconfirmRecord - * - * Instruct the daemon to verify the validity of a resource record that appears - * to be out of date (e.g. because TCP connection to a service's target failed.) - * Causes the record to be flushed from the daemon's cache (as well as all other - * daemons' caches on the network) if the record is determined to be invalid. - * Use this routine conservatively. Reconfirming a record necessarily consumes - * network bandwidth, so this should not be done indiscriminately. - * - * Parameters: - * - * flags: Pass kDNSServiceFlagsForce to force immediate deletion of record, - * instead of after some number of reconfirmation queries have gone unanswered. - * - * interfaceIndex: Specifies the interface of the record in question. - * The caller must specify the interface. - * This API (by design) causes increased network traffic, so it requires - * the caller to be precise about which record should be reconfirmed. - * It is not possible to pass zero for the interface index to perform - * a "wildcard" reconfirmation, where *all* matching records are reconfirmed. - * - * fullname: The resource record's full domain name. - * - * rrtype: The resource record's type (e.g. kDNSServiceType_PTR, kDNSServiceType_SRV, etc) - * - * rrclass: The class of the resource record (usually kDNSServiceClass_IN). - * - * rdlen: The length, in bytes, of the resource record rdata. - * - * rdata: The raw rdata of the resource record. - * - */ - -DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord - ( - DNSServiceFlags flags, - uint32_t interfaceIndex, - const char *fullname, - uint16_t rrtype, - uint16_t rrclass, - uint16_t rdlen, - const void *rdata - ); - - -/********************************************************************************************* - * - * NAT Port Mapping - * - *********************************************************************************************/ - -/* DNSServiceNATPortMappingCreate - * - * Request a port mapping in the NAT gateway, which maps a port on the local machine - * to an external port on the NAT. The NAT should support either the NAT-PMP or the UPnP IGD - * protocol for this API to create a successful mapping. - * - * The port mapping will be renewed indefinitely until the client process exits, or - * explicitly terminates the port mapping request by calling DNSServiceRefDeallocate(). - * The client callback will be invoked, informing the client of the NAT gateway's - * external IP address and the external port that has been allocated for this client. - * The client should then record this external IP address and port using whatever - * directory service mechanism it is using to enable peers to connect to it. - * (Clients advertising services using Wide-Area DNS-SD DO NOT need to use this API - * -- when a client calls DNSServiceRegister() NAT mappings are automatically created - * and the external IP address and port for the service are recorded in the global DNS. - * Only clients using some directory mechanism other than Wide-Area DNS-SD need to use - * this API to explicitly map their own ports.) - * - * It's possible that the client callback could be called multiple times, for example - * if the NAT gateway's IP address changes, or if a configuration change results in a - * different external port being mapped for this client. Over the lifetime of any long-lived - * port mapping, the client should be prepared to handle these notifications of changes - * in the environment, and should update its recorded address and/or port as appropriate. - * - * NOTE: There are two unusual aspects of how the DNSServiceNATPortMappingCreate API works, - * which were intentionally designed to help simplify client code: - * - * 1. It's not an error to request a NAT mapping when the machine is not behind a NAT gateway. - * In other NAT mapping APIs, if you request a NAT mapping and the machine is not behind a NAT - * gateway, then the API returns an error code -- it can't get you a NAT mapping if there's no - * NAT gateway. The DNSServiceNATPortMappingCreate API takes a different view. Working out - * whether or not you need a NAT mapping can be tricky and non-obvious, particularly on - * a machine with multiple active network interfaces. Rather than make every client recreate - * this logic for deciding whether a NAT mapping is required, the PortMapping API does that - * work for you. If the client calls the PortMapping API when the machine already has a - * routable public IP address, then instead of complaining about it and giving an error, - * the PortMapping API just invokes your callback, giving the machine's public address - * and your own port number. This means you don't need to write code to work out whether - * your client needs to call the PortMapping API -- just call it anyway, and if it wasn't - * necessary, no harm is done: - * - * - If the machine already has a routable public IP address, then your callback - * will just be invoked giving your own address and port. - * - If a NAT mapping is required and obtained, then your callback will be invoked - * giving you the external address and port. - * - If a NAT mapping is required but not obtained from the local NAT gateway, - * or the machine has no network connectivity, then your callback will be - * invoked giving zero address and port. - * - * 2. In other NAT mapping APIs, if a laptop computer is put to sleep and woken up on a new - * network, it's the client's job to notice this, and work out whether a NAT mapping - * is required on the new network, and make a new NAT mapping request if necessary. - * The DNSServiceNATPortMappingCreate API does this for you, automatically. - * The client just needs to make one call to the PortMapping API, and its callback will - * be invoked any time the mapping state changes. This property complements point (1) above. - * If the client didn't make a NAT mapping request just because it determined that one was - * not required at that particular moment in time, the client would then have to monitor - * for network state changes to determine if a NAT port mapping later became necessary. - * By unconditionally making a NAT mapping request, even when a NAT mapping not to be - * necessary, the PortMapping API will then begin monitoring network state changes on behalf of - * the client, and if a NAT mapping later becomes necessary, it will automatically create a NAT - * mapping and inform the client with a new callback giving the new address and port information. - * - * DNSServiceNATPortMappingReply() parameters: - * - * sdRef: The DNSServiceRef initialized by DNSServiceNATPortMappingCreate(). - * - * flags: Currently unused, reserved for future use. - * - * interfaceIndex: The interface through which the NAT gateway is reached. - * - * errorCode: Will be kDNSServiceErr_NoError on success. - * Will be kDNSServiceErr_DoubleNAT when the NAT gateway is itself behind one or - * more layers of NAT, in which case the other parameters have the defined values. - * For other failures, will indicate the failure that occurred, and the other - * parameters are undefined. - * - * externalAddress: Four byte IPv4 address in network byte order. - * - * protocol: Will be kDNSServiceProtocol_UDP or kDNSServiceProtocol_TCP or both. - * - * internalPort: The port on the local machine that was mapped. - * - * externalPort: The actual external port in the NAT gateway that was mapped. - * This is likely to be different than the requested external port. - * - * ttl: The lifetime of the NAT port mapping created on the gateway. - * This controls how quickly stale mappings will be garbage-collected - * if the client machine crashes, suffers a power failure, is disconnected - * from the network, or suffers some other unfortunate demise which - * causes it to vanish without explicitly removing its NAT port mapping. - * It's possible that the ttl value will differ from the requested ttl value. - * - * context: The context pointer that was passed to the callout. - * - */ - -typedef void (DNSSD_API *DNSServiceNATPortMappingReply) - ( - DNSServiceRef sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceErrorType errorCode, - uint32_t externalAddress, /* four byte IPv4 address in network byte order */ - DNSServiceProtocol protocol, - uint16_t internalPort, /* In network byte order */ - uint16_t externalPort, /* In network byte order and may be different than the requested port */ - uint32_t ttl, /* may be different than the requested ttl */ - void *context - ); - - -/* DNSServiceNATPortMappingCreate() Parameters: - * - * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it - * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the nat - * port mapping will last indefinitely until the client terminates the port - * mapping request by passing this DNSServiceRef to DNSServiceRefDeallocate(). - * - * flags: Currently ignored, reserved for future use. - * - * interfaceIndex: The interface on which to create port mappings in a NAT gateway. Passing 0 causes - * the port mapping request to be sent on the primary interface. - * - * protocol: To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP, - * or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both. - * The local listening port number must also be specified in the internalPort parameter. - * To just discover the NAT gateway's external IP address, pass zero for protocol, - * internalPort, externalPort and ttl. - * - * internalPort: The port number in network byte order on the local machine which is listening for packets. - * - * externalPort: The requested external port in network byte order in the NAT gateway that you would - * like to map to the internal port. Pass 0 if you don't care which external port is chosen for you. - * - * ttl: The requested renewal period of the NAT port mapping, in seconds. - * If the client machine crashes, suffers a power failure, is disconnected from - * the network, or suffers some other unfortunate demise which causes it to vanish - * unexpectedly without explicitly removing its NAT port mappings, then the NAT gateway - * will garbage-collect old stale NAT port mappings when their lifetime expires. - * Requesting a short TTL causes such orphaned mappings to be garbage-collected - * more promptly, but consumes system resources and network bandwidth with - * frequent renewal packets to keep the mapping from expiring. - * Requesting a long TTL is more efficient on the network, but in the event of the - * client vanishing, stale NAT port mappings will not be garbage-collected as quickly. - * Most clients should pass 0 to use a system-wide default value. - * - * callBack: The function to be called when the port mapping request succeeds or fails asynchronously. - * - * context: An application context pointer which is passed to the callback function - * (may be NULL). - * - * return value: Returns kDNSServiceErr_NoError on success (any subsequent, asynchronous - * errors are delivered to the callback), otherwise returns an error code indicating - * the error that occurred. - * - * If you don't actually want a port mapped, and are just calling the API - * because you want to find out the NAT's external IP address (e.g. for UI - * display) then pass zero for protocol, internalPort, externalPort and ttl. - */ - -DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate - ( - DNSServiceRef *sdRef, - DNSServiceFlags flags, - uint32_t interfaceIndex, - DNSServiceProtocol protocol, /* TCP and/or UDP */ - uint16_t internalPort, /* network byte order */ - uint16_t externalPort, /* network byte order */ - uint32_t ttl, /* time to live in seconds */ - DNSServiceNATPortMappingReply callBack, - void *context /* may be NULL */ - ); - - -/********************************************************************************************* - * - * General Utility Functions - * - *********************************************************************************************/ - -/* DNSServiceConstructFullName() - * - * Concatenate a three-part domain name (as returned by the above callbacks) into a - * properly-escaped full domain name. Note that callbacks in the above functions ALREADY ESCAPE - * strings where necessary. - * - * Parameters: - * - * fullName: A pointer to a buffer that where the resulting full domain name is to be written. - * The buffer must be kDNSServiceMaxDomainName (1009) bytes in length to - * accommodate the longest legal domain name without buffer overrun. - * - * service: The service name - any dots or backslashes must NOT be escaped. - * May be NULL (to construct a PTR record name, e.g. - * "_ftp._tcp.apple.com."). - * - * regtype: The service type followed by the protocol, separated by a dot - * (e.g. "_ftp._tcp"). - * - * domain: The domain name, e.g. "apple.com.". Literal dots or backslashes, - * if any, must be escaped, e.g. "1st\. Floor.apple.com." - * - * return value: Returns kDNSServiceErr_NoError (0) on success, kDNSServiceErr_BadParam on error. - * - */ - -DNSServiceErrorType DNSSD_API DNSServiceConstructFullName - ( - char * const fullName, - const char * const service, /* may be NULL */ - const char * const regtype, - const char * const domain - ); - - -/********************************************************************************************* - * - * TXT Record Construction Functions - * - *********************************************************************************************/ - -/* - * A typical calling sequence for TXT record construction is something like: - * - * Client allocates storage for TXTRecord data (e.g. declare buffer on the stack) - * TXTRecordCreate(); - * TXTRecordSetValue(); - * TXTRecordSetValue(); - * TXTRecordSetValue(); - * ... - * DNSServiceRegister( ... TXTRecordGetLength(), TXTRecordGetBytesPtr() ... ); - * TXTRecordDeallocate(); - * Explicitly deallocate storage for TXTRecord data (if not allocated on the stack) - */ - - -/* TXTRecordRef - * - * Opaque internal data type. - * Note: Represents a DNS-SD TXT record. - */ - -typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignment; } TXTRecordRef; - - -/* TXTRecordCreate() - * - * Creates a new empty TXTRecordRef referencing the specified storage. - * - * If the buffer parameter is NULL, or the specified storage size is not - * large enough to hold a key subsequently added using TXTRecordSetValue(), - * then additional memory will be added as needed using malloc(). - * - * On some platforms, when memory is low, malloc() may fail. In this - * case, TXTRecordSetValue() will return kDNSServiceErr_NoMemory, and this - * error condition will need to be handled as appropriate by the caller. - * - * You can avoid the need to handle this error condition if you ensure - * that the storage you initially provide is large enough to hold all - * the key/value pairs that are to be added to the record. - * The caller can precompute the exact length required for all of the - * key/value pairs to be added, or simply provide a fixed-sized buffer - * known in advance to be large enough. - * A no-value (key-only) key requires (1 + key length) bytes. - * A key with empty value requires (1 + key length + 1) bytes. - * A key with non-empty value requires (1 + key length + 1 + value length). - * For most applications, DNS-SD TXT records are generally - * less than 100 bytes, so in most cases a simple fixed-sized - * 256-byte buffer will be more than sufficient. - * Recommended size limits for DNS-SD TXT Records are discussed in - * - * - * Note: When passing parameters to and from these TXT record APIs, - * the key name does not include the '=' character. The '=' character - * is the separator between the key and value in the on-the-wire - * packet format; it is not part of either the key or the value. - * - * txtRecord: A pointer to an uninitialized TXTRecordRef. - * - * bufferLen: The size of the storage provided in the "buffer" parameter. - * - * buffer: Optional caller-supplied storage used to hold the TXTRecord data. - * This storage must remain valid for as long as - * the TXTRecordRef. - */ - -void DNSSD_API TXTRecordCreate - ( - TXTRecordRef *txtRecord, - uint16_t bufferLen, - void *buffer - ); - - -/* TXTRecordDeallocate() - * - * Releases any resources allocated in the course of preparing a TXT Record - * using TXTRecordCreate()/TXTRecordSetValue()/TXTRecordRemoveValue(). - * Ownership of the buffer provided in TXTRecordCreate() returns to the client. - * - * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). - * - */ - -void DNSSD_API TXTRecordDeallocate - ( - TXTRecordRef *txtRecord - ); - - -/* TXTRecordSetValue() - * - * Adds a key (optionally with value) to a TXTRecordRef. If the "key" already - * exists in the TXTRecordRef, then the current value will be replaced with - * the new value. - * Keys may exist in four states with respect to a given TXT record: - * - Absent (key does not appear at all) - * - Present with no value ("key" appears alone) - * - Present with empty value ("key=" appears in TXT record) - * - Present with non-empty value ("key=value" appears in TXT record) - * For more details refer to "Data Syntax for DNS-SD TXT Records" in - * - * - * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). - * - * key: A null-terminated string which only contains printable ASCII - * values (0x20-0x7E), excluding '=' (0x3D). Keys should be - * 9 characters or fewer (not counting the terminating null). - * - * valueSize: The size of the value. - * - * value: Any binary value. For values that represent - * textual data, UTF-8 is STRONGLY recommended. - * For values that represent textual data, valueSize - * should NOT include the terminating null (if any) - * at the end of the string. - * If NULL, then "key" will be added with no value. - * If non-NULL but valueSize is zero, then "key=" will be - * added with empty value. - * - * return value: Returns kDNSServiceErr_NoError on success. - * Returns kDNSServiceErr_Invalid if the "key" string contains - * illegal characters. - * Returns kDNSServiceErr_NoMemory if adding this key would - * exceed the available storage. - */ - -DNSServiceErrorType DNSSD_API TXTRecordSetValue - ( - TXTRecordRef *txtRecord, - const char *key, - uint8_t valueSize, /* may be zero */ - const void *value /* may be NULL */ - ); - - -/* TXTRecordRemoveValue() - * - * Removes a key from a TXTRecordRef. The "key" must be an - * ASCII string which exists in the TXTRecordRef. - * - * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). - * - * key: A key name which exists in the TXTRecordRef. - * - * return value: Returns kDNSServiceErr_NoError on success. - * Returns kDNSServiceErr_NoSuchKey if the "key" does not - * exist in the TXTRecordRef. - */ - -DNSServiceErrorType DNSSD_API TXTRecordRemoveValue - ( - TXTRecordRef *txtRecord, - const char *key - ); - - -/* TXTRecordGetLength() - * - * Allows you to determine the length of the raw bytes within a TXTRecordRef. - * - * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). - * - * return value: Returns the size of the raw bytes inside a TXTRecordRef - * which you can pass directly to DNSServiceRegister() or - * to DNSServiceUpdateRecord(). - * Returns 0 if the TXTRecordRef is empty. - */ - -uint16_t DNSSD_API TXTRecordGetLength - ( - const TXTRecordRef *txtRecord - ); - - -/* TXTRecordGetBytesPtr() - * - * Allows you to retrieve a pointer to the raw bytes within a TXTRecordRef. - * - * txtRecord: A TXTRecordRef initialized by calling TXTRecordCreate(). - * - * return value: Returns a pointer to the raw bytes inside the TXTRecordRef - * which you can pass directly to DNSServiceRegister() or - * to DNSServiceUpdateRecord(). - */ - -const void * DNSSD_API TXTRecordGetBytesPtr - ( - const TXTRecordRef *txtRecord - ); - - -/********************************************************************************************* - * - * TXT Record Parsing Functions - * - *********************************************************************************************/ - -/* - * A typical calling sequence for TXT record parsing is something like: - * - * Receive TXT record data in DNSServiceResolve() callback - * if (TXTRecordContainsKey(txtLen, txtRecord, "key")) then do something - * val1ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key1", &len1); - * val2ptr = TXTRecordGetValuePtr(txtLen, txtRecord, "key2", &len2); - * ... - * memcpy(myval1, val1ptr, len1); - * memcpy(myval2, val2ptr, len2); - * ... - * return; - * - * If you wish to retain the values after return from the DNSServiceResolve() - * callback, then you need to copy the data to your own storage using memcpy() - * or similar, as shown in the example above. - * - * If for some reason you need to parse a TXT record you built yourself - * using the TXT record construction functions above, then you can do - * that using TXTRecordGetLength and TXTRecordGetBytesPtr calls: - * TXTRecordGetValue(TXTRecordGetLength(x), TXTRecordGetBytesPtr(x), key, &len); - * - * Most applications only fetch keys they know about from a TXT record and - * ignore the rest. - * However, some debugging tools wish to fetch and display all keys. - * To do that, use the TXTRecordGetCount() and TXTRecordGetItemAtIndex() calls. - */ - -/* TXTRecordContainsKey() - * - * Allows you to determine if a given TXT Record contains a specified key. - * - * txtLen: The size of the received TXT Record. - * - * txtRecord: Pointer to the received TXT Record bytes. - * - * key: A null-terminated ASCII string containing the key name. - * - * return value: Returns 1 if the TXT Record contains the specified key. - * Otherwise, it returns 0. - */ - -int DNSSD_API TXTRecordContainsKey - ( - uint16_t txtLen, - const void *txtRecord, - const char *key - ); - - -/* TXTRecordGetValuePtr() - * - * Allows you to retrieve the value for a given key from a TXT Record. - * - * txtLen: The size of the received TXT Record - * - * txtRecord: Pointer to the received TXT Record bytes. - * - * key: A null-terminated ASCII string containing the key name. - * - * valueLen: On output, will be set to the size of the "value" data. - * - * return value: Returns NULL if the key does not exist in this TXT record, - * or exists with no value (to differentiate between - * these two cases use TXTRecordContainsKey()). - * Returns pointer to location within TXT Record bytes - * if the key exists with empty or non-empty value. - * For empty value, valueLen will be zero. - * For non-empty value, valueLen will be length of value data. - */ - -const void * DNSSD_API TXTRecordGetValuePtr - ( - uint16_t txtLen, - const void *txtRecord, - const char *key, - uint8_t *valueLen - ); - - -/* TXTRecordGetCount() - * - * Returns the number of keys stored in the TXT Record. The count - * can be used with TXTRecordGetItemAtIndex() to iterate through the keys. - * - * txtLen: The size of the received TXT Record. - * - * txtRecord: Pointer to the received TXT Record bytes. - * - * return value: Returns the total number of keys in the TXT Record. - * - */ - -uint16_t DNSSD_API TXTRecordGetCount - ( - uint16_t txtLen, - const void *txtRecord - ); - - -/* TXTRecordGetItemAtIndex() - * - * Allows you to retrieve a key name and value pointer, given an index into - * a TXT Record. Legal index values range from zero to TXTRecordGetCount()-1. - * It's also possible to iterate through keys in a TXT record by simply - * calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero - * and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid. - * - * On return: - * For keys with no value, *value is set to NULL and *valueLen is zero. - * For keys with empty value, *value is non-NULL and *valueLen is zero. - * For keys with non-empty value, *value is non-NULL and *valueLen is non-zero. - * - * txtLen: The size of the received TXT Record. - * - * txtRecord: Pointer to the received TXT Record bytes. - * - * itemIndex: An index into the TXT Record. - * - * keyBufLen: The size of the string buffer being supplied. - * - * key: A string buffer used to store the key name. - * On return, the buffer contains a null-terminated C string - * giving the key name. DNS-SD TXT keys are usually - * 9 characters or fewer. To hold the maximum possible - * key name, the buffer should be 256 bytes long. - * - * valueLen: On output, will be set to the size of the "value" data. - * - * value: On output, *value is set to point to location within TXT - * Record bytes that holds the value data. - * - * return value: Returns kDNSServiceErr_NoError on success. - * Returns kDNSServiceErr_NoMemory if keyBufLen is too short. - * Returns kDNSServiceErr_Invalid if index is greater than - * TXTRecordGetCount()-1. - */ - -DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex - ( - uint16_t txtLen, - const void *txtRecord, - uint16_t itemIndex, - uint16_t keyBufLen, - char *key, - uint8_t *valueLen, - const void **value - ); - -#if _DNS_SD_LIBDISPATCH -/* -* DNSServiceSetDispatchQueue -* -* Allows you to schedule a DNSServiceRef on a serial dispatch queue for receiving asynchronous -* callbacks. It's the clients responsibility to ensure that the provided dispatch queue is running. -* -* A typical application that uses CFRunLoopRun or dispatch_main on its main thread will -* usually schedule DNSServiceRefs on its main queue (which is always a serial queue) -* using "DNSServiceSetDispatchQueue(sdref, dispatch_get_main_queue());" -* -* If there is any error during the processing of events, the application callback will -* be called with an error code. For shared connections, each subordinate DNSServiceRef -* will get its own error callback. Currently these error callbacks only happen -* if the mDNSResponder daemon is manually terminated or crashes, and the error -* code in this case is kDNSServiceErr_ServiceNotRunning. The application must call -* DNSServiceRefDeallocate to free the DNSServiceRef when it gets such an error code. -* These error callbacks are rare and should not normally happen on customer machines, -* but application code should be written defensively to handle such error callbacks -* gracefully if they occur. -* -* After using DNSServiceSetDispatchQueue on a DNSServiceRef, calling DNSServiceProcessResult -* on the same DNSServiceRef will result in undefined behavior and should be avoided. -* -* Once the application successfully schedules a DNSServiceRef on a serial dispatch queue using -* DNSServiceSetDispatchQueue, it cannot remove the DNSServiceRef from the dispatch queue, or use -* DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch -* queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until -* the application no longer requires that operation and terminates it using DNSServiceRefDeallocate. -* -* service: DNSServiceRef that was allocated and returned to the application, when the -* application calls one of the DNSService API. -* -* queue: dispatch queue where the application callback will be scheduled -* -* return value: Returns kDNSServiceErr_NoError on success. -* Returns kDNSServiceErr_NoMemory if it cannot create a dispatch source -* Returns kDNSServiceErr_BadParam if the service param is invalid or the -* queue param is invalid -*/ - -DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue - ( - DNSServiceRef service, - dispatch_queue_t queue - ); -#endif //_DNS_SD_LIBDISPATCH - -#ifdef __APPLE_API_PRIVATE - -#define kDNSServiceCompPrivateDNS "PrivateDNS" -#define kDNSServiceCompMulticastDNS "MulticastDNS" - -#endif //__APPLE_API_PRIVATE - -/* Some C compiler cleverness. We can make the compiler check certain things for us, - * and report errors at compile-time if anything is wrong. The usual way to do this would - * be to use a run-time "if" statement or the conventional run-time "assert" mechanism, but - * then you don't find out what's wrong until you run the software. This way, if the assertion - * condition is false, the array size is negative, and the compiler complains immediately. - */ - -struct CompileTimeAssertionChecks_DNS_SD - { - char assert0[(sizeof(union _TXTRecordRef_t) == 16) ? 1 : -1]; - }; - -#ifdef __cplusplus - } -#endif - -#endif /* _DNS_SD_H */ diff --git a/vcnet/dnssdstub.vcxproj b/vcnet/dnssdstub.vcxproj deleted file mode 100644 index e31e94ad26..0000000000 --- a/vcnet/dnssdstub.vcxproj +++ /dev/null @@ -1,105 +0,0 @@ - - - - - Debug - x64 - - - Release - x64 - - - - - - - - - - 15.0 - {C0899B3A-43E7-4BC3-A785-659E1FD2EA83} - Win32Proj - dnssdstub - 10.0 - - - - StaticLibrary - true - v143 - v141 - v142 - Unicode - - - StaticLibrary - false - v143 - v141 - v142 - true - Unicode - - - - - - - - - - - - - - - true - $(Platform)/$(Configuration)/ - $(Platform)/$(Configuration)/$(ProjectName)/ - - - false - $(Platform)/$(Configuration)/ - $(Platform)/$(Configuration)/$(ProjectName)/ - - - - NotUsing - Level3 - Disabled - true - _DEBUG;_LIB;%(PreprocessorDefinitions) - true - - ..\vcnet;..;%(AdditionalIncludeDirectories) - - - Windows - true - - - - - NotUsing - Level3 - MaxSpeed - true - true - true - NDEBUG;_LIB;%(PreprocessorDefinitions) - true - - ..\vcnet;..;%(AdditionalIncludeDirectories) - - - Windows - true - true - true - - - - - - \ No newline at end of file diff --git a/vcnet/testdnssd.vcxproj b/vcnet/testdnssd.vcxproj new file mode 100644 index 0000000000..e190a1560c --- /dev/null +++ b/vcnet/testdnssd.vcxproj @@ -0,0 +1,111 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {CBEFF8C1-C109-4B37-92B9-843DF7EB4FA0} + Win32Proj + 10.0 + + + + Application + v142 + MultiByte + + + Application + v142 + MultiByte + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>12.0.30501.0 + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + true + + + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + false + + + + Disabled + ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + $(OutDir)testdnssd.exe + true + $(OutDir)testdnssd.pdb + Console + false + + + + + + + ..\vcnet;..;..\vcnet\regex;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + MultiThreaded + + + Level3 + + + + + $(OutDir)testdnssd.exe + true + Console + true + true + false + + + + + + + + + + {cb4aa6f2-3e84-45be-b505-95cd375e8be3} + + + + + \ No newline at end of file diff --git a/vcnet/dnssdstub.vcxproj.filters b/vcnet/testdnssd.vcxproj.filters similarity index 67% rename from vcnet/dnssdstub.vcxproj.filters rename to vcnet/testdnssd.vcxproj.filters index 1bbb2f00f6..926710ab32 100644 --- a/vcnet/dnssdstub.vcxproj.filters +++ b/vcnet/testdnssd.vcxproj.filters @@ -3,25 +3,20 @@ {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + h;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx - + Source Files - - - Header Files - - \ No newline at end of file diff --git a/vcnet/dnssdstub.vcxproj.user b/vcnet/testdnssd.vcxproj.user similarity index 100% rename from vcnet/dnssdstub.vcxproj.user rename to vcnet/testdnssd.vcxproj.user