Example #1
0
/** Multicast a message.
 *
 * @param[in] ifaceinfo - A pointer to the SLPIfaceInfo structure that 
 *    contains information about the interfaces on which to send.
 * @param[in] msg - The buffer to be sent.
 * @param[out] socks - The address of storage for the sockets that were used
 *    to multicast.
 * @param[in] dst - The target address, if using ipv6; can be null for IPv4.  
 *
 * @return Zero on sucess, or a non-zero value, with errno set on error.
 *
 * @remarks May be used to receive responses. Must be close by caller using 
 *    SLPXcastSocketsClose.
 */
int SLPMulticastSend(const SLPIfaceInfo * ifaceinfo, const SLPBuffer msg,
      SLPXcastSockets * socks, struct sockaddr_storage * dst)
{
   int flags = 0;
   int xferbytes;

#ifdef MSG_NOSIGNAL
   flags = MSG_NOSIGNAL;
#endif

   for (socks->sock_count = 0;
         socks->sock_count < ifaceinfo->iface_count;
         socks->sock_count++)
   {
      int family = ifaceinfo->iface_addr[socks->sock_count].ss_family;

      socks->sock[socks->sock_count] = socket(family, SOCK_DGRAM, 0);
      if((socks->sock[socks->sock_count] == SLP_INVALID_SOCKET) ||
         (SetMulticastIF(family, socks->sock[socks->sock_count], &ifaceinfo->iface_addr[socks->sock_count]) ||
         (SetMulticastTTL(family, socks->sock[socks->sock_count], SLPPropertyAsInteger("net.slp.multicastTTL")))))
         return -1; /* error creating socket or setting socket option */
      
      SLPNetworkSetSndRcvBuf(socks->sock[socks->sock_count]);
      memcpy(&socks->peeraddr[socks->sock_count], dst, sizeof(struct sockaddr_storage));

      xferbytes = sendto(socks->sock[socks->sock_count], 
         (char *)msg->start, (int)(msg->end - msg->start), flags, 
         (struct sockaddr *)&socks->peeraddr[socks->sock_count],
         SLPNetAddrLen(&socks->peeraddr[socks->sock_count]));
      if (xferbytes <= 0)
         return -1; /* error sending */
   }
   return 0;
}
Example #2
0
/** Writes the datagram to the mcastaddr
 *
 * @param[in] sock - The socket to send on
 * @param[in] maddr - The mcast addr to send to
 * @param[in] buffer - the buffer to send, could be the sockets sendbuf, or an item in the sendlist, etc.
 */
void SLPDOutgoingDatagramMcastWrite(SLPDSocket * sock, struct sockaddr_storage *maddr, SLPBuffer buffer)
{
   if (0 >= sendto(sock->fd, (char*)buffer->start,
               (int)(buffer->end - buffer->start), 0,
               (struct sockaddr *)maddr, SLPNetAddrLen(maddr)))
   {
#ifdef DEBUG
      SLPDLog("ERROR: Data could not send() in SLPDOutgoingDatagramMcastWrite()\n");
#endif
   }
}
Example #3
0
/** Broadcast a message.
 *
 * @param[in] ifaceinfo - A pointer to the SLPIfaceInfo structure that 
 *    contains information about the interfaces on which to send.
 * @param[in] msg - The buffer to be sent.
 * @param[out] socks - The address of storage for returning the sockets
 *    that were used to broadcast. 
 *
 * @return Zero on sucess, or a non-zero value with @a errno set on error.
 *
 * @remarks The sockets returned in @p socks may be used to receive 
 *    responses. Must be close by caller using SLPXcastSocketsClose.
 */                        
