first version of the zeroconf lib

allows browsing (detection) of services using dns-sd, i.e.
DNS Service Discovery, or Bonjour see http://www.zeroconf.org/
The exposed interface is reentrant and threadsafe

Change-Id: I957d69696aa3c8ad625e074389b649b00b9153cf
Reviewed-on: http://codereview.qt-project.org/5410
Reviewed-by: Fawzi Mohamed <fawzi.mohamed@nokia.com>
Sanity-Review: Qt Sanity Bot <qt_sanity_bot@ovi.com>
This commit is contained in:
Fawzi Mohamed
2011-09-22 20:48:00 +02:00
parent 3fb9321bd8
commit f25f1858f0
17 changed files with 7905 additions and 1 deletions

View File

@@ -16,7 +16,8 @@ SUBDIRS = \
qmljsdebugclient \
glsl \
qmleditorwidgets \
qtcomponents/styleitem
qtcomponents/styleitem \
zeroconf
win32:SUBDIRS += utils/process_ctrlc_stub.pro
# Windows: Compile Qt Creator CDB extension if Debugging tools can be detected.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,370 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* Copyright (c) 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.
*/
#include <stdlib.h>
#include <string.h>
#include "dns_sd_types.h"
#if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
//#pragma export on
#endif
#if defined(_WIN32)
// disable warning "conversion from <data> to uint16_t"
#pragma warning(disable:4244)
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif
/*********************************************************************************************
*
* Supporting Functions
*
*********************************************************************************************/
namespace ZeroConf { namespace embeddedLib {
#include "dns_sd_funct.h"
#define mDNSIsDigit(X) ((X) >= '0' && (X) <= '9')
// DomainEndsInDot returns 1 if name ends with a dot, 0 otherwise
// (DNSServiceConstructFullName depends this returning 1 for true, rather than any non-zero value meaning true)
static int DomainEndsInDot(const char *dom)
{
while (dom[0] && dom[1])
{
if (dom[0] == '\\') // advance past escaped byte sequence
{
if (mDNSIsDigit(dom[1]) && mDNSIsDigit(dom[2]) && mDNSIsDigit(dom[3]))
dom += 4; // If "\ddd" then skip four
else dom += 2; // else if "\x" then skip two
}
else dom++; // else goto next character
}
return (dom[0] == '.');
}
static uint8_t *InternalTXTRecordSearch
(
uint16_t txtLen,
const void *txtRecord,
const char *key,
unsigned long *keylen
)
{
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
*keylen = (unsigned long) strlen(key);
while (p<e)
{
uint8_t *x = p;
p += 1 + p[0];
if (p <= e && *keylen <= x[0] && !strncasecmp(key, (char*)x+1, *keylen))
if (*keylen == x[0] || x[1+*keylen] == '=') return(x);
}
return(NULL);
}
/*********************************************************************************************
*
* General Utility Functions
*
*********************************************************************************************/
// Note: Need to make sure we don't write more than kDNSServiceMaxDomainName (1009) bytes to fullName
// In earlier builds this constant was defined to be 1005, so to avoid buffer overruns on clients
// compiled with that constant we'll actually limit the output to 1005 bytes.
DNSServiceErrorType DNSSD_API DNSServiceConstructFullName
(
char *const fullName,
const char *const service, // May be NULL
const char *const regtype,
const char *const domain
)
{
const size_t len = !regtype ? 0 : strlen(regtype) - DomainEndsInDot(regtype);
char *fn = fullName;
char *const lim = fullName + 1005;
const char *s = service;
const char *r = regtype;
const char *d = domain;
// regtype must be at least "x._udp" or "x._tcp"
if (len < 6 || !domain || !domain[0]) return kDNSServiceErr_BadParam;
if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return kDNSServiceErr_BadParam;
if (service && *service)
{
while (*s)
{
unsigned char c = *s++; // Needs to be unsigned, or values like 0xFF will be interpreted as < 32
if (c <= ' ') // Escape non-printable characters
{
if (fn+4 >= lim) goto fail;
*fn++ = '\\';
*fn++ = '0' + (c / 100);
*fn++ = '0' + (c / 10) % 10;
c = '0' + (c ) % 10;
}
else if (c == '.' || (c == '\\')) // Escape dot and backslash literals
{
if (fn+2 >= lim) goto fail;
*fn++ = '\\';
}
else
if (fn+1 >= lim) goto fail;
*fn++ = (char)c;
}
*fn++ = '.';
}
while (*r) if (fn+1 >= lim) goto fail; else *fn++ = *r++;
if (!DomainEndsInDot(regtype)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; }
while (*d) if (fn+1 >= lim) goto fail; else *fn++ = *d++;
if (!DomainEndsInDot(domain)) { if (fn+1 >= lim) goto fail; else *fn++ = '.'; }
*fn = '\0';
return kDNSServiceErr_NoError;
fail:
*fn = '\0';
return kDNSServiceErr_BadParam;
}
/*********************************************************************************************
*
* TXT Record Construction Functions
*
*********************************************************************************************/
typedef struct _TXTRecordRefRealType
{
uint8_t *buffer; // Pointer to data
uint16_t buflen; // Length of buffer
uint16_t datalen; // Length currently in use
uint16_t malloced; // Non-zero if buffer was allocated via malloc()
} TXTRecordRefRealType;
#define txtRec ((TXTRecordRefRealType*)txtRecord)
// The opaque storage defined in the public dns_sd.h header is 16 bytes;
// make sure we don't exceed that.
struct CompileTimeAssertionCheck_dnssd_clientlib
{
char assert0[(sizeof(TXTRecordRefRealType) <= 16) ? 1 : -1];
};
void DNSSD_API TXTRecordCreate
(
TXTRecordRef *txtRecord,
uint16_t bufferLen,
void *buffer
)
{
txtRec->buffer = static_cast<uint8_t *>(buffer);
txtRec->buflen = buffer ? bufferLen : (uint16_t)0;
txtRec->datalen = 0;
txtRec->malloced = 0;
}
void DNSSD_API TXTRecordDeallocate(TXTRecordRef *txtRecord)
{
if (txtRec->malloced) free(txtRec->buffer);
}
DNSServiceErrorType DNSSD_API TXTRecordSetValue
(
TXTRecordRef *txtRecord,
const char *key,
uint8_t valueSize,
const void *value
)
{
uint8_t *start, *p;
const char *k;
unsigned long keysize, keyvalsize;
for (k = key; *k; k++) if (*k < 0x20 || *k > 0x7E || *k == '=') return(kDNSServiceErr_Invalid);
keysize = (unsigned long)(k - key);
keyvalsize = 1 + keysize + (value ? (1 + valueSize) : 0);
if (keysize < 1 || keyvalsize > 255) return(kDNSServiceErr_Invalid);
(void)TXTRecordRemoveValue(txtRecord, key);
if (txtRec->datalen + keyvalsize > txtRec->buflen)
{
unsigned char *newbuf;
unsigned long newlen = txtRec->datalen + keyvalsize;
if (newlen > 0xFFFF) return(kDNSServiceErr_Invalid);
newbuf = static_cast<unsigned char *>(malloc((size_t)newlen));
if (!newbuf) return(kDNSServiceErr_NoMemory);
memcpy(newbuf, txtRec->buffer, txtRec->datalen);
if (txtRec->malloced) free(txtRec->buffer);
txtRec->buffer = newbuf;
txtRec->buflen = (uint16_t)(newlen);
txtRec->malloced = 1;
}
start = txtRec->buffer + txtRec->datalen;
p = start + 1;
memcpy(p, key, keysize);
p += keysize;
if (value)
{
*p++ = '=';
memcpy(p, value, valueSize);
p += valueSize;
}
*start = (uint8_t)(p - start - 1);
txtRec->datalen += p - start;
return(kDNSServiceErr_NoError);
}
DNSServiceErrorType DNSSD_API TXTRecordRemoveValue
(
TXTRecordRef *txtRecord,
const char *key
)
{
unsigned long keylen, itemlen, remainder;
uint8_t *item = InternalTXTRecordSearch(txtRec->datalen, txtRec->buffer, key, &keylen);
if (!item) return(kDNSServiceErr_NoSuchKey);
itemlen = (unsigned long)(1 + item[0]);
remainder = (unsigned long)((txtRec->buffer + txtRec->datalen) - (item + itemlen));
// Use memmove because memcpy behaviour is undefined for overlapping regions
memmove(item, item + itemlen, remainder);
txtRec->datalen -= itemlen;
return(kDNSServiceErr_NoError);
}
uint16_t DNSSD_API TXTRecordGetLength (const TXTRecordRef *txtRecord) { return(txtRec->datalen); }
const void * DNSSD_API TXTRecordGetBytesPtr(const TXTRecordRef *txtRecord) { return(txtRec->buffer); }
/*********************************************************************************************
*
* TXT Record Parsing Functions
*
*********************************************************************************************/
int DNSSD_API TXTRecordContainsKey
(
uint16_t txtLen,
const void *txtRecord,
const char *key
)
{
unsigned long keylen;
return (InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen) ? 1 : 0);
}
const void * DNSSD_API TXTRecordGetValuePtr
(
uint16_t txtLen,
const void *txtRecord,
const char *key,
uint8_t *valueLen
)
{
unsigned long keylen;
uint8_t *item = InternalTXTRecordSearch(txtLen, txtRecord, key, &keylen);
if (!item || item[0] <= keylen) return(NULL); // If key not found, or found with no value, return NULL
*valueLen = (uint8_t)(item[0] - (keylen + 1));
return (item + 1 + keylen + 1);
}
uint16_t DNSSD_API TXTRecordGetCount
(
uint16_t txtLen,
const void *txtRecord
)
{
uint16_t count = 0;
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
while (p<e) { p += 1 + p[0]; count++; }
return((p>e) ? (uint16_t)0 : count);
}
DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
(
uint16_t txtLen,
const void *txtRecord,
uint16_t itemIndex,
uint16_t keyBufLen,
char *key,
uint8_t *valueLen,
const void **value
)
{
uint16_t count = 0;
uint8_t *p = (uint8_t*)txtRecord;
uint8_t *e = p + txtLen;
while (p<e && count<itemIndex) { p += 1 + p[0]; count++; } // Find requested item
if (p<e && p + 1 + p[0] <= e) // If valid
{
uint8_t *x = p+1;
unsigned long len = 0;
e = p + 1 + p[0];
while (x+len<e && x[len] != '=') len++;
if (len >= keyBufLen) return(kDNSServiceErr_NoMemory);
memcpy(key, x, len);
key[len] = 0;
if (x+len<e) // If we found '='
{
*value = x + len + 1;
*valueLen = (uint8_t)(p[0] - (len + 1));
}
else
{
*value = NULL;
*valueLen = 0;
}
return(kDNSServiceErr_NoError);
}
return(kDNSServiceErr_Invalid);
}
/*********************************************************************************************
*
* SCCS-compatible version string
*
*********************************************************************************************/
// For convenience when using the "strings" command, this is the last thing in the file
// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
// To expand "version" to its value before making the string, use STRINGIFY(version) instead
#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
// NOT static -- otherwise the compiler may optimize it out
// The "@(#) " pattern is a special prefix the "what" command looks for
const char VersionString_SCCS_libdnssd[] = "@(#) libdns_sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
}}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* 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.
*/
#include "dnssd_ipc.h"
namespace ZeroConf { namespace embeddedLib {
#if defined(_WIN32)
char *win32_strerror(int inErrorCode)
{
static char buffer[1024];
DWORD n;
memset(buffer, 0, sizeof(buffer));
n = FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
(DWORD) inErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buffer,
sizeof(buffer),
NULL);
if (n > 0)
{
// Remove any trailing CR's or LF's since some messages have them.
while ((n > 0) && isspace(((unsigned char *) buffer)[n - 1]))
buffer[--n] = '\0';
}
return buffer;
}
#endif
void put_uint32(const uint32_t l, char **ptr)
{
(*ptr)[0] = (char)((l >> 24) & 0xFF);
(*ptr)[1] = (char)((l >> 16) & 0xFF);
(*ptr)[2] = (char)((l >> 8) & 0xFF);
(*ptr)[3] = (char)((l ) & 0xFF);
*ptr += sizeof(uint32_t);
}
uint32_t get_uint32(const char **ptr, const char *end)
{
if (!*ptr || *ptr + sizeof(uint32_t) > end)
{
*ptr = NULL;
return(0);
}
else
{
uint8_t *p = (uint8_t*) *ptr;
*ptr += sizeof(uint32_t);
return((uint32_t) ((uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 | (uint32_t)p[2] << 8 | p[3]));
}
}
void put_uint16(uint16_t s, char **ptr)
{
(*ptr)[0] = (char)((s >> 8) & 0xFF);
(*ptr)[1] = (char)((s ) & 0xFF);
*ptr += sizeof(uint16_t);
}
uint16_t get_uint16(const char **ptr, const char *end)
{
if (!*ptr || *ptr + sizeof(uint16_t) > end)
{
*ptr = NULL;
return(0);
}
else
{
uint8_t *p = (uint8_t*) *ptr;
*ptr += sizeof(uint16_t);
return((uint16_t) ((uint16_t)p[0] << 8 | p[1]));
}
}
int put_string(const char *str, char **ptr)
{
if (!str) str = "";
strcpy(*ptr, str);
*ptr += strlen(str) + 1;
return 0;
}
int get_string(const char **ptr, const char *const end, char *buffer, int buflen)
{
if (!*ptr)
{
*buffer = 0;
return(-1);
}
else
{
char *lim = buffer + buflen; // Calculate limit
while (*ptr < end && buffer < lim)
{
char c = *buffer++ = *(*ptr)++;
if (c == 0) return(0); // Success
}
if (buffer == lim) buffer--;
*buffer = 0; // Failed, so terminate string,
*ptr = NULL; // clear pointer,
return(-1); // and return failure indication
}
}
void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr)
{
memcpy(*ptr, rdata, rdlen);
*ptr += rdlen;
}
const char *get_rdata(const char **ptr, const char *end, int rdlen)
{
if (!*ptr || *ptr + rdlen > end)
{
*ptr = NULL;
return(0);
}
else
{
const char *rd = *ptr;
*ptr += rdlen;
return rd;
}
}
void ConvertHeaderBytes(ipc_msg_hdr *hdr)
{
hdr->version = htonl(hdr->version);
hdr->datalen = htonl(hdr->datalen);
hdr->ipc_flags = htonl(hdr->ipc_flags);
hdr->op = htonl(hdr->op );
hdr->reg_index = htonl(hdr->reg_index);
}
}}

