Use Bonjour SDK for mDNS Discovering in Windows



    How to use Bonjour SDK for mDNS is rut, but I found that in the website, there is no simple example WITHOUT window to demonstrate how exploit this library. In the post, I would fill the gap.


   零. Download the Bonjour Library.

       You could download the library in Apple webisite. The apple id is requisite. After you have installed the SDK, check if your Bonjour Service is running or not.


If the service is not running, Download and installed the Bonjour Service .


一.  Create a Visual Studio Project, Copy the Bonjour SDK folders: include and LIB (by default, they locates in C:\Program Files\Bonjour SDK) into the project folder, and add include path and library path refering to them:





 Of course, you should add dnssd.lib as your library reference.

二.

  The discovering code be :

#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "IPHLPAPI.lib")

#include <iphlpapi.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "dns_sd.h"

#pragma comment(lib, "Ws2_32.lib")

#define    MAX_STR_LEN    (256)

#ifdef _DEBUG
#define LOG(fmt, ...)    fprintf(stderr, fmt, __VA_ARGS__)
#else
#define LOG(fmt, ...) /* Don't do anything in release builds */
#endif

#define SAFE_FREE(PTR)     if(NULL != (PTR))\
           free(PTR);\
          PTR = NULL



typedef struct ServiceInfo
{
 char *pServiceType;
 char *pServiceName;
 char *pDomainName;
 unsigned int serviceInterface;
 char *pProtocolNumber;
 char *pAddr;
 unsigned short port;
 char *pHostName;
 char *pText;

 DNSServiceRef sdRef;

 struct ServiceInfo *pNext;

}ServiceInfo, ServiceInfoList;

typedef void(__stdcall *mDNSBrowingCallbackFunPtr)
(
char *pServiceType,
char *pServiceName,
char *pDomainName,
char serviceInterface,
char *pProtocolNumber,
char *pAddr,
unsigned short port,
char *pHostName,
char *pText
);

HANDLE m_browingThreadHandle = NULL;
DWORD m_idBrowsingThread = 0;
UINT_PTR m_browsingTimerId;

ServiceInfoList *m_pServiceInfoList = NULL;


const unsigned char unUsedServiceInfoMemHead[] =
{
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
}; //the impossible memory location value


ServiceInfoList *CreateServiceInfoList(void)
{
 ServiceInfo *pServiceInfo;

 pServiceInfo = (ServiceInfo*)malloc(sizeof(ServiceInfo));
 memset(pServiceInfo, (unsigned char)0xff, sizeof(ServiceInfo));

 return pServiceInfo;
}/*CreateServiceInfoList*/


ServiceInfo *CreateServiceInfoNode(ServiceInfoList *pServiceInfoList, DNSServiceRef sdRef)
{
 ServiceInfo *pCurrent;

 if (NULL == pServiceInfoList)
  return NULL;
 
 pCurrent = pServiceInfoList;

 if (0 == memcmp(pServiceInfoList, &unUsedServiceInfoMemHead[0],
  sizeof(unUsedServiceInfoMemHead)) )
 {
  memset(m_pServiceInfoList, 0, sizeof(ServiceInfo));

  pCurrent->sdRef = sdRef;
  return pCurrent;
 }/*if */

 while (NULL != pCurrent->pNext)
  pCurrent = pCurrent->pNext;

 pCurrent->pNext = (ServiceInfo*)malloc(sizeof(ServiceInfo));
 pCurrent = pCurrent->pNext;

 memset(pCurrent, (unsigned char)0x00, sizeof(ServiceInfo));

 pCurrent->sdRef = sdRef;

 return pCurrent;
}/*CreateServiceInfoNode*/


void CleanServiceInfoData(ServiceInfo *pServiceInfo)
{
 if (NULL == pServiceInfo)
  return;

 SAFE_FREE(pServiceInfo->pServiceType); SAFE_FREE(pServiceInfo->pServiceName);
 SAFE_FREE(pServiceInfo->pDomainName);
 //pServiceInfo->serviceInterface;
 SAFE_FREE(pServiceInfo->pProtocolNumber);
 SAFE_FREE(pServiceInfo->pAddr); SAFE_FREE(pServiceInfo->pHostName);

 if (NULL != pServiceInfo->pText)
  free(pServiceInfo->pText);
 pServiceInfo->pText = NULL;

}/*CleanServiceInfoData*/


