2 Copyright (c) 2010 by Johannes Lieder
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:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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
26 #include <string.h> /* strlen(), strncpy(), strstr(), memset() */
29 #include <signal.h> /* sig_atomic_t */
30 #include <ctype.h> /* toupper() */
35 typedef uint16_t in_port_t; /* all missing */
38 #include <unistd.h> /* close() */
39 #include <sys/types.h>
40 #include <sys/socket.h> /* socket(), bind() */
41 #include <netinet/in.h> /* sockaddr_in */
45 #include <event2/event.h>
46 #include <event2/util.h>
49 #include "transmission.h"
52 #include "peer-mgr.h" /* tr_peerMgrAddPex() */
54 #include "torrent.h" /* tr_torrentFindFromHash() */
55 #include "tr-assert.h"
61 * @brief Local Peer Discovery
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.
69 static void event_callback(evutil_socket_t, short, void*);
73 UPKEEP_INTERVAL_SECS = 5
76 static struct event* upkeep_timer = NULL;
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;
83 static tr_torrent* lpd_torStaticType UNUSED; /* just a helper for static type analysis */
84 static tr_session* session;
88 lpd_maxDatagramLength = 200 /**<the size an LPD datagram must not exceed */
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 */
96 * @brief Protocol-related information carried by a Local Peer Discovery packet */
97 struct lpd_protocolVersion
103 enum lpd_enumTimeToLive
105 lpd_ttlSameSubnet = 1,
106 lpd_ttlSameSite = 32,
107 lpd_ttlSameRegion = 64,
108 lpd_ttlSameContinent = 128,
109 lpd_ttlUnrestricted = 255
114 lpd_announceInterval = 4 * 60, /**<4 min announce interval per torrent */
115 lpd_announceScope = lpd_ttlSameSubnet /**<the maximum scope for LPD datagrams */
119 * @defgroup DoS Message Flood Protection
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
134 * @brief allow at most ten messages per second (interval average)
135 * @note this constraint is only enforced once per housekeeping interval */
138 lpd_announceCapFactor = 10
143 * @brief number of unsolicited messages during the last HK interval
144 * @remark counts downwards */
145 static int lpd_unsolicitedMsgCounter;
149 * @brief a line-feed, as understood by the LPD protocol */
153 * @defgroup HttpReqProc HTTP-style request handling
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.
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.
172 static char const* lpd_extractHeader(char const* s, struct lpd_protocolVersion* const ver)
174 TR_ASSERT(s != NULL);
178 size_t len = strlen(s);
180 /* something might be rotten with this chunk of data */
181 if (len == 0 || len > lpd_maxDatagramLength)
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)
192 if (major < 0 || minor < 0)
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);
202 if (end == NULL || strlen(end) > strlen(two_blank))
214 /* separate the header, begins with CRLF */
215 return strstr(s, CRLF);
219 * @brief Return the value of a named parameter
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
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"
232 static bool lpd_extractParam(char const* const str, char const* const name, int n, char* const val)
234 TR_ASSERT(str != NULL);
235 TR_ASSERT(name != NULL);
236 TR_ASSERT(val != NULL);
240 /* configure maximum length of search string here */
244 char sstr[maxLength] = { 0 };
247 if (strlen(name) > maxLength - strlen(CRLF ": "))
252 /* compose the string token to search for */
253 tr_snprintf(sstr, maxLength, CRLF "%s: ", name);
255 pos = strstr(str, sstr);
259 return false; /* search was not successful */
263 char const* const beg = pos + strlen(sstr);
264 char const* const new_line = strstr(beg, CRLF);
266 /* the value is delimited by the next CRLF */
267 int len = new_line - beg;
269 /* if value string hits the length limit n,
270 * leave space for a trailing '\0' character */
276 strncpy(val, beg, n);
280 /* we successfully returned the value string */
287 static void on_upkeep_timer(evutil_socket_t, short, void*);
290 * @brief Initializes Local Peer Discovery for this node
292 * For the most part, this means setting up an appropriately configured multicast socket
293 * and event-based message handling.
295 * @remark Since the LPD service does not use another protocol family yet, this code is
296 * IPv4 only for the time being.
298 int tr_lpdInit(tr_session* ss, tr_address* tr_addr UNUSED)
300 struct ip_mreq mcastReq;
301 int const opt_on = 1;
302 int const opt_off = 0;
304 if (session != NULL) /* already initialized */
309 TR_ASSERT(lpd_announceInterval > 0);
310 TR_ASSERT(lpd_announceScope > 0);
312 lpd_port = tr_sessionGetPeerPort(ss);
319 tr_logAddNamedDbg("LPD", "Initialising Local Peer Discovery");
321 /* setup datagram socket (receive) */
323 lpd_socket = socket(PF_INET, SOCK_DGRAM, 0);
325 if (lpd_socket == TR_BAD_SOCKET)
330 if (evutil_make_socket_nonblocking(lpd_socket) == -1)
335 if (setsockopt(lpd_socket, SOL_SOCKET, SO_REUSEADDR, (void const*)&opt_on, sizeof(opt_on)) == -1)
340 memset(&lpd_mcastAddr, 0, sizeof(lpd_mcastAddr));
341 lpd_mcastAddr.sin_family = AF_INET;
342 lpd_mcastAddr.sin_port = htons(lpd_mcastPort);
344 if (evutil_inet_pton(lpd_mcastAddr.sin_family, lpd_mcastGroup, &lpd_mcastAddr.sin_addr) == -1)
349 if (bind(lpd_socket, (struct sockaddr*)&lpd_mcastAddr, sizeof(lpd_mcastAddr)) == -1)
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);
359 if (setsockopt(lpd_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void const*)&mcastReq, sizeof(mcastReq)) == -1)
364 if (setsockopt(lpd_socket, IPPROTO_IP, IP_MULTICAST_LOOP, (void const*)&opt_off, sizeof(opt_off)) == -1)
370 /* setup datagram socket (send) */
372 unsigned char const scope = lpd_announceScope;
374 lpd_socket2 = socket(PF_INET, SOCK_DGRAM, 0);
376 if (lpd_socket2 == TR_BAD_SOCKET)
381 if (evutil_make_socket_nonblocking(lpd_socket2) == -1)
386 /* configure outbound multicast TTL */
387 if (setsockopt(lpd_socket2, IPPROTO_IP, IP_MULTICAST_TTL, (void const*)&scope, sizeof(scope)) == -1)
392 if (setsockopt(lpd_socket2, IPPROTO_IP, IP_MULTICAST_LOOP, (void const*)&opt_off, sizeof(opt_off)) == -1)
400 /* Note: lpd_unsolicitedMsgCounter remains 0 until the first timeout event, thus
401 * any announcement received during the initial interval will be discarded. */
403 lpd_event = event_new(ss->event_base, lpd_socket, EV_READ | EV_PERSIST, event_callback, NULL);
404 event_add(lpd_event, NULL);
406 upkeep_timer = evtimer_new(ss->event_base, on_upkeep_timer, ss);
407 tr_timerAdd(upkeep_timer, UPKEEP_INTERVAL_SECS, 0);
409 tr_logAddNamedDbg("LPD", "Local Peer Discovery initialised");
415 int const save = errno;
416 evutil_closesocket(lpd_socket);
417 evutil_closesocket(lpd_socket2);
418 lpd_socket = lpd_socket2 = TR_BAD_SOCKET;
420 tr_logAddNamedDbg("LPD", "LPD initialisation failed (errno = %d)", save);
427 void tr_lpdUninit(tr_session* ss)
434 tr_logAddNamedDbg("LPD", "Uninitialising Local Peer Discovery");
436 event_free(lpd_event);
439 evtimer_del(upkeep_timer);
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");
450 bool tr_lpdEnabled(tr_session const* ss)
452 return ss != NULL && ss == session;
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.
461 UNUSED static inline void lpd_consistencyCheck(void)
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), "");
473 * @defgroup LdsProto LPD announcement processing
478 * @brief Announce the given torrent on the local network
480 * @param[in] t Torrent to announce
481 * @return Returns true on success
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.
487 bool tr_lpdSendAnnounce(tr_torrent const* t)
490 "BT-SEARCH * HTTP/%u.%u" CRLF
497 char hashString[lengthof(t->info.hashString)];
498 char query[lpd_maxDatagramLength + 1] = { 0 };
505 /* make sure the hash string is normalized, just in case */
506 for (size_t i = 0; i < TR_N_ELEMENTS(hashString); ++i)
508 hashString[i] = toupper(t->info.hashString[i]);
511 /* prepare a zero-terminated announce message */
512 tr_snprintf(query, lpd_maxDatagramLength + 1, fmt, 1, 1, lpd_mcastGroup, lpd_mcastPort, lpd_port, hashString);
514 /* actually send the query out using [lpd_socket2] */
516 int const len = strlen(query);
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));
529 tr_logAddTorDbg(t, "LPD announce message away");
535 * @brief Process incoming unsolicited messages and add the peer to the announced
536 * torrent if all checks are passed.
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.
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.
548 static int tr_lpdConsiderAnnounce(tr_pex* peer, char const* const msg)
553 maxHashLen = lengthof(lpd_torStaticType->info.hashString)
556 struct lpd_protocolVersion ver = { .major = -1, .minor = -1 };
557 char value[maxValueLen] = { 0 };
558 char hashString[maxHashLen] = { 0 };
562 if (peer != NULL && msg != NULL)
564 tr_torrent* tor = NULL;
566 char const* params = lpd_extractHeader(msg, &ver);
568 if (params == NULL || ver.major != 1) /* allow messages of protocol v1 */
573 /* save the effort to check Host, which seems to be optional anyway */
575 if (!lpd_extractParam(params, "Port", maxValueLen, value))
580 /* determine announced peer port, refuse if value too large */
581 if (sscanf(value, "%d", &peerPort) != 1 || peerPort > (in_port_t)-1)
586 peer->port = htons(peerPort);
587 res = -1; /* signal caller side-effect to peer->port via return != 0 */
589 if (!lpd_extractParam(params, "Infohash", maxHashLen, hashString))
594 tor = tr_torrentFindFromHashString(session, hashString);
596 if (tr_isTorrent(tor) && tr_torrentAllowsLPD(tor))
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);
602 /* periodic reconnectPulse() deals with the rest... */
608 tr_logAddNamedDbg("LPD", "Cannot serve torrent #%s", hashString);
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.
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?
628 static int tr_lpdAnnounceMore(time_t const now, int const interval)
630 tr_torrent* tor = NULL;
631 int announcesSent = 0;
633 if (!tr_isSession(session))
638 while ((tor = tr_torrentNext(session, tor)) != NULL && tr_sessionAllowsLPD(session))
640 if (tr_isTorrent(tor))
642 int announcePrio = 0;
644 if (!tr_torrentAllowsLPD(tor))
649 /* issue #3208: prioritize downloads before seeds */
650 switch (tr_torrentGetActivity(tor))
652 case TR_STATUS_DOWNLOAD:
660 default: /* fall through */
664 if (announcePrio > 0 && tor->lpdAnnounceAt <= now)
666 if (tr_lpdSendAnnounce(tor))
671 tor->lpdAnnounceAt = now + lpd_announceInterval * announcePrio;
673 break; /* that's enough; for this interval */
678 /* perform housekeeping for the flood protection mechanism */
680 int const maxAnnounceCap = interval * lpd_announceCapFactor;
682 if (lpd_unsolicitedMsgCounter < 0)
684 tr_logAddNamedInfo("LPD", "Dropped %d announces in the last interval (max. %d allowed)", -lpd_unsolicitedMsgCounter,
688 lpd_unsolicitedMsgCounter = maxAnnounceCap;
691 return announcesSent;
694 static void on_upkeep_timer(evutil_socket_t foo UNUSED, short bar UNUSED, void* vsession UNUSED)
696 time_t const now = tr_time();
697 tr_lpdAnnounceMore(now, UPKEEP_INTERVAL_SECS);
698 tr_timerAdd(upkeep_timer, UPKEEP_INTERVAL_SECS, 0);
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
705 static void event_callback(evutil_socket_t s UNUSED, short type, void* ignore UNUSED)
707 TR_ASSERT(tr_isSession(session));
709 /* do not allow announces to be processed if LPD is disabled */
710 if (!tr_sessionAllowsLPD(session))
715 if ((type & EV_READ) != 0)
717 struct sockaddr_in foreignAddr;
718 int addrLen = sizeof(foreignAddr);
719 char foreignMsg[lpd_maxDatagramLength + 1];
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);
725 /* besides, do we get flooded? then bail out! */
726 if (--lpd_unsolicitedMsgCounter < 0)
731 if (res > 0 && res <= lpd_maxDatagramLength)
733 struct tr_pex foreignPeer =
735 .port = 0, /* the peer-to-peer port is yet unknown */
739 /* be paranoid enough about zero terminating the foreign string */
740 foreignMsg[res] = '\0';
742 foreignPeer.addr.addr.addr4 = foreignAddr.sin_addr;
744 if (tr_lpdConsiderAnnounce(&foreignPeer, foreignMsg) != 0)
746 return; /* OK so far, no log message */
750 tr_logAddNamedDbg("LPD", "Discarded invalid multicast message");