View File

@@ -0,0 +1,219 @@
/* -*- Mode: C; tab-width: 4 -*-
*
* 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.
*/
#ifndef DNSSD_IPC_H
#define DNSSD_IPC_H
#include "dns_sd_types.h"
//
// Common cross platform services
//
#if defined(WIN32)
# include <winsock2.h>
# define dnssd_InvalidSocket INVALID_SOCKET
# define dnssd_SocketValid(s) ((s) != INVALID_SOCKET)
# define dnssd_EWOULDBLOCK WSAEWOULDBLOCK
# define dnssd_EINTR WSAEINTR
# define dnssd_ECONNRESET WSAECONNRESET
# define dnssd_sock_t SOCKET
# define dnssd_socklen_t int
# define dnssd_close(sock) closesocket(sock)
# define dnssd_errno WSAGetLastError()
# define dnssd_strerror(X) win32_strerror(X)
# define ssize_t int
# define getpid _getpid
# define unlink _unlink
extern char *win32_strerror(int inErrorCode);
# define USE_TCP_LOOPBACK
#else
# include <sys/types.h>
# include <unistd.h>
# include <sys/un.h>
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/stat.h>
# include <sys/socket.h>
# include <netinet/in.h>
# define dnssd_InvalidSocket -1
# define dnssd_SocketValid(s) ((s) >= 0)
# define dnssd_EWOULDBLOCK EWOULDBLOCK
# define dnssd_EINTR EINTR
# define dnssd_ECONNRESET ECONNRESET
# define dnssd_EPIPE EPIPE
# define dnssd_sock_t int
# define dnssd_socklen_t unsigned int
# define dnssd_close(sock) close(sock)
# define dnssd_errno errno
# define dnssd_strerror(X) strerror(X)
#endif
#if defined(USE_TCP_LOOPBACK)
# define AF_DNSSD AF_INET
# define MDNS_TCP_SERVERADDR "127.0.0.1"
# define MDNS_TCP_SERVERPORT 5354
# define LISTENQ 5
# define dnssd_sockaddr_t struct sockaddr_in
#else
# define AF_DNSSD AF_LOCAL
# ifndef MDNS_UDS_SERVERPATH
# define MDNS_UDS_SERVERPATH "/var/run/mdnsd"
# endif
# define LISTENQ 100
// longest legal control path length
# define MAX_CTLPATH 256
# define dnssd_sockaddr_t struct sockaddr_un
#endif
// Compatibility workaround
#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
#endif
// General UDS constants
#define TXT_RECORD_INDEX ((uint32_t)(-1)) // record index for default text record
// IPC data encoding constants and types
#define VERSION 1
#define IPC_FLAGS_NOREPLY 1 // set flag if no asynchronous replies are to be sent to client
// Structure packing macro. If we're not using GNUC, it's not fatal. Most compilers naturally pack the on-the-wire
// structures correctly anyway, so a plain "struct" is usually fine. In the event that structures are not packed
// correctly, our compile-time assertion checks will catch it and prevent inadvertent generation of non-working code.
#ifndef packedstruct
#if ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
#define packedstruct struct __attribute__((__packed__))
#define packedunion union __attribute__((__packed__))
#else
#define packedstruct struct
#define packedunion union
#endif
#endif
namespace ZeroConf { namespace embeddedLib {
typedef enum
{
request_op_none = 0, // No request yet received on this connection
connection_request = 1, // connected socket via DNSServiceConnect()
reg_record_request, // reg/remove record only valid for connected sockets
remove_record_request,
enumeration_request,
reg_service_request,
browse_request,
resolve_request,
query_request,
reconfirm_record_request,
add_record_request,
update_record_request,
setdomain_request, // Up to here is in Tiger and B4W 1.0.3
getproperty_request, // New in B4W 1.0.4
port_mapping_request, // New in Leopard and B4W 2.0
addrinfo_request,
send_bpf, // New in SL
cancel_request = 63
} request_op_t;
typedef enum
{
enumeration_reply_op = 64,
reg_service_reply_op,
browse_reply_op,
resolve_reply_op,
query_reply_op,
reg_record_reply_op, // Up to here is in Tiger and B4W 1.0.3
getproperty_reply_op, // New in B4W 1.0.4
port_mapping_reply_op, // New in Leopard and B4W 2.0
addrinfo_reply_op
} reply_op_t;
}}
extern "C" {
#if defined(_WIN64)
# pragma pack(4)
#endif
// Define context object big enough to hold a 64-bit pointer,
// to accomodate 64-bit clients communicating with 32-bit daemon.
// There's no reason for the daemon to ever be a 64-bit process, but its clients might be
typedef packedunion
{
void *context;
uint32_t u32[2];
} client_context_t;
typedef packedstruct
{
uint32_t version;
uint32_t datalen;
uint32_t ipc_flags;
uint32_t op; // request_op_t or reply_op_t
client_context_t client_context; // context passed from client, returned by server in corresponding reply
uint32_t reg_index; // identifier for a record registered via DNSServiceRegisterRecord() on a
// socket connected by DNSServiceCreateConnection(). Must be unique in the scope of the connection, such that and
// index/socket pair uniquely identifies a record. (Used to select records for removal by DNSServiceRemoveRecord())
} ipc_msg_hdr;
// routines to write to and extract data from message buffers.
// caller responsible for bounds checking.
// ptr is the address of the pointer to the start of the field.
// it is advanced to point to the next field, or the end of the message
}
namespace ZeroConf { namespace embeddedLib {
void put_uint32(const uint32_t l, char **ptr);
uint32_t get_uint32(const char **ptr, const char *end);
void put_uint16(uint16_t s, char **ptr);
uint16_t get_uint16(const char **ptr, const char *end);
#define put_flags put_uint32
#define get_flags get_uint32
#define put_error_code put_uint32
#define get_error_code get_uint32
int put_string(const char *str, char **ptr);
int get_string(const char **ptr, const char *const end, char *buffer, int buflen);
void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
const char *get_rdata(const char **ptr, const char *end, int rdlen); // return value is rdata pointed to by *ptr -
// rdata is not copied from buffer.
void ConvertHeaderBytes(ipc_msg_hdr *hdr);
struct CompileTimeAssertionChecks_dnssd_ipc
{
// Check that the compiler generated our on-the-wire packet format structure definitions
// properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
char assert0[(sizeof(client_context_t) == 8) ? 1 : -1];
char assert1[(sizeof(ipc_msg_hdr) == 28) ? 1 : -1];
};
}}
#endif // DNSSD_IPC_H

