Esempio n. 1
0
/** Read data from an outbound stream-oriented connection.
 *
 * @param[in] socklist - The list of sockets being monitored.
 * @param[in] sock - The socket to be read from.
 */
void OutgoingStreamRead(SLPList * socklist, SLPDSocket * sock)
{
   int bytesread;
   char peek[16];
   socklen_t peeraddrlen = sizeof(struct sockaddr_storage);
   unsigned int msglen;

   if (sock->state == STREAM_READ_FIRST)
   {
      /*---------------------------------------------------*/
      /* take a peek at the packet to get size information */
      /*---------------------------------------------------*/
      bytesread = recvfrom(sock->fd, peek, 16, MSG_PEEK,
                        (struct sockaddr *) &(sock->peeraddr), &peeraddrlen);
      if (bytesread > 0)
      {
         /* allocate the recvbuf big enough for the whole message */
         msglen = PEEK_LENGTH(peek);

         sock->recvbuf = SLPBufferRealloc(sock->recvbuf, msglen);
         if (sock->recvbuf)
            sock->state = STREAM_READ;
         else
         {
            SLPDLog("INTERNAL_ERROR - out of memory!\n");
            sock->state = SOCKET_CLOSE;
         }
      }
      else if (bytesread == -1)
      {
#ifdef _WIN32
         if (WSAEWOULDBLOCK != WSAGetLastError())
#else
         if (errno != EWOULDBLOCK)
#endif
         {
            /* Error occured or connection was closed. Try to reconnect */
            /* Socket will be closed if connect times out               */
            OutgoingStreamReconnect(socklist, sock);
         }
      }
      else
      {
         sock->state = SOCKET_CLOSE;
      }
   }

   if (sock->state == STREAM_READ)
   {
      /*------------------------------*/
      /* recv the rest of the message */
      /*------------------------------*/
      bytesread = recv(sock->fd, (char *)sock->recvbuf->curpos,
            (int)(sock->recvbuf->end - sock->recvbuf->curpos), 0);
      if (bytesread > 0)
      {
         /* reset age because of activity */
         sock->age = 0;

         /* move buffer pointers */
         sock->recvbuf->curpos += bytesread;

         /* check to see if everything was read */
         if (sock->recvbuf->curpos == sock->recvbuf->end)
            switch (SLPDProcessMessage(&(sock->peeraddr), &(sock->localaddr),
                        sock->recvbuf, &(sock->sendbuf), 0))
            {
               case SLP_ERROR_DA_BUSY_NOW:
                  sock->state = STREAM_WRITE_WAIT;
                  break;
               case SLP_ERROR_PARSE_ERROR:
               case SLP_ERROR_VER_NOT_SUPPORTED:
                  sock->state = SOCKET_CLOSE;
                  break;
               default:
                  /* End of outgoing message exchange. Unlink   */
                  /* send buf from to do list and free it       */
                  SLPBufferFree(sock->sendbuf);
                  sock->sendbuf = NULL;
                  sock->state = STREAM_WRITE_FIRST;
                  /* clear the reconnection count since we actually
                   * transmitted a successful message exchange
                   */
                  sock->reconns = 0;
                  break;
            }
      }
      else
      {
#ifdef _WIN32
         if (WSAEWOULDBLOCK != WSAGetLastError())
#else
         if (errno != EWOULDBLOCK)
#endif
         {
            /* Error occured or connection was closed. Try to reconnect */
            /* Socket will be closed if connect times out               */
            OutgoingStreamReconnect(socklist, sock);
         }
      }
   }
}
Esempio n. 2
0
/** Receives a message.
 *
 * @param[in] sockfd - The pre-configured socket on which to read.
 * @param[in] socktype - The socket type (stream or datagram).
 * @param[out] buf - The buffer into which a message should be read.
 * @param[out] peeraddr - The address of storage for the remote address.
 * @param[in] timeout - The maximum time to wait for network operations.
 *
 * @return Zero on success, or non-zero on failure with errno set. Values
 *    for errno include ENOTCONN on read error, ETIMEOUT on network timeout,
 *    ENOMEM on out-of-memory error, and EINVAL on parse error.
 */ 
