formatting fixes in client test, and made the test build when resolve countries is...
[libtorrent-kjk.git] / src / identify_client.cpp
blobcf837a05b377530e7f93b590b2ef29d4245088bb
1 /*
3 Copyright (c) 2003, Arvid Norberg
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
33 #include "libtorrent/pch.hpp"
35 #include <cctype>
36 #include <algorithm>
38 #ifdef _MSC_VER
39 #pragma warning(push, 1)
40 #endif
42 #include <boost/optional.hpp>
44 #ifdef _MSC_VER
45 #pragma warning(pop)
46 #endif
48 #include "libtorrent/identify_client.hpp"
49 #include "libtorrent/fingerprint.hpp"
51 namespace
54 using namespace libtorrent;
56 int decode_digit(char c)
58 if (std::isdigit(c)) return c - '0';
59 return unsigned(c) - 'A' + 10;
62 // takes a peer id and returns a valid boost::optional
63 // object if the peer id matched the azureus style encoding
64 // the returned fingerprint contains information about the
65 // client's id
66 boost::optional<fingerprint> parse_az_style(const peer_id& id)
68 fingerprint ret("..", 0, 0, 0, 0);
70 if (id[0] != '-' || !std::isprint(id[1]) || (id[2] < '0')
71 || (id[3] < '0') || (id[4] < '0')
72 || (id[5] < '0') || (id[6] < '0')
73 || id[7] != '-')
74 return boost::optional<fingerprint>();
76 ret.name[0] = id[1];
77 ret.name[1] = id[2];
78 ret.major_version = decode_digit(id[3]);
79 ret.minor_version = decode_digit(id[4]);
80 ret.revision_version = decode_digit(id[5]);
81 ret.tag_version = decode_digit(id[6]);
83 return boost::optional<fingerprint>(ret);
86 // checks if a peer id can possibly contain a shadow-style
87 // identification
88 boost::optional<fingerprint> parse_shadow_style(const peer_id& id)
90 fingerprint ret("..", 0, 0, 0, 0);
92 if (!std::isalnum(id[0]))
93 return boost::optional<fingerprint>();
95 if (std::equal(id.begin()+4, id.begin()+6, "--"))
97 if ((id[1] < '0') || (id[2] < '0')
98 || (id[3] < '0'))
99 return boost::optional<fingerprint>();
100 ret.major_version = decode_digit(id[1]);
101 ret.minor_version = decode_digit(id[2]);
102 ret.revision_version = decode_digit(id[3]);
104 else
106 if (id[8] != 0 || id[1] > 127 || id[2] > 127 || id[3] > 127)
107 return boost::optional<fingerprint>();
108 ret.major_version = id[1];
109 ret.minor_version = id[2];
110 ret.revision_version = id[3];
113 ret.name[0] = id[0];
114 ret.name[1] = 0;
116 ret.tag_version = 0;
117 return boost::optional<fingerprint>(ret);
120 // checks if a peer id can possibly contain a mainline-style
121 // identification
122 boost::optional<fingerprint> parse_mainline_style(const peer_id& id)
124 char ids[21];
125 std::copy(id.begin(), id.end(), ids);
126 ids[20] = 0;
127 fingerprint ret("..", 0, 0, 0, 0);
128 ret.name[1] = 0;
129 ret.tag_version = 0;
130 if (sscanf(ids, "%c%d-%d-%d--", &ret.name[0], &ret.major_version, &ret.minor_version
131 , &ret.revision_version) != 4
132 || !std::isprint(ret.name[0]))
133 return boost::optional<fingerprint>();
135 return boost::optional<fingerprint>(ret);
138 struct map_entry
140 char const* id;
141 char const* name;
144 // only support BitTorrentSpecification
145 // must be ordered alphabetically
146 map_entry name_map[] =
148 {"A", "ABC"}
149 , {"AG", "Ares"}
150 , {"AR", "Arctic Torrent"}
151 , {"AV", "Avicora"}
152 , {"AX", "BitPump"}
153 , {"AZ", "Azureus"}
154 , {"A~", "Ares"}
155 , {"BB", "BitBuddy"}
156 , {"BC", "BitComet"}
157 , {"BF", "Bitflu"}
158 , {"BG", "BTG"}
159 , {"BR", "BitRocket"}
160 , {"BS", "BTSlave"}
161 , {"BX", "BittorrentX"}
162 , {"CD", "Enhanced CTorrent"}
163 , {"CT", "CTorrent"}
164 , {"DE", "Deluge Torrent"}
165 , {"EB", "EBit"}
166 , {"ES", "electric sheep"}
167 , {"HL", "Halite"}
168 , {"HN", "Hydranode"}
169 , {"KT", "KTorrent"}
170 , {"LK", "Linkage"}
171 , {"LP", "lphant"}
172 , {"LT", "libtorrent"}
173 , {"M", "Mainline"}
174 , {"ML", "MLDonkey"}
175 , {"MO", "Mono Torrent"}
176 , {"MP", "MooPolice"}
177 , {"MT", "Moonlight Torrent"}
178 , {"O", "Osprey Permaseed"}
179 , {"PD", "Pando"}
180 , {"Q", "BTQueue"}
181 , {"QT", "Qt 4"}
182 , {"R", "Tribler"}
183 , {"S", "Shadow"}
184 , {"SB", "Swiftbit"}
185 , {"SN", "ShareNet"}
186 , {"SS", "SwarmScope"}
187 , {"SZ", "Shareaza"}
188 , {"S~", "Shareaza (beta)"}
189 , {"T", "BitTornado"}
190 , {"TN", "Torrent.NET"}
191 , {"TR", "Transmission"}
192 , {"TS", "TorrentStorm"}
193 , {"TT", "TuoTu"}
194 , {"U", "UPnP"}
195 , {"UL", "uLeecher"}
196 , {"UT", "MicroTorrent"}
197 , {"XT", "XanTorrent"}
198 , {"XX", "Xtorrent"}
199 , {"ZT", "ZipTorrent"}
200 , {"lt", "libTorrent (libtorrent.rakshasa.no/}"}
201 , {"pX", "pHoeniX"}
202 , {"qB", "qBittorrent"}
205 bool compare_id(map_entry const& lhs, map_entry const& rhs)
207 return lhs.id[0] < rhs.id[0]
208 || ((lhs.id[0] == rhs.id[0]) && (lhs.id[1] < rhs.id[1]));
211 std::string lookup(fingerprint const& f)
213 std::stringstream identity;
215 const int size = sizeof(name_map)/sizeof(name_map[0]);
216 map_entry tmp = {f.name, ""};
217 map_entry* i =
218 std::lower_bound(name_map, name_map + size
219 , tmp, &compare_id);
221 #ifndef NDEBUG
222 for (int i = 1; i < size; ++i)
224 assert(compare_id(name_map[i-1]
225 , name_map[i]));
227 #endif
229 if (i < name_map + size && std::equal(f.name, f.name + 2, i->id))
230 identity << i->name;
231 else
233 identity << f.name[0];
234 if (f.name[1] != 0) identity << f.name[1];
237 identity << " " << (int)f.major_version
238 << "." << (int)f.minor_version
239 << "." << (int)f.revision_version;
241 if (f.name[1] != 0)
242 identity << "." << (int)f.tag_version;
244 return identity.str();
247 bool find_string(unsigned char const* id, char const* search)
249 return std::equal(search, search + std::strlen(search), id);
253 namespace libtorrent
256 boost::optional<fingerprint> client_fingerprint(peer_id const& p)
258 // look for azureus style id
259 boost::optional<fingerprint> f;
260 f = parse_az_style(p);
261 if (f) return f;
263 // look for shadow style id
264 f = parse_shadow_style(p);
265 if (f) return f;
267 // look for mainline style id
268 f = parse_mainline_style(p);
269 if (f) return f;
270 return f;
273 std::string identify_client(peer_id const& p)
275 peer_id::const_iterator PID = p.begin();
276 boost::optional<fingerprint> f;
278 if (p.is_all_zeros()) return "Unknown";
280 // ----------------------
281 // non standard encodings
282 // ----------------------
284 if (find_string(PID, "Deadman Walking-")) return "Deadman";
285 if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2";
286 if (find_string(PID, "DansClient")) return "XanTorrent";
287 if (find_string(PID + 4, "btfans")) return "SimpleBT";
288 if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II";
289 if (find_string(PID, "P87.P---")) return "Bittorrent Plus!";
290 if (find_string(PID, "S587Plus")) return "Bittorrent Plus!";
291 if (find_string(PID, "martini")) return "Martini Man";
292 if (find_string(PID, "Plus---")) return "Bittorrent Plus";
293 if (find_string(PID, "turbobt")) return "TurboBT";
294 if (find_string(PID, "a00---0")) return "Swarmy";
295 if (find_string(PID, "a02---0")) return "Swarmy";
296 if (find_string(PID, "T00---0")) return "Teeweety";
297 if (find_string(PID, "BTDWV-")) return "Deadman Walking";
298 if (find_string(PID + 2, "BS")) return "BitSpirit";
299 if (find_string(PID, "btuga")) return "BTugaXP";
300 if (find_string(PID, "oernu")) return "BTugaXP";
301 if (find_string(PID, "Mbrst")) return "Burst!";
302 if (find_string(PID, "Plus")) return "Plus!";
303 if (find_string(PID, "-Qt-")) return "Qt";
304 if (find_string(PID, "exbc")) return "BitComet";
305 if (find_string(PID, "-G3")) return "G3 Torrent";
306 if (find_string(PID, "XBT")) return "XBT";
307 if (find_string(PID, "OP")) return "Opera";
309 if (find_string(PID, "-BOW") && PID[7] == '-')
310 return "Bits on Wheels " + std::string(PID + 4, PID + 7);
313 if (find_string(PID, "eX"))
315 std::string user(PID + 2, PID + 14);
316 return std::string("eXeem ('") + user.c_str() + "')";
319 if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\x97"))
320 return "Experimental 3.2.1b2";
322 if (std::equal(PID, PID + 13, "\0\0\0\0\0\0\0\0\0\0\0\0\0"))
323 return "Experimental 3.1";
326 // look for azureus style id
327 f = parse_az_style(p);
328 if (f) return lookup(*f);
330 // look for shadow style id
331 f = parse_shadow_style(p);
332 if (f) return lookup(*f);
334 // look for mainline style id
335 f = parse_mainline_style(p);
336 if (f) return lookup(*f);
339 if (std::equal(PID, PID + 12, "\0\0\0\0\0\0\0\0\0\0\0\0"))
340 return "Generic";
342 std::string unknown("Unknown [");
343 for (peer_id::const_iterator i = p.begin(); i != p.end(); ++i)
345 unknown += std::isprint(*i)?*i:'.';
347 unknown += "]";
348 return unknown;