11.3 Multicast Socket Code Example

To illustrate the functionality, a simple example is implemented where the host application responds to mDNS (Multicast Domain Name System) queries sent from a computer/mobile application. The computer/mobile is looking for devices which support the zero configuration service as indicated by an mDNS response. The WINC responds, notifying its presence and its capability of sending and receiving multicast messages.

The example consists of a UDP server that binds on port 5353 (mDNS port) and waits for messages, parsing them and replying with a previously saved response message.

  • Server Initialization:
void MDNS_ServerInit()
{
	tstrSockAddr	strAddr ;
	unsigned int MULTICAST_IP =  0xE00000FB; //224.0.0.251
	socketInit();
	dns_server_sock = socket( AF_INET, SOCK_DGRAM,0);
	MDNS_INFO("DNS_server_init \n");
	setsockopt(dns_server_sock,1,IP_ADD_MEMBERSHIP,&MULTICAST_IP,sizeof(MULTICAST_IP));
	strAddr.u16Port	=HTONS(MDNS_SERVER_PORT);
	bind(dns_server_sock,(struct sockaddr*)&strAddr,sizeof(strAddr));
	registerSocketCallback(UDP_SocketEventHandler,AppServerCb);
}
  • Sockets Events Handler:
void MDNS_RecvfromCB(signed char sock,unsigned char *pu8RxBuffer,signed short s16DataSize,
			unsigned char *pu8IPAddr,unsigned short u16Port,void *pvArg)
{
	MDNS_INFO("DnsServer_RecvfromCB \n");
	if((pu8RxBuffer != 0) && (s16DataSize > 0))
	{
		tstrDnsHdr strDnsHdr;
		strdnsquery;
		MDNS_INFO("DNS Packet Recieved  \n");

		if(MDNS_ParseQuery(&pu8RxBuffer[0], &strDnsHdr,&strDnsQuery))
			MDNS_SendResp (sock,pu8IPAddr, u16Port,&strDnsHdr,&strDnsQuery );
	}
	else
	{
		MDNS_INFO("DnsServer_RecvfromCB Error !\n");
	}
}
  • Server Socket Callback:
void MDNS_RecvfromCB(signed char  sock,unsigned char *pu8RxBuffer,signed short s16DataSize,unsigned char *pu8IPAddr,unsigned short u16Port,void *pvArg)
{
	MDNS_INFO("DnsServer_RecvfromCB \n");
	if((pu8RxBuffer != 0) && (s16DataSize > 0))
	{
		tstrDnsHdr strDnsHdr  ;
		strdnsquery ;
		MDNS_INFO("DNS Packet Recieved  \n");

		if(MDNS_ParseQuery(&pu8RxBuffer[0], &strDnsHdr,&strDnsQuery))
		MDNS_SendResp (sock,pu8IPAddr, u16Port,&strDnsHdr,&strDnsQuery );
	}
	else
	{
		MDNS_INFO("DnsServer_RecvfromCB Error !\n");
	}
}
  • Parse mDNS Query:
