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 /** Outgoing request handler.
34 *
35 * Handles "outgoing" network conversations requests made by other agents
36 * to slpd.(slpd_incoming.c handles reqests made by other agents to slpd)
37 *
38 * @file slpd_outgoing.c
39 * @author Matthew Peterson, John Calcote (jcalcote@novell.com)
40 * @attention Please submit patches to http://www.openslp.org
41 * @ingroup SlpdCode
42 */
43
44 #include "slpd_outgoing.h"
45 #include "slpd_property.h"
46 #include "slpd_process.h"
47 #include "slpd_log.h"
48 #include "slpd_knownda.h"
49
50 #include "slp_message.h"
51 #include "slp_net.h"
52
53 SLPList G_OutgoingSocketList = { 0, 0, 0 };
54
55 /** Read a datagram from an outbound socket.
56 *
57 * @param[in] socklist - The list of sockets being monitored.
58 * @param[in] sock - The socket to be read from.
59 */
OutgoingDatagramRead(SLPList * socklist,SLPDSocket * sock)60 void OutgoingDatagramRead(SLPList * socklist, SLPDSocket * sock)
61 {
62 int bytesread;
63 socklen_t peeraddrlen = sizeof(struct sockaddr_storage);
64
65 (void)socklist;
66
67 bytesread = recvfrom(sock->fd, (char*)sock->recvbuf->start,
68 G_SlpdProperty.MTU, 0, (struct sockaddr *)&sock->peeraddr,
69 &peeraddrlen);
70 if (bytesread > 0)
71 {
72 sock->recvbuf->end = sock->recvbuf->start + bytesread;
73
74 if (!sock->sendbuf)
75 /* Some of the error handling code expects a sendbuf to be available
76 * to be emptied, so make sure there is at least a minimal buffer
77 */
78 sock->sendbuf = SLPBufferAlloc(1);
79 SLPDProcessMessage(&sock->peeraddr, &sock->localaddr,
80 sock->recvbuf, &sock->sendbuf, &sock->sendlist);
81
82 /* Completely ignore the message */
83
84 }
85 }
86
87 /** Reconnect an outbound socket.
88 *
89 * @param[in] socklist - The list of sockets being monitored.
90 * @param[in] sock - The socket to be reconnected.
91 */
OutgoingStreamReconnect(SLPList * socklist,SLPDSocket * sock)92 void OutgoingStreamReconnect(SLPList * socklist, SLPDSocket * sock)
93 {
94 char addr_str[INET6_ADDRSTRLEN];
95
96 (void)socklist;
97
98 /*-----------------------------------------------------------------*/
99 /* If socket is already being reconnected but is reconnect blocked */
100 /* just return. Blocking connect sockets will eventually time out */
101 /*-----------------------------------------------------------------*/
102 if (sock->state == STREAM_CONNECT_BLOCK)
103 return;
104
105 #ifdef DEBUG
106 /* Log that reconnect warning */
107 SLPDLog("WARNING: Reconnect to agent at %s. "
108 "Agent may not be making efficient \n"
109 " use of TCP.\n",
110 SLPNetSockAddrStorageToString(&sock->peeraddr,
111 addr_str, sizeof(addr_str)));
112 #endif
113
114 /*----------------------------------------------------------------*/
115 /* Make sure we have not reconnected too many times */
116 /* We only allow SLPD_CONFIG_MAX_RECONN reconnection retries */
117 /* before we stop */
118 /*----------------------------------------------------------------*/
119 if (sock->reconns == -1)
120 sock->reconns = 0;
121 sock->reconns += 1;
122 if (sock->reconns > SLPD_CONFIG_MAX_RECONN)
123 {
124 SLPDLog("WARNING: Reconnect tries to agent at %s "
125 "exceeded maximum. It\n is possible that "
126 "the agent is malicious. Check it out!\n",
127 SLPNetSockAddrStorageToString(&sock->peeraddr,
128 addr_str, sizeof(addr_str)));
129
130 /*Since we can't connect, remove it as a DA*/
131 SLPDKnownDARemove(&(sock->peeraddr));
132 sock->state = SOCKET_CLOSE;
133 return;
134 }
135
136 /*----------------------------------------------------------------*/
137 /* Close the existing socket to clean the stream and open an new */
138 /* socket */
139 /*----------------------------------------------------------------*/
140 closesocket(sock->fd);
141
142 if (sock->peeraddr.ss_family == AF_INET)
143 sock->fd = socket(PF_INET, SOCK_STREAM, 0);
144 else if (sock->peeraddr.ss_family == AF_INET6)
145 sock->fd = socket(PF_INET6, SOCK_STREAM, 0);
146
147 if (sock->fd == SLP_INVALID_SOCKET)
148 {
149 sock->state = SOCKET_CLOSE;
150 return;
151 }
152
153 /*---------------------------------------------*/
154 /* Set the new socket to enable nonblocking IO */
155 /*---------------------------------------------*/
156 #ifdef _WIN32
157 {
158 u_long fdflags = 1;
159 ioctlsocket(sock->fd, FIONBIO, &fdflags);
160 }
161 #else
162 {
163 int fdflags = fcntl(sock->fd, F_GETFL, 0);
164 fcntl(sock->fd, F_SETFL, fdflags | O_NONBLOCK);
165 }
166 #endif
167
168 /*--------------------------*/
169 /* Connect a the new socket */
170 /*--------------------------*/
171 if (connect(sock->fd, (struct sockaddr *)&sock->peeraddr,
172 sizeof(struct sockaddr_storage)))
173 {
174 #ifdef _WIN32
175 if (WSAEWOULDBLOCK == WSAGetLastError())
176 #else
177 if (errno == EINPROGRESS)
178 #endif
179 {
180 /* Connect blocked */
181 sock->state = STREAM_CONNECT_BLOCK;
182 return;
183 }
184 }
185
186 /* Connection occured immediately. Set to WRITE_FIRST so whole */
187 /* packet will be written */
188 sock->state = STREAM_WRITE_FIRST;
189 }
190
191 /** Read data from an outbound stream-oriented connection.
192 *
193 * @param[in] socklist - The list of sockets being monitored.
194 * @param[in] sock - The socket to be read from.
195 */
OutgoingStreamRead(SLPList * socklist,SLPDSocket * sock)196 void OutgoingStreamRead(SLPList * socklist, SLPDSocket * sock)
197 {
198 int bytesread;
199 char peek[16];
200 socklen_t peeraddrlen = sizeof(struct sockaddr_storage);
201 unsigned int msglen;
202
203 if (sock->state == STREAM_READ_FIRST)
204 {
205 /*---------------------------------------------------*/
206 /* take a peek at the packet to get size information */
207 /*---------------------------------------------------*/
208 bytesread = recvfrom(sock->fd, peek, 16, MSG_PEEK,
209 (struct sockaddr *) &(sock->peeraddr), &peeraddrlen);
210 if (bytesread > 0)
211 {
212 /* allocate the recvbuf big enough for the whole message */
213 msglen = PEEK_LENGTH(peek);
214
215 sock->recvbuf = SLPBufferRealloc(sock->recvbuf, msglen);
216 if (sock->recvbuf)
217 sock->state = STREAM_READ;
218 else
219 {
220 SLPDLog("INTERNAL_ERROR - out of memory!\n");
221 sock->state = SOCKET_CLOSE;
222 }
223 }
224 else if (bytesread == -1)
225 {
226 #ifdef _WIN32
227 if (WSAEWOULDBLOCK != WSAGetLastError())
228 #else
229 if (errno != EWOULDBLOCK)
230 #endif
231 {
232 /* Error occured or connection was closed. Try to reconnect */
233 /* Socket will be closed if connect times out */
234 OutgoingStreamReconnect(socklist, sock);
235 }
236 }
237 else
238 {
239 /* An EOF occured. This could mean that the other side closed
240 * the connection due to the idle timeout. If we finished some
241 * requests try a reconnect, otherwise simply drop the connection
242 */
243 if (sock->reconns == -1)
244 OutgoingStreamReconnect(socklist,sock);
245 else
246 sock->state = SOCKET_CLOSE;
247 }
248 }
249
250 if (sock->state == STREAM_READ)
251 {
252 /*------------------------------*/
253 /* recv the rest of the message */
254 /*------------------------------*/
255 bytesread = recv(sock->fd, (char *)sock->recvbuf->curpos,
256 (int)(sock->recvbuf->end - sock->recvbuf->curpos), 0);
257 if (bytesread > 0)
258 {
259 /* reset age because of activity */
260 sock->age = 0;
261
262 /* move buffer pointers */
263 sock->recvbuf->curpos += bytesread;
264
265 /* check to see if everything was read */
266 if (sock->recvbuf->curpos == sock->recvbuf->end)
267 switch (SLPDProcessMessage(&(sock->peeraddr), &(sock->localaddr),
268 sock->recvbuf, &(sock->sendbuf), 0))
269 {
270 case SLP_ERROR_DA_BUSY_NOW:
271 sock->state = STREAM_WRITE_WAIT;
272 break;
273 case SLP_ERROR_PARSE_ERROR:
274 case SLP_ERROR_VER_NOT_SUPPORTED:
275 sock->state = SOCKET_CLOSE;
276 break;
277 default:
278 /* End of outgoing message exchange. Unlink */
279 /* send buf from to do list and free it */
280 SLPBufferFree(sock->sendbuf);
281 sock->sendbuf = NULL;
282 sock->state = STREAM_WRITE_FIRST;
283 /* clear the reconnection count since we actually
284 * transmitted a successful message exchange. We
285 * use -1 to indicate that the socket had at
286 * least one successful communication.
287 */
288 sock->reconns = -1;
289 break;
290 }
291 }
292 else
293 {
294 #ifdef _WIN32
295 if (WSAEWOULDBLOCK != WSAGetLastError())
296 #else
297 if (errno != EWOULDBLOCK)
298 #endif
299 {
300 /* Error occured or connection was closed. Try to reconnect */
301 /* Socket will be closed if connect times out */
302 OutgoingStreamReconnect(socklist, sock);
303 }
304 }
305 }
306 }
307
308 /** Check if the socket is still alive, the server may have closed it.
309 *
310 * @param[in] fd - The socket descriptor to check.
311 *
312 * @return zero on timeout; -1 on any type of error (errno is set)
313 *
314 * @note See the UA version of this function in libslp_network.c
315 *
316 * @internal
317 */
NetworkCheckConnection(sockfd_t fd)318 static int NetworkCheckConnection(sockfd_t fd)
319 {
320 int r;
321 #ifdef HAVE_POLL
322 struct pollfd readfd;
323 #else
324 fd_set readfd;
325 struct timeval tv;
326 #endif
327
328 #ifdef HAVE_POLL
329 readfd.fd = (int)fd;
330 readfd.events = POLLIN;
331 while ((r = poll(&readfd, 1, 0)) == -1 && errno == EINTR)
332 ;
333 #else
334 FD_ZERO(&readfd);
335 FD_SET((int)fd, &readfd);
336 tv.tv_sec = 0;
337 tv.tv_usec = 0;
338 while ((r = select((int)(fd + 1), &readfd, 0, 0, &tv)) == -1 && errno == EINTR)
339 ;
340 #endif
341 /* r == 0 means timeout, everything else is an error */
342 return r == 0 ? 0 : -1;
343 }
344
345 /** Write data to an outbound, stream-oriented socket.
346 *
347 * @param[in] socklist - The list of sockets being monitored.
348 * @param[in] sock - The socket to be written to.
349 */
OutgoingStreamWrite(SLPList * socklist,SLPDSocket * sock)350 void OutgoingStreamWrite(SLPList * socklist, SLPDSocket * sock)
351 {
352 int byteswritten;
353 int flags = 0;
354
355 #if defined(MSG_DONTWAIT)
356 flags = MSG_DONTWAIT;
357 #endif
358
359 if (sock->state == STREAM_WRITE_FIRST)
360 {
361 /* set sendbuf to the first item in the send list if it is not set */
362 if (sock->sendbuf == NULL)
363 {
364 sock->sendbuf = (SLPBuffer) sock->sendlist.head;
365 if (sock->sendbuf == NULL)
366 {
367 /* there is nothing in the to do list */
368 sock->state = STREAM_CONNECT_IDLE;
369 return;
370 }
371 /* Unlink the send buffer we are sending from the send list */
372 SLPListUnlink(&(sock->sendlist), (SLPListItem *) (sock->sendbuf));
373 }
374
375 /* make sure that the start and curpos pointers are the same */
376 sock->sendbuf->curpos = sock->sendbuf->start;
377 sock->state = STREAM_WRITE;
378
379 /* test the socket if it was already used */
380 if (sock->reconns == -1 && sock->age > 10)
381 {
382 if (NetworkCheckConnection(sock->fd) != 0)
383 {
384 OutgoingStreamReconnect(socklist,sock);
385 return;
386 }
387 }
388 }
389
390 if (sock->sendbuf->end - sock->sendbuf->curpos > 0)
391 {
392 byteswritten = send(sock->fd, (char *)sock->sendbuf->curpos,
393 (int)(sock->sendbuf->end - sock->sendbuf->curpos), flags);
394 if (byteswritten > 0)
395 {
396 /* reset age because of activity */
397 sock->age = 0;
398
399 /* move buffer pointers */
400 sock->sendbuf->curpos += byteswritten;
401
402 /* check to see if everything was written */
403 if (sock->sendbuf->curpos == sock->sendbuf->end)
404 {
405 /* Message is completely sent. Set state to read the reply */
406 sock->state = STREAM_READ_FIRST;
407 }
408 }
409 else
410 {
411 #ifdef _WIN32
412 if (WSAEWOULDBLOCK != WSAGetLastError())
413 #else
414 if (errno != EWOULDBLOCK)
415 #endif
416 {
417 /* Error occured or connection was closed. Try to reconnect */
418 /* Socket will be closed if connect times out */
419 OutgoingStreamReconnect(socklist, sock);
420 }
421 }
422 }
423 else
424 {
425 /* nothing to write */
426 #ifdef DEBUG
427 SLPDLog("yikes, an empty socket is being written!\n");
428 #endif
429 sock->state = SOCKET_CLOSE;
430 }
431 }
432
433 /** Connect for outbound traffic to a specified remote address.
434 *
435 * @param[in] is_TCP - if non-0, this is a tcp connection to the remote device
436 * @param[in] addr - The address to be connected to.
437 *
438 * @remarks Get a pointer to a connected socket that is associated with
439 * the outgoing socket list. If a connected socket already exists on the
440 * outgoing list, a pointer to it is returned, otherwise a new connection
441 * is made and added to the outgoing list
442 *
443 * @return A pointer to socket, or null on error.
444 */
SLPDOutgoingConnect(int is_TCP,struct sockaddr_storage * addr)445 SLPDSocket * SLPDOutgoingConnect(int is_TCP, struct sockaddr_storage * addr)
446 {
447 SLPDSocket * sock = 0;
448
449 if(is_TCP)
450 {
451 sock = (SLPDSocket *) G_OutgoingSocketList.head;
452 while (sock)
453 {
454 if (sock->state == STREAM_CONNECT_IDLE
455 || sock->state > STREAM_CONNECT_CLOSE)
456 {
457 if (SLPNetCompareAddrs(&(sock->peeraddr), addr) == 0)
458 break;
459 }
460 sock = (SLPDSocket *) sock->listitem.next;
461 }
462
463 if (sock == 0)
464 {
465 sock = SLPDSocketCreateConnected(addr);
466 if (sock)
467 SLPListLinkTail(&(G_OutgoingSocketList), (SLPListItem *) sock);
468 }
469 }
470 else
471 {
472 sock = SLPDSocketCreateDatagram(addr, DATAGRAM_UNICAST);
473 if (sock)
474 {
475 SLPListLinkTail(&(G_OutgoingSocketList), (SLPListItem *) sock);
476 sock->reconns = 0;
477 sock->age = 0;
478 }
479 }
480
481 return sock;
482 }
483
484 /** Check that there is an outgoing socket for the specified address
485 *
486 * @param[in] addr - The address of the peer to check.
487 *
488 * @return a boolean value; true if there is, false if not.
489 */
SLPDHaveOutgoingConnectedSocket(struct sockaddr_storage * addr)490 int SLPDHaveOutgoingConnectedSocket(struct sockaddr_storage* addr)
491 {
492 SLPDSocket* sock = (SLPDSocket*)G_OutgoingSocketList.head;
493 while (sock)
494 {
495 if (sock->state >= STREAM_CONNECT_IDLE &&
496 SLPNetCompareAddrs(&sock->peeraddr, addr) == 0)
497 return 1;
498 sock = (SLPDSocket*)sock->listitem.next;
499 }
500 return 0;
501 }
502
503 /** Writes the datagram to the socket's peeraddr
504 *
505 * @param[in] sock - The socket whose peer will be sent to.
506 * @param[in] buffer - The buffer to send, could be the sockets sendbuf, or an item in the sendlist, etc.
507 */
SLPDOutgoingDatagramWrite(SLPDSocket * sock,SLPBuffer buffer)508 void SLPDOutgoingDatagramWrite(SLPDSocket * sock, SLPBuffer buffer)
509 {
510 if (0 >= sendto(sock->fd, (char*)buffer->start,
511 (int)(buffer->end - buffer->start), 0,
512 (struct sockaddr *)&sock->peeraddr,
513 SLPNetAddrLen(&sock->peeraddr)))
514 {
515 #ifdef DEBUG
516 SLPDLog("ERROR: Data could not send() in SLPDOutgoingDatagramWrite()\n");
517 #endif
518 }
519 }
520
521 /** Writes the datagram to the mcastaddr
522 *
523 * @param[in] sock - The socket to send on
524 * @param[in] maddr - The mcast addr to send to
525 * @param[in] buffer - the buffer to send, could be the sockets sendbuf, or an item in the sendlist, etc.
526 */
SLPDOutgoingDatagramMcastWrite(SLPDSocket * sock,struct sockaddr_storage * maddr,SLPBuffer buffer)527 void SLPDOutgoingDatagramMcastWrite(SLPDSocket * sock, struct sockaddr_storage *maddr, SLPBuffer buffer)
528 {
529 if (sendto(sock->fd, (char*)buffer->start,
530 (int)(buffer->end - buffer->start), 0,
531 (struct sockaddr *)maddr, SLPNetAddrLen(maddr)) < 0)
532 {
533 #ifdef DEBUG
534 SLPDLog("ERROR: Data could not send() in SLPDOutgoingDatagramMcastWrite()\n");
535 #endif
536 }
537 }
538
539 /** Handles outgoing requests pending on specified file discriptors.
540 *
541 * @param[in,out] fdcount - The number of file descriptors marked in fd_sets.
542 * @param[in] fdset - The set of file descriptors with pending read/write IO.
543 */
SLPDOutgoingHandler(int * fdcount,SLPD_fdset * fdset)544 void SLPDOutgoingHandler(int * fdcount, SLPD_fdset * fdset)
545 {
546 SLPDSocket * sock;
547 sock = (SLPDSocket *) G_OutgoingSocketList.head;
548 while (sock && *fdcount)
549 {
550 if (SLPD_fdset_readok(fdset, sock))
551 {
552 switch (sock->state)
553 {
554 case DATAGRAM_MULTICAST:
555 case DATAGRAM_BROADCAST:
556 case DATAGRAM_UNICAST:
557 OutgoingDatagramRead(&G_OutgoingSocketList, sock);
558 break;
559
560 case STREAM_READ:
561 case STREAM_READ_FIRST:
562 OutgoingStreamRead(&G_OutgoingSocketList, sock);
563 break;
564
565 default:
566 /* No SOCKET_LISTEN sockets should exist */
567 break;
568 }
569
570 *fdcount = *fdcount - 1;
571 }
572 else if (SLPD_fdset_writeok(fdset, sock))
573 {
574 switch (sock->state)
575 {
576 case STREAM_CONNECT_BLOCK:
577 sock->age = 0;
578 sock->state = STREAM_WRITE_FIRST;
579
580 case STREAM_WRITE:
581 case STREAM_WRITE_FIRST:
582 OutgoingStreamWrite(&G_OutgoingSocketList, sock);
583 break;
584
585 default:
586 break;
587 }
588
589 *fdcount = *fdcount - 1;
590 }
591
592 sock = (SLPDSocket *) sock->listitem.next;
593 }
594 }
595
596 /** Resend messages on sockets whose timeout has expired
597 *
598 * @param[in] seconds - The number of seconds old a socket must be to have
599 * its messages resent.
600 *
601 * @remarks - Ideally, this would be at a resolution lower than one second,
602 * but given the default timeout values, this isn't too far off the mark, and
603 * should not add too much of a burden to the main loop.
604 */
SLPDOutgoingRetry(time_t seconds)605 void SLPDOutgoingRetry(time_t seconds)
606 {
607 SLPDSocket * del = 0;
608 SLPDSocket * sock = (SLPDSocket *) G_OutgoingSocketList.head;
609
610 if(seconds <= 0)
611 return;
612
613 while (sock)
614 {
615 switch (sock->state)
616 {
617 case DATAGRAM_UNICAST:
618 if(0 == sock->sendlist.count) /*Clean up as fast as we can, as all messages were sent*/
619 del = sock;
620 else
621 {
622 sock->age += seconds;
623 if(sock->age >= G_SlpdProperty.unicastTimeouts[sock->reconns] / 1000)
624 {
625 ++sock->reconns;
626 if(sock->reconns >= MAX_RETRANSMITS)
627 {
628 char addr_str[INET6_ADDRSTRLEN];
629 SLPDLog("SLPD: Didn't receive response from DA at %s, removing it from list.\n",
630 SLPNetSockAddrStorageToString(&sock->peeraddr, addr_str, sizeof(addr_str)));
631
632 SLPDKnownDARemove(&(sock->peeraddr));
633 del = sock;
634 }
635 else
636 {
637 SLPBuffer pbuf;
638 sock->age = 0;
639 for(pbuf = (SLPBuffer) sock->sendlist.head; pbuf; pbuf = (SLPBuffer) pbuf->listitem.next)
640 SLPDOutgoingDatagramWrite(sock, pbuf);
641 }
642 }
643 }
644 break;
645
646 case DATAGRAM_MULTICAST:
647 case DATAGRAM_BROADCAST:
648 case STREAM_READ_FIRST:
649 case STREAM_WRITE_FIRST:
650 case STREAM_CONNECT_BLOCK:
651 case STREAM_READ:
652 case STREAM_WRITE:
653 case STREAM_CONNECT_IDLE:
654 case STREAM_WRITE_WAIT:
655 default:
656 break;
657 }
658
659 sock = (SLPDSocket *) sock->listitem.next;
660
661 if (del)
662 {
663 SLPDSocketFree((SLPDSocket *)
664 SLPListUnlink(&G_OutgoingSocketList, (SLPListItem *) del));
665 del = 0;
666 }
667 }
668 }
669
670
671
672 /** Age the outgoing socket list.
673 *
674 * @param[in] seconds - The number of seconds old an entry must be to be
675 * removed from the outgoing list.
676 */
SLPDOutgoingAge(time_t seconds)677 void SLPDOutgoingAge(time_t seconds)
678 {
679 SLPDSocket * del = 0;
680 SLPDSocket * sock = (SLPDSocket *) G_OutgoingSocketList.head;
681
682 while (sock)
683 {
684 switch (sock->state)
685 {
686 case DATAGRAM_MULTICAST:
687 case DATAGRAM_BROADCAST:
688 if (sock->age > G_SlpdProperty.unicastMaximumWait / 1000)
689 del = sock;
690 sock->age = sock->age + seconds;
691 break;
692
693 case DATAGRAM_UNICAST:
694 /*The Retry logic ages these out*/
695 break;
696
697 case STREAM_READ_FIRST:
698 case STREAM_WRITE_FIRST:
699 sock->age = 0;
700 break;
701
702 case STREAM_CONNECT_BLOCK:
703 case STREAM_READ:
704 case STREAM_WRITE:
705 if (G_OutgoingSocketList.count > SLPD_COMFORT_SOCKETS)
706 {
707 /* Accelerate ageing cause we are low on sockets */
708 if (sock->age > SLPD_CONFIG_BUSY_CLOSE_CONN)
709 {
710 /* Remove peer from KnownDAs since it might be dead */
711 SLPDKnownDARemove(&(sock->peeraddr));
712 del = sock;
713 }
714 }
715 else
716 {
717 if (sock->age > SLPD_CONFIG_CLOSE_CONN)
718 {
719 /* Remove peer from KnownDAs since it might be dead */
720 SLPDKnownDARemove(&(sock->peeraddr));
721 del = sock;
722 }
723 }
724 sock->age = sock->age + seconds;
725 break;
726
727 case STREAM_CONNECT_IDLE:
728 if (G_OutgoingSocketList.count > SLPD_COMFORT_SOCKETS)
729 {
730 /* Accelerate ageing cause we are low on sockets */
731 if (sock->age > SLPD_CONFIG_BUSY_CLOSE_CONN)
732 del = sock;
733 }
734 else
735 {
736 if (sock->age > SLPD_CONFIG_CLOSE_CONN)
737 del = sock;
738 }
739 sock->age = sock->age + seconds;
740 break;
741
742 case STREAM_WRITE_WAIT:
743 /* this when we are talking to a busy DA */
744 sock->age = 0;
745 sock->state = STREAM_WRITE_FIRST;
746 break;
747
748 default:
749 /* don't age the other sockets at all */
750 break;
751 }
752
753 sock = (SLPDSocket *) sock->listitem.next;
754
755 if (del)
756 {
757 SLPDSocketFree((SLPDSocket *)
758 SLPListUnlink(&G_OutgoingSocketList, (SLPListItem *) del));
759 del = 0;
760 }
761 }
762 }
763
764 /** Initialize outgoing socket list for all network interfaces.
765 *
766 * @return Zero - always.
767 */
SLPDOutgoingInit(void)768 int SLPDOutgoingInit(void)
769 {
770 /*------------------------------------------------------------*/
771 /* First, remove all of the sockets that might be in the list */
772 /*------------------------------------------------------------*/
773 while (G_OutgoingSocketList.count)
774 SLPDSocketFree((SLPDSocket *)
775 SLPListUnlink(&G_OutgoingSocketList,
776 (SLPListItem *) G_OutgoingSocketList.head));
777
778 return 0;
779 }
780
781 /** Release all unused socket on inbound socket list.
782 *
783 * Deinitialize incoming socket list to have appropriate sockets for all
784 * network interfaces.
785 *
786 * @param[in] graceful - Flag indicates do NOT close sockets with pending
787 * writes outstanding.
788 *
789 * @return Zero on success, or a non-zero value when pending writes
790 * remain.
791 */
SLPDOutgoingDeinit(int graceful)792 int SLPDOutgoingDeinit(int graceful)
793 {
794 SLPDSocket * del = 0;
795 SLPDSocket * sock = (SLPDSocket *) G_OutgoingSocketList.head;
796
797 while (sock)
798 {
799 /* graceful only closes sockets without pending I/O */
800 if (graceful == 0)
801 del = sock;
802 else if (sock->state < SOCKET_PENDING_IO)
803 del = sock;
804
805 sock = (SLPDSocket *) sock->listitem.next;
806
807 if (del)
808 {
809 SLPDSocketFree((SLPDSocket *)
810 SLPListUnlink(&G_OutgoingSocketList, (SLPListItem *) del));
811 del = 0;
812 }
813 }
814
815 return G_OutgoingSocketList.count;
816 }
817
818 #ifdef DEBUG
819 /** Dump outbound socket data.
820 *
821 * @note This routine is compiled in Debug code only.
822 */
SLPDOutgoingSocketDump(void)823 void SLPDOutgoingSocketDump(void)
824 {
825 char str1[INET6_ADDRSTRLEN];
826 char str2[INET6_ADDRSTRLEN];
827 char str3[INET6_ADDRSTRLEN];
828 SLPDSocket * sock = (SLPDSocket *) G_OutgoingSocketList.head;
829 SLPDLog("========================================================================\n");
830 SLPDLog("Dumping OutgoingSocketList\n");
831 SLPDLog("========================================================================\n");
832 while (sock)
833 {
834 SLPDLog("localaddr=%s peeraddr=%s mcastaddr=%s\n",
835 SLPNetSockAddrStorageToString(&(sock->localaddr), str1, sizeof(str1)),
836 SLPNetSockAddrStorageToString(&(sock->peeraddr), str2, sizeof(str2)),
837 SLPNetSockAddrStorageToString(&(sock->mcastaddr), str3, sizeof(str3)));
838 sock = (SLPDSocket *) sock->listitem.next;
839 }
840 }
841 #endif
842
843 /*=========================================================================*/
844