View File

@@ -0,0 +1,193 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#ifdef Q_OS_LINUX
#define EMBEDDED_LIB
#endif
#ifdef Q_OS_WIN
# include <Winsock2.h>
#endif
#include "servicebrowser_p.h"
#include <QtCore/QString>
#include <QtCore/QStringList>
#ifdef EMBEDDED_LIB
#include "embed/dnssd_ipc.c"
#include "embed/dnssd_clientlib.c"
#include "embed/dnssd_clientstub.c"
#ifdef Q_OS_WIN
#include "embed/DebugServices.c"
#endif
namespace ZeroConf {
namespace Internal {
// represents a zero conf library exposing the dns-sd interface
class EmbeddedZConfLib : public ZConfLib{
public:
QString daemonPath;
EmbeddedZConfLib(const QString &daemonPath, ZConfLib *fallBack = 0) : ZConfLib(fallBack), daemonPath(daemonPath)
{ }
virtual ~EmbeddedZConfLib() {
}
virtual QString name(){
return QString::fromUtf8("EmbeddedZeroConfLib@%1").arg(size_t(this),0,16);
}
// virtual bool tryStartDaemon();
virtual void refDeallocate(DNSServiceRef sdRef){
embeddedLib::DNSServiceRefDeallocate(sdRef);
}
virtual DNSServiceErrorType resolve(DNSServiceRef *sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
const char *name,
const char *regtype,
const char *domain,
DNSServiceResolveReply callBack,
void *context)
{
return embeddedLib::DNSServiceResolve(sdRef, flags, interfaceIndex, name, regtype, domain, callBack, context);
}
virtual DNSServiceErrorType queryRecord(DNSServiceRef *sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
const char *fullname,
uint16_t rrtype,
uint16_t rrclass,
DNSServiceQueryRecordReply callBack,
void *context)
{
return embeddedLib::DNSServiceQueryRecord(sdRef, flags, interfaceIndex, fullname,
rrtype, rrclass, callBack, context);
}
virtual DNSServiceErrorType getAddrInfo(DNSServiceRef *sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
DNSServiceProtocol protocol,
const char *hostname,
DNSServiceGetAddrInfoReply callBack,
void *context)
{
return embeddedLib::DNSServiceGetAddrInfo(sdRef, flags, interfaceIndex, protocol,
hostname, callBack, context);
}
virtual uint16_t txtRecordGetCount(uint16_t txtLen,
const void *txtRecord)
{
return embeddedLib::TXTRecordGetCount(txtLen, txtRecord);
}
virtual DNSServiceErrorType txtRecordGetItemAtIndex(uint16_t txtLen,
const void *txtRecord,
uint16_t itemIndex,
uint16_t keyBufLen,
char *key,
uint8_t *valueLen,
const void **value)
{
return embeddedLib::TXTRecordGetItemAtIndex(txtLen, txtRecord, itemIndex, keyBufLen,
key, valueLen, value);
}
virtual DNSServiceErrorType reconfirmRecord(DNSServiceFlags flags,
uint32_t interfaceIndex,
const char *fullname,
uint16_t rrtype,
uint16_t rrclass,
uint16_t rdlen,
const void *rdata)
{
return embeddedLib::DNSServiceReconfirmRecord(flags, interfaceIndex, fullname, rrtype,
rrclass, rdlen, rdata);
}
virtual DNSServiceErrorType browse(DNSServiceRef *sdRef,
DNSServiceFlags flags,
uint32_t interfaceIndex,
const char *regtype,
const char *domain, /* may be NULL */
DNSServiceBrowseReply callBack,
void *context /* may be NULL */
)
{
return embeddedLib::DNSServiceBrowse(sdRef, flags, interfaceIndex, regtype, domain, callBack, context);
}
virtual DNSServiceErrorType getProperty(const char *property, /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */
void *result, /* Pointer to place to store result */
uint32_t *size /* size of result location */
)
{
return embeddedLib::DNSServiceGetProperty(property, result, size);
}
virtual DNSServiceErrorType processResult(DNSServiceRef sdRef){
return embeddedLib::DNSServiceProcessResult(sdRef);
}
virtual DNSServiceErrorType createConnection(DNSServiceRef *sdRef){
return embeddedLib::DNSServiceCreateConnection(sdRef);
}
virtual int refSockFD(DNSServiceRef sdRef){
return embeddedLib::DNSServiceRefSockFD(sdRef);
}
};
ZConfLib *ZConfLib::createEmbeddedLib(const QString &daemonPath, ZConfLib *fallback){
return new EmbeddedZConfLib(daemonPath, fallback);
}
} // namespace Internal
} // namespace ZeroConf
#else // no embedded lib
namespace ZeroConf {
namespace Internal {
ZConfLib *ZConfLib::createEmbeddedLib(const QString &, ZConfLib * fallback){
return fallback;
}
} // namespace Internal
} // namespace ZeroConf
#endif

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 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.
*/
#include "mdnsderived.h"
#include "cstddef"
#include "cstring"
#ifdef _WIN32
#define strncasecmp _strnicmp
#endif
namespace ZeroConf {
namespace Internal {
// DomainEndsInDot returns 1 if name ends with a dot, 0 otherwise
// (DNSServiceConstructFullName depends this returning 1 for true, rather than any non-zero value meaning true)
static int DomainEndsInDot(const char *dom)
{
while (dom[0] && dom[1]) {
if (dom[0] == '\\') { // advance past escaped byte sequence
if ('0' <= dom[1] && dom[1] <= '9' &&
'0' <= dom[2] && dom[2] <= '9' &&
'0' <= dom[3] && dom[3] <= '9')
{
dom += 4; // If "\ddd" then skip four
} else {
dom += 2; // else if "\x" then skip two
}
} else {
dom++; // else goto next character
}
}
return (dom[0] == '.');
}
// Note: Need to make sure we don't write more than kDNSServiceMaxDomainName (1009) bytes to fullName
// In earlier builds this constant was defined to be 1005, so to avoid buffer overruns on clients
// compiled with that constant we'll actually limit the output to 1005 bytes.
DNSServiceErrorType myDNSServiceConstructFullName(char *const fullName,
const char *const service, // May be NULL
const char *const regtype,
const char *const domain)
{
const size_t len = !regtype ? 0 : strlen(regtype) - DomainEndsInDot(regtype);
char *fn = fullName;
char *const lim = fullName + 1005;
const char *s = service;
const char *r = regtype;
const char *d = domain;
// regtype must be at least "x._udp" or "x._tcp"
if (len < 6 || !domain || !domain[0]) return kDNSServiceErr_BadParam;
if (strncasecmp((regtype + len - 4), "_tcp", 4) && strncasecmp((regtype + len - 4), "_udp", 4)) return kDNSServiceErr_BadParam;
if (service && *service)
{
while (*s)
{
unsigned char c = *s++; // Needs to be unsigned, or values like 0xFF will be interpreted as < 32
if (c <= ' ') // Escape non-printable characters
{
if (fn + 4 >= lim) goto fail;
*fn++ = '\\';
*fn++ = '0' + (c / 100);
*fn++ = '0' + (c / 10) % 10;
c = '0' + (c ) % 10;
}
else if (c == '.' || (c == '\\')) // Escape dot and backslash literals
{
if (fn + 2 >= lim) goto fail;
*fn++ = '\\';
}
else
if (fn + 1 >= lim) goto fail;
*fn++ = (char)c;
}
*fn++ = '.';
}
while (*r) if (fn + 1 >= lim) goto fail; else *fn++ = *r++;
if (!DomainEndsInDot(regtype)) { if (fn + 1 >= lim) goto fail; else *fn++ = '.'; }
while (*d) if (fn + 1 >= lim) goto fail; else *fn++ = *d++;
if (!DomainEndsInDot(domain)) { if (fn + 1 >= lim) goto fail; else *fn++ = '.'; }
*fn = '\0';
return kDNSServiceErr_NoError;
fail:
*fn = '\0';
return kDNSServiceErr_BadParam;
}
} // namespace ZeroConf
} // namespace Internal

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 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.
*/
#ifndef MDNSDERIVED_H
#define MDNSDERIVED_H
#include "dns_sd_types.h"
namespace ZeroConf {
namespace Internal {
DNSServiceErrorType myDNSServiceConstructFullName(char *const fullName,
const char *const service,
const char *const regtype,
const char *const domain);
}
}
#endif // MDNSDERIVED_H