int SLPBroadcastSend(const SLPIfaceInfo * ifaceinfo, 
      const SLPBuffer msg, SLPXcastSockets * socks)
{
   int xferbytes;
   so_bool_t on = 1;

   for (socks->sock_count = 0; 
         socks->sock_count < ifaceinfo->bcast_count; 
         socks->sock_count++)
   {
      if (ifaceinfo[socks->sock_count].bcast_addr->ss_family == AF_INET) 
      {
         socks->sock[socks->sock_count] = socket(ifaceinfo[socks->sock_count]
               .bcast_addr->ss_family, SOCK_DGRAM, 0);

         if (socks->sock[socks->sock_count] == SLP_INVALID_SOCKET)
            return -1;  /* error creating socket */

         SLPNetworkSetSndRcvBuf(socks->sock[socks->sock_count]);

         if (setsockopt(socks->sock[socks->sock_count], SOL_SOCKET,
               SO_BROADCAST, &on, sizeof(on)) != 0)
            return -1;  /* Error setting socket option */

         memcpy(&socks->peeraddr[socks->sock_count], 
               &ifaceinfo->bcast_addr[socks->sock_count], 
               sizeof(ifaceinfo->bcast_addr[socks->sock_count]));

         SLPNetSetAddr(&socks->peeraddr[socks->sock_count], AF_INET, 
               (uint16_t)SLPPropertyAsInteger("net.slp.port"), 0);
         xferbytes = sendto(socks->sock[socks->sock_count],
               (char *)msg->start, (int)(msg->end - msg->start), 0, 
               (struct sockaddr *)&socks->peeraddr[socks->sock_count],
               SLPNetAddrLen(&socks->peeraddr[socks->sock_count]));
         if (xferbytes  < 0)
            return -1;  /* Error sending to broadcast */
      }
      else 
         socks->sock[socks->sock_count] = 0; /* assume bcast for IPV4 only */
   }
   return 0;
}
Example #4
0
/** Sends a message.
 *
 * @param[in] sockfd - The pre-configured socket to send on.
 * @param[in] socktype - The type of message (datagram or stream).
 * @param[in] buf - The buffer to be sent.
 * @param[in] bufsz - The number of bytes in @p buf to be sent.
 * @param[in] peeraddr - The address to which @p buf should be sent.
 * @param[in] timeout - The maximum time to wait for network operations.
 *
 * @return Zero on success non-zero on failure with errno set. Possible 
 *    values for errno include EPIPE on write error, and ETIMEOUT on 
 *    read timeout error.
 */
int SLPNetworkSendMessage(sockfd_t sockfd, int socktype, 
      const SLPBuffer buf, size_t bufsz, void * peeraddr, 
      struct timeval * timeout)
{
#if HAVE_POLL
   struct pollfd writefd;
#else
   fd_set writefds;
#endif
   int xferbytes;
   int flags = 0;
   const uint8_t * cur = buf->start;
   const uint8_t * end = cur + bufsz;

#ifdef MSG_NOSIGNAL
   flags = MSG_NOSIGNAL;
#endif

   while (cur < end)
   {
#if HAVE_POLL
      writefd.fd = sockfd;
      writefd.events = POLLOUT;
      writefd.revents = 0;
      xferbytes = poll(&writefd, 1, timeout ? timeout->tv_sec * 1000 + timeout->tv_usec / 1000 : -1);
#else
      FD_ZERO(&writefds);
      FD_SET(sockfd, &writefds);

      xferbytes = select((int)sockfd + 1, 0, &writefds, 0, timeout);
#endif
      if (xferbytes > 0)
      {
         if (socktype == SOCK_DGRAM)
            xferbytes = sendto(sockfd, (char *)cur, 
                  (int)(end - cur), flags, peeraddr, 
                  SLPNetAddrLen(peeraddr));
         else
            xferbytes = send(sockfd, (char *)cur, 
                  (int)(end - cur), flags);

         if (xferbytes > 0)
            cur += xferbytes;
         else
         {
            errno = EPIPE;
            return -1;
         }
      }
      else if (xferbytes == 0)
      {
         errno = ETIMEDOUT;
         return -1;
      }
      else
      {
         errno = EPIPE;
         return -1;
      }
   }
   return 0;
}
Example #5
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;
      }
   }
}