]> granicus.if.org Git - transmission/blob - libtransmission/tr-lpd.c
Update to Uncrustify 0.68.1
[transmission] / libtransmission / tr-lpd.c
1 /*
2 Copyright (c) 2010 by Johannes Lieder
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23 /* ansi */
24 #include <errno.h>
25 #include <stdio.h>
26 #include <string.h> /* strlen(), strncpy(), strstr(), memset() */
27
28 /* posix */
29 #include <signal.h> /* sig_atomic_t */
30 #include <ctype.h> /* toupper() */
31
32 #ifdef _WIN32
33 #include <inttypes.h>
34 #include <ws2tcpip.h>
35 typedef uint16_t in_port_t; /* all missing */
36 #else
37 #include <sys/time.h>
38 #include <unistd.h> /* close() */
39 #include <sys/types.h>
40 #include <sys/socket.h> /* socket(), bind() */
41 #include <netinet/in.h> /* sockaddr_in */
42 #endif
43
44 /* third party */
45 #include <event2/event.h>
46 #include <event2/util.h>
47
48 /* libT */
49 #include "transmission.h"
50 #include "log.h"
51 #include "net.h"
52 #include "peer-mgr.h" /* tr_peerMgrAddPex() */
53 #include "session.h"
54 #include "torrent.h" /* tr_torrentFindFromHash() */
55 #include "tr-assert.h"
56 #include "tr-lpd.h"
57 #include "utils.h"
58 #include "version.h"
59
60 /**
61 * @brief Local Peer Discovery
62 * @file tr-lpd.c
63 *
64 * This module implements the Local Peer Discovery (LPD) protocol as supported by the
65 * uTorrent client application. A typical LPD datagram is 119 bytes long.
66 *
67 */
68
69 static void event_callback(evutil_socket_t, short, void*);
70
71 enum
72 {
73     UPKEEP_INTERVAL_SECS = 5
74 };
75
76 static struct event* upkeep_timer = NULL;
77
78 static tr_socket_t lpd_socket; /**<separate multicast receive socket */
79 static tr_socket_t lpd_socket2; /**<and multicast send socket */
80 static struct event* lpd_event = NULL;
81 static tr_port lpd_port;
82
83 static tr_torrent* lpd_torStaticType UNUSED; /* just a helper for static type analysis */
84 static tr_session* session;
85
86 enum
87 {
88     lpd_maxDatagramLength = 200 /**<the size an LPD datagram must not exceed */
89 };
90
91 char const lpd_mcastGroup[] = "239.192.152.143"; /**<LPD multicast group */
92 int const lpd_mcastPort = 6771; /**<LPD source and destination UPD port */
93 static struct sockaddr_in lpd_mcastAddr; /**<initialized from the above constants in tr_lpdInit */
94
95 /**
96 * @brief Protocol-related information carried by a Local Peer Discovery packet */
97 struct lpd_protocolVersion
98 {
99     int major;
100     int minor;
101 };
102
103 enum lpd_enumTimeToLive
104 {
105     lpd_ttlSameSubnet = 1,
106     lpd_ttlSameSite = 32,
107     lpd_ttlSameRegion = 64,
108     lpd_ttlSameContinent = 128,
109     lpd_ttlUnrestricted = 255
110 };
111
112 enum
113 {
114     lpd_announceInterval = 4 * 60, /**<4 min announce interval per torrent */
115     lpd_announceScope = lpd_ttlSameSubnet /**<the maximum scope for LPD datagrams */
116 };
117
118 /**
119 * @defgroup DoS Message Flood Protection
120 * @{
121 * We want to have a means to protect the libtransmission backend against message
122 * flooding: the strategy is to cap event processing once more than ten messages
123 * per second (that is, taking the average over one of our housekeeping intervals)
124 * got into our processing handler.
125 * If we'd really hit the limit and start discarding events, we either joined an
126 * extremely crowded multicast group or a malevolent host is sending bogus data to
127 * our socket. In this situation, we rather miss some announcements than blocking
128 * the actual task.
129 * @}
130 */
131
132 /**
133 * @ingroup DoS
134 * @brief allow at most ten messages per second (interval average)
135 * @note this constraint is only enforced once per housekeeping interval */
136 enum
137 {
138     lpd_announceCapFactor = 10
139 };
140
141 /**
142 * @ingroup DoS
143 * @brief number of unsolicited messages during the last HK interval
144 * @remark counts downwards */
145 static int lpd_unsolicitedMsgCounter;
146
147 /**
148 * @def CRLF
149 * @brief a line-feed, as understood by the LPD protocol */
150 #define CRLF "\r\n"
151
152 /**
153 * @defgroup HttpReqProc HTTP-style request handling
154 * @{
155 */
156
157 /**
158 * @brief Checks for BT-SEARCH method and separates the parameter section
159 * @param[in] s The request string
160 * @param[out] ver If non-NULL, gets filled with protocol info from the request
161 * @return Returns a relative pointer to the beginning of the parameter section;
162 *         if result is NULL, s was invalid and no information will be returned
163 * @remark Note that the returned pointer is only usable as long as the given
164 *         pointer s is valid; that is, return storage is temporary.
165 *
166 * Determines whether the given string checks out to be a valid BT-SEARCH message.
167 * If so, the return value points to the beginning of the parameter section (note:
168 * in this case the function returns a character sequence beginning with CRLF).
169 * If parameter is not NULL, the declared protocol version is returned as part of
170 * the lpd_protocolVersion structure.
171 */
172 static char const* lpd_extractHeader(char const* s, struct lpd_protocolVersion* const ver)
173 {
174     TR_ASSERT(s != NULL);
175
176     int major = -1;
177     int minor = -1;
178     size_t len = strlen(s);
179
180     /* something might be rotten with this chunk of data */
181     if (len == 0 || len > lpd_maxDatagramLength)
182     {
183         return NULL;
184     }
185
186     /* now we can attempt to look up the BT-SEARCH header */
187     if (sscanf(s, "BT-SEARCH * HTTP/%d.%d" CRLF, &major, &minor) != 2)
188     {
189         return NULL;
190     }
191
192     if (major < 0 || minor < 0)
193     {
194         return NULL;
195     }
196
197     {
198         /* a pair of blank lines at the end of the string, no place else */
199         char const* const two_blank = CRLF CRLF CRLF;
200         char const* const end = strstr(s, two_blank);
201
202         if (end == NULL || strlen(end) > strlen(two_blank))
203         {
204             return NULL;
205         }
206     }
207
208     if (ver != NULL)
209     {
210         ver->major = major;
211         ver->minor = minor;
212     }
213
214     /* separate the header, begins with CRLF */
215     return strstr(s, CRLF);
216 }
217
218 /**
219 * @brief Return the value of a named parameter
220 *
221 * @param[in] str Input string of "\r\nName: Value" pairs without HTTP-style method part
222 * @param[in] name Name of parameter to extract
223 * @param[in] n Maximum available storage for value to return
224 * @param[out] val Output parameter for the actual value
225 * @return Returns 1 if value could be copied successfully
226 *
227 * Extracts the associated value of a named parameter from a HTTP-style header by
228 * performing the following steps:
229 *   - assemble search string "\r\nName: " and locate position
230 *   - copy back value from end to next "\r\n"
231 */
232 static bool lpd_extractParam(char const* const str, char const* const name, int n, char* const val)
233 {
234     TR_ASSERT(str != NULL);
235     TR_ASSERT(name != NULL);
236     TR_ASSERT(val != NULL);
237
238     enum
239     {
240         /* configure maximum length of search string here */
241         maxLength = 30
242     };
243
244     char sstr[maxLength] = { 0 };
245     char const* pos;
246
247     if (strlen(name) > maxLength - strlen(CRLF ": "))
248     {
249         return false;
250     }
251
252     /* compose the string token to search for */
253     tr_snprintf(sstr, maxLength, CRLF "%s: ", name);
254
255     pos = strstr(str, sstr);
256
257     if (pos == NULL)
258     {
259         return false; /* search was not successful */
260     }
261
262     {
263         char const* const beg = pos + strlen(sstr);
264         char const* const new_line = strstr(beg, CRLF);
265
266         /* the value is delimited by the next CRLF */
267         int len = new_line - beg;
268
269         /* if value string hits the length limit n,
270          * leave space for a trailing '\0' character */
271         if (len < n--)
272         {
273             n = len;
274         }
275
276         strncpy(val, beg, n);
277         val[n] = 0;
278     }
279
280     /* we successfully returned the value string */
281     return true;
282 }
283
284 /**
285 * @} */
286
287 static void on_upkeep_timer(evutil_socket_t, short, void*);
288
289 /**
290 * @brief Initializes Local Peer Discovery for this node
291 *
292 * For the most part, this means setting up an appropriately configured multicast socket
293 * and event-based message handling.
294 *
295 * @remark Since the LPD service does not use another protocol family yet, this code is
296 * IPv4 only for the time being.
297 */
298 int tr_lpdInit(tr_session* ss, tr_address* tr_addr UNUSED)
299 {
300     struct ip_mreq mcastReq;
301     int const opt_on = 1;
302     int const opt_off = 0;
303
304     if (session != NULL) /* already initialized */
305     {
306         return -1;
307     }
308
309     TR_ASSERT(lpd_announceInterval > 0);
310     TR_ASSERT(lpd_announceScope > 0);
311
312     lpd_port = tr_sessionGetPeerPort(ss);
313
314     if (lpd_port <= 0)
315     {
316         return -1;
317     }
318
319     tr_logAddNamedDbg("LPD", "Initialising Local Peer Discovery");
320
321     /* setup datagram socket (receive) */
322     {
323         lpd_socket = socket(PF_INET, SOCK_DGRAM, 0);
324
325         if (lpd_socket == TR_BAD_SOCKET)
326         {
327             goto fail;
328         }
329
330         if (evutil_make_socket_nonblocking(lpd_socket) == -1)
331         {
332             goto fail;
333         }
334
335         if (setsockopt(lpd_socket, SOL_SOCKET, SO_REUSEADDR, (void const*)&opt_on, sizeof(opt_on)) == -1)
336         {
337             goto fail;
338         }
339
340         memset(&lpd_mcastAddr, 0, sizeof(lpd_mcastAddr));
341         lpd_mcastAddr.sin_family = AF_INET;
342         lpd_mcastAddr.sin_port = htons(lpd_mcastPort);
343
344         if (evutil_inet_pton(lpd_mcastAddr.sin_family, lpd_mcastGroup, &lpd_mcastAddr.sin_addr) == -1)
345         {
346             goto fail;
347         }
348
349         if (bind(lpd_socket, (struct sockaddr*)&lpd_mcastAddr, sizeof(lpd_mcastAddr)) == -1)
350         {
351             goto fail;
352         }
353
354         /* we want to join that LPD multicast group */
355         memset(&mcastReq, 0, sizeof(mcastReq));
356         mcastReq.imr_multiaddr = lpd_mcastAddr.sin_addr;
357         mcastReq.imr_interface.s_addr = htonl(INADDR_ANY);
358
359         if (setsockopt(lpd_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void const*)&mcastReq, sizeof(mcastReq)) == -1)
360         {
361             goto fail;
362         }
363
364         if (setsockopt(lpd_socket, IPPROTO_IP, IP_MULTICAST_LOOP, (void const*)&opt_off, sizeof(opt_off)) == -1)
365         {
366             goto fail;
367         }
368     }
369
370     /* setup datagram socket (send) */
371     {
372         unsigned char const scope = lpd_announceScope;
373
374         lpd_socket2 = socket(PF_INET, SOCK_DGRAM, 0);
375
376         if (lpd_socket2 == TR_BAD_SOCKET)
377         {
378             goto fail;
379         }
380
381         if (evutil_make_socket_nonblocking(lpd_socket2) == -1)
382         {
383             goto fail;
384         }
385
386         /* configure outbound multicast TTL */
387         if (setsockopt(lpd_socket2, IPPROTO_IP, IP_MULTICAST_TTL, (void const*)&scope, sizeof(scope)) == -1)
388         {
389             goto fail;
390         }
391
392         if (setsockopt(lpd_socket2, IPPROTO_IP, IP_MULTICAST_LOOP, (void const*)&opt_off, sizeof(opt_off)) == -1)
393         {
394             goto fail;
395         }
396     }
397
398     session = ss;
399
400     /* Note: lpd_unsolicitedMsgCounter remains 0 until the first timeout event, thus
401      * any announcement received during the initial interval will be discarded. */
402
403     lpd_event = event_new(ss->event_base, lpd_socket, EV_READ | EV_PERSIST, event_callback, NULL);
404     event_add(lpd_event, NULL);
405
406     upkeep_timer = evtimer_new(ss->event_base, on_upkeep_timer, ss);
407     tr_timerAdd(upkeep_timer, UPKEEP_INTERVAL_SECS, 0);
408
409     tr_logAddNamedDbg("LPD", "Local Peer Discovery initialised");
410
411     return 1;
412
413 fail:
414     {
415         int const save = errno;
416         evutil_closesocket(lpd_socket);
417         evutil_closesocket(lpd_socket2);
418         lpd_socket = lpd_socket2 = TR_BAD_SOCKET;
419         session = NULL;
420         tr_logAddNamedDbg("LPD", "LPD initialisation failed (errno = %d)", save);
421         errno = save;
422     }
423
424     return -1;
425 }
426
427 void tr_lpdUninit(tr_session* ss)
428 {
429     if (session != ss)
430     {
431         return;
432     }
433
434     tr_logAddNamedDbg("LPD", "Uninitialising Local Peer Discovery");
435
436     event_free(lpd_event);
437     lpd_event = NULL;
438
439     evtimer_del(upkeep_timer);
440     upkeep_timer = NULL;
441
442     /* just shut down, we won't remember any former nodes */
443     evutil_closesocket(lpd_socket);
444     evutil_closesocket(lpd_socket2);
445     tr_logAddNamedDbg("LPD", "Done uninitialising Local Peer Discovery");
446
447     session = NULL;
448 }
449
450 bool tr_lpdEnabled(tr_session const* ss)
451 {
452     return ss != NULL && ss == session;
453 }
454
455 /**
456 * @cond
457 * @brief Performs some (internal) software consistency checks at compile time.
458 * @remark Declared inline for the compiler not to allege us of feeding unused
459 * functions. In any other respect, lpd_consistencyCheck is an orphaned function.
460 */
461 UNUSED static inline void lpd_consistencyCheck(void)
462 {
463     /* if the following check fails, the definition of a hash string has changed
464      * without our knowledge; revise string handling in functions tr_lpdSendAnnounce
465      * and tr_lpdConsiderAnnounce. However, the code is designed to function as long
466      * as interfaces to the rest of the lib remain compatible with char* strings. */
467     TR_STATIC_ASSERT(sizeof(lpd_torStaticType->info.hashString[0]) == sizeof(char), "");
468 }
469 /**
470 * @endcond */
471
472 /**
473 * @defgroup LdsProto LPD announcement processing
474 * @{
475 */
476
477 /**
478 * @brief Announce the given torrent on the local network
479 *
480 * @param[in] t Torrent to announce
481 * @return Returns true on success
482 *
483 * Send a query for torrent t out to the LPD multicast group (or the LAN, for that
484 * matter). A listening client on the same network might react by adding us to his
485 * peer pool for torrent t.
486 */
487 bool tr_lpdSendAnnounce(tr_torrent const* t)
488 {
489     char const fmt[] =
490         "BT-SEARCH * HTTP/%u.%u" CRLF
491         "Host: %s:%u" CRLF
492         "Port: %u" CRLF
493         "Infohash: %s" CRLF
494         CRLF
495         CRLF;
496
497     char hashString[lengthof(t->info.hashString)];
498     char query[lpd_maxDatagramLength + 1] = { 0 };
499
500     if (t == NULL)
501     {
502         return false;
503     }
504
505     /* make sure the hash string is normalized, just in case */
506     for (size_t i = 0; i < TR_N_ELEMENTS(hashString); ++i)
507     {
508         hashString[i] = toupper(t->info.hashString[i]);
509     }
510
511     /* prepare a zero-terminated announce message */
512     tr_snprintf(query, lpd_maxDatagramLength + 1, fmt, 1, 1, lpd_mcastGroup, lpd_mcastPort, lpd_port, hashString);
513
514     /* actually send the query out using [lpd_socket2] */
515     {
516         int const len = strlen(query);
517
518         /* destination address info has already been set up in tr_lpdInit(),
519          * so we refrain from preparing another sockaddr_in here */
520         int res = sendto(lpd_socket2, (void const*)query, len, 0, (struct sockaddr const*)&lpd_mcastAddr,
521             sizeof(lpd_mcastAddr));
522
523         if (res != len)
524         {
525             return false;
526         }
527     }
528
529     tr_logAddTorDbg(t, "LPD announce message away");
530
531     return true;
532 }
533
534 /**
535 * @brief Process incoming unsolicited messages and add the peer to the announced
536 * torrent if all checks are passed.
537 *
538 * @param[in,out] peer Adress information of the peer to add
539 * @param[in] msg The announcement message to consider
540 * @return Returns 0 if any input parameter or the announce was invalid, 1 if the peer
541 * was successfully added, -1 if not; a non-null return value indicates a side-effect to
542 * the peer in/out parameter.
543 *
544 * @note The port information gets added to the peer structure if tr_lpdConsiderAnnounce
545 * is able to extract the necessary information from the announce message. That is, if
546 * return != 0, the caller may retrieve the value from the passed structure.
547 */
548 static int tr_lpdConsiderAnnounce(tr_pex* peer, char const* const msg)
549 {
550     enum
551     {
552         maxValueLen = 25,
553         maxHashLen = lengthof(lpd_torStaticType->info.hashString)
554     };
555
556     struct lpd_protocolVersion ver = { .major = -1, .minor = -1 };
557     char value[maxValueLen] = { 0 };
558     char hashString[maxHashLen] = { 0 };
559     int res = 0;
560     int peerPort = 0;
561
562     if (peer != NULL && msg != NULL)
563     {
564         tr_torrent* tor = NULL;
565
566         char const* params = lpd_extractHeader(msg, &ver);
567
568         if (params == NULL || ver.major != 1) /* allow messages of protocol v1 */
569         {
570             return 0;
571         }
572
573         /* save the effort to check Host, which seems to be optional anyway */
574
575         if (!lpd_extractParam(params, "Port", maxValueLen, value))
576         {
577             return 0;
578         }
579
580         /* determine announced peer port, refuse if value too large */
581         if (sscanf(value, "%d", &peerPort) != 1 || peerPort > (in_port_t)-1)
582         {
583             return 0;
584         }
585
586         peer->port = htons(peerPort);
587         res = -1; /* signal caller side-effect to peer->port via return != 0 */
588
589         if (!lpd_extractParam(params, "Infohash", maxHashLen, hashString))
590         {
591             return res;
592         }
593
594         tor = tr_torrentFindFromHashString(session, hashString);
595
596         if (tr_isTorrent(tor) && tr_torrentAllowsLPD(tor))
597         {
598             /* we found a suitable peer, add it to the torrent */
599             tr_peerMgrAddPex(tor, TR_PEER_FROM_LPD, peer, -1);
600             tr_logAddTorDbg(tor, "Learned %d local peer from LPD (%s:%u)", 1, tr_address_to_string(&peer->addr), peerPort);
601
602             /* periodic reconnectPulse() deals with the rest... */
603
604             return 1;
605         }
606         else
607         {
608             tr_logAddNamedDbg("LPD", "Cannot serve torrent #%s", hashString);
609         }
610     }
611
612     return res;
613 }
614
615 /**
616 * @} */
617
618 /**
619 * @note Since it possible for tr_lpdAnnounceMore to get called from outside the LPD module,
620 * the function needs to be informed of the externally employed housekeeping interval.
621 * Further, by setting interval to zero (or negative) the caller may actually disable LPD
622 * announces on a per-interval basis.
623 *
624 * FIXME: since this function's been made private and is called by a periodic timer,
625 * most of the previous paragraph isn't true anymore... we weren't using that functionality
626 * before. are there cases where we should? if not, should we remove the bells & whistles?
627 */
628 static int tr_lpdAnnounceMore(time_t const now, int const interval)
629 {
630     tr_torrent* tor = NULL;
631     int announcesSent = 0;
632
633     if (!tr_isSession(session))
634     {
635         return -1;
636     }
637
638     while ((tor = tr_torrentNext(session, tor)) != NULL && tr_sessionAllowsLPD(session))
639     {
640         if (tr_isTorrent(tor))
641         {
642             int announcePrio = 0;
643
644             if (!tr_torrentAllowsLPD(tor))
645             {
646                 continue;
647             }
648
649             /* issue #3208: prioritize downloads before seeds */
650             switch (tr_torrentGetActivity(tor))
651             {
652             case TR_STATUS_DOWNLOAD:
653                 announcePrio = 1;
654                 break;
655
656             case TR_STATUS_SEED:
657                 announcePrio = 2;
658                 break;
659
660             default: /* fall through */
661                 break;
662             }
663
664             if (announcePrio > 0 && tor->lpdAnnounceAt <= now)
665             {
666                 if (tr_lpdSendAnnounce(tor))
667                 {
668                     announcesSent++;
669                 }
670
671                 tor->lpdAnnounceAt = now + lpd_announceInterval * announcePrio;
672
673                 break; /* that's enough; for this interval */
674             }
675         }
676     }
677
678     /* perform housekeeping for the flood protection mechanism */
679     {
680         int const maxAnnounceCap = interval * lpd_announceCapFactor;
681
682         if (lpd_unsolicitedMsgCounter < 0)
683         {
684             tr_logAddNamedInfo("LPD", "Dropped %d announces in the last interval (max. %d allowed)", -lpd_unsolicitedMsgCounter,
685                 maxAnnounceCap);
686         }
687
688         lpd_unsolicitedMsgCounter = maxAnnounceCap;
689     }
690
691     return announcesSent;
692 }
693
694 static void on_upkeep_timer(evutil_socket_t foo UNUSED, short bar UNUSED, void* vsession UNUSED)
695 {
696     time_t const now = tr_time();
697     tr_lpdAnnounceMore(now, UPKEEP_INTERVAL_SECS);
698     tr_timerAdd(upkeep_timer, UPKEEP_INTERVAL_SECS, 0);
699 }
700
701 /**
702 * @brief Processing of timeout notifications and incoming data on the socket
703 * @note maximum rate of read events is limited according to @a lpd_maxAnnounceCap
704 * @see DoS */
705 static void event_callback(evutil_socket_t s UNUSED, short type, void* ignore UNUSED)
706 {
707     TR_ASSERT(tr_isSession(session));
708
709     /* do not allow announces to be processed if LPD is disabled */
710     if (!tr_sessionAllowsLPD(session))
711     {
712         return;
713     }
714
715     if ((type & EV_READ) != 0)
716     {
717         struct sockaddr_in foreignAddr;
718         int addrLen = sizeof(foreignAddr);
719         char foreignMsg[lpd_maxDatagramLength + 1];
720
721         /* process local announcement from foreign peer */
722         int res = recvfrom(lpd_socket, (void*)foreignMsg, lpd_maxDatagramLength, 0, (struct sockaddr*)&foreignAddr,
723             (socklen_t*)&addrLen);
724
725         /* besides, do we get flooded? then bail out! */
726         if (--lpd_unsolicitedMsgCounter < 0)
727         {
728             return;
729         }
730
731         if (res > 0 && res <= lpd_maxDatagramLength)
732         {
733             struct tr_pex foreignPeer =
734             {
735                 .port = 0, /* the peer-to-peer port is yet unknown */
736                 .flags = 0
737             };
738
739             /* be paranoid enough about zero terminating the foreign string */
740             foreignMsg[res] = '\0';
741
742             foreignPeer.addr.addr.addr4 = foreignAddr.sin_addr;
743
744             if (tr_lpdConsiderAnnounce(&foreignPeer, foreignMsg) != 0)
745             {
746                 return; /* OK so far, no log message */
747             }
748         }
749
750         tr_logAddNamedDbg("LPD", "Discarded invalid multicast message");
751     }
752 }