You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
447 lines
16 KiB
447 lines
16 KiB
/***************************************************************************/
|
|
/* */
|
|
/* Project: OpenSLP - OpenSource implementation of Service Location */
|
|
/* Protocol */
|
|
/* */
|
|
/* File: slp_xcast.c */
|
|
/* */
|
|
/* Abstract: Functions used to multicast and broadcast SLP messages */
|
|
/* */
|
|
/*-------------------------------------------------------------------------*/
|
|
/* */
|
|
/* Please submit patches to http://www.openslp.org */
|
|
/* */
|
|
/*-------------------------------------------------------------------------*/
|
|
/* */
|
|
/* Copyright (C) 2000 Caldera Systems, Inc */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* Redistribution and use in source and binary forms, with or without */
|
|
/* modification, are permitted provided that the following conditions are */
|
|
/* met: */
|
|
/* */
|
|
/* Redistributions of source code must retain the above copyright */
|
|
/* notice, this list of conditions and the following disclaimer. */
|
|
/* */
|
|
/* Redistributions in binary form must reproduce the above copyright */
|
|
/* notice, this list of conditions and the following disclaimer in */
|
|
/* the documentation and/or other materials provided with the */
|
|
/* distribution. */
|
|
/* */
|
|
/* Neither the name of Caldera Systems nor the names of its */
|
|
/* contributors may be used to endorse or promote products derived */
|
|
/* from this software without specific prior written permission. */
|
|
/* */
|
|
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
|
|
/* `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
|
|
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
|
|
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA */
|
|
/* SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
|
|
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
|
|
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
|
|
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
|
|
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
|
|
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
|
|
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
|
/* */
|
|
/***************************************************************************/
|
|
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <io.h>
|
|
#include <errno.h>
|
|
#define ETIMEDOUT 110
|
|
#define ENOTCONN 107
|
|
#else
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/time.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#ifndef UNICAST_NOT_SUPPORTED
|
|
#include "../libslp/slp.h"
|
|
#endif
|
|
|
|
#include "slp_xcast.h"
|
|
#include "slp_message.h"
|
|
#include "slp_property.h"
|
|
|
|
/*========================================================================*/
|
|
int SLPBroadcastSend(const SLPIfaceInfo* ifaceinfo,
|
|
SLPBuffer msg,
|
|
SLPXcastSockets* socks)
|
|
/* Description:
|
|
* Broadcast a message.
|
|
*
|
|
* Parameters:
|
|
* ifaceinfo (IN) Pointer to the SLPIfaceInfo structure that contains
|
|
* information about the interfaces to send on
|
|
* msg (IN) Buffer to send
|
|
*
|
|
* socks (OUT) Sockets used broadcast multicast. May be used to
|
|
* recv() responses. MUST be close by caller using
|
|
* SLPXcastSocketsClose()
|
|
*
|
|
* Returns:
|
|
* Zero on sucess. Non-zero with errno set on error
|
|
*========================================================================*/
|
|
{
|
|
int xferbytes;
|
|
int flags = 0;
|
|
|
|
#ifdef _WIN32
|
|
char on = 1;
|
|
#else
|
|
int on = 1;
|
|
#endif
|
|
|
|
|
|
#if defined(MSG_NOSIGNAL)
|
|
flags = MSG_NOSIGNAL;
|
|
#endif
|
|
|
|
for (socks->sock_count = 0;
|
|
socks->sock_count < ifaceinfo->iface_count;
|
|
socks->sock_count++)
|
|
{
|
|
socks->sock[socks->sock_count] = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (socks->sock[socks->sock_count] < 0)
|
|
{
|
|
/* error creating socket */
|
|
return -1;
|
|
}
|
|
|
|
if( (setsockopt(socks->sock[socks->sock_count],
|
|
SOL_SOCKET,
|
|
SO_BROADCAST,
|
|
&on,
|
|
sizeof(on))) )
|
|
{
|
|
/* Error setting socket option */
|
|
return -1;
|
|
}
|
|
|
|
socks->peeraddr[socks->sock_count].sin_family = AF_INET;
|
|
socks->peeraddr[socks->sock_count].sin_port = htons(SLP_RESERVED_PORT);
|
|
socks->peeraddr[socks->sock_count].sin_addr.s_addr = ifaceinfo->bcast_addr[socks->sock_count].sin_addr.s_addr;
|
|
|
|
xferbytes = sendto(socks->sock[socks->sock_count],
|
|
msg->start,
|
|
msg->end - msg->start,
|
|
0,
|
|
(struct sockaddr *) &(socks->peeraddr[socks->sock_count]),
|
|
sizeof(struct sockaddr_in));
|
|
if(xferbytes < 0)
|
|
{
|
|
/* Error sending to broadcast */
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int SLPMulticastSend(const SLPIfaceInfo* ifaceinfo,
|
|
SLPBuffer msg,
|
|
SLPXcastSockets* socks)
|
|
/* Description:
|
|
* Multicast a message.
|
|
*
|
|
* Parameters:
|
|
* ifaceinfo (IN) Pointer to the SLPIfaceInfo structure that contains
|
|
* information about the interfaces to send on
|
|
* msg (IN) Buffer to send
|
|
*
|
|
* socks (OUT) Sockets used to multicast. May be used to recv()
|
|
* responses. MUST be close by caller using
|
|
* SLPXcastSocketsClose()
|
|
*
|
|
* Returns:
|
|
* Zero on sucess. Non-zero with errno set on error
|
|
*========================================================================*/
|
|
{
|
|
int flags = 0;
|
|
int xferbytes;
|
|
struct in_addr saddr;
|
|
int optarg;
|
|
|
|
|
|
#if defined(MSG_NOSIGNAL)
|
|
flags = MSG_NOSIGNAL;
|
|
#endif
|
|
|
|
optarg = atoi(SLPPropertyGet("net.slp.multicastTTL"));
|
|
|
|
for (socks->sock_count = 0;
|
|
socks->sock_count < ifaceinfo->iface_count;
|
|
socks->sock_count++)
|
|
{
|
|
socks->sock[socks->sock_count] = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (socks->sock[socks->sock_count] < 0)
|
|
{
|
|
/* error creating socket */
|
|
return -1;
|
|
}
|
|
|
|
saddr.s_addr = ifaceinfo->iface_addr[socks->sock_count].sin_addr.s_addr;
|
|
if( setsockopt(socks->sock[socks->sock_count],
|
|
IPPROTO_IP,
|
|
IP_MULTICAST_IF,
|
|
(char*)&saddr,
|
|
sizeof(struct in_addr)))
|
|
{
|
|
/* error setting socket option */
|
|
return -1;
|
|
}
|
|
if(setsockopt(socks->sock[socks->sock_count],
|
|
IPPROTO_IP,
|
|
IP_MULTICAST_TTL,
|
|
(char*)&optarg,
|
|
sizeof(optarg)))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
socks->peeraddr[socks->sock_count].sin_family = AF_INET;
|
|
socks->peeraddr[socks->sock_count].sin_port = htons(SLP_RESERVED_PORT);
|
|
socks->peeraddr[socks->sock_count].sin_addr.s_addr = htonl(SLP_MCAST_ADDRESS);
|
|
|
|
xferbytes = sendto(socks->sock[socks->sock_count],
|
|
msg->start,
|
|
msg->end - msg->start,
|
|
flags,
|
|
(struct sockaddr *) &(socks->peeraddr[socks->sock_count]),
|
|
sizeof(struct sockaddr_in));
|
|
if (xferbytes <= 0)
|
|
{
|
|
/* error sending */
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
int SLPXcastSocketsClose(SLPXcastSockets* socks)
|
|
/* Description:
|
|
* Closes sockets that were opened by calls to SLPMulticastSend() and
|
|
* SLPBroadcastSend()
|
|
*
|
|
* Parameters:
|
|
* socks (IN) Pointer to the SLPXcastSockets structure being close
|
|
*
|
|
* Returns:
|
|
* Zero on sucess. Non-zero with errno set on error
|
|
*========================================================================*/
|
|
{
|
|
while(socks->sock_count)
|
|
{
|
|
socks->sock_count = socks->sock_count - 1;
|
|
#ifdef _WIN32
|
|
closesocket(socks->sock[socks->sock_count]);
|
|
#else
|
|
close(socks->sock[socks->sock_count]);
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*=========================================================================*/
|
|
int SLPXcastRecvMessage(const SLPXcastSockets* sockets,
|
|
SLPBuffer* buf,
|
|
struct sockaddr_in* peeraddr,
|
|
struct timeval* timeout)
|
|
/* Description:
|
|
* Receives datagram messages from one of the sockets in the specified
|
|
* SLPXcastsSockets structure
|
|
*
|
|
* Parameters:
|
|
* sockets (IN) Pointer to the SOPXcastSockets structure that describes
|
|
* which sockets to read messages from.
|
|
* buf (OUT) Pointer to SLPBuffer that will contain the message upon
|
|
* successful return.
|
|
* peeraddr (OUT) Pointer to struc sockaddr_in that will contain the
|
|
* address of the peer that sent the received message.
|
|
* timeout (IN/OUT) pointer to the struct timeval that indicates how much
|
|
* time to wait for a message to arrive
|
|
*
|
|
* Returns:
|
|
* Zero on success, non-zero with errno set on failure.
|
|
*==========================================================================*/
|
|
{
|
|
fd_set readfds;
|
|
int highfd;
|
|
int i;
|
|
int readable;
|
|
size_t bytesread;
|
|
int recvloop;
|
|
int peeraddrlen = sizeof(struct sockaddr_in);
|
|
char peek[16];
|
|
int result;
|
|
|
|
/* recv loop */
|
|
result = -1;
|
|
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(highfd + 1,&readfds,NULL,NULL,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 */
|
|
bytesread = recvfrom(sockets->sock[i],
|
|
peek,
|
|
16,
|
|
MSG_PEEK,
|
|
(struct sockaddr *)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 == (size_t)-1 && WSAGetLastError() == WSAEMSGSIZE)
|
|
#endif
|
|
)
|
|
{
|
|
if(AsUINT24(peek + 2) <= SLP_MAX_DATAGRAM_SIZE)
|
|
{
|
|
*buf = SLPBufferRealloc(*buf, AsUINT24(peek + 2));
|
|
bytesread = recv(sockets->sock[i],
|
|
(*buf)->curpos,
|
|
(*buf)->end - (*buf)->curpos,
|
|
0);
|
|
if(bytesread != AsUINT24(peek + 2))
|
|
{
|
|
/* This should never happen but we'll be paranoid*/
|
|
(*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 SLP_MAX_DATAGRAM_SIZE bytes on the socket */
|
|
*buf = SLPBufferRealloc(*buf, SLP_MAX_DATAGRAM_SIZE);
|
|
bytesread = recv(sockets->sock[i],
|
|
(*buf)->curpos,
|
|
(*buf)->end - (*buf)->curpos,
|
|
0);
|
|
if(bytesread != SLP_MAX_DATAGRAM_SIZE)
|
|
{
|
|
/* This should never happen but we'll be paranoid*/
|
|
(*buf)->end = (*buf)->curpos + bytesread;
|
|
}
|
|
result = SLP_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;
|
|
}
|
|
|
|
/*===========================================================================
|
|
* TESTING CODE may be compiling with the following command line:
|
|
*
|
|
* $ gcc -g -DDEBUG -DSLP_XMIT_TEST slp_xcast.c slp_iface.c slp_buffer.c
|
|
* slp_linkedlist.c slp_compare.c slp_xmalloc.c
|
|
*==========================================================================*/
|
|
#ifdef SLP_XMIT_TEST
|
|
main()
|
|
{
|
|
SLPIfaceInfo ifaceinfo;
|
|
SLPXcastSockets socks;
|
|
SLPBuffer buffer;
|
|
#ifdef _WIN32
|
|
WSADATA wsadata;
|
|
WSAStartup(MAKEWORD(2,2), &wsadata);
|
|
#endif
|
|
|
|
buffer = SLPBufferAlloc(SLP_MAX_DATAGRAM_SIZE);
|
|
if(buffer)
|
|
{
|
|
|
|
strcpy(buffer->start,"testdata");
|
|
|
|
SLPIfaceGetInfo(NULL,&ifaceinfo);
|
|
|
|
if (SLPBroadcastSend(&ifaceinfo, buffer,&socks) !=0)
|
|
printf("\n SLPBroadcastSend failed \n");
|
|
SLPXcastSocketsClose(&socks);
|
|
|
|
if (SLPMulticastSend(&ifaceinfo, buffer, &socks) !=0)
|
|
printf("\n SLPMulticast failed \n");
|
|
SLPXcastSocketsClose(&socks);
|
|
|
|
printf("Success\n");
|
|
|
|
SLPBufferFree(buffer);
|
|
}
|
|
#ifdef _WIN32
|
|
WSACleanup();
|
|
#endif
|
|
}
|
|
|
|
#endif
|
|
|