Ejemplo n.º 1
0
/** A callback routine that tests each DA discovered from DHCP.
 *
 * Each DA that passes is added to the DA cache.
 *
 * @param[in] tag - The DHCP option tag for this call.
 * @param[in] optdata - A pointer to the DHCP option data for this call.
 * @param[in] optdatasz - The size of @p optdata.
 * @param[in] context - Callback context data. For this callback routine
 *    this parameter is actually a pointer to DHCPContext data.
 *
 * @return Zero on success, or a non-zero value to stop the caller from 
 *    continuing to parse the buffer and call this routine.
 */
int DHCPParseSLPTags(int tag, void * optdata, size_t optdatasz, 
      void * context)
{
   size_t cpysz, bufsz, dasize;
   DHCPContext * ctxp = (DHCPContext *)context;
   unsigned char * p = (unsigned char *)optdata;
   unsigned char flags;
   int encoding;

   /* filter out zero length options */
   if (!optdatasz)
      return 0;

   switch(tag)
   {
      case TAG_SLP_SCOPE:

         /* Draft 3 format is only supported for ASCII and UNICODE
          *  character encodings - UTF8 encodings must use rfc2610 format.
          *  To determine the format, we parse 2 bytes and see if the result
          *  is a valid encoding. If so it's draft 3, otherwise rfc2610. 
          */
         encoding = (optdatasz > 1)? AS_UINT16(p): 0;
         if (encoding != CT_ASCII && encoding != CT_UNICODE)
         {
            /* rfc2610 format */

            if (optdatasz == 1)
               break;      /* UA's should ignore statically configured
                           *  scopes for this interface - 
                           *  add code to handle this later... 
                           */

            flags = *p++;  /* pick up the mandatory flag... */
            optdatasz--;

            if (flags)
               ;           /* ...and add code to handle it later... */

            /* copy utf8 string into return buffer */
            ctxp->scopelistlen = optdatasz < sizeof(ctxp->scopelist)? 
                  optdatasz: sizeof(ctxp->scopelist);
            strncpy(ctxp->scopelist, (char*)p, ctxp->scopelistlen);
            ctxp->scopelist[sizeof(ctxp->scopelist) - 1] = 0;
         }
         else
         {
            /* Draft 3 format: defined to configure scopes for SA's only
             *  so we should flag the scopes to be used only as registration
             *  filter scopes - add code to handle this case later...
             *
             *  offs     len      name        description
             *  0        2        encoding    character encoding used 
             *  2        n        scopelist   list of scopes as asciiz string.
             *
             */
            optdatasz -= 2;   /* skip encoding bytes */
            p += 2;

            /* if UNICODE encoding is used convert to utf8 */
            if (encoding == CT_UNICODE)
               wcstombs(ctxp->scopelist, (wchar_t*)p, sizeof(ctxp->scopelist));
            else
            {
               ctxp->scopelistlen = optdatasz < sizeof(ctxp->scopelist)? 
                     optdatasz: sizeof(ctxp->scopelist);
               strncpy(ctxp->scopelist, (char*)p, ctxp->scopelistlen);
               ctxp->scopelist[sizeof(ctxp->scopelist) - 1] = 0;
            }
         }
         break;

      case TAG_SLP_DA:
         flags = *p++;
         optdatasz--;

         /* If the flags byte has the high bit set, we know we are
          *  using draft 3 format, otherwise rfc2610 format. 
          */
         if (!(flags & DA_NAME_PRESENT))
         {
            /* rfc2610 format */
            if (flags)
            {
               /* If the mandatory byte is non-zero, indicate that 
                *  multicast is not to be used to dynamically discover 
                *  directory agents on this interface by setting the 
                *  LACBF_STATIC_DA flag in the LACB for this interface. 
                */

               /* skip this for now - deal with it later... */
            }

            bufsz = sizeof(ctxp->addrlist) - ctxp->addrlistlen;
            cpysz = optdatasz < bufsz? optdatasz: bufsz;
            memcpy(ctxp->addrlist + ctxp->addrlistlen, p, cpysz);
            ctxp->addrlistlen += cpysz;
         }
         else
         {
            /* pre-rfc2610 (draft 3) format:
             *     offs     len      name     description
             *     0        1        flags    contains 4 flags (defined above)
             *     1        1        dasize   name or addr length
             *     2        dasize   daname   da name or ip address (flags)
             */
            dasize = *p++;
            optdatasz--;

            if (dasize > optdatasz)
               dasize = optdatasz;
            if (flags & DA_NAME_IS_DNS)
               ;  /* DA name contains dns name - we have to resolve - later... */
            else
            {     /* DA name is one 4-byte ip address */
               if (dasize < 4)
                  break;   /* oops, bad option format */
               dasize = 4;
               bufsz = sizeof(ctxp->addrlist) - ctxp->addrlistlen;
               cpysz = dasize < bufsz? dasize: bufsz;
               memcpy(ctxp->addrlist + ctxp->addrlistlen, p, cpysz);
               ctxp->addrlistlen += cpysz;
            }
            if (flags & DISABLE_DA_MCAST)
               ;  /* this is the equivalent of the rfc2610 mandatory bit */
         }
         break;
   }
   return 0;
}
Ejemplo n.º 2
0
/** Read an inbound datagram.
 *
 * @param[in] socklist - The list of monitored sockets.
 * @param[in] sock - The socket to be read.
 *
 * @internal
 */
