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.
419 lines
15 KiB
419 lines
15 KiB
/***************************************************************************/
|
|
/* */
|
|
/* Project: OpenSLP - OpenSource implementation of Service Location */
|
|
/* Protocol */
|
|
/* */
|
|
/* File: slp_network.c */
|
|
/* */
|
|
/* Abstract: Implementation for functions that are related */
|
|
/* network (and ipc) communication. */
|
|
/* */
|
|
/*-------------------------------------------------------------------------*/
|
|
/* */
|
|
/* 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. */
|
|
/* */
|
|
/***************************************************************************/
|
|
|
|
#include "slp_network.h"
|
|
|
|
/*=========================================================================*/
|
|
int SLPNetworkConnectStream(struct sockaddr_in* peeraddr,
|
|
struct timeval* timeout)
|
|
/* Connect a TCP stream to the specified peer */
|
|
/* */
|
|
/* peeraddr (IN) pointer to the peer to connect to */
|
|
/* */
|
|
/* timeout (IN) pointer to the maximum time to spend connecting */
|
|
/* */
|
|
/* returns: a connected socket or -1 */
|
|
/*=========================================================================*/
|
|
{
|
|
#ifdef _WIN32
|
|
char lowat;
|
|
#else
|
|
int lowat;
|
|
#endif
|
|
int result;
|
|
|
|
/* TODO: Make this connect non-blocking so that it will timeout */
|
|
|
|
result = socket(AF_INET,SOCK_STREAM,0);
|
|
if(result >= 0)
|
|
{
|
|
if(connect(result,
|
|
(struct sockaddr*)peeraddr,
|
|
sizeof(struct sockaddr_in)) == 0)
|
|
{
|
|
/* set the receive and send buffer low water mark to 18 bytes
|
|
(the length of the smallest slpv2 message) */
|
|
lowat = 18;
|
|
setsockopt(result,SOL_SOCKET,SO_RCVLOWAT,&lowat,sizeof(lowat));
|
|
setsockopt(result,SOL_SOCKET,SO_SNDLOWAT,&lowat,sizeof(lowat));
|
|
return result;;
|
|
}
|
|
else
|
|
{
|
|
close(result);
|
|
result = -1;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*=========================================================================*/
|
|
int SLPNetworkConnectToMulticast(struct sockaddr_in* peeraddr, int ttl)
|
|
/* Creates a socket and provides a peeraddr to send to */
|
|
/* */
|
|
/* peeraddr (OUT) pointer to receive the connected DA's address */
|
|
/* */
|
|
/* ttl (IN) ttl for the mcast socket */
|
|
/* */
|
|
/* Returns Valid socket or -1 if no DA connection can be made */
|
|
/*=========================================================================*/
|
|
{
|
|
int sockfd;
|
|
#if defined(linux)
|
|
int optarg;
|
|
#else
|
|
|
|
|
|
|
|
/* Solaris and Tru64 expect a unsigned char parameter */
|
|
unsigned char optarg;
|
|
#endif
|
|
|
|
|
|
#ifdef _WIN32
|
|
BOOL Reuse = TRUE;
|
|
int TTLArg;
|
|
struct sockaddr_in mysockaddr;
|
|
|
|
memset(&mysockaddr, 0, sizeof(mysockaddr));
|
|
mysockaddr.sin_family = AF_INET;
|
|
mysockaddr.sin_port = 0;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* setup multicast socket */
|
|
sockfd = socket(AF_INET,SOCK_DGRAM,0);
|
|
if(sockfd >= 0)
|
|
{
|
|
peeraddr->sin_family = AF_INET;
|
|
peeraddr->sin_port = htons(SLP_RESERVED_PORT);
|
|
peeraddr->sin_addr.s_addr = htonl(SLP_MCAST_ADDRESS);
|
|
optarg = ttl;
|
|
|
|
|
|
#ifdef _WIN32
|
|
TTLArg = ttl;
|
|
if(setsockopt(sockfd,
|
|
SOL_SOCKET,
|
|
SO_REUSEADDR,
|
|
(const char *)&Reuse,
|
|
sizeof(Reuse)) ||
|
|
bind(sockfd,
|
|
(struct sockaddr *)&mysockaddr,
|
|
sizeof(mysockaddr)) ||
|
|
setsockopt(sockfd,
|
|
IPPROTO_IP,
|
|
IP_MULTICAST_TTL,
|
|
(char *)&TTLArg,
|
|
sizeof(TTLArg)))
|
|
{
|
|
return -1;
|
|
}
|
|
#else
|
|
if(setsockopt(sockfd,IPPROTO_IP,IP_MULTICAST_TTL,&optarg,sizeof(optarg)))
|
|
{
|
|
return -1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return sockfd;
|
|
}
|
|
|
|
/*=========================================================================*/
|
|
int SLPNetworkConnectToBroadcast(struct sockaddr_in* peeraddr)
|
|
/* Creates a socket and provides a peeraddr to send to */
|
|
/* */
|
|
/* peeraddr (OUT) pointer to receive the connected DA's address */
|
|
/* */
|
|
/* Returns Valid socket or -1 if no DA connection can be made */
|
|
/*=========================================================================*/
|
|
{
|
|
int sockfd;
|
|
#ifdef _WIN32
|
|
BOOL on = 1;
|
|
#else
|
|
int on = 1;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* setup broadcast */
|
|
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if(sockfd >= 0)
|
|
{
|
|
peeraddr->sin_family = AF_INET;
|
|
peeraddr->sin_port = htons(SLP_RESERVED_PORT);
|
|
peeraddr->sin_addr.s_addr = htonl(SLP_BCAST_ADDRESS);
|
|
|
|
if(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char*)&on, sizeof(on)))
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return sockfd;
|
|
}
|
|
|
|
|
|
/*=========================================================================*/
|
|
int SLPNetworkSendMessage(int sockfd,
|
|
int socktype,
|
|
SLPBuffer buf,
|
|
struct sockaddr_in* peeraddr,
|
|
struct timeval* timeout)
|
|
/* Sends a message */
|
|
/* */
|
|
/* Returns - zero on success non-zero on failure */
|
|
/* */
|
|
/* errno EPIPE error during write */
|
|
/* ETIME read timed out */
|
|
/*=========================================================================*/
|
|
{
|
|
fd_set writefds;
|
|
int xferbytes;
|
|
int flags = 0;
|
|
|
|
#if defined(MSG_NOSIGNAL)
|
|
flags = MSG_NOSIGNAL;
|
|
#endif
|
|
|
|
buf->curpos = buf->start;
|
|
|
|
while(buf->curpos < buf->end)
|
|
{
|
|
FD_ZERO(&writefds);
|
|
FD_SET(sockfd, &writefds);
|
|
|
|
xferbytes = select(sockfd + 1, 0, &writefds, 0, timeout);
|
|
if(xferbytes > 0)
|
|
{
|
|
if(socktype == SOCK_DGRAM)
|
|
{
|
|
xferbytes = sendto(sockfd,
|
|
buf->curpos,
|
|
buf->end - buf->curpos,
|
|
flags,
|
|
(struct sockaddr *)peeraddr,
|
|
sizeof(struct sockaddr_in));
|
|
}
|
|
else
|
|
{
|
|
xferbytes = send(sockfd,
|
|
buf->curpos,
|
|
buf->end - buf->curpos,
|
|
flags);
|
|
}
|
|
|
|
if(xferbytes > 0)
|
|
{
|
|
buf->curpos = buf->curpos + xferbytes;
|
|
}
|
|
else
|
|
{
|
|
errno = EPIPE;
|
|
return -1;
|
|
}
|
|
}
|
|
else if(xferbytes == 0)
|
|
{
|
|
/* timed out */
|
|
errno = ETIMEDOUT;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
errno = EPIPE;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*=========================================================================*/
|
|
int SLPNetworkRecvMessage(int sockfd,
|
|
int socktype,
|
|
SLPBuffer* buf,
|
|
struct sockaddr_in* peeraddr,
|
|
struct timeval* timeout)
|
|
/* Receives a message */
|
|
/* */
|
|
/* Returns - zero on success, non-zero on failure */
|
|
/* */
|
|
/* errno ENOTCONN error during read */
|
|
/* ETIME read timed out */
|
|
/* ENOMEM out of memory */
|
|
/* EINVAL parse error */
|
|
/*=========================================================================*/
|
|
{
|
|
int xferbytes, recvlen;
|
|
fd_set readfds;
|
|
char peek[16];
|
|
int peeraddrlen = sizeof(struct sockaddr_in);
|
|
|
|
/*---------------------------------------------------------------*/
|
|
/* take a peek at the packet to get version and size information */
|
|
/*---------------------------------------------------------------*/
|
|
FD_ZERO(&readfds);
|
|
FD_SET(sockfd, &readfds);
|
|
xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout);
|
|
if(xferbytes > 0)
|
|
{
|
|
if(socktype == SOCK_DGRAM)
|
|
{
|
|
xferbytes = recvfrom(sockfd,
|
|
peek,
|
|
16,
|
|
MSG_PEEK,
|
|
(struct sockaddr *)peeraddr,
|
|
&peeraddrlen);
|
|
}
|
|
else
|
|
{
|
|
xferbytes = recv(sockfd,
|
|
peek,
|
|
16,
|
|
MSG_PEEK);
|
|
}
|
|
|
|
if(xferbytes <= 0)
|
|
{
|
|
#ifdef _WIN32
|
|
if(WSAGetLastError() != WSAEMSGSIZE)
|
|
{
|
|
errno = ENOTCONN;
|
|
return -1;
|
|
}
|
|
#else
|
|
errno = ENOTCONN;
|
|
return -1;
|
|
#endif
|
|
}
|
|
}
|
|
else if(xferbytes == 0)
|
|
{
|
|
errno = ETIMEDOUT;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
errno = ENOTCONN;
|
|
return -1;
|
|
}
|
|
|
|
/*------------------------------*/
|
|
/* Read the rest of the message */
|
|
/*------------------------------*/
|
|
/* check the version */
|
|
if(xferbytes >= 5 && *peek == 2)
|
|
{
|
|
/* allocate the recvmsg big enough for the whole message */
|
|
recvlen = AsUINT24(peek + 2);
|
|
/* one byte is minimum */
|
|
if (recvlen <= 0)
|
|
recvlen = 1;
|
|
*buf = SLPBufferRealloc(*buf, recvlen);
|
|
if(*buf)
|
|
{
|
|
while((*buf)->curpos < (*buf)->end)
|
|
{
|
|
FD_ZERO(&readfds);
|
|
FD_SET(sockfd, &readfds);
|
|
xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout);
|
|
if(xferbytes > 0)
|
|
{
|
|
xferbytes = recv(sockfd,
|
|
(*buf)->curpos,
|
|
(*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;
|
|
}
|
|
} /* end of main read while. */
|
|
}
|
|
else
|
|
{
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|