View File

@@ -0,0 +1,301 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#include "servicebrowser.h"
#include "servicebrowser_p.h"
#include <QtCore/QDebug>
#include <QtCore/QLibrary>
#include <QtCore/QString>
#include <QtCore/QStringList>
#ifndef NO_NATIVE_LIB
#ifdef Q_OS_MACX
#define ZCONF_STATIC_LINKING
#endif
#ifdef ZCONF_STATIC_LINKING
extern "C" {
#include "dns_sd_funct.h"
}
#endif
#ifdef Q_OS_UNIX
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif
namespace ZeroConf {
namespace Internal {
extern "C" {
typedef void (DNSSD_API *RefDeallocatePtr)(DNSServiceRef sdRef);
typedef DNSServiceErrorType (DNSSD_API *ResolvePtr)(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, const char *name,
const char *regtype, const char *domain,
DNSServiceResolveReply callBack, void *context);
typedef DNSServiceErrorType (DNSSD_API *QueryRecordPtr)(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, const char *fullname,
uint16_t rrtype, uint16_t rrclass,
DNSServiceQueryRecordReply callBack, void *context);
typedef DNSServiceErrorType (DNSSD_API *GetAddrInfoPtr)(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceProtocol protocol,
const char *hostname, DNSServiceGetAddrInfoReply callBack,
void *context);
typedef uint16_t (DNSSD_API *TxtRecordGetCountPtr)(uint16_t txtLen, const void *txtRecord);
typedef DNSServiceErrorType (DNSSD_API *TxtRecordGetItemAtIndexPtr)(uint16_t txtLen, const void *txtRecord,
uint16_t itemIndex, uint16_t keyBufLen,
char *key, uint8_t *valueLen, const void **value);
typedef DNSServiceErrorType (DNSSD_API *ReconfirmRecordPtr)(DNSServiceFlags flags, uint32_t interfaceIndex,
const char *fullname, uint16_t rrtype,
uint16_t rrclass, uint16_t rdlen, const void *rdata);
typedef DNSServiceErrorType (DNSSD_API *BrowsePtr)(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, const char *regtype, const char *domain,
DNSServiceBrowseReply callBack, void *context);
typedef DNSServiceErrorType (DNSSD_API *GetPropertyPtr)(const char *property, void *result, uint32_t *size);
typedef DNSServiceErrorType (DNSSD_API *ProcessResultPtr)(DNSServiceRef sdRef);
typedef DNSServiceErrorType (DNSSD_API *CreateConnectionPtr)(DNSServiceRef *sdRef);
typedef int (DNSSD_API *RefSockFDPtr)(DNSServiceRef sdRef);
}
// represents a zero conf library exposing the dns-sd interface
class NativeZConfLib : public ZConfLib{
private:
RefDeallocatePtr m_refDeallocate;
ResolvePtr m_resolve;
QueryRecordPtr m_queryRecord;
GetAddrInfoPtr m_getAddrInfo;
TxtRecordGetCountPtr m_txtRecordGetCount;
TxtRecordGetItemAtIndexPtr m_txtRecordGetItemAtIndex;
ReconfirmRecordPtr m_reconfirmRecord;
BrowsePtr m_browse;
GetPropertyPtr m_getProperty;
ProcessResultPtr m_processResult;
CreateConnectionPtr m_createConnection;
RefSockFDPtr m_refSockFD;
QLibrary nativeLib;
public:
NativeZConfLib(QString libName = QLatin1String("dns_sd"), ZConfLib *fallBack = 0) : ZConfLib(fallBack), nativeLib(libName)
{
#ifndef ZCONF_STATIC_LINKING
// dynamic linking
if (!nativeLib.load()) {
qDebug() << "NativeZConfLib could not load native library";
}
m_refDeallocate = reinterpret_cast<RefDeallocatePtr>(nativeLib.resolve("DNSServiceRefDeallocate"));
m_resolve = reinterpret_cast<ResolvePtr>(nativeLib.resolve("DNSServiceResolve"));
m_queryRecord = reinterpret_cast<QueryRecordPtr>(nativeLib.resolve("DNSServiceQueryRecord"));
m_getAddrInfo = reinterpret_cast<GetAddrInfoPtr>(nativeLib.resolve("DNSServiceGetAddrInfo"));
m_txtRecordGetCount = reinterpret_cast<TxtRecordGetCountPtr>(nativeLib.resolve("TXTRecordGetCount"));
m_txtRecordGetItemAtIndex = reinterpret_cast<TxtRecordGetItemAtIndexPtr>(nativeLib.resolve("TXTRecordGetItemAtIndex")) ;
m_reconfirmRecord = reinterpret_cast<ReconfirmRecordPtr>(nativeLib.resolve("DNSServiceReconfirmRecord"));
m_browse = reinterpret_cast<BrowsePtr>(nativeLib.resolve("DNSServiceBrowse"));
m_getProperty = reinterpret_cast<GetPropertyPtr>(nativeLib.resolve("DNSServiceGetProperty"));
m_processResult = reinterpret_cast<ProcessResultPtr>(nativeLib.resolve("DNSServiceProcessResult")) ;
m_createConnection = reinterpret_cast<CreateConnectionPtr>(nativeLib.resolve("DNSServiceCreateConnection"));
m_refSockFD = reinterpret_cast<RefSockFDPtr>(nativeLib.resolve("DNSServiceRefSockFD"));
#else
// static linking
m_refDeallocate = reinterpret_cast<RefDeallocatePtr>(&DNSServiceRefDeallocate);
m_resolve = reinterpret_cast<ResolvePtr>(&DNSServiceResolve);
m_queryRecord = reinterpret_cast<QueryRecordPtr>(DNSServiceQueryRecord);
m_getAddrInfo = reinterpret_cast<GetAddrInfoPtr>(&DNSServiceGetAddrInfo);
m_txtRecordGetCount = reinterpret_cast<TxtRecordGetCountPtr>(&TXTRecordGetCount);
m_txtRecordGetItemAtIndex = reinterpret_cast<TxtRecordGetItemAtIndexPtr>(&TXTRecordGetItemAtIndex) ;
m_reconfirmRecord = reinterpret_cast<ReconfirmRecordPtr>(&DNSServiceReconfirmRecord);
m_browse = reinterpret_cast<BrowsePtr>(&DNSServiceBrowse);
m_getProperty = reinterpret_cast<GetPropertyPtr>(&DNSServiceGetProperty);
m_processResult = reinterpret_cast<ProcessResultPtr>(&DNSServiceProcessResult) ;
m_createConnection = reinterpret_cast<CreateConnectionPtr>(&DNSServiceCreateConnection);
m_refSockFD = reinterpret_cast<RefSockFDPtr>(&DNSServiceRefSockFD);
#endif
if (m_refDeallocate == 0) qDebug() << QLatin1String("NativeZConfLib.m_refDeallocate == 0");
if (m_resolve == 0) qDebug() << QLatin1String("NativeZConfLib.m_resolve == 0");
if (m_queryRecord == 0) qDebug() << QLatin1String("NativeZConfLib.m_queryRecord == 0");
if (m_getAddrInfo == 0) qDebug() << QLatin1String("NativeZConfLib.m_getAddrInfo == 0");
if (m_txtRecordGetCount == 0) qDebug() << QLatin1String("NativeZConfLib.m_txtRecordGetCount == 0");
if (m_txtRecordGetItemAtIndex == 0) qDebug() << QLatin1String("NativeZConfLib.m_txtRecordGetItemAtIndex == 0");
if (m_reconfirmRecord == 0) qDebug() << QLatin1String("NativeZConfLib.m_reconfirmRecord == 0");
if (m_browse == 0) qDebug() << QLatin1String("NativeZConfLib.m_browse == 0");
if (m_getProperty == 0) qDebug() << QLatin1String("NativeZConfLib.m_getProperty == 0");
if (m_processResult == 0) qDebug() << QLatin1String("NativeZConfLib.m_processResult == 0");
if (m_createConnection == 0) qDebug() << QLatin1String("NativeZConfLib.m_createConnection == 0");
if (m_refSockFD == 0) qDebug() << QLatin1String("NativeZConfLib.m_refSockFD == 0");
}
virtual ~NativeZConfLib() {
}
virtual QString name(){
return QString::fromUtf8("NativeZeroConfLib@%1").arg(size_t(this),0,16);
}
// virtual bool tryStartDaemon();
virtual void refDeallocate(DNSServiceRef sdRef) {
if (m_refDeallocate == 0) return;
m_refDeallocate(sdRef);
}
virtual DNSServiceErrorType resolve(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, const char *name,
const char *regtype, const char *domain,
DNSServiceResolveReply callBack, void *context)
{
if (m_resolve == 0) return kDNSServiceErr_Unsupported;
return m_resolve(sdRef, flags, interfaceIndex, name, regtype, domain, callBack, context);
}
virtual DNSServiceErrorType queryRecord(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, const char *fullname,
uint16_t rrtype, uint16_t rrclass,
DNSServiceQueryRecordReply callBack, void *context)
{
if (m_queryRecord == 0) return kDNSServiceErr_Unsupported;
return m_queryRecord(sdRef, flags, interfaceIndex, fullname,
rrtype, rrclass, callBack, context);
}
virtual DNSServiceErrorType getAddrInfo(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceProtocol protocol,
const char *hostname, DNSServiceGetAddrInfoReply callBack,
void *context)
{
enum { longTTL = 100 };
if (m_getAddrInfo == 0) {
#ifdef Q_OS_UNIX
// try to use getaddrinfo (for example on linux with avahi)
struct addrinfo req, *ans; int err;
memset(&req,0,sizeof(req));
req.ai_flags = 0;
req.ai_family = AF_UNSPEC;
req.ai_socktype = SOCK_STREAM;
req.ai_protocol = 0;
if ((err = getaddrinfo(hostname, 0, &req, &ans)) != 0) {
qDebug() << "getaddrinfo for " << hostname << " failed with " << gai_strerror(err);
return kDNSServiceErr_Unsupported; // use another error here???
}
for (struct addrinfo *ansAtt = ans; ansAtt != 0; ansAtt = ansAtt->ai_next){
callBack(*sdRef, kDNSServiceFlagsAdd, interfaceIndex, kDNSServiceErr_NoError,
hostname, ansAtt->ai_addr, longTTL, context);
}
freeaddrinfo(ans);
return kDNSServiceErr_NoError;
#else
return kDNSServiceErr_Unsupported;
#endif
}
return m_getAddrInfo(sdRef, flags, interfaceIndex, protocol,
hostname, callBack, context);
}
virtual uint16_t txtRecordGetCount(uint16_t txtLen, const void *txtRecord)
{
if (m_txtRecordGetCount == 0) return 0;
return m_txtRecordGetCount(txtLen, txtRecord);
}
virtual DNSServiceErrorType txtRecordGetItemAtIndex(uint16_t txtLen, const void *txtRecord,
uint16_t itemIndex, uint16_t keyBufLen,
char *key, uint8_t *valueLen, const void **value)
{
if (m_txtRecordGetItemAtIndex == 0) return kDNSServiceErr_Unsupported;
return m_txtRecordGetItemAtIndex(txtLen, txtRecord, itemIndex, keyBufLen,
key, valueLen, value);
}
virtual DNSServiceErrorType reconfirmRecord(DNSServiceFlags flags, uint32_t interfaceIndex,
const char *fullname, uint16_t rrtype,
uint16_t rrclass, uint16_t rdlen, const void *rdata)
{
if (m_reconfirmRecord == 0) return kDNSServiceErr_Unsupported;
return m_reconfirmRecord(flags, interfaceIndex, fullname, rrtype,
rrclass, rdlen, rdata);
}
virtual DNSServiceErrorType browse(DNSServiceRef *sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, const char *regtype,
const char *domain, DNSServiceBrowseReply callBack,
void *context)
{
if (m_browse == 0) return kDNSServiceErr_Unsupported;
return m_browse(sdRef, flags, interfaceIndex, regtype, domain, callBack, context);
}
virtual DNSServiceErrorType getProperty(const char *property, // Requested property (i.e. kDNSServiceProperty_DaemonVersion)
void *result, // Pointer to place to store result
uint32_t *size // size of result location
)
{
if (m_getProperty == 0)
return kDNSServiceErr_Unsupported;
return m_getProperty(property, result, size);
}
virtual DNSServiceErrorType processResult(DNSServiceRef sdRef) {
if (m_processResult == 0) return kDNSServiceErr_Unsupported;
return m_processResult(sdRef);
}
virtual DNSServiceErrorType createConnection(DNSServiceRef *sdRef) {
if (m_createConnection == 0) return kDNSServiceErr_Unsupported;
return m_createConnection(sdRef);
}
virtual int refSockFD(DNSServiceRef sdRef) {
if (m_refSockFD == 0) return kDNSServiceErr_Unsupported;
return m_refSockFD(sdRef);
}
};
ZConfLib *ZConfLib::createNativeLib(const QString &libName, ZConfLib *fallback) {
return new NativeZConfLib(libName, fallback);
return fallback;
}
} // namespace Internal
} // namespace ZeroConf
#else // no native lib
namespace ZeroConf {
namespace Internal {
ZConfLib *ZConfLib::createNativeLib(const QString &/*extraPaths*/, ZConfLib * fallback) {
return fallback;
}
} // namespace Internal
} // namespace ZeroConf
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,141 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#ifndef SERVICEBROWSER_H
#define SERVICEBROWSER_H
#include "zeroconf_global.h"
#include <QtCore/QHash>
#include <QtCore/QObject>
#include <QtCore/QSharedPointer>
#include <QtCore/QStringList>
class QHostInfo;
namespace ZeroConf {
namespace Internal {
class ServiceGatherer;
class MainConnection;
class ServiceBrowserPrivate;
}
typedef QSharedPointer<Internal::MainConnection> MainConnectionPtr;
typedef QHash<QString, QString> ServiceTxtRecord;
class ZEROCONFSHARED_EXPORT Service : public QObject
{
Q_OBJECT
friend class Internal::ServiceGatherer;
public:
typedef QSharedPointer<const Service> ConstPtr;
typedef QSharedPointer<Service> Ptr;
Service(const Service &o);
Service(QObject *parent = 0);
~Service();
bool outdated() const { return m_outdated; }
QString name() const { return m_name; }
QString type() const { return m_type; }
QString domain() const { return m_domain; }
QString fullName() const { return m_fullName; }
QString port() const { return m_port; }
const ServiceTxtRecord &txtRecord() const { return m_txtRecord; }
const QHostInfo *host() const { return m_host; }
int interfaceNr() const { return m_interfaceNr; }
bool invalidate() { bool res = m_outdated; m_outdated = true; return res; }
private:
QString m_name;
QString m_type;
QString m_domain;
QString m_fullName;
QString m_port;
ServiceTxtRecord m_txtRecord;
QHostInfo *m_host;
int m_interfaceNr;
bool m_outdated;
};
QDebug operator<<(QDebug dbg, const Service &service);
class ZEROCONFSHARED_EXPORT ServiceBrowser : public QObject
{
Q_OBJECT
friend class Internal::ServiceBrowserPrivate;
public:
ServiceBrowser(const QString &serviceType, const QString &domain = QLatin1String("local."), bool adressesRequired = true, QObject *parent = 0);
// this is here to avoid to instantiate a partially defined type (MainConnectionPtr)
ServiceBrowser(const QString &serviceType, const QString &domain, bool adressesRequired, QObject *parent, MainConnectionPtr mainConnection);
ServiceBrowser(const QString &serviceType, MainConnectionPtr mainConnection);
~ServiceBrowser();
MainConnectionPtr mainConnection();
bool startBrowsing(qint32 interfaceIndex = 0);
void stopBrowsing();
bool isBrowsing() const;
bool didFail() const;
const QString& serviceType() const;
const QString& domain() const;
bool adressesAutoResolved() const;
bool adressesRequired() const;
QList<Service::ConstPtr> services() const;
void reconfirmService(Service::ConstPtr service);
signals:
void serviceChanged(Service::ConstPtr oldService, Service::ConstPtr newService, ServiceBrowser *browser);
void serviceAdded(Service::ConstPtr service, ServiceBrowser *browser);
void serviceRemoved(Service::ConstPtr service, ServiceBrowser *browser);
void servicesUpdated(ServiceBrowser *browser);
void hadError(QStringList errorMsgs, bool completeFailure);
private:
Internal::ServiceBrowserPrivate *d;
};
enum LibUsage {
UseNativeOnly = 1,
UseEmbeddedOnly,
UseNativeOrEmbedded
};
void initLib(LibUsage usage, const QString &libName, const QString & daemonPaths);
}
#endif // SERVICEBROWSER_H

