Ejemplo n.º 1
0
/** Receives datagram messages.
 *
 * Receives messages from one of the sockets in the specified 
 * SLPXcastsSockets structure, @p sockets.
 * 
 * @param[in] sockets - A pointer to the SOPXcastSockets structure that 
 *    describes the sockets from which to read messages.
 * @param[out] buf - A pointer to an SLPBuffer that will contain the 
 *    received message upon successful return.
 * @param[out] peeraddr - A pointer to a sockaddr structure that will 
 *    contain the address of the peer from which the message was received.
 * @param[in,out] timeout - A pointer to the timeval structure that 
 *    indicates how much time to wait for a message to arrive.
 *
 * @return Zero on success, or a non-zero with errno set on failure.
 */
int SLPXcastRecvMessage(const SLPXcastSockets * sockets, SLPBuffer * buf,
      void * peeraddr, struct timeval * timeout)
{
   fd_set readfds;
   sockfd_t highfd;
   int i;
   int readable;
   int bytesread;
   int recvloop;
   char peek[16];
   int result = 0;
   int mtu;

   mtu = SLPPropertyGetMTU();
   /* recv loop */
   recvloop = 1;
   while (recvloop)
   {
      /* Set the readfds */
      FD_ZERO(&readfds);
      highfd = 0;
      for (i = 0; i < sockets->sock_count; i++)
      {
         FD_SET(sockets->sock[i],&readfds);
         if (sockets->sock[i] > highfd)
            highfd = sockets->sock[i];
      }

      /* Select */
      readable = select((int)(highfd + 1), &readfds, 0, 0, timeout);
      if (readable > 0)
      {
         /* Read the datagram */
         for (i = 0; i < sockets->sock_count; i++)
         {
            if (FD_ISSET(sockets->sock[i], &readfds))
            {
               /* Peek at the first 16 bytes of the header */
               socklen_t peeraddrlen = sizeof(struct sockaddr_storage);
               bytesread = recvfrom(sockets->sock[i], peek, 16, MSG_PEEK, 
                     peeraddr, &peeraddrlen);
               if (bytesread == 16
#ifdef _WIN32
                     /* Win32 returns WSAEMSGSIZE if the message is larger 
                      * than the requested size, even with MSG_PEEK. But if 
                      * this is the error code we can be sure that the 
                      * message is at least 16 bytes 
                      */
                     || (bytesread == -1 && WSAGetLastError() == WSAEMSGSIZE)
#endif
               )
               {
                  if (AS_UINT24(peek + 2) <=  (unsigned int)mtu)
                  {
                     *buf = SLPBufferRealloc(*buf, AS_UINT24(peek + 2));
                     bytesread = recv(sockets->sock[i], (char *)(*buf)->curpos,
                           (int)((*buf)->end - (*buf)->curpos), 0);

                     /* This should never happen but we'll be paranoid*/
                     if (bytesread != (int)AS_UINT24(peek + 2))
                        (*buf)->end = (*buf)->curpos + bytesread;

                     /* Message read. We're done! */
                     result = 0; 
                     recvloop = 0;
                     break;
                  }
                  else
                  {
                     /* we got a bad message, or one that is too big! */
#ifndef UNICAST_NOT_SUPPORTED
                     /* Reading mtu bytes on the socket */
                     *buf = SLPBufferRealloc(*buf, mtu);
                     bytesread = recv(sockets->sock[i], (char *)(*buf)->curpos,
                           (int)((*buf)->end - (*buf)->curpos), 0);
                     /* This should never happen but we'll be paranoid*/
                     if (bytesread != mtu)
                        (*buf)->end = (*buf)->curpos + bytesread;

                     result = SLP_ERROR_RETRY_UNICAST;
                     recvloop = 0;
                     return result;
#endif
                  }
               }
               else
               {
                  /* Not even 16 bytes available */
               }
            }
         }   
      }
      else if (readable == 0)
      {
         result = -1;
         errno = ETIMEDOUT;
         recvloop = 0;
      }
      else
      {
         result = -1;
         recvloop = 0;
      }
   }
   return result;
}
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;
      }
   }
}