forked from qt-creator/qt-creator
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:
@@ -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.
|
||||
|
||||
1364
src/libs/zeroconf/dns_sd_funct.h
Normal file
1364
src/libs/zeroconf/dns_sd_funct.h
Normal file
File diff suppressed because it is too large
Load Diff
1154
src/libs/zeroconf/dns_sd_types.h
Normal file
1154
src/libs/zeroconf/dns_sd_types.h
Normal file
File diff suppressed because it is too large
Load Diff
370
src/libs/zeroconf/embed/dnssd_clientlib.c
Normal file
370
src/libs/zeroconf/embed/dnssd_clientlib.c
Normal 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__ ")";
|
||||
}}
|
||||
1947
src/libs/zeroconf/embed/dnssd_clientstub.c
Normal file
1947
src/libs/zeroconf/embed/dnssd_clientstub.c
Normal file
File diff suppressed because it is too large
Load Diff
163
src/libs/zeroconf/embed/dnssd_ipc.c
Normal file
163
src/libs/zeroconf/embed/dnssd_ipc.c
Normal 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);
|
||||
}
|
||||
}}
|
||||
219
src/libs/zeroconf/embed/dnssd_ipc.h
Normal file
219
src/libs/zeroconf/embed/dnssd_ipc.h
Normal 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
|
||||
193
src/libs/zeroconf/embeddedLib.cpp
Normal file
193
src/libs/zeroconf/embeddedLib.cpp
Normal 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
|
||||
117
src/libs/zeroconf/mdnsderived.cpp
Normal file
117
src/libs/zeroconf/mdnsderived.cpp
Normal 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
|
||||
42
src/libs/zeroconf/mdnsderived.h
Normal file
42
src/libs/zeroconf/mdnsderived.h
Normal 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
|
||||
301
src/libs/zeroconf/nativeLib.cpp
Normal file
301
src/libs/zeroconf/nativeLib.cpp
Normal 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
|
||||
|
||||
1521
src/libs/zeroconf/servicebrowser.cpp
Normal file
1521
src/libs/zeroconf/servicebrowser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
141
src/libs/zeroconf/servicebrowser.h
Normal file
141
src/libs/zeroconf/servicebrowser.h
Normal 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
|
||||
299
src/libs/zeroconf/servicebrowser_p.h
Normal file
299
src/libs/zeroconf/servicebrowser_p.h
Normal 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
|
||||
3
src/libs/zeroconf/zeroconf.pri
Normal file
3
src/libs/zeroconf/zeroconf.pri
Normal file
@@ -0,0 +1,3 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
LIBS *= -l$$qtLibraryName(zeroconf)
|
||||
25
src/libs/zeroconf/zeroconf.pro
Normal file
25
src/libs/zeroconf/zeroconf.pro
Normal 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
|
||||
}
|
||||
|
||||
44
src/libs/zeroconf/zeroconf_global.h
Normal file
44
src/libs/zeroconf/zeroconf_global.h
Normal 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
|
||||
Reference in New Issue
Block a user