void DestroyServiceInfo(ServiceInfo **ppServiceInfo)
{
 CleanServiceInfoData(*ppServiceInfo);
 SAFE_FREE(*ppServiceInfo);
}/*DestoryServiceInfo*/


void DestroyServiceInfoList(ServiceInfoList **ppServiceInfoList)
{
 ServiceInfo *pCurrent;

 pCurrent = *ppServiceInfoList;

 if (0 == memcmp(pCurrent, &unUsedServiceInfoMemHead[0],
  sizeof(unUsedServiceInfoMemHead)))
 {
  SAFE_FREE(pCurrent);
  return;
 }/*if unused*/

 while (NULL != pCurrent)
 {
  ServiceInfo *pNext;

  pNext = pCurrent->pNext;
  DestroyServiceInfo(&pCurrent);
  pCurrent = pNext;
 }/*while*/

 *ppServiceInfoList = NULL;
}/*CleanServiceInfoList*/


int GetServiceInfoListLength(ServiceInfoList *pServiceInfoList)
{
 int i;
 ServiceInfo *pCurrent;

 if (NULL == pServiceInfoList)
  return -1;

 if (0 == memcmp(pServiceInfoList, &unUsedServiceInfoMemHead[0],
  sizeof(unUsedServiceInfoMemHead)))
 {
  return 0;
 }/*if */


 pCurrent = pServiceInfoList;
 i = 0;
 while (NULL != pCurrent)
 {
  pCurrent = pCurrent->pNext;
  i++;
 }/*while*/

 return i;
}/*GetServiceInfoListLength*/


void RemoveSpecificServiceInfoNode(
 ServiceInfoList *pServiceInfoList, DNSServiceRef sdRef)
{
 ServiceInfo *pCurrent, *pPrevious;
 int n;

 n = GetServiceInfoListLength(pServiceInfoList);
 pCurrent = pServiceInfoList;

 if (0 == n)
  return;

 if (1 == n)
 {
  if (pCurrent->sdRef == sdRef)
  {
   memset(pCurrent, 0xff, sizeof(ServiceInfo));
   return;
  }/*if */

 }/*if 1 == n*/

 /*if 1 < n  and i == 0*/
 if (pCurrent->sdRef == sdRef)
 {
  ServiceInfo *p2ndNode;

  p2ndNode = pCurrent->pNext;

  memcpy(pCurrent, p2ndNode, sizeof(ServiceInfo));
  DestroyServiceInfo(&p2ndNode); p2ndNode = NULL;
  return ;
 }/*if */

 
 pPrevious = pCurrent;
 pCurrent = pCurrent->pNext;

 while (NULL != pCurrent)
 {
  if (pCurrent->sdRef == sdRef)
  {
   pPrevious->pNext = pCurrent->pNext;
   DestroyServiceInfo(&pCurrent);
   break;
  }
  pPrevious = pCurrent;
  pCurrent = pCurrent->pNext;
 }/*if */

}/*RemoveSpecificServiceInfoNode*/


ServiceInfo *FindSpecificServiceInfoNode(
 ServiceInfoList *pServiceInfoList, DNSServiceRef sdRef)
{
 ServiceInfo *pCurrent;

 pCurrent = pServiceInfoList;

 while (NULL != pCurrent)
 {
  if (pCurrent->sdRef == sdRef)
   break;

  pCurrent = pCurrent->pNext;
 }/*if */

 return pCurrent;
}/*FindSpecificServiceInfoNode*/