int MDNS_ParseQuery(unsigned char * pu8RxBuffer, tstrDnsHdr *pstrDnsHdr, strdnsquery *pstrDnsQuery  )
{
	unsigned char  dot_size,temp=0;
	unsigned short n=0,i=0,u16index=0;
	int	bDNSmatch = 0;
	/*  ----Identification--------------------------|QR|	Opcode       |AA|TC|RD|RA|Z|AD|CD|Rcode   | */
	/*	----Total Questions------------------------|-----------------Total Answer RRs---------------*/
	/*	----Total Authority RRs	--------------------|----------------Total Additional RRs------------*/
	/*	---------------------------------      Questions	  --------------------------------- */
	/*	------------------------------------ Answer RRs	  ------------------------------------------*/
	/*	----------------------------------- Authority RRs	  ----------------------------------*/
	/*	-----------------------------------Additional RRs	  ----------------------------------*/
	MDNS_INFO("Parsing DNS Packet\n");
	pstrDnsHdr->id = (( pu8RxBuffer[u16index]<<8)| (pu8RxBuffer[u16index+1]));
	MDNS_INFO ("id =  %.4x \n",pstrDnsHdr->id);
	u16index+=2;
	pstrDnsHdr->flags1= pu8RxBuffer[u16index++];
	pstrDnsHdr->flags2= pu8RxBuffer[u16index++];
	MDNS_INFO ("flags =  %.2x %.2x \n",pstrDnsHdr->flags1,pstrDnsHdr->flags2);
	pstrDnsHdr->numquestions = ((pu8RxBuffer[u16index]<<8)| (pu8RxBuffer[u16index+1]));
	MDNS_INFO ("numquestions =  %.4x \n",pstrDnsHdr->numquestions);
	u16index+=2;
	pstrDnsHdr->numanswers = ((pu8RxBuffer[u16index]<<8)| (pu8RxBuffer[u16index+1]));
	MDNS_INFO ("numanswers =  %.4x \n",pstrDnsHdr->numanswers);
	u16index+=2;
	pstrDnsHdr->numauthrr = ((pu8RxBuffer[u16index]<<8)| (pu8RxBuffer[u16index+1]));
	MDNS_INFO ("numauthrr =  %.4x \n",pstrDnsHdr->numauthrr);
	u16index+=2;
	pstrDnsHdr->numextrarr = ((pu8RxBuffer[u16index]<<8)| (pu8RxBuffer[u16index+1]));
	MDNS_INFO ("numextrarr =  %.4x \n",pstrDnsHdr->numextrarr);
	u16index+=2;
	dot_size =pstrDnsQuery->query[n++]= pu8RxBuffer[u16index++];
	pstrDnsQuery->u16size=1;
	while (dot_size--!=0) //(pu8RxBuffer[++u16index] != 0)
	{
		pstrDnsQuery->query[n++]=pstrDnsQuery->queryForChecking[i++]=pu8RxBuffer[u16index++] ;
		pstrDnsQuery->u16size++;
		gu8pos=temp;
		if (dot_size == 0 )
		{
			pstrDnsQuery->queryForChecking[i++]= '.' ;
			temp=u16index;
			dot_size =pstrDnsQuery->query[n++]= pu8RxBuffer[u16index++];
			pstrDnsQuery->u16size++;
		}
	}
	pstrDnsQuery->queryForChecking[--i] = 0;

	MDNS_INFO("parsed query <%s>\n",pstrDnsQuery->queryForChecking);
	// Search for any match in the local DNS table.
	for(n = 0; n < DNS_SERVER_CACHE_SIZE; n++)
	{
		MDNS_INFO("Saved URL <%s>\n",gpacDnsServerCache[n]);
		if(strcmp(gpacDnsServerCache[n], pstrDnsQuery->queryForChecking) ==0)
		{
			bDNSmatch= 1;
			MDNS_INFO("MATCH \n");
		}
		else
		{
		MDNS_INFO("Mismatch\n");
		}
	}
	pstrDnsQuery->u16class = ((pu8RxBuffer[u16index]<<8)| (pu8RxBuffer[u16index+1]));
	u16index+=2;
	pstrDnsQuery->u16type= ((pu8RxBuffer[u16index]<<8)| (pu8RxBuffer[u16index+1]));
	return bDNSmatch;
}
  • Send mDNS Response:
