关闭

Use Bonjour SDK for mDNS Discovering in Windows

565人阅读 评论(0) 收藏 举报
分类:


    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
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:30369次
    • 积分:746
    • 等级:
    • 排名:千里之外
    • 原创:46篇
    • 转载:0篇
    • 译文:0篇
    • 评论:2条
    文章分类
    最新评论