void DNSSD_API ServiceGetAddressInfoCallback(DNSServiceRef sdRef,
 DNSServiceFlags flags,
 uint32_t interfaceIndex,
 DNSServiceErrorType errorCode,
 const char *pHostname,
 const struct sockaddr *pAddress,
 uint32_t ttl,
 void *pContext)
{
 if (0 == errorCode) 
 {
  const struct sockaddr_in *in = (const struct sockaddr_in *)pAddress;
  ServiceInfo *pNode;
  pNode = FindSpecificServiceInfoNode(m_pServiceInfoList, sdRef);

  if (NULL != pNode)
  {
   char temp[MAX_STR_LEN];
   memset(&temp[0], 0, MAX_STR_LEN);

   inet_ntop(AF_INET, (PVOID)&in->sin_addr, &temp[0], MAX_STR_LEN);
   pNode->pAddr = _strdup(&temp[0]);
   
   pNode->pProtocolNumber = _strdup("IPv4");
   pNode->pHostName = _strdup(pHostname);
  }

  if (NULL != pContext)
  {
   mDNSBrowingCallbackFunPtr callbackPtr;
   callbackPtr = (mDNSBrowingCallbackFunPtr)pContext;
   callbackPtr(pNode->pServiceType, pNode->pServiceName, pNode->pDomainName,
    pNode->serviceInterface, pNode->pProtocolNumber, pNode->pAddr,
    pNode->port, pNode->pHostName, pNode->pText);
  }

 }/*if 0 == errorCode*/

 //if (0 == (flags & kDNSServiceFlagsMoreComing)) {}

}/*ServiceGetAddressInfoCallback*/


void DNSSD_API ResolveServiceCallback(DNSServiceRef sdRef,
 DNSServiceFlags flags,
 uint32_t interfaceIndex,
 DNSServiceErrorType errorCode,
 const char *pFullname,
 const char *pHosttarget,
 uint16_t port,
 uint16_t txtLen,
 const unsigned char *pTxtRecord,
 void *pContext)
{
 char organizedTxt[MAX_STR_LEN];
 MIB_IFROW IfRow;
 DNSServiceRef client;
 DWORD result;

 DNSServiceErrorType err;
 int i;
 LOG("%s\n", __FUNCTION__);

 if (0 != errorCode)
 {
  LOG("errorCode = %d\n", errorCode);
  return;
 }/*if 0 != errorCode*/

 memset(&organizedTxt[0], 0, MAX_STR_LEN);

 for (i = 0; i < txtLen; i++){
  char c;
  c = pTxtRecord[i];

  if (0x20 > c || '/' == c)
   c = '\n';

  organizedTxt[i] = c;
 }/*for i*/
 organizedTxt[strlen(&organizedTxt[0])] = '\n';


 IfRow.dwIndex = interfaceIndex;
 result = GetIfEntry(&IfRow);

 if (0 != result)
 {
  LOG("Error in GetIfEntry , error code = %d\n", result);
  return ;
 }/*if 0 != result*/

 client = NULL;

 err = DNSServiceGetAddrInfo(&client,
  kDNSServiceFlagsTimeout,
  interfaceIndex,
  kDNSServiceProtocol_IPv4,
  pHosttarget,
  ServiceGetAddressInfoCallback,
  pContext);

 if (0 == err) 
 {
  ServiceInfo *pNode;
  pNode = FindSpecificServiceInfoNode(m_pServiceInfoList, sdRef);


  if (NULL != pNode)
  {
   pNode->serviceInterface = interfaceIndex;
   pNode->port = ((0xff & port) << 8) + (port >> 8);

   if (0 == pTxtRecord || 0 == pTxtRecord[0])
    pNode->pText = NULL;
   else
    pNode->pText = _strdup(&organizedTxt[0]);

   //for next callback, the sdRef has been change, it is nessary to 
   //update the sdRef value for specifying the parameters in correct groups.
   pNode->sdRef = client;
  }/*if NULL != pNode */

  LOG("Looking up %s on %s\n", pHosttarget, IfRow.bDescr);
 }
 else 
 {
  LOG("Error looking up address info for %s\n", pHosttarget);
 }/*if 0 == err*/

}/*ResolveServiceCallback*/


