src/mk_mdns_client.c
static int mk_parse_response_mdns_pkt(unsigned char *rxpkt, int rxlen, struct mk_mdns_sn_record *sn_result)
{

/*
   // Our Super Node response typically contains:
   // dns.flags.response == 1  // It is a response
   // dns.count.queries == 0   //  0 question
   // dns.count.answers == 1   //  Answer RRs: 1
       // PTR(12)  -  Pointer to Domain Name (contains our Super Node Name)
   // dns.count.auth_rr == 0   //  Authority RRs: 0
   // dns.count.add_rr == 4    //  Additional RRs: 4
       // A(1)    -  Address record (32-bit IPv4 address in network order)
       // TXT(16) -  Text Record (All our supernode json strings are sent here as L1S1L2S2L3S3...)
       // SRV(33) -  Service locator (contains our service TCP port)
*/

   uint16_t *pU16 = (uint16_t *)rxpkt;
   int readlen = 0;
   int rc = 0;

   uint16_t val16 = 0;
   uint16_t ans_rr_cnt = 0;
   uint16_t aut_rr_cnt = 0;
   uint16_t add_rr_cnt = 0;
   uint16_t t_rr_cnt = 0;
   uint16_t r = 0;

   if ((!rxpkt)||(rxlen < MDNS_HDRSZ)) {
      MK_LOG(LOG_ERR,"%s() error rxlen = %d \n",__func__,rxlen);
      return -1;
   }

   // mdns Identifier(id)  // Not interested in mdns id value skip
   // val16 = ntohs(pU16[0]);

   // check flags for QR (Query(0)/Response(1)) Bit at (0x8000)
   val16 = ntohs(pU16[1]);
   if ((val16 & (1<<15)) != 0x8000) {
     MK_LOG(LOG_ERR,"%s() mdns.flags.response not as expected. flags=%hu\n",__func__,val16);
     return -1;
   }

   // check for dns.count.queries == 0
   val16 = ntohs(pU16[2]);
   if (val16 != 0) {
     MK_LOG(LOG_ERR,"%s() mdns.count.queries(%hu) != expected(0) \n",__func__,val16);
     return -1;
   }

   // dns.count.answers == 1  // response should have RR:1 for answers 
   ans_rr_cnt = ntohs(pU16[3]);

   // check for dns.count.auth_rr == 0 // should have RR: 0 for 
   aut_rr_cnt = ntohs(pU16[4]);
   if (aut_rr_cnt != 0) {
     MK_LOG(LOG_INFO,"%s() mdns.count.auth_rr(%hu) != expected(0) \n",__func__,val16);
   }

   // dns.count.add_rr > 1    // should have Additional RRs: 4
   add_rr_cnt = ntohs(pU16[5]);

   t_rr_cnt = ans_rr_cnt + aut_rr_cnt + add_rr_cnt;

   if (t_rr_cnt == 0) {
     MK_LOG(LOG_ERR,"%s() unexpected response records =%u \n",__func__,t_rr_cnt);
     return -1;
   }
   
   readlen += MDNS_HDRSZ;
  
  // MK_LOG(LOG_DEBUG,"%s() t_rr_cnt = %d \n",__func__,t_rr_cnt);

   for (r=0; (r < t_rr_cnt) && (readlen < rxlen); r++) {

      uint16_t RRType = 0;
      uint16_t RDLength = 0;

     // MK_LOG(LOG_DEBUG,"\n\n %s rr-loop(r=%d) readlen=%d \n",__func__,r,readlen);

      // We are not interested in copying RRNAME now: just parse and skip read bytes
      // However when we need a name and directed here through a
      // a refernce, then that time will parse that section.
      // The intent is to MINIMIZE parsing and copying as much as possible, only to what we NEED.

      rc = mk_parse_get_rrname(rxpkt, rxlen, readlen, NULL, 1);
      if ( rc > 0 ) {
         readlen += rc;
      }

      if (readlen >= rxlen) {
         MK_LOG(LOG_ERR,"%s() readlen(%d) > rxlen(%d) r=%d error \n",__func__,readlen,rxlen,r);
	 return -1;
      }

      // RRTYPE - 2 bytes in network byte order
      pU16 = (uint16_t *)&rxpkt[readlen];
      RRType = ntohs(pU16[0]);
      readlen += 2;

      // CACHE-FLUSH(1) + RRCLASS(15) - skip, we are not interested RRCLASS
      readlen += 2;

      //TTL - skip,  We are not interested in TTL - 4 bytes 
      readlen += 4;

      // RDLENGTH - 2 bytes in network byte order
      pU16 = (uint16_t *)&rxpkt[readlen];
      RDLength = ntohs(pU16[0]);
      readlen += 2;

     // MK_LOG(LOG_DEBUG,"%s() r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType);

      // Now process variable RDATA resource data based on RRType
      switch (RRType) {

	 case RRTYPE_PTR:
	  // MK_LOG(LOG_DEBUG,"%s(RRTYPE_PTR) r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType);
	    //get PTRDNAME name containing backward reference to names if any.
	    //L1.S1.L2.S2.....c0-pointer[2bytes]0
	    // https://tools.ietf.org/html/rfc1035 : 3.3.12. PTR RDATA format
	    // and section 4.1.4. Message compression
            mk_parse_get_rrname(rxpkt, rxlen, readlen, sn_result->sn_Name, 0);
	    MK_LOG(LOG_INFO,"%s(RRTYPE_PTR) Parsed SuperNode Record Name=%s \n",__func__,sn_result->sn_Name);
	 break;

	 case RRTYPE_SRV: 
	   // MK_LOG(LOG_DEBUG,"%s(RRTYPE_SRV) r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType);
	    pU16 = (uint16_t *)&rxpkt[readlen];
	    //[priority(2 bytes)+weight(2 bytes)+port(2 bytes )+hostname...(variabe length)]
	    // skip reading priority, weight, and hostname as we do not need.
	    sn_result->snPort = ntohs(pU16[2]);
	    MK_LOG(LOG_INFO,"%s(RRTYPE_SRV) Parsed SuperNode port=%hu \n",__func__,sn_result->snPort);
	 break;

	 case RRTYPE_A:
	   // MK_LOG(LOG_DEBUG,"%s(RRTYPE_A) r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType);
	    //contains 4 bytes ipv4 address in network byte order
	    //struct in_addr in = {0};
	    sn_result->snAddr = *((unsigned int*)&rxpkt[readlen]);
	    //in.s_addr = sn_result->snAddr;
	    snprintf(sn_result->snIpStr,sizeof(sn_result->snIpStr),"%u.%u.%u.%u",
			  rxpkt[readlen], rxpkt[readlen+1], rxpkt[readlen+2], rxpkt[readlen+3]);
	    //strncpy(sn_result->snIpStr,inet_ntoa(in),sizeof(sn_result->snIpStr));
	    MK_LOG(LOG_INFO,"%s(RRTYPE_A) Parsed SuperNode ipv4=%s and as in.s_addr=%u \n",__func__,sn_result->snIpStr,sn_result->snAddr);
	 break;

	 case RRTYPE_TXT:
	   // MK_LOG(LOG_DEBUG,"%s(RRTYPE_TXT) r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType);
            mk_parse_get_rrtxt(rxpkt, rxlen, readlen, RDLength, sn_result->sn_Txt);
	    MK_LOG(LOG_INFO,"%s(RRTYPE_TXT) Parsed SuperNode Record Txt=%s \n",__func__,sn_result->sn_Txt);
	 break;

	 default:
	    //break and proceed.
	    // MK_LOG(LOG_DEBUG,"%s(default) r=%d RDLength=%d readlen=%d RRType=%d SKIPPING \n",__func__,r,RDLength,readlen,RRType);
	 break;

       } //end of switch RRType/RRDATA parsing

      //update index with RDLength
      readlen += RDLength;

   } // end of for RR records processing

   // MK_LOG(LOG_INFO,"%s(leave) r=%d readlen=%d \n",__func__,r,readlen);

   return 0;
}
//returns 0 on success and -1 on failure
returns 0 on success and -1 on failure
returns 0 on success and - 1 on failure
static int mk_parse_response_mdns_pkt(unsigned char *rxpkt, int rxlen, struct mk_mdns_sn_record *sn_result)
{
   uint16_t *pU16 = (uint16_t *)rxpkt;
   int readlen = 0;
   int rc = 0;
   uint16_t val16 = 0;
   uint16_t ans_rr_cnt = 0;
   uint16_t aut_rr_cnt = 0;
   uint16_t add_rr_cnt = 0;
   uint16_t t_rr_cnt = 0;
   uint16_t r = 0;
   if ((!rxpkt)||(rxlen < MDNS_HDRSZ)) {
      MK_LOG(LOG_ERR,"%s() error rxlen = %d \n",__func__,rxlen);
      return -1;
   }
   val16 = ntohs(pU16[1]);
   if ((val16 & (1<<15)) != 0x8000) {
     MK_LOG(LOG_ERR,"%s() mdns.flags.response not as expected. flags=%hu\n",__func__,val16);
     return -1;
   }
   val16 = ntohs(pU16[2]);
   if (val16 != 0) {
     MK_LOG(LOG_ERR,"%s() mdns.count.queries(%hu) != expected(0) \n",__func__,val16);
     return -1;
   }
   ans_rr_cnt = ntohs(pU16[3]);
   aut_rr_cnt = ntohs(pU16[4]);
   if (aut_rr_cnt != 0) {
     MK_LOG(LOG_INFO,"%s() mdns.count.auth_rr(%hu) != expected(0) \n",__func__,val16);
   }
   add_rr_cnt = ntohs(pU16[5]);
   t_rr_cnt = ans_rr_cnt + aut_rr_cnt + add_rr_cnt;
   if (t_rr_cnt == 0) {
     MK_LOG(LOG_ERR,"%s() unexpected response records =%u \n",__func__,t_rr_cnt);
     return -1;
   }
   readlen += MDNS_HDRSZ;
   for (r=0; (r < t_rr_cnt) && (readlen < rxlen); r++) {
      uint16_t RRType = 0;
      uint16_t RDLength = 0;
      rc = mk_parse_get_rrname(rxpkt, rxlen, readlen, NULL, 1);
      if ( rc > 0 ) {
         readlen += rc;
      }
      if (readlen >= rxlen) {
         MK_LOG(LOG_ERR,"%s() readlen(%d) > rxlen(%d) r=%d error \n",__func__,readlen,rxlen,r);
	 return -1;
      }
      pU16 = (uint16_t *)&rxpkt[readlen];
      RRType = ntohs(pU16[0]);
      readlen += 2;
      readlen += 2;
      readlen += 4;
      pU16 = (uint16_t *)&rxpkt[readlen];
      RDLength = ntohs(pU16[0]);
      readlen += 2;
      switch (RRType) {
	 case RRTYPE_PTR:
            mk_parse_get_rrname(rxpkt, rxlen, readlen, sn_result->sn_Name, 0);
	    MK_LOG(LOG_INFO,"%s(RRTYPE_PTR) Parsed SuperNode Record Name=%s \n",__func__,sn_result->sn_Name);
	 break;
	 case RRTYPE_SRV: 
	    pU16 = (uint16_t *)&rxpkt[readlen];
	    sn_result->snPort = ntohs(pU16[2]);
	    MK_LOG(LOG_INFO,"%s(RRTYPE_SRV) Parsed SuperNode port=%hu \n",__func__,sn_result->snPort);
	 break;
	 case RRTYPE_A:
	    sn_result->snAddr = *((unsigned int*)&rxpkt[readlen]);
	    snprintf(sn_result->snIpStr,sizeof(sn_result->snIpStr),"%u.%u.%u.%u",
			  rxpkt[readlen], rxpkt[readlen+1], rxpkt[readlen+2], rxpkt[readlen+3]);
	    MK_LOG(LOG_INFO,"%s(RRTYPE_A) Parsed SuperNode ipv4=%s and as in.s_addr=%u \n",__func__,sn_result->snIpStr,sn_result->snAddr);
	 break;
	 case RRTYPE_TXT:
            mk_parse_get_rrtxt(rxpkt, rxlen, readlen, RDLength, sn_result->sn_Txt);
	    MK_LOG(LOG_INFO,"%s(RRTYPE_TXT) Parsed SuperNode Record Txt=%s \n",__func__,sn_result->sn_Txt);
	 break;
	 default:
	 break;
       } 
      readlen += RDLength;
   } 
   return 0;
}
static int mk_parse_response_mdns_pkt ( unsigned char * rxpkt , int rxlen , struct mk_mdns_sn_record * sn_result ) { uint16_t * pU16 = ( uint16_t * ) rxpkt ; int readlen = 0 ; int rc = 0 ; uint16_t val16 = 0 ; uint16_t ans_rr_cnt = 0 ; uint16_t aut_rr_cnt = 0 ; uint16_t add_rr_cnt = 0 ; uint16_t t_rr_cnt = 0 ; uint16_t r = 0 ; if ( ( ! rxpkt ) || ( rxlen < MDNS_HDRSZ ) ) { MK_LOG ( LOG_ERR , " \n " , __func__ , rxlen ) ; return -1 ; } val16 = ntohs ( pU16 [ 1 ] ) ; if ( ( val16 & ( 1 << 15 ) ) != 0x8000 ) { MK_LOG ( LOG_ERR , " \n " , __func__ , val16 ) ; return -1 ; } val16 = ntohs ( pU16 [ 2 ] ) ; if ( val16 != 0 ) { MK_LOG ( LOG_ERR , " \n " , __func__ , val16 ) ; return -1 ; } ans_rr_cnt = ntohs ( pU16 [ 3 ] ) ; aut_rr_cnt = ntohs ( pU16 [ 4 ] ) ; if ( aut_rr_cnt != 0 ) { MK_LOG ( LOG_INFO , " \n " , __func__ , val16 ) ; } add_rr_cnt = ntohs ( pU16 [ 5 ] ) ; t_rr_cnt = ans_rr_cnt + aut_rr_cnt + add_rr_cnt ; if ( t_rr_cnt == 0 ) { MK_LOG ( LOG_ERR , " \n " , __func__ , t_rr_cnt ) ; return -1 ; } readlen += MDNS_HDRSZ ; for ( r = 0 ; ( r < t_rr_cnt ) && ( readlen < rxlen ) ; r ++ ) { uint16_t RRType = 0 ; uint16_t RDLength = 0 ; rc = mk_parse_get_rrname ( rxpkt , rxlen , readlen , NULL , 1 ) ; if ( rc > 0 ) { readlen += rc ; } if ( readlen >= rxlen ) { MK_LOG ( LOG_ERR , " \n " , __func__ , readlen , rxlen , r ) ; return -1 ; } pU16 = ( uint16_t * ) & rxpkt [ readlen ] ; RRType = ntohs ( pU16 [ 0 ] ) ; readlen += 2 ; readlen += 2 ; readlen += 4 ; pU16 = ( uint16_t * ) & rxpkt [ readlen ] ; RDLength = ntohs ( pU16 [ 0 ] ) ; readlen += 2 ; switch ( RRType ) { case RRTYPE_PTR : mk_parse_get_rrname ( rxpkt , rxlen , readlen , sn_result -> sn_Name , 0 ) ; MK_LOG ( LOG_INFO , " \n " , __func__ , sn_result -> sn_Name ) ; break ; case RRTYPE_SRV : pU16 = ( uint16_t * ) & rxpkt [ readlen ] ; sn_result -> snPort = ntohs ( pU16 [ 2 ] ) ; MK_LOG ( LOG_INFO , " \n " , __func__ , sn_result -> snPort ) ; break ; case RRTYPE_A : sn_result -> snAddr = * ( ( unsigned int * ) & rxpkt [ readlen ] ) ; snprintf ( sn_result -> snIpStr , sizeof ( sn_result -> snIpStr ) , " " , rxpkt [ readlen ] , rxpkt [ readlen + 1 ] , rxpkt [ readlen + 2 ] , rxpkt [ readlen + 3 ] ) ; MK_LOG ( LOG_INFO , " \n " , __func__ , sn_result -> snIpStr , sn_result -> snAddr ) ; break ; case RRTYPE_TXT : mk_parse_get_rrtxt ( rxpkt , rxlen , readlen , RDLength , sn_result -> sn_Txt ) ; MK_LOG ( LOG_INFO , " \n " , __func__ , sn_result -> sn_Txt ) ; break ; default : break ; } readlen += RDLength ; } return 0 ; }
returns 0 on success and -1 on failure
returns 0 on success and - 1 on failure
/*
   // Our Super Node response typically contains:
   // dns.flags.response == 1  // It is a response
   // dns.count.queries == 0   //  0 question
   // dns.count.answers == 1   //  Answer RRs: 1
       // PTR(12)  -  Pointer to Domain Name (contains our Super Node Name)
   // dns.count.auth_rr == 0   //  Authority RRs: 0
   // dns.count.add_rr == 4    //  Additional RRs: 4
       // A(1)    -  Address record (32-bit IPv4 address in network order)
       // TXT(16) -  Text Record (All our supernode json strings are sent here as L1S1L2S2L3S3...)
       // SRV(33) -  Service locator (contains our service TCP port)
*/ // mdns Identifier(id)  // Not interested in mdns id value skip // val16 = ntohs(pU16[0]); // check flags for QR (Query(0)/Response(1)) Bit at (0x8000) // check for dns.count.queries == 0 // dns.count.answers == 1  // response should have RR:1 for answers  // check for dns.count.auth_rr == 0 // should have RR: 0 for  // dns.count.add_rr > 1    // should have Additional RRs: 4 // MK_LOG(LOG_DEBUG,"%s() t_rr_cnt = %d \n",__func__,t_rr_cnt); // MK_LOG(LOG_DEBUG,"\n\n %s rr-loop(r=%d) readlen=%d \n",__func__,r,readlen); // We are not interested in copying RRNAME now: just parse and skip read bytes // However when we need a name and directed here through a // a refernce, then that time will parse that section. // The intent is to MINIMIZE parsing and copying as much as possible, only to what we NEED. // RRTYPE - 2 bytes in network byte order // CACHE-FLUSH(1) + RRCLASS(15) - skip, we are not interested RRCLASS //TTL - skip,  We are not interested in TTL - 4 bytes  // RDLENGTH - 2 bytes in network byte order // MK_LOG(LOG_DEBUG,"%s() r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType); // Now process variable RDATA resource data based on RRType // MK_LOG(LOG_DEBUG,"%s(RRTYPE_PTR) r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType); //get PTRDNAME name containing backward reference to names if any. //L1.S1.L2.S2.....c0-pointer[2bytes]0 // https://tools.ietf.org/html/rfc1035 : 3.3.12. PTR RDATA format // and section 4.1.4. Message compression // MK_LOG(LOG_DEBUG,"%s(RRTYPE_SRV) r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType); //[priority(2 bytes)+weight(2 bytes)+port(2 bytes )+hostname...(variabe length)] // skip reading priority, weight, and hostname as we do not need. // MK_LOG(LOG_DEBUG,"%s(RRTYPE_A) r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType); //contains 4 bytes ipv4 address in network byte order //struct in_addr in = {0}; //in.s_addr = sn_result->snAddr; //strncpy(sn_result->snIpStr,inet_ntoa(in),sizeof(sn_result->snIpStr)); // MK_LOG(LOG_DEBUG,"%s(RRTYPE_TXT) r=%d RDLength=%d readlen=%d RRType=%d \n",__func__,r,RDLength,readlen,RRType); //break and proceed. // MK_LOG(LOG_DEBUG,"%s(default) r=%d RDLength=%d readlen=%d RRType=%d SKIPPING \n",__func__,r,RDLength,readlen,RRType); //end of switch RRType/RRDATA parsing //update index with RDLength // end of for RR records processing // MK_LOG(LOG_INFO,"%s(leave) r=%d readlen=%d \n",__func__,r,readlen);