static void IncomingDatagramRead(SLPList * socklist, SLPDSocket * sock)
{
   int bytesread;
   int byteswritten;
   socklen_t peeraddrlen = sizeof(struct sockaddr_storage);
   char addr_str[INET6_ADDRSTRLEN];
   sockfd_t sendsock = SLP_INVALID_SOCKET;

   (void)socklist;

   bytesread = recvfrom(sock->fd, (char*)sock->recvbuf->start,
         G_SlpdProperty.MTU, 0, (struct sockaddr *)&sock->peeraddr,
         &peeraddrlen);
   if (bytesread > 0)
   {
      sock->recvbuf->end = sock->recvbuf->start + bytesread;

      if (!sock->sendbuf)
         /* Some of the error handling code expects a sendbuf to be available
          * to be emptied, so make sure there is at least a minimal buffer
          */
         sock->sendbuf = SLPBufferAlloc(1);

      switch (SLPDProcessMessage(&sock->peeraddr, &sock->localaddr,
            sock->recvbuf, &sock->sendbuf, 0))
      {
         case SLP_ERROR_PARSE_ERROR:
         case SLP_ERROR_VER_NOT_SUPPORTED:
         case SLP_ERROR_MESSAGE_NOT_SUPPORTED:
            break;

         default:
#ifdef DARWIN
            /* If the socket is a multicast socket, find the designated UDP output socket for sending */
            if (sock->state == DATAGRAM_MULTICAST)
               if ((sendsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != SLP_INVALID_SOCKET)
                  SLPNetworkSetSndRcvBuf(sendsock);
#endif
            if (sendsock == SLP_INVALID_SOCKET)
               sendsock = sock->fd;

            /* check to see if we should send anything, breaking up individual packets in the buffer
               into different sendto calls (should only be an issue with the loopback DA response)*/
            if (sock->sendbuf)
            {
               sock->sendbuf->curpos = sock->sendbuf->start;
               while (sock->sendbuf->curpos < sock->sendbuf->end)
               {
                  int packetbytes = AS_UINT24(sock->sendbuf->curpos + 2);
                  byteswritten = sendto(sendsock, (char*)sock->sendbuf->curpos,
                        packetbytes, 0, (struct sockaddr *)&sock->peeraddr,
                        SLPNetAddrLen(&sock->peeraddr));

                  if (byteswritten != packetbytes)
                  {
                     /* May be an overflow reply */
                     int flags = AS_UINT16(sock->sendbuf->curpos + 5);
                     if ((byteswritten == -1) &&
#ifdef _WIN32
                           (WSAGetLastError() == WSAEMSGSIZE) &&
#else
                           (errno == EMSGSIZE) &&
#endif
                           (flags & SLP_FLAG_OVERFLOW))
                     {
                        int byteswrittenmax = sendto(sendsock, (char*)sock->sendbuf->curpos,
                                G_SlpdProperty.MTU, 0, (struct sockaddr *)&sock->peeraddr,
                                SLPNetAddrLen(&sock->peeraddr));
                        if (byteswrittenmax == G_SlpdProperty.MTU)
                           byteswritten = packetbytes;
                     }
                  }

                  if (byteswritten != packetbytes)
                     SLPDLog("NETWORK_ERROR - %d replying %s\n", errno,
                           SLPNetSockAddrStorageToString(&(sock->peeraddr),
                                 addr_str, sizeof(addr_str)));

                  sock->sendbuf->curpos += packetbytes;
               }

               /* Only close if we allocated a new socket */
               if (sendsock != sock->fd)
                  closesocket(sendsock);
            }
            break;
      }
   }
}