Use Bonjour SDK for mDNS Discovering in Windows

原创 2016年08月29日 16:20:37


    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.



版权声明:本文歡迎轉載 但請留下原文出處

关于airplay协议实现镜像功能研究

最近在学习关于airplay相关协议,将了解到的内容记录下来,如有理解错误,请大神指正。   Airplay可以实现将设备中音频、视频、图像通过本地无线网络发送远端设备;Airplay功能实现利用...
  • b_xjie
  • b_xjie
  • 2014年09月26日 16:14
  • 13051

bonjour简单使用心得

前段时间因为项目需要,开始研究Bonjour,下面先来介绍下Bonjour吧。 1.什么是Bonjour? Bonjour这个词来源于法语,是“你好”的意思。在这里它是指由Apple推出的...
  • lhf19891003
  • lhf19891003
  • 2014年01月16日 09:42
  • 1950

Bonjour SDK

  • 2013年06月27日 22:49
  • 4.58MB
  • 下载

bonjourSDK工具包

  • 2011年07月03日 19:47
  • 4.58MB
  • 下载

bonjour

+###一.Bonjour介绍   4 +一般在进行Socket编程或者网络访问的时候,首先需要确认对方网络服务已经开启,且需要知道对方的域名或地址以及端口,然后才可以进行进...
  • li_yangyang_li
  • li_yangyang_li
  • 2016年02月23日 11:00
  • 242

bonjour windows 最新开发包

  • 2014年06月30日 22:16
  • 4.52MB
  • 下载

mDNS原理的简单理解

From: http://www.binkery.com/post/318.html mDNS multicast DNS , 使用5353端口。 在局域网内,你要通过一...
  • ustcxiangchun
  • ustcxiangchun
  • 2014年11月14日 14:40
  • 12846

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 ...
  • u013606170
  • u013606170
  • 2016年08月29日 16:20
  • 974

windows下批量下载android源码

安装git        源码下载地址https://android.googlesource.com/ 将下面的name下面的复制出来放到记事本下面   运行以下程序 import java...
  • jgszhuzhu
  • jgszhuzhu
  • 2012年11月10日 15:42
  • 668

局域网设备发现之Bonjour协议

WIFI物联网解决方案中,通常我们需要对设备进行绑定,需要通过某种方法先对设备进行发现,比如微信硬件采用广播的方式,定时向外发送上线消息或者采用一问一答的方式进行发现,Bonjour是由苹果公司实现的...
  • yueqian_scut
  • yueqian_scut
  • 2016年09月28日 23:37
  • 7240
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Use Bonjour SDK for mDNS Discovering in Windows
举报原因:
原因补充:

(最多只允许输入30个字)