View File

@@ -0,0 +1,299 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#ifndef SERVICEBROWSER_P_H
#define SERVICEBROWSER_P_H
#include "dns_sd_types.h"
#include "servicebrowser.h"
#include <QtCore/QAtomicInt>
#include <QtCore/QHash>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QMutex>
#include <QtCore/QSharedPointer>
#include <QtCore/QStringList>
#include <QtCore/QThread>
class QHostInfo;
namespace ZeroConf {
namespace Internal {
// represents a zero conf library exposing the dns-sd interface
class ZConfLib {
public:
ZConfLib *fallbackLib;
ZConfLib(ZConfLib *fallBack);
virtual ~ZConfLib();
virtual QString name();
virtual bool tryStartDaemon();
virtual void refDeallocate(DNSServiceRef sdRef) = 0;
virtual DNSServiceErrorType resolve(DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
const char *name, const char *regtype, const char *domain,
DNSServiceResolveReply callBack, void *context) = 0;
virtual DNSServiceErrorType queryRecord(DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
const char *fullname, uint16_t rrtype, uint16_t rrclass,
DNSServiceQueryRecordReply callBack, void *context) = 0;
virtual DNSServiceErrorType getAddrInfo(DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceProtocol protocol, const char *hostname,
DNSServiceGetAddrInfoReply callBack, void *context) = 0;
// remove txt functions from lib and always embed?
virtual uint16_t DNSSD_API txtRecordGetCount(uint16_t txtLen, const void *txtRecord) = 0;
virtual DNSServiceErrorType DNSSD_API txtRecordGetItemAtIndex(uint16_t txtLen, const void *txtRecord,
uint16_t itemIndex, uint16_t keyBufLen, char *key,
uint8_t *valueLen, const void **value) = 0;
virtual DNSServiceErrorType reconfirmRecord(DNSServiceFlags flags, uint32_t interfaceIndex,
const char *fullname, uint16_t rrtype, uint16_t rrclass,
uint16_t rdlen, const void *rdata) = 0; // opt
virtual DNSServiceErrorType browse(DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
const char *regtype, const char *domain, DNSServiceBrowseReply callBack,
void *context) = 0;
virtual DNSServiceErrorType getProperty(const char *property, void *result, uint32_t *size) = 0;
virtual DNSServiceErrorType processResult(DNSServiceRef sdRef) = 0;
virtual DNSServiceErrorType createConnection(DNSServiceRef *sdRef) = 0;
virtual int refSockFD(DNSServiceRef sdRef) = 0;
bool isOk();
static ZConfLib *createEmbeddedLib(const QString &daemonPath, ZConfLib *fallback=0);
static ZConfLib *createNativeLib(const QString &libName, ZConfLib *fallback=0);
static ZConfLib *defaultLib();
private:
bool m_isOk;
};
/// class that gathers all needed info on a service, all its methods (creation included) are supposed to be called by the listener/reaction thread
class ServiceGatherer {
public:
QHash<QString, QString> txtRecord;
short port;
QString serviceName;
QString serviceType;
QString domain;
QString fullName;
QString hostName;
ServiceBrowserPrivate *serviceBrowser;
QHostInfo *host;
Service::Ptr publishedService;
Service *currentService;
typedef QSharedPointer<ServiceGatherer> Ptr;
enum Status{
ResolveConnectionFailed = 1 << 0,
ResolveConnectionActive = 1 << 1,
ResolveConnectionSuccess = 1 << 2,
TxtConnectionFailed = 1 << 3,
TxtConnectionActive = 1 << 4,
TxtConnectionSuccess = 1 << 5,
AddrConnectionFailed = 1 << 6,
AddrConnectionActive = 1 << 7,
AddrConnectionSuccess = 1 << 8
};
void enactServiceChange();
void retireService();
Ptr gatherer();
void stopResolve();
void stopTxt();
void stopHostResolution();
void restartResolve();
void restartTxt();
void restartHostResolution();
bool currentServiceCanBePublished();
~ServiceGatherer();
static Ptr createGatherer(const QString &newService, const QString &newType, const QString &newDomain,
const QString &fullName, uint32_t interfaceIndex, ServiceBrowserPrivate *serviceBrowser);
void serviceResolveReply(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 *rawTxtRecord);
void txtRecordReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype,
uint16_t rrclass, uint16_t txtLen, const void *rawTxtRecord, uint32_t ttl);
void addrReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address,
uint32_t ttl);
void maybeRemove();
void stop();
void reload(qint32 interfaceIndex=0);
void remove();
void reconfirm();
ZConfLib *lib();
private:
ServiceGatherer(const QString &newService, const QString &newType, const QString &newDomain,
const QString &fullName, uint32_t interfaceIndex, ServiceBrowserPrivate *serviceBrowser);
DNSServiceRef resolveConnection;
DNSServiceRef txtConnection;
DNSServiceRef addrConnection;
uint32_t interfaceIndex;
quint32 status;
QWeakPointer<ServiceGatherer> self;
};
//Q_DECLARE_METATYPE(Service::ConstPtr)
class ConnectionThread;
class MainConnection{
public:
enum RequestFlowStatus {
NormalRFS,
MoreComingRFS,
ForceUpdateRFS
};
RequestFlowStatus flowStatus;
enum {
// Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
LONG_TIME = 100000000
};
/// WARNING order matters in this enum, and status should only be changed with increaseStatusTo
enum Status {
Starting,
Started,
Running,
Stopping,
Stopped
};
ZConfLib *lib;
MainConnection();
~MainConnection();
QMutex *lock();
void waitStartup();
void stop(bool wait=true);
void addBrowser(ServiceBrowserPrivate *browser);
void removeBrowser(ServiceBrowserPrivate *browser);
void updateFlowStatusForCancel();
void updateFlowStatusForFlags(DNSServiceFlags flags);
void maybeUpdateLists();
QString tr(const char *s);
void gotoValidLib();
void abortLib();
void createConnection();
void destroyConnection();
bool handleEvent();
bool increaseStatusTo(int s);
void selectLoop();
void handleEvents();
DNSServiceRef mainRef();
QStringList errors();
void clearErrors();
void appendError(const QStringList &msgs,bool fullFailure);
bool isOk();
private:
mutable QMutex m_lock;
QList<ServiceBrowserPrivate *> m_browsers;
DNSServiceRef m_mainRef;
volatile int m_timeOut;
bool m_failed;
ConnectionThread *m_thread;
QAtomicInt m_status;
int m_nErrs;
bool m_useSelect;
QStringList m_errors;
};
class ServiceBrowserPrivate {
friend class ServiceBrowser;
public:
ServiceBrowser *q;
QString serviceType;
QString domain;
MainConnectionPtr mainConnection;
DNSServiceRef serviceConnection;
DNSServiceFlags flags;
uint32_t interfaceIndex;
QList<QString> knownServices;
QMap<QString, ServiceGatherer::Ptr> gatherers;
QList<Service::ConstPtr> activeServices;
QList<Service::ConstPtr> nextActiveServices;
QList<ServiceGatherer::Ptr> pendingGatherers;
bool failed;
bool browsing;
bool autoResolveAddresses;
bool requireAddresses;
DNSServiceRef mainRef();
void updateFlowStatusForCancel();
void updateFlowStatusForFlags(DNSServiceFlags flags);
void pendingGathererAdd(ServiceGatherer::Ptr gatherer);
ServiceBrowserPrivate(const QString &serviceType, const QString &domain, bool requireAddresses,
MainConnectionPtr conn);
~ServiceBrowserPrivate();
void insertGatherer(const QString &fullName);
void maybeUpdateLists();
bool startBrowsing(quint32 interfaceIndex);
void stopBrowsing();
void reconfirmService(Service::ConstPtr s);
void browseReply(DNSServiceRef sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName,
const char *regtype, const char *replyDomain);
void serviceChanged(const Service::ConstPtr &oldService, const Service::ConstPtr &newService, ServiceBrowser *browser);
void serviceAdded(const Service::ConstPtr &service, ServiceBrowser *browser);
void serviceRemoved(const Service::ConstPtr &service, ServiceBrowser *browser);
void servicesUpdated(ServiceBrowser *browser);
void hadError(QStringList errorMsgs, bool completeFailure);
};
class ConnectionThread: public QThread{
MainConnection &connection;
void run();
public:
ConnectionThread(MainConnection &mc, QObject *parent=0);
};
} // namespace Internal
} // namespace Zeroconf
#endif // SERVICEBROWSER_P_H

View File

@@ -0,0 +1,3 @@
INCLUDEPATH += $$PWD
LIBS *= -l$$qtLibraryName(zeroconf)

View File

@@ -0,0 +1,25 @@
QT -= gui
QT += network
TARGET = zeroconf
TEMPLATE = lib
DEFINES += ZEROCONF_LIBRARY
SOURCES += servicebrowser.cpp \
embeddedLib.cpp \
nativeLib.cpp \
mdnsderived.cpp
HEADERS += servicebrowser.h\
zeroconf_global.h \
dns_sd_types.h \
servicebrowser_p.h \
mdnsderived.h
include(../../qtcreatorlibrary.pri)
win32{
LIBS += -lws2_32
}

View File

@@ -0,0 +1,44 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#ifndef ZEROCONF_GLOBAL_H
#define ZEROCONF_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(ZEROCONF_LIBRARY)
# define ZEROCONFSHARED_EXPORT Q_DECL_EXPORT
#else
# define ZEROCONFSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // ZEROCONF_GLOBAL_H