/** 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; }
/** 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 } }
/** 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; }
/** 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; }
/** 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; } } }