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.
1321 lines
48 KiB
1321 lines
48 KiB
4 years ago
|
/***************************************************************************/
|
||
|
/* */
|
||
|
/* Project: OpenSLP - OpenSource implementation of Service Location */
|
||
|
/* Protocol */
|
||
|
/* */
|
||
|
/* File: libslp_network.c */
|
||
|
/* */
|
||
|
/* Abstract: Implementation for functions that are related to INTERNAL */
|
||
|
/* library 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.h"
|
||
|
#include "libslp.h"
|
||
|
|
||
|
|
||
|
/*=========================================================================*/
|
||
|
int NetworkConnectToSlpd(struct sockaddr_in* peeraddr)
|
||
|
/* Connects to slpd and provides a peeraddr to send to */
|
||
|
/* */
|
||
|
/* peeraddr (OUT) pointer to receive the connected DA's address */
|
||
|
/* */
|
||
|
/* Returns Connected socket or -1 if no DA connection can be made */
|
||
|
/*=========================================================================*/
|
||
|
{
|
||
|
#ifdef _WIN32 /* on WIN32 setsockopt takes a const char * argument */
|
||
|
char lowat;
|
||
|
#else
|
||
|
int lowat;
|
||
|
#endif
|
||
|
int result;
|
||
|
|
||
|
result = socket(AF_INET,SOCK_STREAM,0);
|
||
|
if(result >= 0)
|
||
|
{
|
||
|
peeraddr->sin_family = AF_INET;
|
||
|
peeraddr->sin_port = htons(SLP_RESERVED_PORT);
|
||
|
peeraddr->sin_addr.s_addr = htonl(LOOPBACK_ADDRESS);
|
||
|
|
||
|
/* TODO: the following connect() could block for a long time. */
|
||
|
|
||
|
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));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Could not connect to the slpd through the loopback */
|
||
|
close(result);
|
||
|
result = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*=========================================================================*/
|
||
|
void NetworkDisconnectDA(PSLPHandleInfo handle)
|
||
|
/* Called after DA fails to respond */
|
||
|
/* */
|
||
|
/* handle (IN) a handle previously passed to NetworkConnectToDA() */
|
||
|
/*=========================================================================*/
|
||
|
{
|
||
|
if(handle->dasock)
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
closesocket(handle->dasock);
|
||
|
#else
|
||
|
close(handle->dasock);
|
||
|
#endif
|
||
|
handle->dasock = -1;
|
||
|
}
|
||
|
|
||
|
/* Mark this DA as bad */
|
||
|
KnownDABadDA(&(handle->daaddr.sin_addr));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*=========================================================================*/
|
||
|
void NetworkDisconnectSA(PSLPHandleInfo handle)
|
||
|
/* Called after SA fails to respond */
|
||
|
/* */
|
||
|
/* handle (IN) a handle previously passed to NetworkConnectToSA() */
|
||
|
/*=========================================================================*/
|
||
|
{
|
||
|
if(handle->sasock)
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
closesocket(handle->sasock);
|
||
|
#else
|
||
|
close(handle->sasock);
|
||
|
#endif
|
||
|
handle->sasock = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*=========================================================================*/
|
||
|
int NetworkConnectToDA(PSLPHandleInfo handle,
|
||
|
const char* scopelist,
|
||
|
int scopelistlen,
|
||
|
struct sockaddr_in* peeraddr)
|
||
|
/* Connects to slpd and provides a peeraddr to send to */
|
||
|
/* */
|
||
|
/* handle (IN) SLPHandle info (caches connection info */
|
||
|
/* */
|
||
|
/* scopelist (IN) Scope that must be supported by DA. Pass in NULL */
|
||
|
/* for any scope */
|
||
|
/* */
|
||
|
/* scopelistlen (IN) Length of the scope list in bytes. Ignored if */
|
||
|
/* scopelist is NULL */
|
||
|
/* */
|
||
|
/* peeraddr (OUT) pointer to receive the connected DA's address */
|
||
|
/* */
|
||
|
/* Returns Connected socket or -1 if no DA connection can be made */
|
||
|
/*=========================================================================*/
|
||
|
{
|
||
|
/*-----------------------------------------------------------------*/
|
||
|
/* attempt to use a cached socket if scope is supported otherwise */
|
||
|
/* discover a DA that supports the scope */
|
||
|
/*-----------------------------------------------------------------*/
|
||
|
if(handle->dasock >= 0 &&
|
||
|
handle->dascope &&
|
||
|
SLPCompareString(handle->dascopelen,
|
||
|
handle->dascope,
|
||
|
scopelistlen,
|
||
|
scopelist) == 0)
|
||
|
{
|
||
|
memcpy(peeraddr,&(handle->daaddr),sizeof(struct sockaddr_in));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* close handle cause it can't support the scope */
|
||
|
if(handle->dasock >= 0)
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
closesocket(handle->dasock);
|
||
|
#else
|
||
|
close(handle->dasock);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/* Attempt to connect to DA that does support the scope */
|
||
|
handle->dasock = KnownDAConnect(handle,
|
||
|
scopelistlen,
|
||
|
scopelist,
|
||
|
&(handle->daaddr));
|
||
|
if(handle->dasock >= 0)
|
||
|
{
|
||
|
if(handle->dascope) xfree(handle->dascope);
|
||
|
handle->dascope = memdup(scopelist,scopelistlen);
|
||
|
handle->dascopelen = scopelistlen;
|
||
|
memcpy(peeraddr,&(handle->daaddr),sizeof(struct sockaddr_in));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return handle->dasock;
|
||
|
}
|
||
|
|
||
|
/*=========================================================================*/
|
||
|
int NetworkConnectToSA(PSLPHandleInfo handle,
|
||
|
const char* scopelist,
|
||
|
int scopelistlen,
|
||
|
struct sockaddr_in* peeraddr)
|
||
|
/* Connects to slpd and provides a peeraddr to send to */
|
||
|
/* */
|
||
|
/* handle (IN) SLPHandle info (caches connection info) */
|
||
|
/* */
|
||
|
/* scopelist (IN) Scope that must be supported by SA. Pass in NULL */
|
||
|
/* for any scope */
|
||
|
/* */
|
||
|
/* scopelistlen (IN) Length of the scope list in bytes. Ignored if */
|
||
|
/* scopelist is NULL */
|
||
|
/* */
|
||
|
/* peeraddr (OUT) pointer to receive the connected SA's address */
|
||
|
/* */
|
||
|
/* Returns Connected socket or -1 if no SA connection can be made */
|
||
|
{
|
||
|
|
||
|
/*-----------------------------------------------------------------*/
|
||
|
/* attempt to use a cached socket if scope is supported otherwise */
|
||
|
/* look to connect to local slpd or a DA that supports the scope */
|
||
|
/*-----------------------------------------------------------------*/
|
||
|
if(handle->sasock >= 0 &&
|
||
|
handle->sascope &&
|
||
|
SLPCompareString(handle->sascopelen,
|
||
|
handle->sascope,
|
||
|
scopelistlen,
|
||
|
scopelist) == 0)
|
||
|
{
|
||
|
memcpy(peeraddr,&(handle->saaddr),sizeof(struct sockaddr_in));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* close handle cause it can't support the scope */
|
||
|
if(handle->sasock >= 0)
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
closesocket(handle->sasock);
|
||
|
#else
|
||
|
close(handle->sasock);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*-----------------------------------------*/
|
||
|
/* Attempt to connect to slpd via loopback */
|
||
|
/*-----------------------------------------*/
|
||
|
handle->sasock = NetworkConnectToSlpd(&(handle->saaddr));
|
||
|
|
||
|
/*----------------------------------------------------------*/
|
||
|
/* if we connected to something, cache scope and addr info */
|
||
|
/*----------------------------------------------------------*/
|
||
|
if(handle->sasock >= 0)
|
||
|
{
|
||
|
if(handle->sascope) xfree(handle->sascope);
|
||
|
handle->sascope = memdup(scopelist,scopelistlen);
|
||
|
handle->sascopelen = scopelistlen;
|
||
|
memcpy(peeraddr,&(handle->saaddr),sizeof(struct sockaddr_in));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return handle->sasock;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*=========================================================================*/
|
||
|
SLPError NetworkRqstRply(int sock,
|
||
|
struct sockaddr_in* destaddr,
|
||
|
const char* langtag,
|
||
|
int extoffset,
|
||
|
char* buf,
|
||
|
char buftype,
|
||
|
int bufsize,
|
||
|
NetworkRplyCallback callback,
|
||
|
void * cookie)
|
||
|
/* Transmits and receives SLP messages via multicast convergence algorithm */
|
||
|
/* */
|
||
|
/* Returns - SLP_OK on success */
|
||
|
/*=========================================================================*/
|
||
|
{
|
||
|
struct timeval timeout;
|
||
|
struct sockaddr_in peeraddr;
|
||
|
SLPBuffer sendbuf = 0;
|
||
|
SLPBuffer recvbuf = 0;
|
||
|
SLPError result = 0;
|
||
|
int looprecv = 0;
|
||
|
int langtaglen = 0;
|
||
|
int prlistlen = 0;
|
||
|
char* prlist = 0;
|
||
|
int xid = 0;
|
||
|
int mtu = 0;
|
||
|
int size = 0;
|
||
|
int xmitcount = 0;
|
||
|
int rplycount = 0;
|
||
|
int maxwait = 0;
|
||
|
int totaltimeout = 0;
|
||
|
#ifdef _WIN32 /* on WIN32 setsockopt takes a const char * argument */
|
||
|
char socktype = 0;
|
||
|
#else
|
||
|
int socktype = 0;
|
||
|
#endif
|
||
|
int timeouts[MAX_RETRANSMITS];
|
||
|
unsigned short flags;
|
||
|
|
||
|
|
||
|
/*----------------------------------------------------*/
|
||
|
/* Save off a few things we don't want to recalculate */
|
||
|
/*----------------------------------------------------*/
|
||
|
langtaglen = strlen(langtag);
|
||
|
xid = SLPXidGenerate();
|
||
|
mtu = SLPPropertyAsInteger(SLPGetProperty("net.slp.MTU"));
|
||
|
sendbuf = SLPBufferAlloc(mtu);
|
||
|
if(sendbuf == 0)
|
||
|
{
|
||
|
result = SLP_MEMORY_ALLOC_FAILED;
|
||
|
goto CLEANUP;
|
||
|
}
|
||
|
|
||
|
/* Figure unicast/multicast,TCP/UDP, wait and time out stuff */
|
||
|
if(ISMCAST(destaddr->sin_addr))
|
||
|
{
|
||
|
/* Multicast or broadcast */
|
||
|
maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.multicastMaximumWait"));
|
||
|
SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.multicastTimeouts"),
|
||
|
timeouts,
|
||
|
MAX_RETRANSMITS );
|
||
|
xmitcount = 0;
|
||
|
looprecv = 1;
|
||
|
socktype = SOCK_DGRAM;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.unicastMaximumWait"));
|
||
|
SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.unicastTimeouts"),
|
||
|
timeouts,
|
||
|
MAX_RETRANSMITS );
|
||
|
size = sizeof(socktype);
|
||
|
getsockopt(sock,SOL_SOCKET,SO_TYPE,&socktype,&size);
|
||
|
if(socktype == SOCK_DGRAM)
|
||
|
{
|
||
|
xmitcount = 0;
|
||
|
looprecv = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
xmitcount = MAX_RETRANSMITS;
|
||
|
looprecv = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Special case for fake SLP_FUNCT_DASRVRQST */
|
||
|
if(buftype == SLP_FUNCT_DASRVRQST)
|
||
|
{
|
||
|
/* do something special for SRVRQST that will be discovering DAs */
|
||
|
maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.DADiscoveryMaximumWait"));
|
||
|
SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.DADiscoveryTimeouts"),
|
||
|
timeouts,
|
||
|
MAX_RETRANSMITS );
|
||
|
/* SLP_FUNCT_DASRVRQST is a fake function. We really want to */
|
||
|
/* send a SRVRQST */
|
||
|
buftype = SLP_FUNCT_SRVRQST;
|
||
|
looprecv = 1;
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
/* Allocate memory for the prlist for appropriate messages. */
|
||
|
/* Notice that the prlist is as large as the MTU -- thus assuring that */
|
||
|
/* there will not be any buffer overwrites regardless of how many */
|
||
|
/* previous responders there are. This is because the retransmit */
|
||
|
/* code terminates if ever MTU is exceeded for any datagram message. */
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
if(buftype == SLP_FUNCT_SRVRQST ||
|
||
|
buftype == SLP_FUNCT_ATTRRQST ||
|
||
|
buftype == SLP_FUNCT_SRVTYPERQST)
|
||
|
{
|
||
|
prlist = (char*)xmalloc(mtu);
|
||
|
if(prlist == 0)
|
||
|
{
|
||
|
result = SLP_MEMORY_ALLOC_FAILED;
|
||
|
goto CLEANUP;
|
||
|
}
|
||
|
*prlist = 0;
|
||
|
prlistlen = 0;
|
||
|
}
|
||
|
|
||
|
/*--------------------------*/
|
||
|
/* Main retransmission loop */
|
||
|
/*--------------------------*/
|
||
|
while(xmitcount <= MAX_RETRANSMITS)
|
||
|
{
|
||
|
xmitcount++;
|
||
|
|
||
|
/*--------------------*/
|
||
|
/* setup recv timeout */
|
||
|
/*--------------------*/
|
||
|
if(socktype == SOCK_DGRAM)
|
||
|
{
|
||
|
totaltimeout += timeouts[xmitcount];
|
||
|
if(totaltimeout >= maxwait || timeouts[xmitcount] == 0)
|
||
|
{
|
||
|
/* we are all done */
|
||
|
break;
|
||
|
}
|
||
|
timeout.tv_sec = timeouts[xmitcount] / 1000;
|
||
|
timeout.tv_usec = (timeouts[xmitcount] % 1000) * 1000;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
timeout.tv_sec = maxwait / 1000;
|
||
|
timeout.tv_usec = (maxwait % 1000) * 1000;
|
||
|
}
|
||
|
|
||
|
/*------------------------------------------------------------------*/
|
||
|
/* re-allocate buffer and make sure that the send buffer does not */
|
||
|
/* exceed MTU for datagram transmission */
|
||
|
/*------------------------------------------------------------------*/
|
||
|
size = 14 + langtaglen + bufsize;
|
||
|
if(buftype == SLP_FUNCT_SRVRQST ||
|
||
|
buftype == SLP_FUNCT_ATTRRQST ||
|
||
|
buftype == SLP_FUNCT_SRVTYPERQST)
|
||
|
{
|
||
|
/* add in room for the prlist */
|
||
|
size += 2 + prlistlen;
|
||
|
}
|
||
|
if(size > mtu && socktype == SOCK_DGRAM)
|
||
|
{
|
||
|
if(xmitcount == 0)
|
||
|
{
|
||
|
result = SLP_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
if((sendbuf = SLPBufferRealloc(sendbuf,size)) == 0)
|
||
|
{
|
||
|
result = SLP_MEMORY_ALLOC_FAILED;
|
||
|
goto CLEANUP;
|
||
|
}
|
||
|
|
||
|
/*-----------------------------------*/
|
||
|
/* Add the header to the send buffer */
|
||
|
/*-----------------------------------*/
|
||
|
/*version*/
|
||
|
*(sendbuf->start) = 2;
|
||
|
/*function id*/
|
||
|
*(sendbuf->start + 1) = buftype;
|
||
|
/*length*/
|
||
|
ToUINT24(sendbuf->start + 2, size);
|
||
|
/*flags*/
|
||
|
flags = (ISMCAST(destaddr->sin_addr) ? SLP_FLAG_MCAST : 0);
|
||
|
if (buftype == SLP_FUNCT_SRVREG)
|
||
|
{
|
||
|
flags |= SLP_FLAG_FRESH;
|
||
|
}
|
||
|
ToUINT16(sendbuf->start + 5, flags);
|
||
|
/*ext offset*/
|
||
|
/* TRICKY: the extoffset passed into us was the offset not
|
||
|
* including the header. We need to fix up the offset so
|
||
|
* that it is from the beginning of the SLP message
|
||
|
*/
|
||
|
if(extoffset != 0)
|
||
|
{
|
||
|
ToUINT24(sendbuf->start + 7,extoffset + langtaglen + 14);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ToUINT24(sendbuf->start + 7, 0);
|
||
|
}
|
||
|
/*xid*/
|
||
|
ToUINT16(sendbuf->start + 10,xid);
|
||
|
/*lang tag len*/
|
||
|
ToUINT16(sendbuf->start + 12,langtaglen);
|
||
|
/*lang tag*/
|
||
|
memcpy(sendbuf->start + 14, langtag, langtaglen);
|
||
|
sendbuf->curpos = sendbuf->start + langtaglen + 14 ;
|
||
|
|
||
|
/*-----------------------------------*/
|
||
|
/* Add the prlist to the send buffer */
|
||
|
/*-----------------------------------*/
|
||
|
if(prlist)
|
||
|
{
|
||
|
ToUINT16(sendbuf->curpos,prlistlen);
|
||
|
sendbuf->curpos = sendbuf->curpos + 2;
|
||
|
memcpy(sendbuf->curpos, prlist, prlistlen);
|
||
|
sendbuf->curpos = sendbuf->curpos + prlistlen;
|
||
|
}
|
||
|
|
||
|
/*-----------------------------*/
|
||
|
/* Add the rest of the message */
|
||
|
/*-----------------------------*/
|
||
|
memcpy(sendbuf->curpos, buf, bufsize);
|
||
|
|
||
|
/*----------------------*/
|
||
|
/* send the send buffer */
|
||
|
/*----------------------*/
|
||
|
result = SLPNetworkSendMessage(sock,
|
||
|
socktype,
|
||
|
sendbuf,
|
||
|
destaddr,
|
||
|
&timeout);
|
||
|
if(result != 0)
|
||
|
{
|
||
|
/* we could not send the message for some reason */
|
||
|
/* we're done */
|
||
|
if(errno == ETIMEDOUT)
|
||
|
{
|
||
|
result = SLP_NETWORK_TIMED_OUT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = SLP_NETWORK_ERROR;
|
||
|
}
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
|
||
|
/*----------------*/
|
||
|
/* Main recv loop */
|
||
|
/*----------------*/
|
||
|
do
|
||
|
{
|
||
|
if(SLPNetworkRecvMessage(sock,
|
||
|
socktype,
|
||
|
&recvbuf,
|
||
|
&peeraddr,
|
||
|
&timeout) != 0)
|
||
|
{
|
||
|
/* An error occured while receiving the message */
|
||
|
/* probably a just time out error. break for re-send. */
|
||
|
if(errno == ETIMEDOUT)
|
||
|
{
|
||
|
result = SLP_NETWORK_TIMED_OUT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = SLP_NETWORK_ERROR;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Sneek in and check the XID */
|
||
|
if(AsUINT16(recvbuf->start+10) == xid)
|
||
|
{
|
||
|
rplycount += 1;
|
||
|
|
||
|
/* Call the callback with the result and recvbuf */
|
||
|
if(callback(result,&peeraddr,recvbuf,cookie) == SLP_FALSE)
|
||
|
{
|
||
|
/* Caller does not want any more info */
|
||
|
/* We are done! */
|
||
|
goto CLEANUP;
|
||
|
}
|
||
|
|
||
|
/* add the peer to the previous responder list */
|
||
|
/* Note that prlist will be NULL if message type is not */
|
||
|
/* SLP_FUNCT_SRVRQST, SLP_FUNCT_ATTRRQST, or */
|
||
|
/* SLP_FUNCT_SRVTYPERQST) */
|
||
|
if(prlist && socktype == SOCK_DGRAM)
|
||
|
{
|
||
|
/* calculate the peeraddr string and length */
|
||
|
char* peeraddrstr = NULL;
|
||
|
int peeraddrstrlen = 0;
|
||
|
peeraddrstr = inet_ntoa(peeraddr.sin_addr);
|
||
|
if(peeraddrstr)
|
||
|
{
|
||
|
peeraddrstrlen = strlen(peeraddrstr);
|
||
|
|
||
|
/* Append to the prlist if we won't overflow */
|
||
|
if((prlistlen + peeraddrstrlen + 1) < mtu )
|
||
|
{
|
||
|
/* append comma if necessary */
|
||
|
if(prlistlen != 0)
|
||
|
{
|
||
|
strcat(prlist,",");
|
||
|
prlistlen ++;
|
||
|
}
|
||
|
/* append address string */
|
||
|
strcat(prlist,peeraddrstr);
|
||
|
prlistlen += peeraddrstrlen;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}while(looprecv);
|
||
|
}
|
||
|
|
||
|
FINISHED:
|
||
|
|
||
|
/*-----------------------------------------------*/
|
||
|
/* Notify the last time callback that we're done */
|
||
|
/*-----------------------------------------------*/
|
||
|
|
||
|
if(rplycount)
|
||
|
{
|
||
|
result = SLP_LAST_CALL;
|
||
|
}
|
||
|
|
||
|
if(result == SLP_NETWORK_TIMED_OUT && ISMCAST(destaddr->sin_addr))
|
||
|
{
|
||
|
result = SLP_LAST_CALL;
|
||
|
}
|
||
|
|
||
|
callback(result, &peeraddr, recvbuf, cookie);
|
||
|
|
||
|
if(result == SLP_LAST_CALL)
|
||
|
{
|
||
|
result = 0;
|
||
|
}
|
||
|
|
||
|
/*----------------*/
|
||
|
/* Free resources */
|
||
|
/*----------------*/
|
||
|
CLEANUP:
|
||
|
if(prlist) xfree(prlist);
|
||
|
SLPBufferFree(sendbuf);
|
||
|
SLPBufferFree(recvbuf);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/*=========================================================================*/
|
||
|
#ifndef MI_NOT_SUPPORTED
|
||
|
SLPError NetworkMcastRqstRply(PSLPHandleInfo handle,
|
||
|
#else
|
||
|
SLPError NetworkMcastRqstRply(const char* langtag,
|
||
|
#endif /* MI_NOT_SUPPORTED */
|
||
|
char* buf,
|
||
|
char buftype,
|
||
|
int bufsize,
|
||
|
NetworkRplyCallback callback,
|
||
|
void * cookie)
|
||
|
/* Description: */
|
||
|
/* */
|
||
|
/* Broadcasts/multicasts SLP messages via multicast convergence algorithm */
|
||
|
/* */
|
||
|
/* langtag (IN) Language tag to use in SLP message header */
|
||
|
/* */
|
||
|
/* buf (IN) pointer to the portion of the SLP message to send. The */
|
||
|
/* portion to that should be pointed to is everything after */
|
||
|
/* the pr-list. NetworkXcastRqstRply() automatically */
|
||
|
/* generates the header and the prlist. */
|
||
|
/* */
|
||
|
/* buftype (IN) the function-id to use in the SLPMessage header */
|
||
|
/* */
|
||
|
/* bufsize (IN) the size of the buffer pointed to by buf */
|
||
|
/* */
|
||
|
/* callback (IN) the callback to use for reporting results */
|
||
|
/* */
|
||
|
/* cookie (IN) the cookie to pass to the callback */
|
||
|
/* */
|
||
|
/* Returns - SLP_OK on success. SLP_ERROR on failure */
|
||
|
/*=========================================================================*/
|
||
|
{
|
||
|
struct timeval timeout;
|
||
|
struct sockaddr_in peeraddr;
|
||
|
SLPBuffer sendbuf = 0;
|
||
|
SLPBuffer recvbuf = 0;
|
||
|
SLPError result = 0;
|
||
|
int langtaglen = 0;
|
||
|
int prlistlen = 0;
|
||
|
char* prlist = 0;
|
||
|
int xid = 0;
|
||
|
int mtu = 0;
|
||
|
int size = 0;
|
||
|
int xmitcount = 0;
|
||
|
int rplycount = 0;
|
||
|
int maxwait = 0;
|
||
|
int totaltimeout = 0;
|
||
|
int usebroadcast = 0;
|
||
|
int timeouts[MAX_RETRANSMITS];
|
||
|
SLPIfaceInfo ifaceinfo;
|
||
|
SLPXcastSockets xcastsocks;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
/* This function only supports multicast or broadcast of the following
|
||
|
* messages
|
||
|
*/
|
||
|
if(buftype != SLP_FUNCT_SRVRQST &&
|
||
|
buftype != SLP_FUNCT_ATTRRQST &&
|
||
|
buftype != SLP_FUNCT_SRVTYPERQST &&
|
||
|
buftype != SLP_FUNCT_DASRVRQST)
|
||
|
{
|
||
|
return SLP_PARAMETER_BAD;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*----------------------------------------------------*/
|
||
|
/* Save off a few things we don't want to recalculate */
|
||
|
/*----------------------------------------------------*/
|
||
|
#ifndef MI_NOT_SUPPORTED
|
||
|
langtaglen = strlen(handle->langtag);
|
||
|
#else
|
||
|
langtaglen = strlen(langtag);
|
||
|
#endif /* MI_NOT_SUPPORTED */
|
||
|
xid = SLPXidGenerate();
|
||
|
mtu = SLPPropertyAsInteger(SLPGetProperty("net.slp.MTU"));
|
||
|
sendbuf = SLPBufferAlloc(mtu);
|
||
|
if(sendbuf == 0)
|
||
|
{
|
||
|
result = SLP_MEMORY_ALLOC_FAILED;
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
|
||
|
#ifndef MI_NOT_SUPPORTED
|
||
|
if(handle->McastIFList != NULL)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
fprintf(stderr, "McastIFList = %s\n", handle->McastIFList);
|
||
|
#endif
|
||
|
SLPIfaceGetInfo(handle->McastIFList, &ifaceinfo);
|
||
|
}
|
||
|
else
|
||
|
#endif /* MI_NOT_SUPPORTED */
|
||
|
if(SLPIfaceGetInfo(SLPGetProperty("net.slp.interfaces"),&ifaceinfo))
|
||
|
{
|
||
|
result = SLP_NETWORK_ERROR;
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
usebroadcast = SLPPropertyAsBoolean(SLPGetProperty("net.slp.useBroadcast"));
|
||
|
|
||
|
/*-----------------------------------*/
|
||
|
/* Multicast/broadcast wait timeouts */
|
||
|
/*-----------------------------------*/
|
||
|
maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.multicastMaximumWait"));
|
||
|
SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.multicastTimeouts"),
|
||
|
timeouts,
|
||
|
MAX_RETRANSMITS );
|
||
|
|
||
|
/* Special case for fake SLP_FUNCT_DASRVRQST */
|
||
|
if(buftype == SLP_FUNCT_DASRVRQST)
|
||
|
{
|
||
|
/* do something special for SRVRQST that will be discovering DAs */
|
||
|
maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.DADiscoveryMaximumWait"));
|
||
|
SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.DADiscoveryTimeouts"),
|
||
|
timeouts,
|
||
|
MAX_RETRANSMITS );
|
||
|
/* SLP_FUNCT_DASRVRQST is a fake function. We really want to */
|
||
|
/* send a SRVRQST */
|
||
|
buftype = SLP_FUNCT_SRVRQST;
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
/* Allocate memory for the prlist for appropriate messages. */
|
||
|
/* Notice that the prlist is as large as the MTU -- thus assuring that */
|
||
|
/* there will not be any buffer overwrites regardless of how many */
|
||
|
/* previous responders there are. This is because the retransmit */
|
||
|
/* code terminates if ever MTU is exceeded for any datagram message. */
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
prlist = (char*)xmalloc(mtu);
|
||
|
if(prlist == 0)
|
||
|
{
|
||
|
result = SLP_MEMORY_ALLOC_FAILED;
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
*prlist = 0;
|
||
|
prlistlen = 0;
|
||
|
|
||
|
/*--------------------------*/
|
||
|
/* Main retransmission loop */
|
||
|
/*--------------------------*/
|
||
|
xmitcount = 0;
|
||
|
while(xmitcount <= MAX_RETRANSMITS)
|
||
|
{
|
||
|
xmitcount++;
|
||
|
|
||
|
totaltimeout += timeouts[xmitcount];
|
||
|
if(totaltimeout >= maxwait || timeouts[xmitcount] == 0)
|
||
|
{
|
||
|
/* we are all done */
|
||
|
break;
|
||
|
}
|
||
|
timeout.tv_sec = timeouts[xmitcount] / 1000;
|
||
|
timeout.tv_usec = (timeouts[xmitcount] % 1000) * 1000;
|
||
|
|
||
|
/*------------------------------------------------------------------*/
|
||
|
/* re-allocate buffer and make sure that the send buffer does not */
|
||
|
/* exceed MTU for datagram transmission */
|
||
|
/*------------------------------------------------------------------*/
|
||
|
size = 14 + langtaglen + bufsize;
|
||
|
if(buftype == SLP_FUNCT_SRVRQST ||
|
||
|
buftype == SLP_FUNCT_ATTRRQST ||
|
||
|
buftype == SLP_FUNCT_SRVTYPERQST)
|
||
|
{
|
||
|
/* add in room for the prlist */
|
||
|
size += 2 + prlistlen;
|
||
|
}
|
||
|
if(size > mtu)
|
||
|
{
|
||
|
if(xmitcount == 0)
|
||
|
{
|
||
|
result = SLP_BUFFER_OVERFLOW;
|
||
|
}
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
if((sendbuf = SLPBufferRealloc(sendbuf,size)) == 0)
|
||
|
{
|
||
|
result = SLP_MEMORY_ALLOC_FAILED;
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
|
||
|
/*-----------------------------------*/
|
||
|
/* Add the header to the send buffer */
|
||
|
/*-----------------------------------*/
|
||
|
/*version*/
|
||
|
*(sendbuf->start) = 2;
|
||
|
/*function id*/
|
||
|
*(sendbuf->start + 1) = buftype;
|
||
|
/*length*/
|
||
|
ToUINT24(sendbuf->start + 2, size);
|
||
|
/*flags*/
|
||
|
ToUINT16(sendbuf->start + 5, SLP_FLAG_MCAST);
|
||
|
/*ext offset*/
|
||
|
ToUINT24(sendbuf->start + 7,0);
|
||
|
/*xid*/
|
||
|
ToUINT16(sendbuf->start + 10,xid);
|
||
|
/*lang tag len*/
|
||
|
ToUINT16(sendbuf->start + 12,langtaglen);
|
||
|
/*lang tag*/
|
||
|
#ifndef MI_NOT_SUPPORTED
|
||
|
memcpy(sendbuf->start + 14, handle->langtag, langtaglen);
|
||
|
#else
|
||
|
memcpy(sendbuf->start + 14, langtag, langtaglen);
|
||
|
#endif /* MI_NOT_SUPPORTED */
|
||
|
sendbuf->curpos = sendbuf->start + langtaglen + 14 ;
|
||
|
|
||
|
/*-----------------------------------*/
|
||
|
/* Add the prlist to the send buffer */
|
||
|
/*-----------------------------------*/
|
||
|
if(prlist)
|
||
|
{
|
||
|
ToUINT16(sendbuf->curpos,prlistlen);
|
||
|
sendbuf->curpos = sendbuf->curpos + 2;
|
||
|
memcpy(sendbuf->curpos, prlist, prlistlen);
|
||
|
sendbuf->curpos = sendbuf->curpos + prlistlen;
|
||
|
}
|
||
|
|
||
|
/*-----------------------------*/
|
||
|
/* Add the rest of the message */
|
||
|
/*-----------------------------*/
|
||
|
memcpy(sendbuf->curpos, buf, bufsize);
|
||
|
|
||
|
/*----------------------*/
|
||
|
/* send the send buffer */
|
||
|
/*----------------------*/
|
||
|
if(usebroadcast)
|
||
|
{
|
||
|
result = SLPBroadcastSend(&ifaceinfo,sendbuf,&xcastsocks);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = SLPMulticastSend(&ifaceinfo,sendbuf,&xcastsocks);
|
||
|
}
|
||
|
if(result != 0)
|
||
|
{
|
||
|
/* we could not send the message for some reason */
|
||
|
result = SLP_NETWORK_ERROR;
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
|
||
|
/*----------------*/
|
||
|
/* Main recv loop */
|
||
|
/*----------------*/
|
||
|
while(1)
|
||
|
{
|
||
|
#ifndef UNICAST_NOT_SUPPORTED
|
||
|
int retval = 0;
|
||
|
if((retval = SLPXcastRecvMessage(&xcastsocks,
|
||
|
&recvbuf,
|
||
|
&peeraddr,
|
||
|
&timeout)) != 0)
|
||
|
#else
|
||
|
|
||
|
if(SLPXcastRecvMessage(&xcastsocks,
|
||
|
&recvbuf,
|
||
|
&peeraddr,
|
||
|
&timeout) != 0)
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
/* An error occured while receiving the message */
|
||
|
/* probably a just time out error. break for re-send. */
|
||
|
if(errno == ETIMEDOUT)
|
||
|
{
|
||
|
result = SLP_NETWORK_TIMED_OUT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = SLP_NETWORK_ERROR;
|
||
|
}
|
||
|
#ifndef UNICAST_NOT_SUPPORTED
|
||
|
/* retval = SLP_RETRY_UNICAST signifies that we received a
|
||
|
* multicast packet of size > MTU and hence we are now sending
|
||
|
* a unicast request to this IP-address
|
||
|
*/
|
||
|
if ( retval == SLP_RETRY_UNICAST )
|
||
|
{
|
||
|
int tcpsockfd, retval1, retval2, unicastwait = 0;
|
||
|
unicastwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.unicastMaximumWait"));
|
||
|
timeout.tv_sec = unicastwait / 1000;
|
||
|
timeout.tv_usec = (unicastwait % 1000) * 1000;
|
||
|
|
||
|
tcpsockfd = SLPNetworkConnectStream(&peeraddr, &timeout);
|
||
|
if ( tcpsockfd >= 0 )
|
||
|
{
|
||
|
ToUINT16(sendbuf->start + 5, SLP_FLAG_UCAST);
|
||
|
xid = SLPXidGenerate();
|
||
|
ToUINT16(sendbuf->start + 10,xid);
|
||
|
|
||
|
retval1 = SLPNetworkSendMessage(tcpsockfd, SOCK_STREAM, sendbuf, &peeraddr, &timeout);
|
||
|
if ( retval1 != 0 )
|
||
|
{
|
||
|
/* we could not send the message for some reason */
|
||
|
/* we close the TCP connection and break */
|
||
|
if(errno == ETIMEDOUT)
|
||
|
{
|
||
|
result = SLP_NETWORK_TIMED_OUT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = SLP_NETWORK_ERROR;
|
||
|
}
|
||
|
#ifdef _WIN32
|
||
|
closesocket(tcpsockfd);
|
||
|
#else
|
||
|
close(tcpsockfd);
|
||
|
#endif
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
retval2 = SLPNetworkRecvMessage(tcpsockfd, SOCK_STREAM, &recvbuf, &peeraddr, &timeout);
|
||
|
if ( retval2 != 0 )
|
||
|
{
|
||
|
/* An error occured while receiving the message */
|
||
|
/* probably a just time out error. break for re-send. */
|
||
|
if(errno == ETIMEDOUT)
|
||
|
{
|
||
|
result = SLP_NETWORK_TIMED_OUT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
result = SLP_NETWORK_ERROR;
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
closesocket(tcpsockfd);
|
||
|
#else
|
||
|
close(tcpsockfd);
|
||
|
#endif
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
closesocket(tcpsockfd);
|
||
|
#else
|
||
|
close(tcpsockfd);
|
||
|
#endif
|
||
|
result = SLP_OK;
|
||
|
goto SNEEK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Unsuccessful in opening a TCP connection */
|
||
|
/* just break and retry everything */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#endif
|
||
|
break;
|
||
|
#ifndef UNICAST_NOT_SUPPORTED
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
#ifndef UNICAST_NOT_SUPPORTED
|
||
|
SNEEK:
|
||
|
#endif
|
||
|
/* Sneek in and check the XID */
|
||
|
if(AsUINT16(recvbuf->start+10) == xid)
|
||
|
{
|
||
|
rplycount += 1;
|
||
|
|
||
|
/* Call the callback with the result and recvbuf */
|
||
|
#ifndef MI_NOT_SUPPORTED
|
||
|
if (cookie == NULL)
|
||
|
{
|
||
|
cookie = (PSLPHandleInfo)handle;
|
||
|
}
|
||
|
#endif /* MI_NOT_SUPPORTED */
|
||
|
if(callback(result,&peeraddr,recvbuf,cookie) == SLP_FALSE)
|
||
|
{
|
||
|
/* Caller does not want any more info */
|
||
|
/* We are done! */
|
||
|
goto CLEANUP;
|
||
|
}
|
||
|
if (prlistlen + 14 < mtu)
|
||
|
{
|
||
|
/* add the peer to the previous responder list */
|
||
|
if(prlistlen != 0)
|
||
|
{
|
||
|
strcat(prlist,",");
|
||
|
}
|
||
|
strcat(prlist,inet_ntoa(peeraddr.sin_addr));
|
||
|
prlistlen = strlen(prlist);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SLPXcastSocketsClose(&xcastsocks);
|
||
|
}
|
||
|
|
||
|
|
||
|
FINISHED:
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
/* Notify the callback with SLP_LAST_CALL so that they know we're done */
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
if(rplycount || result == SLP_NETWORK_TIMED_OUT)
|
||
|
{
|
||
|
result = SLP_LAST_CALL;
|
||
|
}
|
||
|
|
||
|
#ifndef MI_NOT_SUPPORTED
|
||
|
if (cookie == NULL)
|
||
|
{
|
||
|
cookie = (PSLPHandleInfo)handle;
|
||
|
}
|
||
|
#endif /* MI_NOT_SUPPORTED */
|
||
|
|
||
|
callback(result, NULL,NULL,cookie);
|
||
|
|
||
|
if(result == SLP_LAST_CALL)
|
||
|
{
|
||
|
result = SLP_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
CLEANUP:
|
||
|
/*----------------*/
|
||
|
/* Free resources */
|
||
|
/*----------------*/
|
||
|
if(prlist) xfree(prlist);
|
||
|
SLPBufferFree(sendbuf);
|
||
|
SLPBufferFree(recvbuf);
|
||
|
SLPXcastSocketsClose(&xcastsocks);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef UNICAST_NOT_SUPPORTED
|
||
|
/*=========================================================================*/
|
||
|
SLPError NetworkUcastRqstRply(PSLPHandleInfo handle,
|
||
|
char* buf,
|
||
|
char buftype,
|
||
|
int bufsize,
|
||
|
NetworkRplyCallback callback,
|
||
|
void * cookie)
|
||
|
/* Description: */
|
||
|
/* */
|
||
|
/* Unicasts SLP messages */
|
||
|
/* */
|
||
|
/* handle (IN) pointer to the SLP handle */
|
||
|
/* */
|
||
|
/* buf (IN) pointer to the portion of the SLP message to send. */
|
||
|
/* */
|
||
|
/* buftype (IN) the function-id to use in the SLPMessage header */
|
||
|
/* */
|
||
|
/* bufsize (IN) the size of the buffer pointed to by buf */
|
||
|
/* */
|
||
|
/* callback (IN) the callback to use for reporting results */
|
||
|
/* */
|
||
|
/* cookie (IN) the cookie to pass to the callback */
|
||
|
/* */
|
||
|
/* Returns - SLP_OK on success. SLP_ERROR on failure */
|
||
|
/*=========================================================================*/
|
||
|
{
|
||
|
struct timeval timeout;
|
||
|
struct sockaddr_in peeraddr;
|
||
|
SLPBuffer sendbuf = 0;
|
||
|
SLPBuffer recvbuf = 0;
|
||
|
SLPError result = 0;
|
||
|
int langtaglen = 0;
|
||
|
int prlistlen = 0;
|
||
|
char* prlist = 0;
|
||
|
int xid = 0;
|
||
|
int mtu = 0;
|
||
|
int size = 0;
|
||
|
int rplycount = 0;
|
||
|
int maxwait = 0;
|
||
|
int timeouts[MAX_RETRANSMITS];
|
||
|
int retval1, retval2;
|
||
|
#ifdef DEBUG
|
||
|
/* This function only supports unicast of the following messages
|
||
|
*/
|
||
|
if(buftype != SLP_FUNCT_SRVRQST &&
|
||
|
buftype != SLP_FUNCT_ATTRRQST &&
|
||
|
buftype != SLP_FUNCT_SRVTYPERQST &&
|
||
|
buftype != SLP_FUNCT_DASRVRQST)
|
||
|
{
|
||
|
return SLP_PARAMETER_BAD;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*----------------------------------------------------*/
|
||
|
/* Save off a few things we don't want to recalculate */
|
||
|
/*----------------------------------------------------*/
|
||
|
langtaglen = strlen(handle->langtag);
|
||
|
xid = SLPXidGenerate();
|
||
|
mtu = SLPPropertyAsInteger(SLPGetProperty("net.slp.MTU"));
|
||
|
sendbuf = SLPBufferAlloc(mtu);
|
||
|
if(sendbuf == 0)
|
||
|
{
|
||
|
result = SLP_MEMORY_ALLOC_FAILED;
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
|
||
|
/*-----------------------------------*/
|
||
|
/* Unicast wait timeouts */
|
||
|
/*-----------------------------------*/
|
||
|
maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.unicastMaximumWait"));
|
||
|
SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.unicastTimeouts"),
|
||
|
timeouts,
|
||
|
MAX_RETRANSMITS );
|
||
|
|
||
|
/* Special case for fake SLP_FUNCT_DASRVRQST */
|
||
|
if(buftype == SLP_FUNCT_DASRVRQST)
|
||
|
{
|
||
|
/* do something special for SRVRQST that will be discovering DAs */
|
||
|
maxwait = SLPPropertyAsInteger(SLPGetProperty("net.slp.DADiscoveryMaximumWait"));
|
||
|
SLPPropertyAsIntegerVector(SLPGetProperty("net.slp.DADiscoveryTimeouts"), timeouts, MAX_RETRANSMITS );
|
||
|
/* SLP_FUNCT_DASRVRQST is a fake function. We really want to */
|
||
|
/* send a SRVRQST */
|
||
|
buftype = SLP_FUNCT_SRVRQST;
|
||
|
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
/* Allocate memory for the prlist for appropriate messages. */
|
||
|
/* Notice that the prlist is as large as the MTU -- thus assuring that */
|
||
|
/* there will not be any buffer overwrites regardless of how many */
|
||
|
/* previous responders there are. This is because the retransmit */
|
||
|
/* code terminates if ever MTU is exceeded for any datagram message. */
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
prlist = (char*)xmalloc(mtu);
|
||
|
if(prlist == 0)
|
||
|
{
|
||
|
result = SLP_MEMORY_ALLOC_FAILED;
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
|
||
|
*prlist = 0;
|
||
|
prlistlen = 0;
|
||
|
|
||
|
/*--------------------------*/
|
||
|
/* Main unicast segment */
|
||
|
/*--------------------------*/
|
||
|
{
|
||
|
timeout.tv_sec = timeouts[0] / 1000;
|
||
|
timeout.tv_usec = (timeouts[0] % 1000) * 1000;
|
||
|
|
||
|
size = 14 + langtaglen + bufsize;
|
||
|
if(buftype == SLP_FUNCT_SRVRQST ||
|
||
|
buftype == SLP_FUNCT_ATTRRQST ||
|
||
|
buftype == SLP_FUNCT_SRVTYPERQST)
|
||
|
{
|
||
|
/* add in room for the prlist */
|
||
|
size += 2 + prlistlen;
|
||
|
}
|
||
|
|
||
|
if((sendbuf = SLPBufferRealloc(sendbuf,size)) == 0)
|
||
|
{
|
||
|
result = SLP_MEMORY_ALLOC_FAILED;
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
|
||
|
/*-----------------------------------*/
|
||
|
/* Add the header to the send buffer */
|
||
|
/*-----------------------------------*/
|
||
|
/*version*/
|
||
|
*(sendbuf->start) = 2;
|
||
|
/*function id*/
|
||
|
*(sendbuf->start + 1) = buftype;
|
||
|
/*length*/
|
||
|
ToUINT24(sendbuf->start + 2, size);
|
||
|
/*flags*/
|
||
|
ToUINT16(sendbuf->start + 5, SLP_FLAG_UCAST); /*this is a unicast */
|
||
|
/*ext offset*/
|
||
|
ToUINT24(sendbuf->start + 7,0);
|
||
|
/*xid*/
|
||
|
ToUINT16(sendbuf->start + 10,xid);
|
||
|
/*lang tag len*/
|
||
|
ToUINT16(sendbuf->start + 12,langtaglen);
|
||
|
/*lang tag*/
|
||
|
memcpy(sendbuf->start + 14, handle->langtag, langtaglen);
|
||
|
sendbuf->curpos = sendbuf->start + langtaglen + 14 ;
|
||
|
|
||
|
/*-----------------------------------*/
|
||
|
/* Add the prlist to the send buffer */
|
||
|
/*-----------------------------------*/
|
||
|
if(prlist)
|
||
|
{
|
||
|
ToUINT16(sendbuf->curpos,prlistlen);
|
||
|
sendbuf->curpos = sendbuf->curpos + 2;
|
||
|
memcpy(sendbuf->curpos, prlist, prlistlen);
|
||
|
sendbuf->curpos = sendbuf->curpos + prlistlen;
|
||
|
}
|
||
|
|
||
|
/*-----------------------------*/
|
||
|
/* Add the rest of the message */
|
||
|
/*-----------------------------*/
|
||
|
memcpy(sendbuf->curpos, buf, bufsize);
|
||
|
|
||
|
/*----------------------*/
|
||
|
/* send the send buffer */
|
||
|
/*----------------------*/
|
||
|
|
||
|
handle->unicastsock = SLPNetworkConnectStream(&(handle->unicastaddr), &timeout);
|
||
|
if ( handle->unicastsock >= 0 ) {
|
||
|
retval1 = SLPNetworkSendMessage(handle->unicastsock, SOCK_STREAM, sendbuf, &(handle->unicastaddr), &timeout);
|
||
|
if ( retval1 != 0 ) {
|
||
|
/* we could not send the message for some reason */
|
||
|
/* we close the TCP connection and break */
|
||
|
if(errno == ETIMEDOUT) {
|
||
|
result = SLP_NETWORK_TIMED_OUT;
|
||
|
}else {
|
||
|
result = SLP_NETWORK_ERROR;
|
||
|
}
|
||
|
#ifdef _WIN32
|
||
|
closesocket(handle->unicastsock);
|
||
|
#else
|
||
|
close(handle->unicastsock);
|
||
|
#endif
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
|
||
|
retval2 = SLPNetworkRecvMessage(handle->unicastsock, SOCK_STREAM, &recvbuf, &(handle->unicastaddr), &timeout);
|
||
|
if ( retval2 != 0 ) {
|
||
|
/* An error occured while receiving the message */
|
||
|
/* probably just a time out error. */
|
||
|
/* we close the TCP connection and break */
|
||
|
if(errno == ETIMEDOUT) {
|
||
|
result = SLP_NETWORK_TIMED_OUT;
|
||
|
} else {
|
||
|
result = SLP_NETWORK_ERROR;
|
||
|
}
|
||
|
#ifdef _WIN32
|
||
|
closesocket(handle->unicastsock);
|
||
|
#else
|
||
|
close(handle->unicastsock);
|
||
|
#endif
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
#ifdef _WIN32
|
||
|
closesocket(handle->unicastsock);
|
||
|
#else
|
||
|
close(handle->unicastsock);
|
||
|
#endif
|
||
|
result = SLP_OK;
|
||
|
} else {
|
||
|
result = SLP_NETWORK_TIMED_OUT;
|
||
|
/* Unsuccessful in opening a TCP connection */
|
||
|
/* just break */
|
||
|
goto FINISHED;
|
||
|
}
|
||
|
/* Sneek in and check the XID */
|
||
|
if(AsUINT16(recvbuf->start+10) == xid)
|
||
|
{
|
||
|
rplycount += 1;
|
||
|
/* Call the callback with the result and recvbuf */
|
||
|
if(callback(result,&peeraddr,recvbuf,cookie) == SLP_FALSE)
|
||
|
{
|
||
|
/* Caller does not want any more info */
|
||
|
/* We are done! */
|
||
|
goto CLEANUP;
|
||
|
}
|
||
|
/* add the peer to the previous responder list */
|
||
|
if(prlistlen != 0)
|
||
|
{
|
||
|
strcat(prlist,",");
|
||
|
}
|
||
|
strcat(prlist,inet_ntoa(peeraddr.sin_addr));
|
||
|
prlistlen = strlen(prlist);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FINISHED:
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
/* Notify the callback with SLP_LAST_CALL so that they know we're done */
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
if(rplycount || result == SLP_NETWORK_TIMED_OUT)
|
||
|
{
|
||
|
result = SLP_LAST_CALL;
|
||
|
}
|
||
|
|
||
|
callback(result, NULL,NULL,cookie);
|
||
|
if(result == SLP_LAST_CALL)
|
||
|
{
|
||
|
result = SLP_OK;
|
||
|
}
|
||
|
|
||
|
CLEANUP:
|
||
|
/*----------------*/
|
||
|
/* Free resources */
|
||
|
/*----------------*/
|
||
|
if(prlist) xfree(prlist);
|
||
|
SLPBufferFree(sendbuf);
|
||
|
SLPBufferFree(recvbuf);
|
||
|
|
||
|
return result;
|
||
|
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|