source: trunk/libtransmission/clients.c @ 6822

Last change on this file since 6822 was 6822, checked in by charles, 12 years ago

(libT) better handling of Shad0w-style peer ids that don't have trailing dashes, such as Osprey Permaseed

  • Property svn:keywords set to Date Rev Author Id
File size: 23.1 KB
Line 
1/*
2 * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: clients.c 6822 2008-10-01 18:11:28Z charles $
11 */
12
13/* thanks amc1! */
14
15#include <ctype.h> /* isprint, tolower */
16#include <stdio.h>
17#include <stdlib.h> /* strtol */
18#include <string.h>
19
20#include <libevent/event.h> /* evbuffer */
21
22#include "transmission.h"
23#include "clients.h"
24#include "utils.h"
25
26static int
27charint( char ch )
28{
29    if( '0' <= ch && ch <= '9' ) return ch - '0';
30    if( 'A' <= ch && ch <= 'Z' ) return 10 + ch - 'A';
31    if( 'a' <= ch && ch <= 'z' ) return 36 + ch - 'a';
32    return 0;
33}
34
35static int
36getShadowInt( char ch, int * setme )
37{
38    const char * str = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.-";
39    const char * pch = strchr( str, ch );
40    if( !pch )
41        return 0;
42    *setme = pch - str;
43    return 1;
44}
45
46static int
47strint( const void * pch,
48        int          span )
49{
50    char tmp[64];
51
52    memcpy( tmp, pch, span );
53    tmp[span] = '\0';
54    return strtol( tmp, NULL, 0 );
55}
56
57static const char*
58getMnemonicEnd( char ch )
59{
60    switch( ch )
61    {
62        case 'b':
63        case 'B':
64            return " (Beta)";
65
66        case 'd':
67            return " (Debug)";
68
69        case 'x':
70        case 'X':
71        case 'Z':
72            return " (Dev)";
73
74        default:
75            return "";
76    }
77}
78
79static void
80three_digits( char *          buf,
81              size_t          buflen,
82              const char *    name,
83              const uint8_t * digits )
84{
85    tr_snprintf( buf, buflen, "%s %d.%d.%d", name,
86                charint( digits[0] ),
87                charint( digits[1] ),
88                charint( digits[2] ) );
89}
90
91static void
92four_digits( char *          buf,
93             size_t          buflen,
94             const char *    name,
95             const uint8_t * digits )
96{
97    tr_snprintf( buf, buflen, "%s %d.%d.%d.%d", name,
98                charint( digits[0] ),
99                charint( digits[1] ),
100                charint( digits[2] ),
101                charint( digits[3] ) );
102}
103
104static void
105two_major_two_minor( char *          buf,
106                     size_t          buflen,
107                     const char *    name,
108                     const uint8_t * digits )
109{
110    tr_snprintf( buf, buflen, "%s %d.%02d", name,
111                strint( digits, 2 ),
112                strint( digits + 2, 2 ) );
113}
114
115static void
116no_version( char *       buf,
117            size_t       buflen,
118            const char * name )
119{
120    tr_strlcpy( buf, name, buflen );
121}
122
123static void
124mainline_style( char *          buf,
125                size_t          buflen,
126                const char *    name,
127                const uint8_t * id )
128{
129    if( id[4] == '-' && id[6] == '-' )
130        tr_snprintf( buf, buflen, "%s %c.%c.%c", name, id[1], id[3], id[5] );
131    else if( id[5] == '-' )
132        tr_snprintf( buf, buflen, "%s %c.%c%c.%c", name, id[1], id[3],
133                     id[4],
134                     id[6] );
135}
136
137static int
138isMainlineStyle( const uint8_t * peer_id )
139{
140    /**
141     * One of the following styles will be used:
142     *   Mx-y-z--
143     *   Mx-yy-z-
144     */
145    return peer_id[2] == '-'
146           && peer_id[7] == '-'
147           && ( peer_id[4] == '-' || peer_id[5] == '-' );
148}
149
150static int
151decodeBitCometClient( char *          buf,
152                      size_t          buflen,
153                      const uint8_t * id )
154{
155    int          is_bitlord;
156    int          major, minor;
157    const char * name;
158    const char * mod = NULL;
159
160    if( !memcmp( id, "exbc", 4 ) ) mod = "";
161    else if( !memcmp( id, "FUTB", 4 ) ) mod = "(Solidox Mod) ";
162    else if( !memcmp( id, "xUTB", 4 ) ) mod = "(Mod 2) ";
163    else return FALSE;
164
165    is_bitlord = !memcmp( id + 6, "LORD", 4 );
166    name = ( is_bitlord ) ? "BitLord " : "BitComet ";
167    major = id[4];
168    minor = id[5];
169
170    /**
171     * Bitcomet, and older versions of BitLord, are of the form x.yy.
172     * Bitcoment 1.0 and onwards are of the form x.y.
173     */
174    if( is_bitlord && major > 0 )
175        tr_snprintf( buf, buflen, "%s%s%d.%d", name, mod, major, minor );
176    else
177        tr_snprintf( buf, buflen, "%s%s%d.%02d", name, mod, major, minor );
178
179    return TRUE;
180}
181
182static int
183decodeBitSpiritClient( char *          buf,
184                       size_t          buflen,
185                       const uint8_t * id )
186{
187    const int isBS = !memcmp( id + 2, "BS", 2 );
188
189    if( isBS )
190    {
191        const int version = id[1] ? id[1] : 1;
192        tr_snprintf( buf, buflen, "BitSpirit v%d", version );
193    }
194    return isBS;
195}
196
197void
198tr_clientForId( char *       buf,
199                size_t       buflen,
200                const void * id_in )
201{
202    const uint8_t * id = id_in;
203
204    *buf = '\0';
205
206    if( !id )
207        return;
208
209    /* Azureus-style */
210    if( id[0] == '-' && id[7] == '-' )
211    {
212        if( !memcmp( id + 1, "UT", 2 ) )
213        {
214            tr_snprintf( buf, buflen, "\xc2\xb5Torrent %d.%d.%d%s",
215                        strint( id + 3,
216                                1 ),
217                        strint( id + 4, 1 ), strint( id + 5,
218                                                     1 ),
219                        getMnemonicEnd( id[6] ) );
220        }
221        else if( !memcmp( id + 1, "TR", 2 ) )
222        {
223            if( !memcmp( id + 3, "000", 3 ) ) /* very old client style: -TR0006-
224                                                is 0.6 */
225                tr_snprintf( buf, buflen, "Transmission 0.%c", id[6] );
226            else if( !memcmp( id + 3, "00", 2 ) ) /* previous client style:
227                                                    -TR0072- is 0.72 */
228                tr_snprintf( buf, buflen, "Transmission 0.%02d",
229                            strint( id + 5, 2 ) );
230            else /* current client style: -TR111Z- is 1.11+ */
231                tr_snprintf( buf, buflen, "Transmission %d.%02d%s",
232                             strint( id + 3, 1 ), strint( id + 4, 2 ),
233                             id[6] == 'Z' || id[6] == 'X' ? "+" : "" );
234        }
235        else if( !memcmp( id + 1, "AZ", 2 ) )
236        {
237            if( id[3] > '3' || ( id[3] == '3' && id[4] >= '1' ) ) /* Vuze starts
238                                                                    at version
239                                                                    3.1.0.0 */
240                four_digits( buf, buflen, "Vuze", id + 3 );
241            else
242                four_digits( buf, buflen, "Azureus", id + 3 );
243        }
244        else if( !memcmp( id + 1, "KT", 2 ) )
245        {
246            if( id[5] == 'D' )
247                tr_snprintf( buf, buflen, "KTorrent %d.%d Dev %d",
248                            charint( id[3] ), charint( id[4] ),
249                            charint( id[6] ) );
250            else if( id[5] == 'R' )
251                tr_snprintf( buf, buflen, "KTorrent %d.%d RC %d",
252                            charint( id[3] ), charint( id[4] ),
253                            charint( id[6] ) );
254            else
255                three_digits( buf, buflen, "KTorrent", id + 3 );
256        }
257        else if( !memcmp( id + 1, "AR", 2 ) ) four_digits( buf, buflen,
258                                                           "Ares",
259                                                           id + 3 );
260        else if( !memcmp( id + 1, "AT", 2 ) ) four_digits( buf, buflen,
261                                                           "Artemis",
262                                                           id + 3 );
263        else if( !memcmp( id + 1, "AV", 2 ) ) four_digits( buf, buflen,
264                                                           "Avicora",
265                                                           id + 3 );
266        else if( !memcmp( id + 1, "BG", 2 ) ) four_digits( buf, buflen,
267                                                           "BTGetit",
268                                                           id + 3 );
269        else if( !memcmp( id + 1, "BM", 2 ) ) four_digits( buf, buflen,
270                                                           "BitMagnet",
271                                                           id + 3 );
272        else if( !memcmp( id + 1, "BX", 2 ) ) four_digits( buf, buflen,
273                                                           "BittorrentX",
274                                                           id + 3 );
275        else if( !memcmp( id + 1, "bk", 2 ) ) four_digits(
276                buf, buflen, "BitKitten (libtorrent)", id + 3 );
277        else if( !memcmp( id + 1, "BS", 2 ) ) four_digits( buf, buflen,
278                                                           "BTSlave",
279                                                           id + 3 );
280        else if( !memcmp( id + 1, "BX", 2 ) ) four_digits( buf, buflen,
281                                                           "BittorrentX",
282                                                           id + 3 );
283        else if( !memcmp( id + 1, "EB", 2 ) ) four_digits( buf, buflen,
284                                                           "EBit",
285                                                           id + 3 );
286        else if( !memcmp( id + 1, "DE", 2 ) ) four_digits( buf, buflen,
287                                                           "Deluge",
288                                                           id + 3 );
289        else if( !memcmp( id + 1, "DP", 2 ) ) four_digits(
290                buf, buflen, "Propogate Data Client", id + 3 );
291        else if( !memcmp( id + 1, "FC", 2 ) ) four_digits( buf, buflen,
292                                                           "FileCroc",
293                                                           id + 3 );
294        else if( !memcmp( id + 1, "FT", 2 ) ) four_digits(
295                buf, buflen, "FoxTorrent/RedSwoosh", id + 3 );
296        else if( !memcmp( id + 1, "GR", 2 ) ) four_digits( buf, buflen,
297                                                           "GetRight",
298                                                           id + 3 );
299        else if( !memcmp( id + 1, "HN", 2 ) ) four_digits( buf, buflen,
300                                                           "Hydranode",
301                                                           id + 3 );
302        else if( !memcmp( id + 1, "LH", 2 ) ) four_digits( buf, buflen,
303                                                           "LH-ABC",
304                                                           id + 3 );
305        else if( !memcmp( id + 1, "NX", 2 ) ) four_digits( buf, buflen,
306                                                           "Net Transport",
307                                                           id + 3 );
308        else if( !memcmp( id + 1, "MO", 2 ) ) four_digits( buf, buflen,
309                                                           "MonoTorrent",
310                                                           id + 3 );
311        else if( !memcmp( id + 1, "MR", 2 ) ) four_digits( buf, buflen,
312                                                           "Miro",
313                                                           id + 3 );
314        else if( !memcmp( id + 1, "MT", 2 ) ) four_digits( buf, buflen,
315                                                           "Moonlight",
316                                                           id + 3 );
317        else if( !memcmp( id + 1, "PD", 2 ) ) four_digits( buf, buflen,
318                                                           "Pando",
319                                                           id + 3 );
320        else if( !memcmp( id + 1, "RS", 2 ) ) four_digits( buf, buflen,
321                                                           "Rufus",
322                                                           id + 3 );
323        else if( !memcmp( id + 1, "RT", 2 ) ) four_digits( buf, buflen,
324                                                           "Retriever",
325                                                           id + 3 );
326        else if( !memcmp( id + 1, "SS", 2 ) ) four_digits( buf, buflen,
327                                                           "SwarmScope",
328                                                           id + 3 );
329        else if( !memcmp( id + 1, "SZ", 2 ) ) four_digits( buf, buflen,
330                                                           "Shareaza",
331                                                           id + 3 );
332        else if( !memcmp( id + 1, "S~", 2 ) ) four_digits( buf, buflen,
333                                                           "Shareaza",
334                                                           id + 3 );
335        else if( !memcmp( id + 1, "st", 2 ) ) four_digits( buf, buflen,
336                                                           "SharkTorrent",
337                                                           id + 3 );
338        else if( !memcmp( id + 1, "TN", 2 ) ) four_digits( buf, buflen,
339                                                           "Torrent .NET",
340                                                           id + 3 );
341        else if( !memcmp( id + 1, "TS", 2 ) ) four_digits( buf, buflen,
342                                                           "TorrentStorm",
343                                                           id + 3 );
344        else if( !memcmp( id + 1, "UL", 2 ) ) four_digits( buf, buflen,
345                                                           "uLeecher!",
346                                                           id + 3 );
347        else if( !memcmp( id + 1, "VG", 2 ) ) four_digits( buf, buflen,
348                                                           "Vagaa",
349                                                           id + 3 );
350        else if( !memcmp( id + 1, "WT", 2 ) ) four_digits( buf, buflen,
351                                                           "BitLet",
352                                                           id + 3 );
353        else if( !memcmp( id + 1, "WY", 2 ) ) four_digits( buf, buflen,
354                                                           "Wyzo",
355                                                           id + 3 );
356        else if( !memcmp( id + 1, "XL", 2 ) ) four_digits( buf, buflen,
357                                                           "Xunlei",
358                                                           id + 3 );
359        else if( !memcmp( id + 1, "XT", 2 ) ) four_digits( buf, buflen,
360                                                           "XanTorrent",
361                                                           id + 3 );
362        else if( !memcmp( id + 1, "ZT", 2 ) ) four_digits( buf, buflen,
363                                                           "Zip Torrent",
364                                                           id + 3 );
365
366        else if( !memcmp( id + 1, "AG", 2 ) ) three_digits( buf, buflen,
367                                                            "Ares",
368                                                            id + 3 );
369        else if( !memcmp( id + 1, "A~", 2 ) ) three_digits( buf, buflen,
370                                                            "Ares",
371                                                            id + 3 );
372        else if( !memcmp( id + 1, "ES", 2 ) ) three_digits(
373                buf, buflen, "Electric Sheep", id + 3 );
374        else if( !memcmp( id + 1, "HL", 2 ) ) three_digits( buf, buflen,
375                                                            "Halite",
376                                                            id + 3 );
377        else if( !memcmp( id + 1, "LT", 2 ) ) three_digits(
378                buf, buflen, "libtorrent (Rasterbar)", id + 3 );
379        else if( !memcmp( id + 1, "lt", 2 ) ) three_digits(
380                buf, buflen, "libTorrent (Rakshasa)", id + 3 );
381        else if( !memcmp( id + 1, "MP", 2 ) ) three_digits( buf, buflen,
382                                                            "MooPolice",
383                                                            id + 3 );
384        else if( !memcmp( id + 1, "TT", 2 ) ) three_digits( buf, buflen,
385                                                            "TuoTu",
386                                                            id + 3 );
387        else if( !memcmp( id + 1, "qB", 2 ) ) three_digits( buf, buflen,
388                                                            "qBittorrent",
389                                                            id + 3 );
390
391        else if( !memcmp( id + 1, "AX", 2 ) ) two_major_two_minor(
392                buf, buflen, "BitPump", id + 3 );
393        else if( !memcmp( id + 1, "BC", 2 ) ) two_major_two_minor(
394                buf, buflen, "BitComet", id + 3 );
395        else if( !memcmp( id + 1, "CD", 2 ) ) two_major_two_minor(
396                buf, buflen, "Enhanced CTorrent", id + 3 );
397        else if( !memcmp( id + 1, "LP", 2 ) ) two_major_two_minor( buf,
398                                                                   buflen,
399                                                                   "Lphant",
400                                                                   id + 3 );
401
402        else if( !memcmp( id + 1, "BF", 2 ) ) no_version( buf, buflen,
403                                                          "BitFlu" );
404        else if( !memcmp( id + 1, "LW", 2 ) ) no_version( buf, buflen,
405                                                          "LimeWire" );
406
407        else if( !memcmp( id + 1, "BB", 2 ) )
408        {
409            tr_snprintf( buf, buflen, "BitBuddy %c.%c%c%c", id[3], id[4],
410                         id[5],
411                         id[6] );
412        }
413        else if( !memcmp( id + 1, "BR", 2 ) )
414        {
415            tr_snprintf( buf, buflen, "BitRocket %c.%c (%c%c)", id[3],
416                         id[4], id[5],
417                         id[6] );
418        }
419        else if( !memcmp( id + 1, "CT", 2 ) )
420        {
421            tr_snprintf( buf, buflen, "CTorrent %d.%d.%02d", charint(
422                            id[3] ), charint( id[4] ), strint( id + 5, 2 ) );
423        }
424        else if( !memcmp( id + 1, "XX", 2 ) )
425        {
426            tr_snprintf( buf, buflen, "Xtorrent %d.%d (%d)", charint(
427                            id[3] ), charint( id[4] ), strint( id + 5, 2 ) );
428        }
429        else if( !memcmp( id + 1, "BOW", 3 ) )
430        {
431            if( !memcmp( &id[4], "A0B", 3 ) ) tr_snprintf(
432                    buf, buflen, "Bits on Wheels 1.0.5" );
433            else if( !memcmp( &id[4], "A0C", 3 ) ) tr_snprintf(
434                    buf, buflen, "Bits on Wheels 1.0.6" );
435            else tr_snprintf( buf, buflen, "Bits on Wheels %c.%c.%c", id[4],
436                              id[5],
437                              id[5] );
438        }
439
440        if( *buf )
441            return;
442    }
443
444    /* Mainline */
445    if( isMainlineStyle( id ) )
446    {
447        if( *id == 'M' ) mainline_style( buf, buflen, "BitTorrent", id );
448        if( *id == 'Q' ) mainline_style( buf, buflen, "Queen Bee", id );
449        if( *buf ) return;
450    }
451
452    if( decodeBitCometClient( buf, buflen, id ) )
453        return;
454    if( decodeBitSpiritClient( buf, buflen, id ) )
455        return;
456
457    /* Clients with no version */
458    if( !memcmp( id, "AZ2500BT", 8 ) ) no_version(
459            buf, buflen, "BitTyrant (Azureus Mod)" );
460    else if( !memcmp( id, "LIME", 4 ) ) no_version( buf, buflen, "Limewire" );
461    else if( !memcmp( id, "martini", 7 ) ) no_version( buf, buflen,
462                                                       "Martini Man" );
463    else if( !memcmp( id, "Pando", 5 ) ) no_version( buf, buflen, "Pando" );
464    else if( !memcmp( id, "a00---0", 7 ) ) no_version( buf, buflen,
465                                                       "Swarmy" );
466    else if( !memcmp( id, "a02---0", 7 ) ) no_version( buf, buflen,
467                                                       "Swarmy" );
468    else if( !memcmp( id, "-G3", 3 ) ) no_version( buf, buflen,
469                                                   "G3 Torrent" );
470    else if( !memcmp( id, "10-------", 9 ) ) no_version( buf, buflen,
471                                                         "JVtorrent" );
472    else if( !memcmp( id, "346-", 4 ) ) no_version( buf, buflen,
473                                                    "TorrentTopia" );
474    else if( !memcmp( id, "eX", 2 ) ) no_version( buf, buflen, "eXeem" );
475    else if( !memcmp( id, "-FG", 3 ) ) two_major_two_minor( buf, buflen,
476                                                            "FlashGet",
477                                                            id + 3 );
478
479    /* Everything else */
480    else if( !memcmp( id, "S3",
481                      2 ) && id[2] == '-' && id[4] == '-' && id[6] == '-' )
482    {
483        tr_snprintf( buf, buflen, "Amazon S3 %c.%c.%c", id[3], id[5], id[7] );
484    }
485    else if( !memcmp( id, "OP", 2 ) )
486    {
487        tr_snprintf( buf, buflen, "Opera (Build %c%c%c%c)", id[2], id[3],
488                     id[4],
489                     id[5] );
490    }
491    else if( !memcmp( id, "-ML", 3 ) )
492    {
493        tr_snprintf( buf, buflen, "MLDonkey %c%c%c%c%c", id[3], id[4],
494                     id[5], id[6],
495                     id[7] );
496    }
497    else if( !memcmp( id, "DNA", 3 ) )
498    {
499        tr_snprintf( buf, buflen, "BitTorrent DNA %d.%d.%d",
500                    strint( id + 3, 2 ),
501                    strint( id + 5, 2 ),
502                    strint( id + 7, 2 ) );
503    }
504    else if( !memcmp( id, "Plus", 4 ) )
505    {
506        tr_snprintf( buf, buflen, "Plus! v2 %c.%c%c", id[4], id[5], id[6] );
507    }
508    else if( !memcmp( id, "XBT", 3 ) )
509    {
510        tr_snprintf( buf, buflen, "XBT Client %c.%c.%c%s", id[3], id[4],
511                    id[5], getMnemonicEnd(
512                        id[6] ) );
513    }
514    else if( !memcmp( id, "Mbrst", 5 ) )
515    {
516        tr_snprintf( buf, buflen, "burst! %c.%c.%c", id[5], id[7], id[9] );
517    }
518    else if( !memcmp( id, "btpd", 4 ) )
519    {
520        tr_snprintf( buf, buflen, "BT Protocol Daemon %c%c%c", id[5], id[6],
521                     id[7] );
522    }
523    else if( !memcmp( id, "BLZ", 3 ) )
524    {
525        tr_snprintf( buf, buflen, "Blizzard Downloader %d.%d", id[3] + 1,
526                     id[4] );
527    }
528    else if( '\0' == id[0] && !memcmp( &id[1], "BS", 2 ) )
529    {
530        tr_snprintf( buf, buflen, "BitSpirit %u", ( id[1] == 0 ? 1 : id[1] ) );
531    }
532
533    /* Shad0w-style */
534    {
535        int a, b, c;
536        if( strchr( "AOQRSTU", id[0] )
537            && getShadowInt( id[1], &a )
538            && getShadowInt( id[2], &b )
539            && getShadowInt( id[3], &c ) )
540        {
541            const char * name = NULL;
542
543            switch( id[0] )
544            {
545                case 'A': name = "ABC"; break;
546                case 'O': name = "Osprey"; break;
547                case 'Q': name = "BTQueue"; break;
548                case 'R': name = "Tribler"; break;
549                case 'S': name = "Shad0w"; break;
550                case 'T': name = "BitTornado"; break;
551                case 'U': name = "UPnP NAT Bit Torrent"; break;
552            }
553
554            if( name )
555            {
556                tr_snprintf( buf, buflen, "%s %d.%d.%d", name, a, b, c );
557                return;
558            }
559        }
560    }
561
562    /* No match */
563    if( !*buf )
564    {
565        struct evbuffer * out = evbuffer_new( );
566        const char *      in, *in_end;
567        for( in = (const char*)id, in_end = in + 8; in != in_end; ++in )
568        {
569            if( isprint( *in ) )
570                evbuffer_add_printf( out, "%c", *in );
571            else
572                evbuffer_add_printf( out, "%%%02X", (unsigned int)*in );
573        }
574
575        tr_strlcpy( buf, EVBUFFER_DATA( out ), buflen );
576        evbuffer_free( out );
577    }
578}
Note: See TracBrowser for help on using the repository browser.