垓恪兮編程雜記

台灣碼工之編程手記

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.



阅读更多
版权声明:本文歡迎轉載 但請留下原文出處 https://blog.csdn.net/u013606170/article/details/52354189
个人分类: windows
想对作者说点什么? 我来说一句

Bonjour SDK

2013年06月27日 4.58MB 下载

Bonjour SDK 3.0

2017年07月05日 8.28MB 下载

Bonjour_64bit for windows

2014年05月21日 1.12MB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