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"