void DNSSD_API IterateServiceNameCallback(DNSServiceRef sdRef,
 DNSServiceFlags flags,
 uint32_t interfaceIndex,
 DNSServiceErrorType errorCode,
 const char *pServiceName,
 const char *pRegtype,
 const char *pReplyDomain,
 void *context)
{
 LOG("%s\n", __FUNCTION__);

 if (0 == errorCode && (flags & kDNSServiceFlagsAdd))
 {
   DNSServiceRef client = NULL;
   DNSServiceErrorType err = DNSServiceResolve(&client,
    0,
    interfaceIndex,
    pServiceName,
    pRegtype,
    pReplyDomain,
    ResolveServiceCallback,
    context);

   if (0 == err) 
   {
    ServiceInfo *pNode;
    pNode = FindSpecificServiceInfoNode(m_pServiceInfoList, sdRef);

    if (NULL != pNode)
    {
     pNode->pServiceName = _strdup(pServiceName);
     pNode->pServiceType = _strdup(pRegtype);
     pNode->pDomainName = _strdup(pReplyDomain);

     //for next callback, the sdRef has been change, it is nessary to 
     //update the sdRef value 
     //for specifying the parameters in correct groups.
     pNode->sdRef = client; 
    }/*if NULL != pNode*/
   }
   else
   {
    LOG("Error trying to browse service instance: %s", pServiceName);
   }
 }
 //if (0 == (kDNSServiceFlagsMoreComing & flags)){}

}/*IterateServiceNameCallback*/


void DNSSD_API IterateServiceTypesCallback(DNSServiceRef sdRef,
 DNSServiceFlags flags,
 uint32_t interfaceIndex,
 DNSServiceErrorType errorCode,
 const char *pServiceName,
 const char *pRegtype,
 const char *pReplyDomain,
 void *pContext)
{
 LOG("%s\n", __FUNCTION__);

 if (0 == errorCode && (kDNSServiceFlagsAdd & flags))
 {
  unsigned int len, copyLen;
  char serviceType[MAX_STR_LEN];
  memset(&serviceType[0], 0, MAX_STR_LEN);
  
  {
   unsigned int i;

   len = strlen(pRegtype);
   copyLen = len;

   if ('.' == pRegtype[len - 1])
    len -= 1;

   for (i = len - 1; i >= 0; i--){
    if ('.' == pRegtype[i]){
     copyLen = i;
     break;
    }
   }/*for i*/
   strncpy_s(&serviceType[0], MAX_STR_LEN, pServiceName, strlen(pServiceName));
   strncat_s(&serviceType[0], MAX_STR_LEN, ".", 1);
   strncat_s(&serviceType[0], MAX_STR_LEN, pRegtype, copyLen);
   strncat_s(&serviceType[0], MAX_STR_LEN, ".", 1);
  }/*local variable*/


  {
   DNSServiceRef client;
   DNSServiceErrorType err;

   err = DNSServiceBrowse(&client, 0, 0,&serviceType[0], "", 
    IterateServiceNameCallback, pContext);

   LOG("Browsing for instances of %s\n", &serviceType[0]);

   if (0 == err)
    CreateServiceInfoNode(m_pServiceInfoList, client);
   else 
    LOG("Error trying to browse service type: %s\n", &serviceType[0]);
  }/*local variable*/

 }/*if 0 == errorCode && (kDNSServiceFlagsAdd & flags) */


 if (0 == (kDNSServiceFlagsMoreComing & flags))
  RemoveSpecificServiceInfoNode(m_pServiceInfoList, sdRef);

 return;
}/*IterateServiceTypesCallback*/


#define BROWERING_INTERVAL     (250)

void CALLBACK BrowingTimerCallback(HWND hwnd, UINT uMsg, UINT timerId, DWORD dwTime)
{
 int count = 0;

 while (1)
 {
  fd_set readfds;
  ServiceInfo *pCurrent;
  struct timeval tv = { 0, 1000 };

  if (0 == GetServiceInfoListLength(m_pServiceInfoList))
  {
   LOG("Done browsing\n");
   KillTimer(NULL, m_browsingTimerId);
   break;
  }
 
  FD_ZERO(&readfds);

  pCurrent = m_pServiceInfoList;

  while (NULL != pCurrent)
  {
   FD_SET(DNSServiceRefSockFD(pCurrent->sdRef), &readfds);
   pCurrent = pCurrent->pNext;
  }

  if (0 < select(0, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv))
  {
   //
   // While iterating through the loop, the callback functions might delete
   // the client pointed to by the current iterator, so I have to increment
   // it BEFORE calling DNSServiceProcessResult
   //
   
   pCurrent = m_pServiceInfoList;

   while (NULL != pCurrent)
   {
    if (FD_ISSET(DNSServiceRefSockFD(pCurrent->sdRef), &readfds))
    {
     DNSServiceErrorType err 
      = DNSServiceProcessResult(pCurrent->sdRef);

     if (++count > 10)
      break;
    }
    pCurrent = pCurrent->pNext;
   }/*while */

  }
  else
   break;
  if (count > 10)
   break;
 }/*while 1*/

}/*BrowingTimerCallback*/