int SLPNetworkRecvMessage(sockfd_t sockfd, int socktype, 
      SLPBuffer * buf, void * peeraddr, struct timeval * timeout)
{
   int xferbytes, recvlen;
#if HAVE_POLL
   struct pollfd readfd;
#else
   fd_set readfds;
#endif
   char peek[16];

   /* Take a peek at the packet to get version and size information. */
#if HAVE_POLL
    readfd.fd = sockfd;
    readfd.events = POLLIN;
    readfd.revents = 0;
    xferbytes = poll(&readfd, 1, timeout ? timeout->tv_sec * 1000 + timeout->tv_usec / 1000 : -1);
#else
   FD_ZERO(&readfds);
   FD_SET(sockfd, &readfds);
   xferbytes = select((int)sockfd + 1, &readfds, 0, 0, timeout);
#endif
   if (xferbytes > 0)
   {
      if (socktype == SOCK_DGRAM)
      {
         socklen_t addrlen = sizeof(struct sockaddr_storage);
         xferbytes = recvfrom(sockfd, peek, 16, MSG_PEEK,
               peeraddr, &addrlen);
      }
      else
         xferbytes = recv(sockfd, peek, 16, MSG_PEEK);

      if (xferbytes <= 0)
      {
#ifdef _WIN32
         /* Winsock return WSAEMSGSIZE (even on MSG_PEEK!) if the amount of 
          * data queued on the socket is larger than the specified buffer. 
          * Just ignore it.
          */
         if (WSAGetLastError() == WSAEMSGSIZE)
		 {
			 xferbytes = 16;
		 }
		 else
#endif
         {
            errno = ENOTCONN;
            return -1;
         }
      }
   }
   else if (xferbytes == 0)
   {
      errno = ETIMEDOUT;
      return -1;
   }
   else
   {
      errno = ENOTCONN;
      return -1;
   }

   /* Now check the version and read the rest of the message. */
   if (xferbytes >= 5 && (*peek == 1 || *peek == 2))
   {
      /* Allocate the receive buffer as large as necessary. */
      recvlen = PEEK_LENGTH(peek);
      *buf = SLPBufferRealloc(*buf, recvlen);
      if (*buf)
      {
         while ((*buf)->curpos < (*buf)->end)
         {
#if HAVE_POLL
            readfd.fd = sockfd;
            readfd.events = POLLIN;
            readfd.revents = 0;
            xferbytes = poll(&readfd, 1, timeout ? timeout->tv_sec * 1000 + timeout->tv_usec / 1000 : -1);
#else
            FD_SET(sockfd, &readfds);
            xferbytes = select((int)sockfd + 1, &readfds, 0, 0, timeout);
#endif
            if (xferbytes > 0)
            {
               xferbytes = recv(sockfd, (char *)(*buf)->curpos,
                     (int)((*buf)->end - (*buf)->curpos), 0);
               if (xferbytes > 0)
                  (*buf)->curpos = (*buf)->curpos + xferbytes;
               else
               {
                  errno = ENOTCONN;
                  return -1;
               }
            }
            else if (xferbytes == 0)
            {
               errno = ETIMEDOUT;
               return -1;
            }
            else
            {
               errno = ENOTCONN;
               return -1;
            }
         }
      }
      else
      {
         errno = ENOMEM;
         return -1;
      }
   }
   else
   {
      errno = EINVAL;
      return -1;
   }
   return 0;
}
Esempio n. 3
0
/** Read inbound stream data.
 *
 * @param[in] socklist - The list of monitored sockets.
 * @param[in] sock - The socket to be read.
 *
 * @internal
 */
static void IncomingStreamRead(SLPList * socklist, SLPDSocket * sock)
{
   int bytesread;
   size_t recvlen = 0;
   char peek[16];
   socklen_t peeraddrlen = sizeof(struct sockaddr_storage);

   if (sock->state == STREAM_READ_FIRST)
   {
      /*---------------------------------------------------*/
      /* take a peek at the packet to get size information */
      /*---------------------------------------------------*/
      bytesread = recvfrom(sock->fd, (char *)peek, 16, MSG_PEEK,
            (struct sockaddr *)&sock->peeraddr, &peeraddrlen);
      if (bytesread > 0 && bytesread >= (*peek == 2? 5: 4))
      {
         recvlen = PEEK_LENGTH(peek);

         /* allocate the recvbuf big enough for the whole message */
         sock->recvbuf = SLPBufferRealloc(sock->recvbuf, recvlen);
         if (sock->recvbuf)
            sock->state = STREAM_READ;
         else
         {
            SLPDLog("INTERNAL_ERROR - out of memory!\n");
            sock->state = SOCKET_CLOSE;
         }
      }
      else
      {
         sock->state = SOCKET_CLOSE;
         return;
      }
   }

   if (sock->state == STREAM_READ)
   {
      /*------------------------------*/
      /* recv the rest of the message */
      /*------------------------------*/
      bytesread = recv(sock->fd, (char *)sock->recvbuf->curpos,
            (int)(sock->recvbuf->end - sock->recvbuf->curpos), 0);

      if (bytesread > 0)
      {
         /* reset age to max because of activity */
         sock->age = 0;
         sock->recvbuf->curpos += bytesread;
         if (sock->recvbuf->curpos == sock->recvbuf->end) {
            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:
                  sock->state = SOCKET_CLOSE;
                  break;

               default:
                  if (!sock->sendbuf || sock->sendbuf->end == sock->sendbuf->start)
                  {
                     /* no answer available, just close socket */
                     sock->state = SOCKET_CLOSE;
                     break;
                  }

                  /* some clients cannot cope with the OVERFLOW
                   * bit set on a TCP stream, so always clear it
                   */
                  if (sock->sendbuf->end - sock->sendbuf->start > 5)
                  {
                     if (sock->sendbuf->start[0] == 1)
                        sock->sendbuf->start[4] &= ~SLPv1_FLAG_OVERFLOW;
                     else
                        sock->sendbuf->start[5] &= ~(SLP_FLAG_OVERFLOW >> 8);
                  }
                  sock->state = STREAM_WRITE_FIRST;
                  IncomingStreamWrite(socklist, sock);
            }
         }
      }