1 /*-------------------------------------------------------------------------
2  * Copyright (C) 2000 Caldera Systems, Inc
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *    Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  *    Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  *    Neither the name of Caldera Systems nor the names of its
17  *    contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA
24  * SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *-------------------------------------------------------------------------*/
32 
33 /** Networking routines.
34  *
35  * Implementation for functions that are related to INTERNAL library
36  * network (and ipc) communication.
37  *
38  * @file       libslp_network.c
39  * @author     Matthew Peterson, John Calcote (jcalcote@novell.com)
40  * @attention  Please submit patches to http://www.openslp.org
41  * @ingroup    LibSLPCode
42  */
43 
44 /*#include <netinet/tcp.h>*/
45 #include "slp.h"
46 #include "libslp.h"
47 #include "slp_net.h"
48 #include "slp_network.h"
49 #include "slp_iface.h"
50 #include "slp_message.h"
51 #include "slp_v1message.h"
52 #include "slp_compare.h"
53 #include "slp_xmalloc.h"
54 #include "slp_xcast.h"
55 #include "slp_socket.h"
56 
57 /*Maximum MTU value that can be specified in config. See getmtu() */
58 #define MAX_MTU 65535
59 
60 /** Obtains the MTU value to be used from configuration.
61  *
62  * The maximum transmission unit size that is specified in configuration
63  * determines many other parameter sizings.  This routines checks the
64  * value for reasonability (against MAX_MTU) and either fails (debug)
65  * or caps the value at MAX_MTU to enhance stability.
66  *
67  * @return The MTU use size from config.
68  *
69  * @internal
70  */
getmtu(void)71 static size_t getmtu(void)
72 {
73    size_t mtu = SLPPropertyGetMTU();
74    SLP_ASSERT(mtu <= MAX_MTU); /*Fail in debug*/
75    if (mtu > MAX_MTU)          /*Cap in non debug*/
76    {
77       mtu = MAX_MTU;
78    }
79    return mtu;
80 }
81 
82 #ifdef _WIN32
83 
84 #define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
85 struct timezone
86 {
87   int  tz_minuteswest; /* minutes W of Greenwich */
88   int  tz_dsttime;     /* type of dst correction */
89 };
90 
91 /** A version of gettimeofday for Windows.
92  *
93  * @param[in] tp - timeval containing number of seconds/microseconds since Jan 1 1970
94  * @param[in] tzp - time zone modifier -- Ignored, since the code isn't using it
95  *
96  * A version of gettimeofday for Windows.  Grabbed from MSDN.
97  *
98  * @internal
99  */
gettimeofday(struct timeval * tv,struct timezone * tz)100 int gettimeofday(struct timeval *tv, struct timezone *tz)
101 {
102   FILETIME ft;
103   unsigned __int64 tmpres = 0;
104   static int tzflag;
105 
106   if (NULL != tv)
107   {
108     GetSystemTimeAsFileTime(&ft);
109 
110     tmpres |= ft.dwHighDateTime;
111     tmpres <<= 32;
112     tmpres |= ft.dwLowDateTime;
113 
114     /*converting file time to unix epoch*/
115     tmpres -= DELTA_EPOCH_IN_MICROSECS;
116     tmpres /= 10;  /*convert into microseconds*/
117     tv->tv_sec = (long)(tmpres / 1000000UL);
118     tv->tv_usec = (long)(tmpres % 1000000UL);
119   }
120 
121   if (NULL != tz)
122   {
123     if (!tzflag)
124     {
125       _tzset();
126       tzflag++;
127     }
128     tz->tz_minuteswest = _timezone / 60;
129     tz->tz_dsttime = _daylight;
130   }
131 
132   return 0;
133 }
134 #endif
135 
136 /** Subtracts one timeval from another.
137  *
138  * @param[in] lhs - timeval to be subtracted from
139  * @param[in] rhs - timeval to subtract
140  *
141  * Subtract the rhs from the lhs, putting the result into the lhs
142  *
143  * @internal
144  */
timeval_subtract(struct timeval * lhs,struct timeval * rhs)145 void timeval_subtract(struct timeval *lhs, struct timeval *rhs)
146 {
147     lhs->tv_sec -= rhs->tv_sec;
148     lhs->tv_usec -= rhs->tv_usec;
149     if (lhs->tv_usec < 0)
150     {
151         lhs->tv_usec += 1000000;
152         --lhs->tv_sec;
153     }
154 }
155 
156 /** Adds one timeval to another.
157  *
158  * @param[in] lhs - timeval to be added to
159  * @param[in] rhs - timeval to add
160  *
161  * Add the rhs to the lhs, putting the result into the lhs
162  *
163  * @internal
164  */
timeval_add(struct timeval * lhs,struct timeval * rhs)165 void timeval_add(struct timeval *lhs, struct timeval *rhs)
166 {
167     lhs->tv_sec += rhs->tv_sec;
168     lhs->tv_usec += rhs->tv_usec;
169     if (lhs->tv_usec >= 1000000)
170     {
171         lhs->tv_usec -= 1000000;
172         ++lhs->tv_sec;
173     }
174 }
175 
176 /** Returns the appropriate buffer size for the various RequestReply functions
177  *
178  * @param[in] v1 - Whether or not this is a SLPv1 packet
179  * @param[in] buftype - The message type
180  * @param[in] langsize - the language tag size
181  * @param[in] prlistlen - the current size of the prlist, only used for appropriate buftypes
182  * @param[in] bufsize - The size of the message
183  *
184  * @return the size
185  */
CalcBufferSize(int v1,char buftype,size_t langsize,size_t prlistlen,size_t bufsize)186 size_t CalcBufferSize(int v1, char buftype, size_t langsize, size_t prlistlen, size_t bufsize)
187 {
188    size_t size = 0;
189 
190    if(v1)
191    {
192       /*  1  Version
193         + 1  Function-ID
194         + 2  Length
195         + 1  Flags/Reserved
196         + 1  Dialect
197         + 2  Language Code
198         + 2  Char Encoding
199         + 2  XID                  */
200       size =  12;
201    }
202    else
203    {
204       /*  1  Version
205         + 1  Function-ID
206         + 3  Length
207         + 2  Flags
208         + 3  Extension Offset
209         + 2  XID
210         + 2  Lang Tag Len   */
211       size = 14 + langsize;
212    }
213 
214    size += bufsize;
215 
216    if (buftype == SLP_FUNCT_SRVRQST
217          || buftype == SLP_FUNCT_ATTRRQST
218          || buftype == SLP_FUNCT_SRVTYPERQST)
219    {
220          size += (2 + prlistlen); /* <PRList> Len/String  */
221    }
222 
223    return size;
224 }
225 
226 #if !defined(MI_NOT_SUPPORTED)
227 
228 /** Returns all multi-cast addresses to which a message type can be sent.
229  *
230  * Returns all the multicast addresses the msgtype can be sent out to. If
231  * there is more than one address returned, the addresses will be in the
232  * order that they should be consumed (according to policy).
233  *
234  * @param[in] msgtype - The function-id to use in the SLPMessage header
235  * @param[in] msg - A pointer to the portion of the SLP message to send.
236  *    The portion to that should be pointed to is everything after the
237  *    pr-list. Only needed for Service Requests. Set to NULL if not needed.
238  * @param[out] ifaceinfo - The interface to send the msg to.
239  *
240  * @return SLP_OK on success. SLP_ERROR on failure.
241  *
242  * @internal
243  */
NetworkGetMcastAddrs(const char msgtype,uint8_t * msg,SLPIfaceInfo * ifaceinfo)244 static int NetworkGetMcastAddrs(const char msgtype, uint8_t * msg,
245       SLPIfaceInfo * ifaceinfo)
246 {
247    uint16_t port;
248 
249    if (!ifaceinfo)
250       return SLP_PARAMETER_BAD;
251 
252    port = (uint16_t)SLPPropertyAsInteger("net.slp.port");
253    ifaceinfo->bcast_count = ifaceinfo->iface_count = 0;
254    switch (msgtype)
255    {
256       case SLP_FUNCT_SRVRQST:
257          if (!msg)
258             return SLP_PARAMETER_BAD;
259          if (SLPNetIsIPV6())
260          {
261             uint16_t srvtype_len = GetUINT16(&msg);
262             const char * srvtype = GetStrPtr(&msg, srvtype_len);
263             /* Add IPv6 multicast groups in order they should appear. */
264             SLPNetGetSrvMcastAddr(srvtype, srvtype_len, SLP_SCOPE_NODE_LOCAL,
265                   &ifaceinfo->iface_addr[ifaceinfo->iface_count++]);
266             SLPNetGetSrvMcastAddr(srvtype, srvtype_len, SLP_SCOPE_LINK_LOCAL,
267                   &ifaceinfo->iface_addr[ifaceinfo->iface_count++]);
268             SLPNetGetSrvMcastAddr(srvtype, srvtype_len, SLP_SCOPE_SITE_LOCAL,
269                   &ifaceinfo->iface_addr[ifaceinfo->iface_count++]);
270          }
271          if (SLPNetIsIPV4())
272          {
273             struct in_addr mcastaddr;
274             mcastaddr.s_addr = SLP_MCAST_ADDRESS;
275             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
276                   AF_INET, port, &mcastaddr);
277             ifaceinfo->iface_count++;
278          }
279          break;
280 
281       case SLP_FUNCT_ATTRRQST:
282          if (SLPNetIsIPV6())
283          {
284             /* Add IPv6 multicast groups in order they should appear. */
285             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
286                   AF_INET6, port, &in6addr_srvloc_node);
287             ifaceinfo->iface_count++;
288             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
289                   AF_INET6, port, &in6addr_srvloc_link);
290             ifaceinfo->iface_count++;
291             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
292                   AF_INET6, port, &in6addr_srvloc_site);
293             ifaceinfo->iface_count++;
294          }
295          if (SLPNetIsIPV4())
296          {
297             struct in_addr mcastaddr;
298             mcastaddr.s_addr = SLP_MCAST_ADDRESS;
299             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
300                   AF_INET, port, &mcastaddr);
301             ifaceinfo->iface_count++;
302          }
303          break;
304 
305       case SLP_FUNCT_SRVTYPERQST:
306          if (SLPNetIsIPV6())
307          {
308             /* Add IPv6 multicast groups in order they should appear. */
309             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
310                   AF_INET6, port, &in6addr_srvloc_node);
311             ifaceinfo->iface_count++;
312             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
313                   AF_INET6, port, &in6addr_srvloc_link);
314             ifaceinfo->iface_count++;
315             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
316                   AF_INET6, port, &in6addr_srvloc_site);
317             ifaceinfo->iface_count++;
318          }
319          if (SLPNetIsIPV4())
320          {
321             struct in_addr mcastaddr;
322             mcastaddr.s_addr = SLP_MCAST_ADDRESS;
323             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
324                   AF_INET, port, &mcastaddr);
325             ifaceinfo->iface_count++;
326          }
327          break;
328 
329       case SLP_FUNCT_DASRVRQST:
330          if (SLPNetIsIPV6())
331          {
332             /* Add IPv6 multicast groups in order they should appear. */
333             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
334                   AF_INET6, port, &in6addr_srvlocda_node);
335             ifaceinfo->iface_count++;
336             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
337                   AF_INET6, port, &in6addr_srvlocda_link);
338             ifaceinfo->iface_count++;
339             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
340                   AF_INET6, port, &in6addr_srvlocda_site);
341             ifaceinfo->iface_count++;
342          }
343          if (SLPNetIsIPV4())
344          {
345             struct in_addr mcastaddr;
346             mcastaddr.s_addr = SLP_MCAST_ADDRESS;
347             SLPNetSetAddr(&ifaceinfo->iface_addr[ifaceinfo->iface_count],
348                   AF_INET, port, &mcastaddr);
349             ifaceinfo->iface_count++;
350          }
351          break;
352 
353       default:
354          return SLP_PARAMETER_BAD;
355    }
356    return SLP_OK;
357 }
358 
359 #endif   /* ! MI_NOT_SUPPORTED */
360 
361 /** Connects to slpd and provides a peeraddr to send to.
362  *
363  * @param[out] peeraddr - The address of storage for the connected
364  *    DA's address.
365  * @param[in,out] peeraddrsz - The size in bytes of @p peeraddr on
366  *    entry; the size of the address stored in @p peeraddr on exit.
367  *
368  * @return The connected socket, or -1 if no DA connection can be made.
369  */
NetworkConnectToSlpd(void * peeraddr)370 sockfd_t NetworkConnectToSlpd(void * peeraddr)
371 {
372    sockfd_t sock = SLP_INVALID_SOCKET;
373 
374    /*Note that these don't actually test the connection to slpd.
375      They don't have to, since all code that calls this function eventually
376     does a NetworkRqstRply, which has retry logic for the datagram case*/
377 
378    if (SLPNetIsIPV6())
379       if (!SLPNetSetAddr(peeraddr, AF_INET6, (uint16_t)SLPPropertyAsInteger("net.slp.port"),
380             &slp_in6addr_loopback))
381          sock = SLPNetworkCreateDatagram(AF_INET6);
382 
383    if (sock == SLP_INVALID_SOCKET && SLPNetIsIPV4())
384    {
385       int tempAddr = INADDR_LOOPBACK;
386       if (SLPNetSetAddr(peeraddr, AF_INET,
387             (uint16_t)SLPPropertyAsInteger("net.slp.port"), &tempAddr) == 0)
388          sock = SLPNetworkCreateDatagram(AF_INET);
389    }
390    return sock;
391 }
392 
393 /** Check if the socket is still alive - the server may have closed it.
394  *
395  * @param[in] fd - The socket decriptor to check.
396  *
397  * @return SLP_OK if socket is still alive; SLP_NETWORK_ERROR if not.
398  */
NetworkCheckConnection(sockfd_t fd)399 static SLPError NetworkCheckConnection(sockfd_t fd)
400 {
401    int r;
402 #ifdef HAVE_POLL
403     struct pollfd readfd;
404 #else
405     fd_set readfd;
406     struct timeval tv;
407 #endif
408 
409 #ifdef HAVE_POLL
410     readfd.fd = fd;
411     readfd.events = POLLIN;
412     while ((r = poll(&readfd, 1, 0)) == -1 && errno == EINTR)
413         ;
414 #else
415    FD_ZERO(&readfd);
416    FD_SET(fd, &readfd);
417    tv.tv_sec = 0;
418    tv.tv_usec = 0;
419    while ((r = select((int)(fd + 1), &readfd, 0, 0, &tv)) == -1)
420    {
421 #ifdef _WIN32
422      if (WSAGetLastError() != WSAEINTR)
423 #else
424      if (errno != EINTR)
425 #endif
426         break;
427    }
428 #endif
429    /* r == 0 means timeout, everything else is an error */
430    return r == 0 ? SLP_OK : SLP_NETWORK_ERROR;
431 }
432 
433 /** Disconnect from the connected DA.
434  *
435  * Called after DA fails to respond.
436  *
437  * @param[in] handle - The SLP handle containing the socket to close.
438  */
NetworkDisconnectDA(SLPHandleInfo * handle)439 void NetworkDisconnectDA(SLPHandleInfo * handle)
440 {
441    if (handle->dasock != SLP_INVALID_SOCKET)
442    {
443       closesocket(handle->dasock);
444       handle->dasock = SLP_INVALID_SOCKET;
445    }
446    KnownDABadDA(&handle->daaddr);
447 }
448 
449 /** Disconnect from the connected SA.
450  *
451  * Called after SA fails to respond.
452  *
453  * @param[in] handle - The SLP handle containing the socket to close.
454  */
NetworkDisconnectSA(SLPHandleInfo * handle)455 void NetworkDisconnectSA(SLPHandleInfo * handle)
456 {
457    if (handle->sasock != SLP_INVALID_SOCKET)
458    {
459       closesocket(handle->sasock);
460       handle->sasock = SLP_INVALID_SOCKET;
461    }
462 }
463 
464 /** Connects to slpd and provides a peeraddr to send to
465  *
466  * @param[in] handle - The SLP handle containing the socket to close.
467  * @param[in] scopelist - The scope that must be supported by DA. Pass
468  *    in NULL for any scope
469  * @param[in] scopelistlen - The length of @p scopelist. Ignored if
470  *    @p scopelist is NULL.
471  * @param[out] peeraddr - The address of storage to receive the connected
472  *    DA's address.
473  *
474  * @return The connected socket, or -1 if no DA connection can be made.
475  */
NetworkConnectToDA(SLPHandleInfo * handle,const char * scopelist,size_t scopelistlen,void * peeraddr)476 sockfd_t NetworkConnectToDA(SLPHandleInfo * handle, const char * scopelist,
477       size_t scopelistlen, void * peeraddr)
478 {
479    /* Attempt to use a cached socket if scope is supported otherwise
480     * discover a DA that supports the scope.
481     */
482    if (handle->dasock != SLP_INVALID_SOCKET && handle->dascope != 0
483          && SLPSubsetStringList(handle->dascopelen, handle->dascope,
484                scopelistlen, scopelist) != 0
485          && NetworkCheckConnection(handle->dasock) == SLP_OK)
486       memcpy(peeraddr, &handle->daaddr, sizeof(struct sockaddr_storage));
487    else
488    {
489       /* Close existing handle because it doesn't support the scope. */
490       if (handle->dasock != SLP_INVALID_SOCKET)
491          closesocket(handle->dasock);
492 
493       /* Attempt to connect to DA that does support the scope. */
494       handle->dasock = KnownDAConnect(handle, scopelistlen, scopelist,
495             &handle->daaddr);
496       if (handle->dasock != SLP_INVALID_SOCKET)
497       {
498          xfree(handle->dascope);
499          handle->dascope = xmemdup(scopelist, scopelistlen);
500          handle->dascopelen = scopelistlen;
501          memcpy(peeraddr, &handle->daaddr, sizeof(struct sockaddr_storage));
502       }
503    }
504    return handle->dasock;
505 }
506 
507 /** Connects to slpd and provides a network address to send to.
508  *
509  * This routine attempts to use a cached socket if the cached socket supports
510  * one of the scopes specified in @p scopelist, otherwise it attempts to
511  * connect to the local Service Agent, or a DA that supports the scope, in
512  * order to register directly, if no local SA is present.
513  *
514  * @param[in] handle - SLPHandle info (caches connection info).
515  * @param[in] scopelist - Scope that must be supported by SA. Pass in
516  *    NULL for any scope.
517  * @param[in] scopelistlen - The length of @p scopelist in bytes.
518  *    Ignored if @p scopelist is NULL.
519  * @param[out] saaddr - The address of storage to receive the connected
520  *    SA's address.
521  *
522  * @return The connected socket, or -1 if no SA connection can be made.
523  *
524  * @note The memory pointed to by @p saaddr must at least as large as a
525  * sockaddr_storage buffer.
526  */
NetworkConnectToSA(SLPHandleInfo * handle,const char * scopelist,size_t scopelistlen,void * saaddr)527 sockfd_t NetworkConnectToSA(SLPHandleInfo * handle, const char * scopelist,
528       size_t scopelistlen, void * saaddr)
529 {
530    if (handle->sasock != SLP_INVALID_SOCKET && handle->sascope != 0
531          && SLPSubsetStringList(handle->sascopelen, handle->sascope,
532                scopelistlen, scopelist) != 0
533          && NetworkCheckConnection(handle->sasock) == SLP_OK)
534       memcpy(saaddr, &handle->saaddr, sizeof(handle->saaddr));
535    else
536    {
537       /* Close last cached SA socket - scopes not supported. */
538       if (handle->sasock != SLP_INVALID_SOCKET)
539          closesocket(handle->sasock);
540 
541       /* Attempt to connect to slpd via loopback. */
542       handle->sasock = NetworkConnectToSlpd(&handle->saaddr);
543 
544       /* If we connected to something, cache scope and addr info. */
545       if (handle->sasock != SLP_INVALID_SOCKET)
546       {
547          xfree(handle->sascope);
548          handle->sascope = xmemdup(scopelist, scopelistlen);
549          handle->sascopelen = scopelistlen;
550          memcpy(saaddr, &handle->saaddr, sizeof(handle->saaddr));
551       }
552    }
553    return handle->sasock;
554 }
555 
556 /** Make a request and wait for a reply, or timeout.
557  *
558  * @param[in] sock - The socket to send/receive on.
559  * @param[in] peeraddr - The address to send to.
560  * @param[in] langtag - The language to send in.
561  * @param[in] extoffset - The offset to the first extension in @p buf.
562  * @param[in] buf - The message to send.
563  * @param[in] buftype - The type of @p buf.
564  * @param[in] bufsize - The size of @p buf.
565  * @param[in] callback - The user callback to call with response data.
566  * @param[in] cookie - A pass through value from the caller to @p callback.
567  * @param[in] isV1 - Whether or not to use a V1 header.
568  *
569  * @return SLP_OK on success, or an SLP error code on failure.
570  */
NetworkRqstRply(sockfd_t sock,void * peeraddr,const char * langtag,size_t extoffset,void * buf,char buftype,size_t bufsize,NetworkRplyCallback callback,void * cookie,int isV1)571 SLPError NetworkRqstRply(sockfd_t sock, void * peeraddr,
572       const char * langtag, size_t extoffset, void * buf, char buftype,
573       size_t bufsize, NetworkRplyCallback callback, void * cookie, int isV1)
574 {
575    char * prlist = 0;
576    unsigned short flags;
577    char v1flags;
578 
579    size_t mtu = 0;
580    size_t prlistlen = 0;
581    SLPBuffer sendbuf = 0;
582    SLPBuffer recvbuf = 0;
583    SLPError result = SLP_OK;
584 
585    int looprecv;   /*If non-zero, keep receiving until you timeout/error, etc.*/
586    int stoploopifrecv;   /*... but if this is non-zero, stop on the first valid receipt*/
587    int xmitcount;
588    int maxwait;
589    int socktype;
590    int rplycount = 0;
591    int totaltimeout = 0;
592    int xid = SLPXidGenerate();
593    int timeouts[MAX_RETRANSMITS];
594 
595    struct sockaddr_storage addr;
596    size_t langtaglen = strlen(langtag);
597 
598    /* Determine unicast/multicast, TCP/UDP and timeout values. */
599    if (SLPNetIsMCast(peeraddr))
600    {
601       /* Multicast or broadcast target address. */
602       maxwait = SLPPropertyAsInteger("net.slp.multicastMaximumWait");
603       SLPPropertyAsIntegerVector("net.slp.multicastTimeouts",
604             timeouts, MAX_RETRANSMITS);
605       xmitcount = 0;          /* Only retry to specific listeners. */
606       looprecv = 1;
607       stoploopifrecv = 0;     /* Several responders would respond to the multicast */
608       socktype = SOCK_DGRAM;  /* Broad/multicast are datagrams. */
609    }
610    else
611    {
612       /* Unicast/stream target address. */
613       socklen_t stypesz = sizeof(socktype);
614       maxwait = SLPPropertyAsInteger("net.slp.unicastMaximumWait");
615       SLPPropertyAsIntegerVector("net.slp.unicastTimeouts",
616             timeouts, MAX_RETRANSMITS);
617       getsockopt(sock, SOL_SOCKET, SO_TYPE, (char *)&socktype, &stypesz);
618       if (socktype == SOCK_DGRAM)
619       {
620          xmitcount = 0;                /* Datagrams must be retried. */
621          looprecv  = 1;
622          stoploopifrecv = 1;           /* The peer has sent the single response. */
623       }
624       else
625       {
626          xmitcount = MAX_RETRANSMITS -1;  /* Streams manage own retries, so we want the loop to iterate once. */
627          looprecv  = 0;
628          stoploopifrecv = 0;
629       }
630    }
631 
632    /* Special case for fake SLP_FUNCT_DASRVRQST. */
633    if (buftype == SLP_FUNCT_DASRVRQST)
634    {
635       /* do something special for SRVRQST that will be discovering DAs */
636       maxwait = SLPPropertyAsInteger("net.slp.DADiscoveryMaximumWait");
637       SLPPropertyAsIntegerVector("net.slp.DADiscoveryTimeouts",
638             timeouts, MAX_RETRANSMITS);
639       /* DASRVRQST is a fake function - change to SRVRQST. */
640       buftype  = SLP_FUNCT_SRVRQST;
641       looprecv = 1;  /* We're streaming replies in from the DA. */
642       stoploopifrecv = 0;  /* These replies are separate datagram responses. */
643    }
644 
645    /* Allocate memory for the prlist on datagram sockets for appropriate
646     * messages. Note that the prlist is as large as the MTU -- thus assuring
647     * that there will not be any buffer overwrites regardless of how many
648     * previous responders there are. This is because the retransmit code
649     * terminates if ever MTU is exceeded for any datagram message.
650     */
651    mtu = getmtu();
652    if (buftype == SLP_FUNCT_SRVRQST
653          || buftype == SLP_FUNCT_ATTRRQST
654          || buftype == SLP_FUNCT_SRVTYPERQST)
655    {
656       prlist = (char *)xmalloc(mtu);
657       if (!prlist)
658       {
659          result = SLP_MEMORY_ALLOC_FAILED;
660          goto CLEANUP;
661       }
662       *prlist = 0;
663       prlistlen = 0;
664    }
665 
666    /* ----- Main Retransmission Loop ----- */
667    while (xmitcount < MAX_RETRANSMITS)
668    {
669       size_t size;
670       struct timeval timeout;
671       result = SLP_OK;
672 
673       /* Setup receive timeout. */
674       if (socktype == SOCK_DGRAM)
675       {
676          /*If we've already received replies from the peer, no need to resend.*/
677          if((rplycount != 0) && (!SLPNetIsMCast(peeraddr)))
678             break;
679 
680          totaltimeout += timeouts[xmitcount];
681          if (totaltimeout >= maxwait || !timeouts[xmitcount])
682          {
683             result = SLP_NETWORK_TIMED_OUT;
684             break; /* Max timeout exceeded - we're done. */
685          }
686 
687          timeout.tv_sec = timeouts[xmitcount] / 1000;
688          timeout.tv_usec = (timeouts[xmitcount] % 1000) * 1000;
689       }
690       else
691       {
692          timeout.tv_sec = maxwait / 1000;
693          timeout.tv_usec = (maxwait % 1000) * 1000;
694       }
695 
696       size = CalcBufferSize(isV1, buftype, langtaglen, prlistlen, bufsize);
697 
698       /* Ensure the send buffer size does not exceed MTU for datagrams. */
699       if (socktype == SOCK_DGRAM && size > mtu)
700       {
701          if (!xmitcount)
702             result = SLP_BUFFER_OVERFLOW;
703          goto FINISHED;
704       }
705 
706       /* (Re)Allocate the send buffer based on the (new) size. */
707       if ((sendbuf = SLPBufferRealloc(sendbuf, size)) == 0)
708       {
709          result = SLP_MEMORY_ALLOC_FAILED;
710          goto CLEANUP;
711       }
712       xmitcount++;
713 
714       /* -- Begin SLP Header -- */
715       if(isV1)
716       {
717          /* Version */
718          *sendbuf->curpos++ = 1;
719 
720          /* Function-ID */
721          *sendbuf->curpos++ = buftype;
722 
723          /* Length */
724          PutUINT16(&sendbuf->curpos, size);
725 
726          /* flags */
727          v1flags = 0;
728          if (buftype == SLP_FUNCT_SRVREG)
729             v1flags |= SLPv1_FLAG_FRESH;
730          *sendbuf->curpos++ = v1flags;
731 
732          /* dialect */
733          *sendbuf->curpos++ = 0;
734 
735          /* Language code.  For now, we'll take the first two bytes of the tag */
736          if(langtaglen < 2)
737          {
738             *sendbuf->curpos++ = 'e';
739             *sendbuf->curpos++ = 'n';
740          }
741          else
742          {
743             *sendbuf->curpos++ = langtag[0];
744             *sendbuf->curpos++ = langtag[1];
745          }
746 
747          /* Character encoding -- assume UTF8 */
748          PutUINT16(&sendbuf->curpos, SLP_CHAR_UTF8);
749 
750          /* XID */
751          PutUINT16(&sendbuf->curpos, xid);
752       }
753       else
754       {
755          /* Version */
756          *sendbuf->curpos++ = 2;
757 
758          /* Function-ID */
759          *sendbuf->curpos++ = buftype;
760 
761          /* Length */
762          PutUINT24(&sendbuf->curpos, size);
763 
764          /* Flags */
765          flags = (SLPNetIsMCast(peeraddr)? SLP_FLAG_MCAST : 0);
766          if (buftype == SLP_FUNCT_SRVREG)
767             flags |= SLP_FLAG_FRESH;
768          PutUINT16(&sendbuf->curpos, flags);
769 
770          /* Extension Offset - TRICKY: The extoffset was passed into us
771           * relative to the start of the user's message, not the SLP header.
772           * We need to fix up the offset to be relative to the beginning of
773           * the SLP message.
774           */
775          if (extoffset != 0)
776             PutUINT24(&sendbuf->curpos, extoffset + langtaglen + 14);
777          else
778             PutUINT24(&sendbuf->curpos, 0);
779 
780          /* XID */
781          PutUINT16(&sendbuf->curpos, xid);
782 
783          /* Language Tag Length */
784          PutUINT16(&sendbuf->curpos, langtaglen);
785 
786          /* Language Tag */
787          memcpy(sendbuf->curpos, langtag, langtaglen);
788          sendbuf->curpos += langtaglen;
789       }
790       /* -- End SLP Header -- */
791 
792       /* -- Begin SLP Message -- */
793 
794       /* Add the prlist for appropriate message types. */
795       if (prlist)
796       {
797          PutUINT16(&sendbuf->curpos, prlistlen);
798          memcpy(sendbuf->curpos, prlist, prlistlen);
799          sendbuf->curpos += prlistlen;
800       }
801 
802       /* @todo Add scatter-gather so we don't have to copy buffers. */
803 
804       /* Add the rest of the message. */
805       memcpy(sendbuf->curpos, buf, bufsize);
806       sendbuf->curpos += bufsize;
807 
808       /* -- End SLP Message -- */
809 
810       /* Send the buffer. */
811       if (SLPNetworkSendMessage(sock, socktype, sendbuf,
812             sendbuf->curpos - sendbuf->start, peeraddr,
813             &timeout) != 0)
814       {
815          if (errno == ETIMEDOUT)
816             result = SLP_NETWORK_TIMED_OUT;
817          else
818             result = SLP_NETWORK_ERROR;
819          goto FINISHED;
820       }
821 
822       /* ----- Main Receive Loop ----- */
823       do
824       {
825          /* Set peer family to "not set" so we can detect if it was set. */
826          addr.ss_family = AF_UNSPEC;
827 
828          /* Receive the response. */
829          if (SLPNetworkRecvMessage(sock, socktype, &recvbuf,
830                &addr, &timeout) != 0)
831          {
832             if (errno == ETIMEDOUT)
833                result = SLP_NETWORK_TIMED_OUT;
834             else
835                result = SLP_NETWORK_ERROR;
836             break;
837          }
838          else
839          {
840             /* Sneek in and validate the XID. */
841             if (AS_UINT16(recvbuf->start + 10) == xid)
842             {
843                rplycount += 1;
844 
845                /* Check the family type of the addr. If it is not set,
846                 * assume the addr is the peeraddr. addr is only set on
847                 * datagram sockets in the SLPNetworkRecvMessage call.
848                 */
849                if (addr.ss_family == AF_UNSPEC)
850                   memcpy(&addr, peeraddr, sizeof(addr));
851 
852                /* Call the callback with the result and recvbuf. */
853                if (callback(result, &addr, recvbuf, cookie) == SLP_FALSE)
854                   goto CLEANUP; /* Caller doesn't want any more info. */
855 
856                /* Add the peer to the prlist on appropriate message types. */
857                if (prlist)
858                {
859                   /* Convert peeraddr to string and length. */
860                   size_t addrstrlen;
861                   char addrstr[INET6_ADDRSTRLEN] = "";
862                   SLPNetSockAddrStorageToString(&addr,
863                            addrstr, sizeof(addrstr));
864                   addrstrlen = strlen(addrstr);
865                   if (addrstrlen > 0 && SLPContainsStringList(prlistlen,
866                            prlist, addrstrlen, addrstr) == 0)
867                   {
868                      /* Append to the prlist if we won't overflow. */
869                      if (prlistlen + addrstrlen + 1 < mtu)
870                      {
871                         /* Append comma if necessary. */
872                         if (prlistlen)
873                            prlist[prlistlen++] = ',';
874 
875                         /* Append address string. */
876                         strcpy(prlist + prlistlen, addrstr);
877                         prlistlen += addrstrlen;
878                      }
879                   }
880                }
881 
882                if(stoploopifrecv)
883                   break;
884             }
885          }
886       } while (looprecv);
887    }
888 
889 FINISHED:
890 
891    /* Notify the callback that we're done. */
892    if (rplycount != 0 || (result == SLP_NETWORK_TIMED_OUT
893          && SLPNetIsMCast(peeraddr)))
894       result = SLP_LAST_CALL;
895 
896    if(recvbuf)
897       callback(result, &addr, recvbuf, cookie);
898 
899    if (result == SLP_LAST_CALL)
900       result = 0;
901 
902 CLEANUP:
903 
904    /* Free resources. */
905    xfree(prlist);
906    SLPBufferFree(sendbuf);
907    SLPBufferFree(recvbuf);
908 
909    return result;
910 }
911 
912 /** Make a request and wait for a reply, or timeout.
913  *
914  * @param[in] handle - The SLP handle associated with this request.
915 
916  * param[in] langtag - Language tag to use in SLP message header
917 
918  * @param[in] buf - The pointer to the portion of the SLP message to
919  *    send. The portion that should be pointed to is everything after
920  *    the pr-list. NetworkXcastRqstRply() automatically generates the
921  *    header and the prlist.
922  * @param[in] buftype - The function-id to use in the SLPMessage header.
923  * @param[in] bufsize - The size of the buffer pointed to by buf.
924  * @param[in] callback - The callback to use for reporting results.
925  * @param[in] cookie - The cookie to pass to the callback.
926  * @param[in] isV1 - Whether or not to use a v1 header.
927  *
928  * @return SLP_OK on success. SLP_ERROR on failure.
929  */
NetworkMcastRqstRply(SLPHandleInfo * handle,void * buf,char buftype,size_t bufsize,NetworkRplyCallback callback,void * cookie,int isV1)930 SLPError NetworkMcastRqstRply(SLPHandleInfo * handle, void * buf,
931       char buftype, size_t bufsize, NetworkRplyCallback callback,
932       void * cookie, int isV1)
933 {
934    struct timeval timeout;
935    struct sockaddr_storage addr;
936    SLPBuffer sendbuf = 0;
937    SLPBuffer recvbuf = 0;
938    SLPError result = 0;
939    size_t langtaglen = 0;
940    size_t prlistlen = 0;
941    size_t prlistsize = 0;
942    int size = 0;
943    char * prlist = 0;
944    int xid = 0;
945    size_t mtu = 0;
946    int xmitcount = 0;
947    int rplycount = 0;
948    int maxwait = 0;
949    int totaltimeout = 0;
950    int usebroadcast = 0;
951    int timeouts[MAX_RETRANSMITS];
952    SLPIfaceInfo dstifaceinfo;
953    SLPIfaceInfo v4outifaceinfo;
954    SLPIfaceInfo v6outifaceinfo;
955    SLPXcastSockets xcastsocks;
956    int alistsize;
957    int currIntf = 0;
958 
959 #if defined(DEBUG)
960    /* This function only supports multicast or broadcast of these messages */
961    if (buftype != SLP_FUNCT_SRVRQST && buftype != SLP_FUNCT_ATTRRQST
962          && buftype != SLP_FUNCT_SRVTYPERQST && buftype != SLP_FUNCT_DASRVRQST)
963       return SLP_PARAMETER_BAD;
964 #endif
965 
966    /* save off a few things we don't want to recalculate */
967    langtaglen = strlen(handle->langtag);
968 
969    /* initialize pointers freed on error */
970    dstifaceinfo.iface_addr = NULL;
971    dstifaceinfo.bcast_addr = NULL;
972    v4outifaceinfo.iface_addr = NULL;
973    v4outifaceinfo.bcast_addr = NULL;
974    v6outifaceinfo.iface_addr = NULL;
975    v6outifaceinfo.bcast_addr = NULL;
976    xcastsocks.sock = NULL;
977    xcastsocks.peeraddr = NULL;
978 
979    xid = SLPXidGenerate();
980    mtu = getmtu();
981    sendbuf = SLPBufferAlloc(mtu);
982    if (!sendbuf)
983    {
984       result = SLP_MEMORY_ALLOC_FAILED;
985       goto FINISHED;
986    }
987 
988    alistsize = slp_max_ifaces * sizeof(struct sockaddr_storage);
989 
990    dstifaceinfo.iface_count = 0;
991    dstifaceinfo.iface_addr = malloc(alistsize);
992    if (dstifaceinfo.iface_addr == NULL)
993    {
994       result = SLP_MEMORY_ALLOC_FAILED;
995       goto FINISHED;
996    }
997    dstifaceinfo.bcast_addr = malloc(alistsize);
998    if (dstifaceinfo.bcast_addr == NULL)
999    {
1000       result = SLP_MEMORY_ALLOC_FAILED;
1001       goto FINISHED;
1002    }
1003    v4outifaceinfo.iface_count = 0;
1004    v4outifaceinfo.iface_addr = malloc(alistsize);
1005    if (v4outifaceinfo.iface_addr == NULL)
1006    {
1007       result = SLP_MEMORY_ALLOC_FAILED;
1008       goto FINISHED;
1009    }
1010    v4outifaceinfo.bcast_addr = malloc(alistsize);
1011    if (v4outifaceinfo.bcast_addr == NULL)
1012    {
1013       result = SLP_MEMORY_ALLOC_FAILED;
1014       goto FINISHED;
1015    }
1016    v6outifaceinfo.iface_count = 0;
1017    v6outifaceinfo.iface_addr = malloc(alistsize);
1018    if (v6outifaceinfo.iface_addr == NULL)
1019    {
1020       result = SLP_MEMORY_ALLOC_FAILED;
1021       goto FINISHED;
1022    }
1023    v6outifaceinfo.bcast_addr = malloc(alistsize);
1024    if (v6outifaceinfo.bcast_addr == NULL)
1025    {
1026       result = SLP_MEMORY_ALLOC_FAILED;
1027       goto FINISHED;
1028    }
1029    xcastsocks.sock_count = 0;
1030    xcastsocks.sock = malloc(slp_max_ifaces * sizeof(sockfd_t));
1031    if (xcastsocks.sock == NULL)
1032    {
1033       result = SLP_MEMORY_ALLOC_FAILED;
1034       goto FINISHED;
1035    }
1036    xcastsocks.peeraddr = malloc(alistsize);
1037    if (xcastsocks.peeraddr == NULL)
1038    {
1039       result = SLP_MEMORY_ALLOC_FAILED;
1040       goto FINISHED;
1041    }
1042 
1043 #if !defined(MI_NOT_SUPPORTED)
1044    /* Determine which multicast addresses to send to. */
1045    NetworkGetMcastAddrs(buftype, buf, &dstifaceinfo);
1046    /* Determine which interfaces to send out on. */
1047    if(handle->McastIFList)
1048    {
1049 #if defined(DEBUG)
1050       fprintf(stderr, "McastIFList = %s\n", handle->McastIFList);
1051 #endif
1052       SLPIfaceGetInfo(handle->McastIFList, &v4outifaceinfo, AF_INET);
1053       SLPIfaceGetInfo(handle->McastIFList, &v6outifaceinfo, AF_INET6);
1054    }
1055    else
1056 #endif /* MI_NOT_SUPPORTED */
1057 
1058    {
1059       char * iflist = SLPPropertyXDup("net.slp.interfaces");
1060       if (SLPNetIsIPV4())
1061          SLPIfaceGetInfo(iflist, &v4outifaceinfo, AF_INET);
1062       if (SLPNetIsIPV6())
1063          SLPIfaceGetInfo(iflist, &v6outifaceinfo, AF_INET6);
1064       xfree(iflist);
1065       if (!v4outifaceinfo.iface_count && !v6outifaceinfo.iface_count)
1066       {
1067          result = SLP_NETWORK_ERROR;
1068          goto FINISHED;
1069       }
1070    }
1071 
1072    usebroadcast = SLPPropertyAsBoolean("net.slp.useBroadcast");
1073 
1074    /* multicast/broadcast wait timeouts */
1075    maxwait = SLPPropertyAsInteger("net.slp.multicastMaximumWait");
1076    SLPPropertyAsIntegerVector("net.slp.multicastTimeouts",
1077          timeouts, MAX_RETRANSMITS);
1078 
1079    /* special case for fake SLP_FUNCT_DASRVRQST */
1080    if (buftype == SLP_FUNCT_DASRVRQST)
1081    {
1082       /* do something special for SRVRQST that will be discovering DAs */
1083       maxwait = SLPPropertyAsInteger("net.slp.DADiscoveryMaximumWait");
1084       SLPPropertyAsIntegerVector("net.slp.DADiscoveryTimeouts",
1085             timeouts, MAX_RETRANSMITS);
1086       /* SLP_FUNCT_DASRVRQST is a fake function.  We really want a SRVRQST */
1087       buftype  = SLP_FUNCT_SRVRQST;
1088    }
1089 
1090    /* Allocate memory for the prlist for appropriate messages.
1091     * Notice that the prlist is as large as the MTU -- thus assuring that
1092     * there will not be any buffer overwrites regardless of how many
1093     * previous responders there are.   This is because the retransmit
1094     * code terminates if ever MTU is exceeded for any datagram message.
1095     */
1096    prlistsize = mtu;
1097    prlist = (char *)xmalloc(mtu);
1098    if (!prlist)
1099    {
1100       result = SLP_MEMORY_ALLOC_FAILED;
1101       goto FINISHED;
1102    }
1103    *prlist = 0;
1104    prlistlen = 0;
1105 
1106 #if !defined(MI_NOT_SUPPORTED)
1107    /* iterate through each multicast scope until we found a provider. */
1108    while (currIntf < dstifaceinfo.iface_count)
1109 #endif
1110    {
1111       /* main retransmission loop */
1112       xmitcount = 0;
1113       totaltimeout = 0;
1114       while (xmitcount < MAX_RETRANSMITS)
1115       {
1116          int replies_this_period = 0;
1117          totaltimeout += timeouts[xmitcount];
1118          if (totaltimeout > maxwait || !timeouts[xmitcount])
1119             break; /* we are all done */
1120 
1121          timeout.tv_sec = timeouts[xmitcount] / 1000;
1122          timeout.tv_usec = (timeouts[xmitcount] % 1000) * 1000;
1123 
1124          /* re-allocate buffer and make sure that the send buffer does not
1125           * exceed MTU for datagram transmission
1126           */
1127          size = (int)CalcBufferSize(isV1, buftype, langtaglen, prlistlen, bufsize);
1128 
1129          if (size > (int)mtu)
1130          {
1131             if (!xmitcount)
1132                result = SLP_BUFFER_OVERFLOW;
1133             goto FINISHED;
1134          }
1135          if ((sendbuf = SLPBufferRealloc(sendbuf, size)) == 0)
1136          {
1137             result = SLP_MEMORY_ALLOC_FAILED;
1138             goto FINISHED;
1139          }
1140          xmitcount++;
1141 
1142          /* Add the header to the send buffer */
1143          if(isV1)
1144          {
1145             /* Version */
1146             *sendbuf->curpos++ = 1;
1147 
1148             /* Function-ID */
1149             *sendbuf->curpos++ = buftype;
1150 
1151             /* Length */
1152             PutUINT16(&sendbuf->curpos, size);
1153 
1154             /* flags */
1155             *sendbuf->curpos++ = 0;
1156 
1157             /* dialect */
1158             *sendbuf->curpos++ = 0;
1159 
1160             /* Language code.  For now, we'll take the first two bytes of the tag */
1161             if(langtaglen < 2)
1162             {
1163                *sendbuf->curpos++ = 'e';
1164                *sendbuf->curpos++ = 'n';
1165             }
1166             else
1167             {
1168                *sendbuf->curpos++ = handle->langtag[0];
1169                *sendbuf->curpos++ = handle->langtag[1];
1170             }
1171 
1172             /* Character encoding -- assume UTF8 */
1173             PutUINT16(&sendbuf->curpos, SLP_CHAR_UTF8);
1174 
1175             /* XID */
1176             PutUINT16(&sendbuf->curpos, xid);
1177          }
1178          else
1179          {
1180             /* version */
1181             *sendbuf->curpos++ = 2;
1182 
1183             /* function id */
1184             *sendbuf->curpos++ = buftype;
1185 
1186             /* length */
1187             PutUINT24(&sendbuf->curpos, size);
1188 
1189             /* flags */
1190             PutUINT16(&sendbuf->curpos, SLP_FLAG_MCAST);
1191 
1192             /* ext offset */
1193             PutUINT24(&sendbuf->curpos, 0);
1194 
1195             /* xid */
1196             PutUINT16(&sendbuf->curpos, xid);
1197 
1198             /* lang tag len */
1199             PutUINT16(&sendbuf->curpos, langtaglen);
1200 
1201             /* lang tag */
1202             memcpy(sendbuf->curpos, handle->langtag, langtaglen);
1203             sendbuf->curpos += langtaglen;
1204          }
1205 
1206          /* Add the prlist to the send buffer */
1207          if (prlist)
1208          {
1209             PutUINT16(&sendbuf->curpos, prlistlen);
1210             memcpy(sendbuf->curpos, prlist, prlistlen);
1211             sendbuf->curpos += prlistlen;
1212          }
1213 
1214          /* add the rest of the message */
1215          memcpy(sendbuf->curpos, buf, bufsize);
1216          sendbuf->curpos += bufsize;
1217 
1218          /* send the send buffer */
1219          if (usebroadcast)
1220             result = SLPBroadcastSend(&v4outifaceinfo,sendbuf,&xcastsocks);
1221          else
1222          {
1223             if (dstifaceinfo.iface_addr[currIntf].ss_family == AF_INET)
1224                result = SLPMulticastSend(&v4outifaceinfo, sendbuf, &xcastsocks,
1225                      &dstifaceinfo.iface_addr[currIntf]);
1226             else if (dstifaceinfo.iface_addr[currIntf].ss_family == AF_INET6)
1227                result = SLPMulticastSend(&v6outifaceinfo, sendbuf, &xcastsocks,
1228                      &dstifaceinfo.iface_addr[currIntf]);
1229          }
1230 
1231          /* main recv loop */
1232          while(1)
1233          {
1234 #if !defined(UNICAST_NOT_SUPPORTED)
1235             int retval = 0;
1236             if ((retval = SLPXcastRecvMessage(&xcastsocks, &recvbuf,
1237                   &addr, &timeout)) != SLP_ERROR_OK)
1238 #else
1239             if (SLPXcastRecvMessage(&xcastsocks, &recvbuf,
1240                   &addr, &timeout) != SLP_ERROR_OK)
1241 #endif
1242             {
1243                /* An error occured while receiving the message
1244                 * probably a just time out error. break for re-send.
1245                 */
1246                if (errno == ETIMEDOUT)
1247                   result = SLP_NETWORK_TIMED_OUT;
1248                else
1249                   result = SLP_NETWORK_ERROR;
1250 
1251 #if !defined(UNICAST_NOT_SUPPORTED)
1252                /* retval == SLP_ERROR_RETRY_UNICAST signifies that we
1253                 * received a multicast packet of size > MTU and hence we
1254                 * are now sending a unicast request to this IP-address.
1255                 */
1256                if (retval == SLP_ERROR_RETRY_UNICAST)
1257                {
1258                   sockfd_t tcpsockfd;
1259                   int retval1, retval2, unicastwait = 0;
1260                   /* Use a local timeout variable here so we don't corrupt the multicast timeout */
1261                   struct timeval timeout;
1262                   unicastwait = SLPPropertyAsInteger("net.slp.unicastMaximumWait");
1263                   timeout.tv_sec = unicastwait / 1000;
1264                   timeout.tv_usec = (unicastwait % 1000) * 1000;
1265 
1266                   tcpsockfd = SLPNetworkConnectStream(&addr, &timeout);
1267                   if (tcpsockfd != SLP_INVALID_SOCKET)
1268                   {
1269                      TO_UINT16(sendbuf->start + 5, SLP_FLAG_UCAST);
1270                      xid = SLPXidGenerate();
1271                      TO_UINT16(sendbuf->start + 10, xid);
1272 
1273                      retval1 = SLPNetworkSendMessage(tcpsockfd, SOCK_STREAM,
1274                            sendbuf, sendbuf->curpos - sendbuf->start, &addr,
1275                            &timeout);
1276                      if (retval1)
1277                      {
1278                         if (errno == ETIMEDOUT)
1279                            result = SLP_NETWORK_TIMED_OUT;
1280                         else
1281                            result = SLP_NETWORK_ERROR;
1282                         closesocket(tcpsockfd);
1283                         break;
1284                      }
1285 
1286                      retval2 = SLPNetworkRecvMessage(tcpsockfd, SOCK_STREAM,
1287                            &recvbuf, &addr, &timeout);
1288                      if (retval2)
1289                      {
1290                         /* An error occured while receiving the message
1291                          *  probably a just time out error. break for re-send.
1292                          */
1293                         if(errno == ETIMEDOUT)
1294                            result = SLP_NETWORK_TIMED_OUT;
1295                         else
1296                            result = SLP_NETWORK_ERROR;
1297                         closesocket(tcpsockfd);
1298                         break;
1299                      }
1300                      closesocket(tcpsockfd);
1301                      result = SLP_OK;
1302                      goto SNEEK;
1303                   }
1304                   else
1305                      break; /* Unsuccessful in opening a TCP conn - retry */
1306                }
1307                else
1308                {
1309 #endif
1310                   break;
1311 #if !defined(UNICAST_NOT_SUPPORTED)
1312                }
1313 #endif
1314             }
1315 #if !defined(UNICAST_NOT_SUPPORTED)
1316 SNEEK:
1317 #endif
1318             /* Sneek in and check the XID -- it's in the same place in v1 and v2*/
1319             if (AS_UINT16(recvbuf->start + 10) == xid)
1320             {
1321                char addrstr[INET6_ADDRSTRLEN] = "";
1322                size_t addrstrlen;
1323 
1324                SLPNetSockAddrStorageToString(&addr, addrstr, sizeof(addrstr));
1325 
1326                ++replies_this_period;
1327                rplycount += 1;
1328 
1329                /* Call the callback with the result and recvbuf */
1330 #if !defined(MI_NOT_SUPPORTED)
1331                if (!cookie)
1332                   cookie = (SLPHandleInfo *)handle;
1333 #endif
1334                if (callback(result, &addr, recvbuf, cookie) == SLP_FALSE)
1335                   goto CLEANUP; /* Caller does not want any more info */
1336 
1337                /* add the peer to the previous responder list */
1338                addrstrlen = strlen(addrstr);
1339                if (addrstrlen > 0 && SLPContainsStringList(prlistlen,
1340                            prlist, addrstrlen, addrstr) == 0)
1341                {
1342                   if (prlistlen + 1 + addrstrlen >= prlistsize)
1343                   {
1344                      prlist = xrealloc(prlist, prlistsize + mtu);
1345                      prlistsize += mtu;
1346                   }
1347                   if (prlistlen != 0)
1348                      strcat(prlist, ",");
1349                   strcat(prlist, addrstr);
1350                   prlistlen = strlen(prlist);
1351                }
1352             }
1353          }
1354          SLPXcastSocketsClose(&xcastsocks);
1355          if (!replies_this_period && (xmitcount > 1))
1356          {
1357              /* stop after a period with no replies, but wait at least two periods */
1358              break;
1359          }
1360       }
1361       currIntf++;
1362    }
1363 
1364 FINISHED:
1365 
1366    /* notify the callback with SLP_LAST_CALL so that they know we're done */
1367    if (rplycount || result == SLP_NETWORK_TIMED_OUT)
1368       result = SLP_LAST_CALL;
1369 
1370 #if !defined(MI_NOT_SUPPORTED)
1371    if (!cookie)
1372       cookie = (SLPHandleInfo *)handle;
1373 #endif
1374 
1375    callback(result, 0, 0, cookie);
1376 
1377    if (result == SLP_LAST_CALL)
1378       result = SLP_OK;
1379 
1380 CLEANUP:
1381 
1382    /* free resources */
1383    xfree(prlist);
1384    SLPBufferFree(sendbuf);
1385    SLPBufferFree(recvbuf);
1386    SLPXcastSocketsClose(&xcastsocks);
1387    xfree(xcastsocks.sock);
1388    xfree(xcastsocks.peeraddr);
1389    xfree(dstifaceinfo.iface_addr);
1390    xfree(dstifaceinfo.bcast_addr);
1391    xfree(v4outifaceinfo.iface_addr);
1392    xfree(v4outifaceinfo.bcast_addr);
1393    xfree(v6outifaceinfo.iface_addr);
1394    xfree(v6outifaceinfo.bcast_addr);
1395 
1396    return result;
1397 }
1398 
1399 #if !defined(UNICAST_NOT_SUPPORTED)
1400 /** Unicasts SLP messages.
1401  *
1402  * @param[in] handle - A pointer to the SLP handle.
1403  * @param[in] buf - A pointer to the portion of the SLP message to send.
1404  * @param[in] buftype - The function-id to use in the SLPMessage header.
1405  * @param[in] bufsize - the size of the buffer pointed to by @p buf.
1406  * @param[in] callback - The callback to use for reporting results.
1407  * @param[in] cookie - The cookie to pass to the callback.
1408  * @param[in] isV1 - Whether or not to use a v1 header.
1409  *
1410  * @return SLP_OK on success. SLP_ERROR on failure.
1411  */
NetworkUcastRqstRply(SLPHandleInfo * handle,void * buf,char buftype,size_t bufsize,NetworkRplyCallback callback,void * cookie,int isV1)1412 SLPError NetworkUcastRqstRply(SLPHandleInfo * handle, void * buf,
1413       char buftype, size_t bufsize, NetworkRplyCallback callback,
1414       void * cookie, int isV1)
1415 {
1416    /*In reality, this function just sets things up for NetworkRqstRply to operate*/
1417 
1418    if(handle->unicastsock == SLP_INVALID_SOCKET) /*The unicast code will certainly reuse this socket*/
1419       handle->unicastsock  = SLPNetworkCreateDatagram(handle->ucaddr.ss_family);
1420 
1421    if (handle->unicastsock == SLP_INVALID_SOCKET)
1422       return SLP_NETWORK_ERROR;
1423 
1424    return NetworkRqstRply(handle->unicastsock, &handle->ucaddr, handle->langtag, 0, buf, buftype, bufsize, callback, cookie, isV1);
1425 }
1426 
1427 /** Set the given socket to be non-blocking
1428  *
1429  * @param[in] sock - the socket to be set up
1430  *
1431  * @internal
1432  */
SetNonBlocking(int sock)1433 static int SetNonBlocking(int sock)
1434 {
1435 #ifdef _WIN32
1436    u_long fdflags = 1;
1437    return ioctlsocket(sock, FIONBIO, &fdflags);
1438 #else
1439    int fdflags = fcntl(sock, F_GETFL, 0);
1440    return fcntl(sock, F_SETFL, fdflags | O_NONBLOCK);
1441 #endif
1442 }
1443 
1444 /** Transmit and receive a unicast SLP message to the list of addresses given
1445  *
1446  * @param[in] destaddr - pointer to the array of IP addresses of the hosts
1447  *               to send the message to
1448  * @param[in] langtag - language tag to use in SLP message header
1449  * @param[in] buf - pointer to the portion of the SLP message to send,
1450  *               excluding the SLP header  ie. everything after the prlist
1451  * @param[in] buftype - the function-id to use in the SLPMessage header
1452  * @param[in] bufsize - the size of the buffer pointed to by buf
1453  * @param[in] callback - the callback to use for reporting results
1454  * @param[in] cookie - the cookie to pass to the callback
1455  * @param[in] isV1 - Whether or not to use a V1 header.
1456  *
1457  * @return SLP_OK on success
1458  *
1459  * @internal
1460  */
NetworkMultiUcastRqstRply(struct sockaddr_in * destaddr,const char * langtag,char * buf,char buftype,size_t bufsize,NetworkRplyCallback callback,void * cookie,int isV1)1461 SLPError NetworkMultiUcastRqstRply(
1462                          struct sockaddr_in* destaddr,		// This is an array of addresses
1463                          const char* langtag,
1464                          char* buf,
1465                          char buftype,
1466                          size_t bufsize,
1467                          NetworkRplyCallback callback,
1468                          void * cookie,
1469                          int isV1)
1470 {
1471     /* Minimum amount of data we need to read to get the packet length */
1472     #define             MIN_RECEIVE_SIZE  5
1473 
1474     /* Connection state values */
1475     #define CONN_UDP                      0
1476     #define CONN_TCP_CONNECT              1
1477     #define CONN_TCP_SEND                 2
1478     #define CONN_TCP_RECEIVE              3
1479     #define CONN_COMPLETE                 4
1480     #define CONN_FAILED                   5
1481 
1482     int                 i;
1483     SLPBuffer           sendbuf         = 0;
1484     SLPBuffer           udp_recvbuf     = 0;
1485     SLPError            result          = SLP_OK;
1486     size_t              langtaglen      = 0;
1487     int                 prlistlen       = 0;
1488     int                 xid             = 0;
1489     size_t              mtu             = 0;
1490     int                 ndests          = 0;    // Number of destinations
1491     sockfd_t            nfds            = 0;    // Number of file descriptors in the FD_SET
1492     size_t              send_size       = 0;
1493     int                 selected        = 0;
1494     int                 xmitcount       = 0;
1495     int                 rplycount       = 0;
1496     int                 maxwait         = 0;
1497     int                 timeouts[MAX_RETRANSMITS];
1498     sockfd_t            udp_socket      = (sockfd_t)-1;
1499     int                 udp_active      = 0;
1500     int                 do_send         = 1;
1501     unsigned short      flags;
1502     char                v1flags;
1503     unsigned int        msglen;
1504     struct timeval      now;
1505     struct timeval      timeout;
1506     struct timeval      timeout_end;
1507     struct timeval      max_timeout_end;
1508     struct sockaddr_in  udp_bind_address;
1509     char                peek[MIN_RECEIVE_SIZE];
1510     struct sockaddr_in  peeraddr;
1511     socklen_t           peeraddrlen = sizeof (struct sockaddr_in);
1512     struct _UcastConnection {
1513         int         state;
1514         sockfd_t    socket;
1515         int         send_offset;
1516         int         recv_offset;
1517         int         recv_size;
1518         SLPBuffer   read_buffer;
1519     }                   *pconnections   = 0;
1520 
1521 #ifdef DEBUG
1522     /* This function only supports unicast of the following messages
1523      */
1524     if(buftype != SLP_FUNCT_SRVRQST &&
1525        buftype != SLP_FUNCT_ATTRRQST &&
1526        buftype != SLP_FUNCT_SRVTYPERQST &&
1527        buftype != SLP_FUNCT_DASRVRQST)
1528     {
1529         return SLP_PARAMETER_BAD;
1530     }
1531 #endif
1532 
1533 #ifdef _WIN32
1534     /*windows gives a warning that timeout_end may not be initted --
1535       apparently it doesn't understand while(1)*/
1536     timeout_end.tv_sec = 0;
1537     timeout_end.tv_usec = 0;
1538 #endif
1539 
1540     /*----------------------------------------------------*/
1541     /* Save off a few things we don't want to recalculate */
1542     /*----------------------------------------------------*/
1543     langtaglen = (int)strlen(langtag);
1544     xid = SLPXidGenerate();
1545     mtu = getmtu();
1546     sendbuf = SLPBufferAlloc(mtu);
1547     if(sendbuf == 0)
1548     {
1549         result = SLP_MEMORY_ALLOC_FAILED;
1550         goto CLEANUP;
1551     }
1552     udp_recvbuf = SLPBufferAlloc(mtu);
1553     if(udp_recvbuf == 0)
1554     {
1555         result = SLP_MEMORY_ALLOC_FAILED;
1556         goto CLEANUP;
1557     }
1558     maxwait = SLPPropertyAsInteger("net.slp.unicastMaximumWait");
1559     SLPPropertyAsIntegerVector("net.slp.unicastTimeouts",
1560                                timeouts,
1561                                MAX_RETRANSMITS );
1562 
1563     /* Special case for fake SLP_FUNCT_DASRVRQST */
1564     if(buftype == SLP_FUNCT_DASRVRQST)
1565     {
1566         /* do something special for SRVRQST that will be discovering DAs */
1567         maxwait = SLPPropertyAsInteger("net.slp.DADiscoveryMaximumWait");
1568         SLPPropertyAsIntegerVector("net.slp.DADiscoveryTimeouts",
1569                                    timeouts,
1570                                    MAX_RETRANSMITS );
1571         /* SLP_FUNCT_DASRVRQST is a fake function.  We really want to */
1572         /* send a SRVRQST                                             */
1573         buftype  = SLP_FUNCT_SRVRQST;
1574     }
1575 
1576     /*---------------------------------------------------------------------*/
1577     /* Don't need to allocate memory for the prlist, as the message is     */
1578     /* only unicast to each of the destinations                            */
1579     /*---------------------------------------------------------------------*/
1580     prlistlen = 0;
1581 
1582     /*------------------------------------------*/
1583     /* Allocate the connection structures array */
1584     /*------------------------------------------*/
1585     /* First find out how many there are        */
1586     for (ndests = 0; ; ndests++)
1587     {
1588         if (destaddr[ndests].sin_addr.s_addr == 0)
1589         {
1590             break;
1591         }
1592     }
1593     /* Now allocate the array                   */
1594     pconnections = (struct _UcastConnection*)xmalloc(ndests * sizeof pconnections[0]);
1595     if(pconnections == 0)
1596     {
1597         result = SLP_MEMORY_ALLOC_FAILED;
1598         goto CLEANUP;
1599     }
1600 
1601     /*--------------------------------------------*/
1602     /* Initialise the connection structures array */
1603     /* and initiate the connections               */
1604     /*--------------------------------------------*/
1605     for (i = 0; i < ndests; i++)
1606     {
1607         struct _UcastConnection *pconn = &pconnections[i];
1608         pconn->state = CONN_UDP;
1609         pconn->socket = (sockfd_t)-1;
1610         pconn->send_offset = 0;
1611         pconn->recv_offset = 0;
1612         pconn->recv_size = MIN_RECEIVE_SIZE;            /* enough to receive the length field */
1613         pconn->read_buffer = NULL;
1614     }
1615     if (result != SLP_OK)
1616         goto FINISHED;
1617 
1618     /*----------------------------------------*/
1619     /* Create a UDP socket to use             */
1620     /*----------------------------------------*/
1621     udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
1622     if (udp_socket < 0)
1623     {
1624         result = SLP_NETWORK_ERROR;
1625         goto FINISHED;
1626     }
1627 
1628     SLPNetworkSetSndRcvBuf(udp_socket);
1629 
1630     udp_bind_address.sin_family = AF_INET;
1631     udp_bind_address.sin_addr.s_addr = htonl(INADDR_ANY);
1632     udp_bind_address.sin_port = htons(0);
1633     if (bind(udp_socket, (struct sockaddr *)&udp_bind_address, sizeof udp_bind_address) < 0)
1634     {
1635         result = SLP_NETWORK_ERROR;
1636         goto FINISHED;
1637     }
1638 
1639     /*----------------------------------------*/
1640     /* re-allocate buffer if necessary        */
1641     /*----------------------------------------*/
1642     send_size = (int)CalcBufferSize(isV1, buftype, langtaglen, prlistlen, bufsize);
1643     if (send_size > mtu)
1644     {
1645         if((sendbuf = SLPBufferRealloc(sendbuf,send_size)) == 0)
1646         {
1647             result = SLP_MEMORY_ALLOC_FAILED;
1648             goto CLEANUP;
1649         }
1650     }
1651 
1652     /*-----------------------------------*/
1653     /* Add the header to the send buffer */
1654     /*-----------------------------------*/
1655     if(isV1)
1656     {
1657          /* Version */
1658          *sendbuf->curpos++ = 1;
1659          /* Function-ID */
1660          *sendbuf->curpos++ = buftype;
1661          /* Length */
1662          PutUINT16(&sendbuf->curpos, send_size);
1663          /* flags */
1664          v1flags = 0;
1665          if (buftype == SLP_FUNCT_SRVREG)
1666             v1flags |= SLPv1_FLAG_FRESH;
1667          *sendbuf->curpos++ = v1flags;
1668          /* dialect */
1669          *sendbuf->curpos++ = 0;
1670          /* Language code.  For now, we'll take the first two bytes of the tag */
1671          if(langtaglen < 2)
1672          {
1673             *sendbuf->curpos++ = 'e';
1674             *sendbuf->curpos++ = 'n';
1675          }
1676          else
1677          {
1678             *sendbuf->curpos++ = langtag[0];
1679             *sendbuf->curpos++ = langtag[1];
1680          }
1681          /* Character encoding -- assume UTF8 */
1682          PutUINT16(&sendbuf->curpos, SLP_CHAR_UTF8);
1683          /* XID */
1684          PutUINT16(&sendbuf->curpos, xid);
1685     }
1686     else
1687     {
1688        /*version*/
1689        sendbuf->curpos = sendbuf->start ;
1690        *(sendbuf->curpos++)       = 2;
1691        /*function id*/
1692        *(sendbuf->curpos++)   = buftype;
1693        /*length*/
1694        PutUINT24(&sendbuf->curpos, send_size);
1695        /*flags*/
1696        flags = 0;
1697        if (buftype == SLP_FUNCT_SRVREG)
1698        {
1699            flags |= SLP_FLAG_FRESH;
1700        }
1701        PutUINT16(&sendbuf->curpos, flags);
1702        /*ext offset*/
1703        PutUINT24(&sendbuf->curpos, 0);
1704        /*xid*/
1705        PutUINT16(&sendbuf->curpos, xid);
1706        /*lang tag len*/
1707        PutUINT16(&sendbuf->curpos,langtaglen);
1708        /*lang tag*/
1709        memcpy(sendbuf->curpos, langtag, langtaglen);
1710        sendbuf->curpos = sendbuf->curpos + langtaglen ;
1711     }
1712 
1713     /*-----------------------------------------------*/
1714     /* Add the zero length prlist to the send buffer */
1715     /*-----------------------------------------------*/
1716     PutUINT16(&sendbuf->curpos,prlistlen);
1717 
1718     /*-----------------------------*/
1719     /* Add the rest of the message */
1720     /*-----------------------------*/
1721     memcpy(sendbuf->curpos, buf, bufsize);
1722     sendbuf->curpos = sendbuf->curpos + bufsize;
1723 
1724     /*----------------------------------------*/
1725     /* Calculate the max timeout end          */
1726     /*----------------------------------------*/
1727     timeout.tv_sec = maxwait / 1000;
1728     timeout.tv_usec = (maxwait % 1000) * 1000;
1729     gettimeofday(&max_timeout_end, 0);
1730     timeval_add(&max_timeout_end, &timeout);
1731 
1732     /*--------------------------*/
1733     /* Main processing loop     */
1734     /*--------------------------*/
1735     while(1)
1736     {
1737         fd_set read_fds;
1738         fd_set write_fds;
1739 
1740         if (do_send)
1741         {
1742             /*---------------------------------*/
1743             /* Send the UDP messages out       */
1744             /*---------------------------------*/
1745             for (i = 0; i < ndests; i++)
1746             {
1747                 struct _UcastConnection *pconn = &pconnections[i];
1748                 if (pconn->state == CONN_UDP)
1749                 {
1750                     int flags = 0;
1751 
1752 #if defined(MSG_NOSIGNAL)
1753                     flags = MSG_NOSIGNAL;
1754 #endif
1755                     if (sendto(udp_socket,
1756                                (char*)sendbuf->start,
1757                                (int)(sendbuf->curpos - sendbuf->start),
1758                                flags,
1759                                (struct sockaddr *)&destaddr[i],
1760                                sizeof destaddr[i]) < 0)
1761                     {
1762                         result = SLP_NETWORK_ERROR;
1763                         goto FINISHED;
1764                     }
1765                 }
1766             }
1767 
1768             /*----------------------------------------*/
1769             /* Calculate the end point of the timeout */
1770             /* for this period                        */
1771             /*----------------------------------------*/
1772             timeout.tv_sec = timeouts[xmitcount] / 1000;
1773             timeout.tv_usec = (timeouts[xmitcount] % 1000) * 1000;
1774             gettimeofday(&timeout_end, 0);
1775             timeval_add(&timeout_end, &timeout);
1776 
1777             do_send = 0;
1778         }
1779 
1780         FD_ZERO(&read_fds);
1781         FD_ZERO(&write_fds);
1782 
1783         /*---------------------------------*/
1784         /* Mark the active sockets         */
1785         /*---------------------------------*/
1786         nfds = 0;
1787         udp_active = 0;
1788         for (i = 0; i < ndests; i++)
1789         {
1790             struct _UcastConnection *pconn = &pconnections[i];
1791             if ((pconn->state == CONN_TCP_CONNECT) || (pconn->state == CONN_TCP_SEND))
1792             {
1793                 FD_SET(pconn->socket, &write_fds);
1794                 if (nfds <= pconn->socket)
1795                     nfds = pconn->socket + 1;
1796             }
1797             else if (pconn->state == CONN_TCP_RECEIVE)
1798             {
1799                 FD_SET(pconn->socket, &read_fds);
1800                 if (nfds <= pconn->socket)
1801                     nfds = pconn->socket + 1;
1802             }
1803             else if (pconn->state == CONN_UDP)
1804             {
1805                 udp_active = 1;
1806             }
1807         }
1808         if (udp_active)
1809         {
1810             FD_SET(udp_socket, &read_fds);
1811             if (nfds <= udp_socket)
1812                 nfds = udp_socket + 1;
1813         }
1814 
1815         if (nfds == 0)
1816         {
1817             /* No active sockets - must all have failed or completed */
1818             break;
1819         }
1820 
1821         /*---------------------------------*/
1822         /* Calculate the remaining timeout */
1823         /* for this period                 */
1824         /*---------------------------------*/
1825         gettimeofday(&now, 0);
1826         memcpy(&timeout, &timeout_end, sizeof (struct timeval));
1827         timeval_subtract(&timeout, &now);
1828         if ((timeout.tv_sec < 0) || (timeout.tv_sec > (maxwait/1000)))
1829         {
1830             /* timeout has passed */
1831             timeout.tv_sec  = 0;
1832             timeout.tv_usec = 0;
1833         }
1834 
1835         /*---------------------------------*/
1836         /* Wait for something to do        */
1837         /*---------------------------------*/
1838         selected = select((int)nfds,
1839                           &read_fds,
1840                           &write_fds,
1841                           0,
1842                           &timeout);
1843 
1844         /*----------------------------------*/
1845         /* Check for termination conditions */
1846         /*----------------------------------*/
1847         if (selected == 0)
1848         {
1849             /* Nothing in the remainder of the timeout period */
1850             ++xmitcount;
1851             gettimeofday(&now, NULL);
1852 
1853             /* First check whether the max timeout has been exceeded */
1854             if (now.tv_sec >= max_timeout_end.tv_sec)
1855             {
1856                 if ((now.tv_sec > max_timeout_end.tv_sec) || (now.tv_usec >= max_timeout_end.tv_usec))
1857                 {
1858                     /* Timed out */
1859                     result = SLP_NETWORK_TIMED_OUT;
1860                     break;
1861                 }
1862             }
1863 
1864             /* Next check whether we've used up all the retry periods */
1865             if (xmitcount >= MAX_RETRANSMITS)
1866             {
1867                 /* Timed out */
1868                 result = SLP_NETWORK_TIMED_OUT;
1869                 break;
1870             }
1871 
1872             /* OK - resend to all the UDP destinations that haven't replied yet */
1873             do_send = 1;
1874 
1875         }
1876         if (selected < 0)
1877         {
1878 #ifdef _WIN32
1879             if (WSAGetLastError() == WSAEINTR)
1880 #else
1881             if (errno == EINTR)
1882 #endif
1883                 /* interrupted - just carry on */
1884                 continue;
1885             /* error - can't carry on */
1886             result = SLP_NETWORK_ERROR;
1887             break;
1888         }
1889 
1890         /*---------------------------------------*/
1891         /* Check whether the UDP socket has data */
1892         /* and from whom                         */
1893         /*---------------------------------------*/
1894         udp_active = 0;
1895         if (FD_ISSET(udp_socket, &read_fds))
1896         {
1897             ssize_t bytesread;
1898 
1899             /* Peek at the first few bytes of the header */
1900             bytesread = recvfrom(udp_socket,
1901                                  peek,
1902                                  MIN_RECEIVE_SIZE,
1903                                  MSG_PEEK,
1904                                  (struct sockaddr *)&peeraddr,
1905                                  &peeraddrlen);
1906             if (!bytesread)
1907             {
1908                result = SLP_NETWORK_ERROR;
1909                break;
1910             }
1911             if (bytesread == MIN_RECEIVE_SIZE
1912 #ifdef _WIN32
1913             /* Win32 returns WSAEMSGSIZE if the message is larger than
1914              * the requested size, even with MSG_PEEK. But if this is the
1915              * error code we can be sure that the message is at least the
1916              * required number of bytes
1917              */
1918                || (bytesread == (size_t)-1 && WSAGetLastError() == WSAEMSGSIZE)
1919 #endif
1920                )
1921             {
1922                 msglen = PEEK_LENGTH(peek);
1923 
1924                 if(msglen <=  (unsigned int)mtu)
1925                 {
1926                     udp_recvbuf = SLPBufferRealloc(udp_recvbuf, msglen);
1927                     if (udp_recvbuf == 0)
1928                     {
1929                        result = SLP_MEMORY_ALLOC_FAILED;
1930                        goto CLEANUP;
1931                     }
1932                     bytesread = recv(udp_socket,
1933                                      (char*)udp_recvbuf->curpos,
1934                                      (int)(udp_recvbuf->end - udp_recvbuf->curpos),
1935                                      0);
1936                     if(bytesread != (int32_t)msglen)
1937                     {
1938                         /* This should never happen but we'll be paranoid*/
1939                         udp_recvbuf->end = udp_recvbuf->curpos + bytesread;
1940                     }
1941 
1942                     /* Message read. We're done! */
1943                     udp_active = 1;
1944                     result = SLP_OK;
1945                 }
1946                 else
1947                 {
1948                     /* we got a bad message, or one that is too big! */
1949 #ifdef UNICAST_NOT_SUPPORTED
1950                     /* We need to read the message to clear the UDP socket */
1951                     bytesread = recv(udp_socket,
1952                                      udp_recvbuf->start,
1953                                      1,
1954                                      0);
1955 #else
1956                     /* Reading MTU bytes on the socket */
1957                     if ((udp_recvbuf = SLPBufferRealloc(udp_recvbuf, mtu)) == 0)
1958                     {
1959                        result = SLP_MEMORY_ALLOC_FAILED;
1960                        goto CLEANUP;
1961                     }
1962                     bytesread = recv(udp_socket,
1963                                      (char*)udp_recvbuf->curpos,
1964                                      (int)(udp_recvbuf->end - udp_recvbuf->curpos),
1965                                      0);
1966                     if (bytesread != (int)mtu)
1967                     {
1968                         /* This should never happen but we'll be paranoid*/
1969                         udp_recvbuf->end = udp_recvbuf->curpos + bytesread;
1970                     }
1971                     udp_active = 1;
1972                     result = SLP_ERROR_RETRY_UNICAST;
1973 #endif
1974                 }
1975             }
1976             else
1977             {
1978                 /* Not even the minimum bytes available - read and discard */
1979                 bytesread = recv(udp_socket,
1980                                  (char*)udp_recvbuf->start,
1981                                  1,
1982                                  0);
1983             }
1984         }
1985 
1986         /*---------------------------------------*/
1987         /* Check which connections need handling */
1988         /*---------------------------------------*/
1989         for (i = 0; (i < ndests) && selected; i++)
1990         {
1991             struct _UcastConnection *pconn = &pconnections[i];
1992             if ((pconn->socket >= 0) && FD_ISSET(pconn->socket, &write_fds))
1993             {
1994                 /*---------------------------------------*/
1995                 /* Handle a TCP write or connect         */
1996                 /*---------------------------------------*/
1997                 --selected;
1998                 if ((pconn->state == CONN_TCP_CONNECT) || (pconn->state == CONN_TCP_SEND))
1999                 {
2000                     int bytes_sent;
2001 
2002                     pconn->state = CONN_TCP_SEND;
2003                      bytes_sent = send(pconn->socket,
2004                                       (char*)sendbuf->start+pconn->send_offset,
2005                                       (int)(send_size-pconn->send_offset),
2006                                       0);
2007                     if (bytes_sent > 0)
2008                     {
2009                         pconn->send_offset += bytes_sent;
2010                         if (pconn->send_offset >= (int)send_size)
2011                         {
2012                             pconn->state = CONN_TCP_RECEIVE;
2013                         }
2014                     }
2015                     else if (bytes_sent < 0)
2016                     {
2017                         /* Shouldn't get this if the socket is not in error */
2018                         pconn->state = CONN_FAILED;
2019                     }
2020                 }
2021                 else
2022                 {
2023                     /* Should never get here */
2024                     pconn->state = CONN_FAILED;
2025                 }
2026             }
2027             else if ((pconn->socket >= 0) && FD_ISSET(pconn->socket, &read_fds))
2028             {
2029                 /*---------------------------------------*/
2030                 /* Handle received TCP data              */
2031                 /*---------------------------------------*/
2032                 --selected;
2033                 if (pconn->state == CONN_TCP_RECEIVE)
2034                 {
2035                     int size_to_read = pconn->recv_size - pconn->recv_offset;
2036                     int bytes_read = recv(pconn->socket, (char*)pconn->read_buffer->start+pconn->recv_offset, size_to_read, 0);
2037                     if (bytes_read > 0)
2038                     {
2039                         pconn->recv_offset += bytes_read;
2040                         if ((pconn->recv_offset == pconn->recv_size) && (pconn->recv_size == MIN_RECEIVE_SIZE))
2041                         {
2042                             /* Determine the full message size */
2043                             int full_size = PEEK_LENGTH(pconn->read_buffer->start);
2044 
2045                             if (full_size > MIN_RECEIVE_SIZE)
2046                             {
2047                                 SLPBuffer new_buffer = SLPBufferAlloc(full_size);
2048                                 if (new_buffer == 0)
2049                                 {
2050                                     pconn->state = CONN_FAILED;
2051                                     result = SLP_MEMORY_ALLOC_FAILED;
2052                                     goto FINISHED;
2053                                 }
2054                                 memcpy(new_buffer->start, pconn->read_buffer->start, pconn->recv_size);
2055                                 SLPFree(pconn->read_buffer);
2056                                 pconn->read_buffer = new_buffer;
2057                                 pconn->recv_size = full_size;
2058                             }
2059                         }
2060                         if (pconn->recv_offset == pconn->recv_size)
2061                         {
2062                             /* Complete message read successfully */
2063                             if(AS_UINT16((const char *)pconn->read_buffer->start+10) == xid)
2064                             {
2065                                 ++rplycount;
2066                                 pconn->read_buffer->curpos = pconn->read_buffer->end;
2067                                 pconn->state = CONN_COMPLETE;
2068 
2069                                 /* Call the callback with the result and the receive buffer */
2070                                 if(callback(result,&destaddr[i],pconn->read_buffer,cookie) == SLP_FALSE)
2071                                 {
2072                                     /* Caller does not want any more info */
2073                                     /* We are done!                       */
2074                                     goto CLEANUP;
2075                                 }
2076                             }
2077                         }
2078                     }
2079                 }
2080                 else
2081                 {
2082                     /* Should never get here */
2083                     pconn->state = CONN_FAILED;
2084                 }
2085             }
2086             else if (udp_active && (pconn->state == CONN_UDP) && (memcmp(&peeraddr.sin_addr, &destaddr[i].sin_addr, sizeof peeraddr.sin_addr) == 0))
2087             {
2088                 /*---------------------------------------*/
2089                 /* Handle received UDP data              */
2090                 /*---------------------------------------*/
2091                 --selected;
2092                 if (result == SLP_ERROR_RETRY_UNICAST)
2093                 {
2094                     result = SLP_OK;
2095                     pconn->socket = socket(AF_INET, SOCK_STREAM, 0);
2096                     if (pconn->socket < 0)
2097                     {
2098                         result = SLP_NETWORK_ERROR;
2099                         pconn->state = CONN_FAILED;
2100                     }
2101                     else
2102                     {
2103                         if (SetNonBlocking((int)pconn->socket) < 0)
2104                         {
2105                             result = SLP_NETWORK_ERROR;
2106                             closesocket(pconn->socket);
2107                             pconn->socket = (sockfd_t)-1;
2108                             pconn->state = CONN_FAILED;
2109                         }
2110                     }
2111                     if (result == SLP_OK)
2112                     {
2113                         pconn->read_buffer = SLPBufferAlloc(pconn->recv_size);
2114                         if (pconn->read_buffer == 0)
2115                         {
2116                             result = SLP_MEMORY_ALLOC_FAILED;
2117                             pconn->state = CONN_FAILED;
2118                         }
2119                         else
2120                         {
2121                             /* We now have a non-blocking socket and a buffer to read into */
2122                             /* Initiate a connect to the destination                */
2123                             if (connect(pconn->socket, (struct sockaddr *)&destaddr[i], sizeof destaddr[i]) < 0)
2124                             {
2125 #ifdef _WIN32
2126                                 if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK)
2127 #else
2128                                 if ((errno != 0) && (errno != EINPROGRESS))
2129 #endif
2130                                 {
2131                                     /* Connect operation failed immediately ! */
2132                                     result = SLP_NETWORK_ERROR;
2133                                     pconn->state = CONN_FAILED;
2134                                 }
2135                                 else
2136                                     pconn->state = CONN_TCP_CONNECT;
2137                             }
2138                             else
2139                             {
2140                                 /* Connection succeeded immediately */
2141                                 pconn->state = CONN_TCP_SEND;
2142                             }
2143                         }
2144                     }
2145                 }
2146                 else
2147                 {
2148                     /* UDP reply from this DA */
2149                     if(AS_UINT16((const char *)udp_recvbuf->start+10) == xid)
2150                     {
2151                         ++rplycount;
2152                         udp_recvbuf->curpos = udp_recvbuf->end;
2153                         pconn->state = CONN_COMPLETE;
2154 
2155                         /* Call the callback with the result and the receive buffer */
2156                         if(callback(result,&destaddr[i],udp_recvbuf,cookie) == SLP_FALSE)
2157                         {
2158                             /* Caller does not want any more info */
2159                             /* We are done!                       */
2160                             goto CLEANUP;
2161                         }
2162                     }
2163                 }
2164             }
2165         }
2166     }
2167 
2168     FINISHED:
2169 
2170     /*-----------------------------------------------*/
2171     /* Mark any failed DAs as bad so we don't use    */
2172     /* them again                                    */
2173     /*-----------------------------------------------*/
2174 
2175     for (i = 0; i < ndests; i++)
2176     {
2177         struct _UcastConnection *pconn = &pconnections[i];
2178         if (pconn->state != CONN_COMPLETE)
2179         {
2180             /* this DA failed or timed out, so mark it as bad */
2181             KnownDABadDA(&destaddr[i].sin_addr);
2182         }
2183     }
2184 
2185     /*-----------------------------------------------*/
2186     /* Notify the last time callback that we're done */
2187     /*-----------------------------------------------*/
2188 
2189     if(rplycount)
2190     {
2191         result = SLP_LAST_CALL;
2192     }
2193 
2194     callback(result, NULL, NULL, cookie);
2195 
2196     if(result == SLP_LAST_CALL)
2197     {
2198         result = SLP_OK;
2199     }
2200 
2201     /*----------------*/
2202     /* Free resources */
2203     /*----------------*/
2204     CLEANUP:
2205     if (udp_socket >= 0)
2206     {
2207 #ifdef _WIN32
2208         closesocket(udp_socket);
2209 #else
2210         close(udp_socket);
2211 #endif
2212     }
2213     if(pconnections)
2214     {
2215         for (i = 0; i < ndests; i++)
2216         {
2217             struct _UcastConnection *pconn = &pconnections[i];
2218             if (pconn->socket >= 0)
2219 #ifdef _WIN32
2220                 closesocket(pconn->socket);
2221 #else
2222                 close(pconn->socket);
2223 #endif
2224             if (pconn->read_buffer)
2225                 SLPBufferFree(pconn->read_buffer);
2226         }
2227         xfree(pconnections);
2228     }
2229     SLPBufferFree(sendbuf);
2230     SLPBufferFree(udp_recvbuf);
2231 
2232     return result;
2233 }
2234 
2235 #endif
2236 
2237 /*===========================================================================
2238  *  TESTING CODE : compile with the following command lines:
2239  *
2240  *  $ gcc -g -DSLP_NETWORK_TEST -DDEBUG libslp_network.c
2241  *
2242  *  C:\> cl -DSLP_NETWORK_TEST -DDEBUG libslp_network.c
2243  */
2244 #ifdef SLP_NETWORK_TEST
2245 
main(int argc,char * argv[])2246 int main(int argc, char * argv[])
2247 {
2248    // static routines
2249    int NetworkGetMcastAddrs(const char msgtype, uint8_t * msg,
2250          SLPIfaceInfo * ifaceinfo)
2251 
2252    // non-static routines
2253    sockfd_t NetworkConnectToSlpd(void * peeraddr)
2254    void NetworkDisconnectDA(SLPHandleInfo * handle)
2255    void NetworkDisconnectSA(SLPHandleInfo * handle)
2256    sockfd_t NetworkConnectToDA(SLPHandleInfo * handle, const char * scopelist,
2257          size_t scopelistlen, void * peeraddr)
2258    sockfd_t NetworkConnectToSA(SLPHandleInfo * handle, const char * scopelist,
2259          size_t scopelistlen, void * saaddr)
2260    SLPError NetworkRqstRply(sockfd_t sock, void * peeraddr,
2261          const char * langtag, size_t extoffset, void * buf, char buftype,
2262          size_t bufsize, NetworkRplyCallback callback, void * cookie)
2263    SLPError NetworkMcastRqstRply(SLPHandleInfo * handle, void * buf,
2264          char buftype, size_t bufsize, NetworkRplyCallback callback,
2265          void * cookie)
2266    SLPError NetworkUcastRqstRply(SLPHandleInfo * handle, void * buf,
2267          char buftype, size_t bufsize, NetworkRplyCallback callback,
2268          void * cookie)
2269 }
2270 #endif
2271 
2272 /*=========================================================================*/
2273