DWORD WINAPI BrowsingThread(LPVOID lpParam)
{
 MSG msg;
 DNSServiceRef client = NULL;

 DNSServiceErrorType err = DNSServiceBrowse(&client, 0, 0,
  "_services._dns-sd._udp", "", IterateServiceTypesCallback, (void*)lpParam);

 if (0 == err) 
 {
  LOG("Browsing for service types using _services._dns-sd._udp\n");
  SetTimer(NULL, 0, BROWERING_INTERVAL,
   (TIMERPROC)&BrowingTimerCallback);

  CreateServiceInfoNode(m_pServiceInfoList, client);
 }
 else 
 {
  LOG("Error starting discovery: %d\n", err);
 }/*if */


 while (FALSE != GetMessage(&msg, NULL, 0, 0))
 {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
 }/*while*/

 return 0;
}/*BrowsingThread*/


void mDNSBrowsingStop(void)
{
 KillTimer(NULL, m_browsingTimerId);

 if (0 != m_idBrowsingThread)
  PostThreadMessage(m_idBrowsingThread, WM_QUIT, 0, 0);
 m_idBrowsingThread = 0;

 if (NULL != m_browingThreadHandle)
  WaitForSingleObject(m_browingThreadHandle, 5 * 1000);
 m_browingThreadHandle = NULL;

 m_pServiceInfoList = NULL;
}/*mDNSStopmiscover*/


int mDNSBrowsingStart(mDNSBrowingCallbackFunPtr browingResultFunPtr)
{
 mDNSBrowsingStop();

 m_pServiceInfoList = CreateServiceInfoList();
 m_browingThreadHandle = CreateThread(NULL, 0,
  BrowsingThread, browingResultFunPtr, 0, &m_idBrowsingThread);

 if (NULL == m_browingThreadHandle)
  return -1;

 return 0;
}/*mDNSDiscoverStart*/


void __stdcall mDNSBrowingResult(
 char *pServiceType,
 char *pServiceName,
 char *pDomainName,
 char serviceInterface,
 char *pProtocolNumber,
 char *pAddr,
 unsigned short port,
 char *pHostName,
 char *pText
 )
{
 printf("\n");
 printf("\tServiceType : %s\n", pServiceType);
 printf("\tServiceName : %s\n", pServiceName);
 
 printf("\tDomainName : %s\n", pDomainName);

 printf("\tInterface : %d\n", serviceInterface);
 printf("\tProtocol Number : %s\n", pProtocolNumber);
 printf("\tAddress : %s\n", pAddr);
 printf("\tport : %d\n", port);
 printf("\tHostName : %s\n", pHostName);
 printf("\tText : ");

 if (NULL == pText || '\n' == pText[0] && '\n' == pText[1])
 {
  HANDLE  hConsole;

  hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
  SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN | 
   FOREGROUND_BLUE | FOREGROUND_INTENSITY);
  
  printf("NULL\n");

  SetConsoleTextAttribute(hConsole, FOREGROUND_RED 
   | FOREGROUND_GREEN | FOREGROUND_BLUE);
  printf("\n");
 }
 else
 {
  printf("%s\n", pText);
 }
 printf("\n");

}/*mDNSBrowingResult*/


int main(int argc, char *argv[])
{
#if(0)
 WSADATA wsaData;

 if (0 != WSAStartup(MAKEWORD(2, 0), &wsaData))
  return -1;
#endif

 mDNSBrowsingStart(mDNSBrowingResult);

 getchar();

 mDNSBrowsingStop();
#if(0) 
 WSACleanup();
#endif
 return 0;
}/*main*/


After press Play (build and run) button, the discovering result would be printed in the console.



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值