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