void MDNS_SendResp (signed char sock,unsigned char * pu8IPAddr,
	unsigned short u16Port,tstrDnsHdr *pstrDnsHdr,strdnsquery *pstrDnsQuery)
{
	unsigned short u16index=0;
	tstrSockAddr strclientAddr ;
	unsigned char * pu8sendBuf;
	char * serviceName2 = (char*)malloc(sizeof(serviceName)+1);
	unsigned int MULTICAST_IP =  0xFB0000E0;
	pu8sendBuf= gPu8Buf;
	memcpy(&strclientAddr.u32IPAddr,&MULTICAST_IP,IPV4_DATA_LENGTH);
	strclientAddr.u16Port=u16Port;
	MDNS_INFO("%s \n",pstrDnsQuery->query);
	MDNS_INFO("Query Size = %d \n",pstrDnsQuery->u16size);
	MDNS_INFO("class = %.4x \n",pstrDnsQuery->u16class);
	MDNS_INFO("type  = %.4x \n",pstrDnsQuery->u16type);
	MDNS_INFO("PREPARING DNS ANSWER BEFORE SENDING\n");

	/*----------------------------ID 2 Bytes -----------------------------*/
	pu8sendBuf [u16index++] =0;  //( pstrDnsHdr->id>>8);
	pu8sendBuf [u16index++] =  0;//( pstrDnsHdr->id)&(0xFF);
	MDNS_INFO ("(ResPonse) id = %.2x %.2x  \n", pu8sendBuf[u16index-2],pu8sendBuf[u16index-1]);
	/*----------------------------Flags 2 Bytes----------------------------*/
	pu8sendBuf [u16index++] =  DNS_RSP_FLAG_1;
	pu8sendBuf [u16index++] =  DNS_RSP_FLAG_2;
	MDNS_INFO ("(ResPonse) Flags = %.2x %.2x  \n", pu8sendBuf[u16index-2],pu8sendBuf[u16index-1]);
	/*----------------------------No of Questions--------------------------*/
	pu8sendBuf [u16index++] =0x00;
	pu8sendBuf [u16index++] =0x01;
	MDNS_INFO ("(ResPonse) Questions  = %.2x %.2x  \n", pu8sendBuf[u16index-2],pu8sendBuf[u16index-1]);
	/*---------------------------No of Answers----------------------------*/
	pu8sendBuf [u16index++] =0x00;
	pu8sendBuf [u16index++] =0x01;
	MDNS_INFO ("(ResPonse) Answers = %.2x %.2x  \n", pu8sendBuf[u16index-2],pu8sendBuf[u16index-1]);
	/*---------------------------No of Authority RRs------------------------*/
	pu8sendBuf [u16index++] =0x00;
	pu8sendBuf [u16index++] =0x00;
	MDNS_INFO ("(ResPonse) Authority RRs = %.2x %.2x  \n", pu8sendBuf[u16index-2],pu8sendBuf[u16index-1]);
	/*----------------------------No of Additional RRs----------------------*/
	pu8sendBuf [u16index++] =0x00;
	pu8sendBuf [u16index++] =0x00;
	MDNS_INFO ("(ResPonse) Additional RRs = %.2x %.2x  \n", pu8sendBuf[u16index-2],pu8sendBuf[u16index-1]);
	/*--------------------------------Query-----------------------------*/
	memcpy(&pu8sendBuf[u16index],pstrDnsQuery->query,pstrDnsQuery->u16size);
	MDNS_INFO("\nsize = %d \n",pstrDnsQuery->u16size);
	u16index+=pstrDnsQuery->u16size;
	/*-------------------------------Query Type----------------------------*/
	pu8sendBuf [u16index++] = ( pstrDnsQuery->u16type>>8);//MDNS_TYPE>>8;
	pu8sendBuf [u16index++] = ( pstrDnsQuery->u16type)&(0xFF);//(MDNS_TYPE&0xFF);
	MDNS_INFO ("Query Type =  %.2x %.2x \n", pu8sendBuf[u16index-2],pu8sendBuf[u16index-1]);
	/*------------------------------Query Class-----------------------------------*/
	pu8sendBuf [u16index++] =MDNS_CLASS>>8;//(( pstrDnsQuery->u16class>>8)|0x80);
	pu8sendBuf [u16index++] = (MDNS_CLASS & 0xFF);//( pstrDnsQuery->u16class)&(0xFF);
	MDNS_INFO ("Query Class =  %.2x %.2x \n", pu8sendBuf[u16index-2],pu8sendBuf[u16index-1]);

	/*########################Answers#########################*/
	/*------------------------------Name---------------------------------*/
	pu8sendBuf [u16index++]=  0xC0 ; //pointer to query name location
	pu8sendBuf [u16index++]= 0x0C ; // instead of writing the whole query name again
	/*-----------------------------Type----------------------------------*/
	pu8sendBuf [u16index++] =MDNS_TYPE>>8;  //Type 12 PTR (domain name Pointer).
	pu8sendBuf [u16index++] =(MDNS_TYPE&0xFF);
	/*------------------------------Class-----------------------------------*/
	pu8sendBuf [u16index++] =0x00;//MDNS_CLASS;  //Class IN, Internet.
	pu8sendBuf [u16index++] =0x01;// (MDNS_CLASS & 0xFF);
	/*-----------------------------TTL----------------------------------*/
	pu8sendBuf [u16index++] =(TIME_TO_LIVE >>24);
	pu8sendBuf [u16index++] =(TIME_TO_LIVE >>16);
	pu8sendBuf [u16index++] =(TIME_TO_LIVE >>8);
	pu8sendBuf [u16index++] =(TIME_TO_LIVE );
	/*---------------------------Date Length----------------------------------*/
	pu8sendBuf [u16index++] =(sizeof(serviceName)+2)>>8;//added 2 bytes for the pointer
	pu8sendBuf [u16index++] =(sizeof(serviceName)+2);
	/*-----------------------------DATA--------------------------------*/
	convertServiceName(serviceName,sizeof(serviceName),serviceName2);
	memcpy(&pu8sendBuf[u16index],serviceName2,sizeof(serviceName)+1);
	u16index+=sizeof(serviceName);
	pu8sendBuf [u16index++] =0xC0;//Pointer to .local (from name)
	pu8sendBuf [u16index++] =gu8pos;//23
	/*###########################################################*/
	strclientAddr.u16Port=HTONS(MDNS_SERVER_PORT);
	// MultiCast RESPONSE
	sendto( sock, pu8sendBuf,(uint16)u16index,0,(struct sockaddr*)&strclientAddr,sizeof(strclientAddr));
	strclientAddr.u16Port=u16Port;
	memcpy(&strclientAddr.u32IPAddr,pu8IPAddr,IPV4_DATA_LENGTH);
}
  • Service Name:
static char gpacDnsServerCache[DNS_SERVER_CACHE_SIZE][MDNS_HOSTNAME_SIZE] =
{
	"_services._dns-sd._udp.local","_workstation._tcp.local","_http._tcp.local"
};	
unsigned char    gPu8Buf [MDNS_BUF_SIZE];
unsigned char    gu8pos ;
signed char      dns_server_sock ;

#define serviceName "_ATMELWIFI._tcp"