olifre

Untitled

Jul 20th, 2014
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.16 KB | None | 0 0
  1. Description: Enable support for IPv6. Closes: #490277.
  2. Author: Steinar H. Gunderson <[email protected]>
  3. Reviewed-By: Rogério Theodoro de Brito <[email protected]>
  4. Bug-Debian: http://bugs.debian.org/490277
  5. Origin: http://home.samfundet.no/~sesse/rtorrent-0.8.6-ipv6.patch
  6. Last-Update: 2011-03-20
  7.  
  8. --- a/rak/socket_address.h
  9. +++ b/rak/socket_address.h
  10. @@ -145,7 +145,7 @@
  11. };
  12. };
  13.  
  14. -// Remeber to set the AF_INET.
  15. +// Remember to set the AF_INET.
  16.  
  17. class socket_address_inet {
  18. public:
  19. @@ -184,6 +184,10 @@
  20.  
  21. const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
  22. const sockaddr_in* c_sockaddr_inet() const { return &m_sockaddr; }
  23. +
  24. +#ifdef RAK_USE_INET6
  25. + socket_address_inet6 to_mapped_address() const;
  26. +#endif
  27.  
  28. bool operator == (const socket_address_inet& rhs) const;
  29. bool operator < (const socket_address_inet& rhs) const;
  30. @@ -192,6 +196,52 @@
  31. struct sockaddr_in m_sockaddr;
  32. };
  33.  
  34. +#ifdef RAK_USE_INET6
  35. +// Remember to set the AF_INET6.
  36. +
  37. +class socket_address_inet6 {
  38. +public:
  39. + bool is_any() const { return is_port_any() && is_address_any(); }
  40. + bool is_valid() const { return !is_port_any() && !is_address_any(); }
  41. + bool is_port_any() const { return port() == 0; }
  42. + bool is_address_any() const { return std::memcmp(&m_sockaddr.sin6_addr, &in6addr_any, sizeof(in6_addr)) == 0; }
  43. +
  44. + void clear() { std::memset(this, 0, sizeof(socket_address_inet6)); set_family(); }
  45. +
  46. + uint16_t port() const { return ntohs(m_sockaddr.sin6_port); }
  47. + uint16_t port_n() const { return m_sockaddr.sin6_port; }
  48. + void set_port(uint16_t p) { m_sockaddr.sin6_port = htons(p); }
  49. + void set_port_n(uint16_t p) { m_sockaddr.sin6_port = p; }
  50. +
  51. + in6_addr address() const { return m_sockaddr.sin6_addr; }
  52. + std::string address_str() const;
  53. + bool address_c_str(char* buf, socklen_t size) const;
  54. +
  55. + void set_address(in6_addr a) { m_sockaddr.sin6_addr = a; }
  56. + bool set_address_str(const std::string& a) { return set_address_c_str(a.c_str()); }
  57. + bool set_address_c_str(const char* a);
  58. +
  59. + void set_address_any() { set_port(0); set_address(in6addr_any); }
  60. +
  61. + sa_family_t family() const { return m_sockaddr.sin6_family; }
  62. + void set_family() { m_sockaddr.sin6_family = AF_INET6; }
  63. +
  64. + sockaddr* c_sockaddr() { return reinterpret_cast<sockaddr*>(&m_sockaddr); }
  65. + sockaddr_in6* c_sockaddr_inet6() { return &m_sockaddr; }
  66. +
  67. + const sockaddr* c_sockaddr() const { return reinterpret_cast<const sockaddr*>(&m_sockaddr); }
  68. + const sockaddr_in6* c_sockaddr_inet6() const { return &m_sockaddr; }
  69. +
  70. + socket_address normalize_address() const;
  71. +
  72. + bool operator == (const socket_address_inet6& rhs) const;
  73. + bool operator < (const socket_address_inet6& rhs) const;
  74. +
  75. +private:
  76. + struct sockaddr_in6 m_sockaddr;
  77. +};
  78. +#endif
  79. +
  80. // Unique key for the address, excluding port numbers etc.
  81. class socket_address_key {
  82. public:
  83. @@ -241,8 +291,10 @@
  84. switch (family()) {
  85. case af_inet:
  86. return sa_inet()->is_valid();
  87. -// case af_inet6:
  88. -// return sa_inet6().is_valid();
  89. +#ifdef RAK_USE_INET6
  90. + case af_inet6:
  91. + return sa_inet6()->is_valid();
  92. +#endif
  93. default:
  94. return false;
  95. }
  96. @@ -253,6 +305,10 @@
  97. switch (family()) {
  98. case af_inet:
  99. return !sa_inet()->is_address_any();
  100. +#ifdef RAK_USE_INET6
  101. + case af_inet6:
  102. + return !sa_inet6()->is_address_any();
  103. +#endif
  104. default:
  105. return false;
  106. }
  107. @@ -263,6 +319,10 @@
  108. switch (family()) {
  109. case af_inet:
  110. return sa_inet()->is_address_any();
  111. +#ifdef RAK_USE_INET6
  112. + case af_inet6:
  113. + return sa_inet6()->is_address_any();
  114. +#endif
  115. default:
  116. return true;
  117. }
  118. @@ -273,6 +333,10 @@
  119. switch (family()) {
  120. case af_inet:
  121. return sa_inet()->port();
  122. +#ifdef RAK_USE_INET6
  123. + case af_inet6:
  124. + return sa_inet6()->port();
  125. +#endif
  126. default:
  127. return 0;
  128. }
  129. @@ -283,6 +347,10 @@
  130. switch (family()) {
  131. case af_inet:
  132. return sa_inet()->set_port(p);
  133. +#ifdef RAK_USE_INET6
  134. + case af_inet6:
  135. + return sa_inet6()->set_port(p);
  136. +#endif
  137. default:
  138. break;
  139. }
  140. @@ -293,6 +361,10 @@
  141. switch (family()) {
  142. case af_inet:
  143. return sa_inet()->address_str();
  144. +#ifdef RAK_USE_INET6
  145. + case af_inet6:
  146. + return sa_inet6()->address_str();
  147. +#endif
  148. default:
  149. return std::string();
  150. }
  151. @@ -303,6 +375,10 @@
  152. switch (family()) {
  153. case af_inet:
  154. return sa_inet()->address_c_str(buf, size);
  155. +#ifdef RAK_USE_INET6
  156. + case af_inet6:
  157. + return sa_inet6()->address_c_str(buf, size);
  158. +#endif
  159. default:
  160. return false;
  161. }
  162. @@ -314,6 +390,12 @@
  163. sa_inet()->set_family();
  164. return true;
  165.  
  166. +#ifdef RAK_USE_INET6
  167. + } else if (sa_inet6()->set_address_c_str(a)) {
  168. + sa_inet6()->set_family();
  169. + return true;
  170. +#endif
  171. +
  172. } else {
  173. return false;
  174. }
  175. @@ -325,6 +407,10 @@
  176. switch(family()) {
  177. case af_inet:
  178. return sizeof(sockaddr_in);
  179. +#ifdef RAK_USE_INET6
  180. + case af_inet6:
  181. + return sizeof(sockaddr_in6);
  182. +#endif
  183. default:
  184. return 0;
  185. }
  186. @@ -349,8 +435,10 @@
  187. switch (family()) {
  188. case af_inet:
  189. return *sa_inet() == *rhs.sa_inet();
  190. -// case af_inet6:
  191. -// return *sa_inet6() == *rhs.sa_inet6();
  192. +#ifdef RAK_USE_INET6
  193. + case af_inet6:
  194. + return *sa_inet6() == *rhs.sa_inet6();
  195. +#endif
  196. default:
  197. throw std::logic_error("socket_address::operator == (rhs) invalid type comparison.");
  198. }
  199. @@ -364,8 +452,10 @@
  200. switch (family()) {
  201. case af_inet:
  202. return *sa_inet() < *rhs.sa_inet();
  203. -// case af_inet6:
  204. -// return *sa_inet6() < *rhs.sa_inet6();
  205. +#ifdef RAK_USE_INET6
  206. + case af_inet6:
  207. + return *sa_inet6() < *rhs.sa_inet6();
  208. +#endif
  209. default:
  210. throw std::logic_error("socket_address::operator < (rhs) invalid type comparison.");
  211. }
  212. @@ -391,6 +481,23 @@
  213. return inet_pton(AF_INET, a, &m_sockaddr.sin_addr);
  214. }
  215.  
  216. +#ifdef RAK_USE_INET6
  217. +inline socket_address_inet6
  218. +socket_address_inet::to_mapped_address() const {
  219. + uint32_t addr32[4];
  220. + addr32[0] = 0;
  221. + addr32[1] = 0;
  222. + addr32[2] = htonl(0xffff);
  223. + addr32[3] = m_sockaddr.sin_addr.s_addr;
  224. +
  225. + socket_address_inet6 sa;
  226. + sa.clear();
  227. + sa.set_address(*reinterpret_cast<in6_addr *>(addr32));
  228. + sa.set_port_n(m_sockaddr.sin_port);
  229. + return sa;
  230. +}
  231. +#endif
  232. +
  233. inline bool
  234. socket_address_inet::operator == (const socket_address_inet& rhs) const {
  235. return
  236. @@ -406,6 +513,59 @@
  237. m_sockaddr.sin_port < rhs.m_sockaddr.sin_port);
  238. }
  239.  
  240. +#ifdef RAK_USE_INET6
  241. +
  242. +inline std::string
  243. +socket_address_inet6::address_str() const {
  244. + char buf[INET6_ADDRSTRLEN];
  245. +
  246. + if (!address_c_str(buf, INET6_ADDRSTRLEN))
  247. + return std::string();
  248. +
  249. + return std::string(buf);
  250. +}
  251. +
  252. +inline bool
  253. +socket_address_inet6::address_c_str(char* buf, socklen_t size) const {
  254. + return inet_ntop(family(), &m_sockaddr.sin6_addr, buf, size);
  255. +}
  256. +
  257. +inline bool
  258. +socket_address_inet6::set_address_c_str(const char* a) {
  259. + return inet_pton(AF_INET6, a, &m_sockaddr.sin6_addr);
  260. +}
  261. +
  262. +inline socket_address
  263. +socket_address_inet6::normalize_address() const {
  264. + const uint32_t *addr32 = reinterpret_cast<const uint32_t *>(m_sockaddr.sin6_addr.s6_addr);
  265. + if (addr32[0] == 0 && addr32[1] == 0 && addr32[2] == htonl(0xffff)) {
  266. + socket_address addr4;
  267. + addr4.sa_inet()->set_family();
  268. + addr4.sa_inet()->set_address_n(addr32[3]);
  269. + addr4.sa_inet()->set_port_n(m_sockaddr.sin6_port);
  270. + return addr4;
  271. + }
  272. + return *reinterpret_cast<const socket_address*>(this);
  273. +}
  274. +
  275. +inline bool
  276. +socket_address_inet6::operator == (const socket_address_inet6& rhs) const {
  277. + return
  278. + memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr)) == 0 &&
  279. + m_sockaddr.sin6_port == rhs.m_sockaddr.sin6_port;
  280. +}
  281. +
  282. +inline bool
  283. +socket_address_inet6::operator < (const socket_address_inet6& rhs) const {
  284. + int addr_comp = memcmp(&m_sockaddr.sin6_addr, &rhs.m_sockaddr.sin6_addr, sizeof(in6_addr));
  285. + return
  286. + addr_comp < 0 ||
  287. + (addr_comp == 0 ||
  288. + m_sockaddr.sin6_port < rhs.m_sockaddr.sin6_port);
  289. +}
  290. +
  291. +#endif
  292. +
  293. }
  294.  
  295. #endif
  296. --- a/src/command_peer.cc
  297. +++ b/src/command_peer.cc
  298. @@ -69,7 +69,13 @@
  299.  
  300. torrent::Object
  301. retrieve_p_address(torrent::Peer* peer) {
  302. - return rak::socket_address::cast_from(peer->peer_info()->socket_address())->address_str();
  303. + const rak::socket_address *addr = rak::socket_address::cast_from(peer->peer_info()->socket_address());
  304. +#ifdef RAK_USE_INET6
  305. + if (addr->family() == rak::socket_address::af_inet6)
  306. + return "[" + addr->address_str() + "]";
  307. + else
  308. +#endif
  309. + return addr->address_str();
  310. }
  311.  
  312. torrent::Object
  313. --- a/src/core/curl_get.cc
  314. +++ b/src/core/curl_get.cc
  315. @@ -91,8 +91,20 @@
  316. curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1);
  317. curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
  318. curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5);
  319. +
  320. + // Even when IPv6-enabled, we don't want to use CURL_IPRESOLVE_WHATEVER,
  321. + // since that will usually prefer connecting over IPv6 to the tracker.
  322. + // Since it's usually a lot easier to find our global IPv6 address
  323. + // (if we have one) than our global IPv4 address, we prefer connecting
  324. + // over IPv4 if we can, so that the tracker will get our IPv4 address
  325. + // that way. If the resolve fails, CurlStack will call retry_ipv6()
  326. + // on us and we'll make a second attempt with CURL_IPRESOLVE_V6.
  327. curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  328. +
  329. curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
  330. +#ifdef RAK_USE_INET6
  331. + m_ipv6 = false;
  332. +#endif
  333.  
  334. m_stack->add_get(this);
  335. }
  336. @@ -110,6 +122,17 @@
  337. m_handle = NULL;
  338. }
  339.  
  340. +#ifdef RAK_USE_INET6
  341. +void
  342. +CurlGet::retry_ipv6() {
  343. + CURL* nhandle = curl_easy_duphandle(m_handle);
  344. + curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
  345. + curl_easy_cleanup(m_handle);
  346. + m_handle = nhandle;
  347. + m_ipv6 = true;
  348. +}
  349. +#endif
  350. +
  351. void
  352. CurlGet::receive_timeout() {
  353. return m_stack->transfer_done(m_handle, "Timed out");
  354. --- a/src/core/curl_get.h
  355. +++ b/src/core/curl_get.h
  356. @@ -56,6 +56,10 @@
  357.  
  358. void start();
  359. void close();
  360. +#ifdef RAK_USE_INET6
  361. + bool is_using_ipv6() { return m_ipv6; }
  362. + void retry_ipv6();
  363. +#endif
  364.  
  365. bool is_busy() const { return m_handle; }
  366. bool is_active() const { return m_active; }
  367. @@ -74,6 +78,9 @@
  368. void receive_timeout();
  369.  
  370. bool m_active;
  371. +#ifdef RAK_USE_INET6
  372. + bool m_ipv6;
  373. +#endif
  374.  
  375. rak::priority_item m_taskTimeout;
  376.  
  377. --- a/src/core/curl_stack.cc
  378. +++ b/src/core/curl_stack.cc
  379. @@ -112,6 +112,21 @@
  380. if (msg->msg != CURLMSG_DONE)
  381. throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
  382.  
  383. +#ifdef RAK_USE_INET6
  384. + if (msg->data.result == CURLE_COULDNT_RESOLVE_HOST) {
  385. + iterator itr = std::find_if(begin(), end(), rak::equal(msg->easy_handle, std::mem_fun(&CurlGet::handle)));
  386. +
  387. + if (itr == end())
  388. + throw torrent::internal_error("Could not find CurlGet when calling CurlStack::receive_action.");
  389. +
  390. + if (!(*itr)->is_using_ipv6()) {
  391. + (*itr)->retry_ipv6();
  392. + if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
  393. + throw torrent::internal_error("Error calling curl_multi_add_handle.");
  394. + continue;
  395. + }
  396. + } else
  397. +#endif
  398. transfer_done(msg->easy_handle, msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
  399. }
  400.  
  401. --- a/src/display/window_peer_list.cc
  402. +++ b/src/display/window_peer_list.cc
  403. @@ -68,7 +68,11 @@
  404. int x = 2;
  405. int y = 0;
  406.  
  407. - m_canvas->print(x, y, "IP"); x += 16;
  408. +#ifdef RAK_USE_INET6
  409. + m_canvas->print(x, y, "IP"); x += 25;
  410. +#else
  411. + m_canvas->print(x, y, "IP"); x += 16;
  412. +#endif
  413. m_canvas->print(x, y, "UP"); x += 7;
  414. m_canvas->print(x, y, "DOWN"); x += 7;
  415. m_canvas->print(x, y, "PEER"); x += 7;
  416. @@ -99,10 +103,21 @@
  417.  
  418. x = 0;
  419.  
  420. + std::string ip_address = rak::socket_address::cast_from(p->address())->address_str();
  421. +#ifdef RAK_USE_INET6
  422. + if (ip_address.size() >= 24) {
  423. + ip_address.replace(ip_address.begin() + 21, ip_address.end(), "...");
  424. + }
  425. +#endif
  426. +
  427. m_canvas->print(x, y, "%c %s",
  428. range.first == *m_focus ? '*' : ' ',
  429. - rak::socket_address::cast_from(p->address())->address_str().c_str());
  430. + ip_address.c_str());
  431. +#ifdef RAK_USE_INET6
  432. + x += 27;
  433. +#else
  434. x += 18;
  435. +#endif
  436.  
  437. m_canvas->print(x, y, "%.1f", (double)p->up_rate()->rate() / 1024); x += 7;
  438. m_canvas->print(x, y, "%.1f", (double)p->down_rate()->rate() / 1024); x += 7;
  439. --- a/src/utils/socket_fd.cc
  440. +++ b/src/utils/socket_fd.cc
  441. @@ -71,6 +71,11 @@
  442. check_valid();
  443. int opt = p;
  444.  
  445. +#ifdef RAK_USE_INET6
  446. + if (m_ipv6_socket)
  447. + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
  448. + else
  449. +#endif
  450. return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
  451. }
  452.  
  453. @@ -130,12 +135,36 @@
  454.  
  455. bool
  456. SocketFd::open_stream() {
  457. +#ifdef RAK_USE_INET6
  458. + m_fd = socket(rak::socket_address::pf_inet6, SOCK_STREAM, IPPROTO_TCP);
  459. + if (m_fd == -1) {
  460. + m_ipv6_socket = false;
  461. + return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
  462. + }
  463. + m_ipv6_socket = true;
  464. +
  465. + int zero = 0;
  466. + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
  467. +#else
  468. return (m_fd = socket(rak::socket_address::pf_inet, SOCK_STREAM, IPPROTO_TCP)) != -1;
  469. +#endif
  470. }
  471.  
  472. bool
  473. SocketFd::open_datagram() {
  474. +#ifdef RAK_USE_INET6
  475. + m_fd = socket(rak::socket_address::pf_inet6, SOCK_DGRAM, 0);
  476. + if (m_fd == -1) {
  477. + m_ipv6_socket = false;
  478. + return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
  479. + }
  480. + m_ipv6_socket = true;
  481. +
  482. + int zero = 0;
  483. + return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
  484. +#else
  485. return (m_fd = socket(rak::socket_address::pf_inet, SOCK_DGRAM, 0)) != -1;
  486. +#endif
  487. }
  488.  
  489. bool
  490. @@ -153,6 +182,12 @@
  491. SocketFd::bind(const rak::socket_address& sa) {
  492. check_valid();
  493.  
  494. +#ifdef RAK_USE_INET6
  495. + if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
  496. + rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
  497. + return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
  498. + }
  499. +#endif
  500. return !::bind(m_fd, sa.c_sockaddr(), sa.length());
  501. }
  502.  
  503. @@ -160,6 +195,12 @@
  504. SocketFd::bind(const rak::socket_address& sa, unsigned int length) {
  505. check_valid();
  506.  
  507. +#ifdef RAK_USE_INET6
  508. + if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
  509. + rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
  510. + return !::bind(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped));
  511. + }
  512. +#endif
  513. return !::bind(m_fd, sa.c_sockaddr(), length);
  514. }
  515.  
  516. @@ -167,10 +208,34 @@
  517. SocketFd::connect(const rak::socket_address& sa) {
  518. check_valid();
  519.  
  520. +#ifdef RAK_USE_INET6
  521. + if (m_ipv6_socket && sa.family() == rak::socket_address::pf_inet) {
  522. + rak::socket_address_inet6 sa_mapped = sa.sa_inet()->to_mapped_address();
  523. + return !::connect(m_fd, sa_mapped.c_sockaddr(), sizeof(sa_mapped)) || errno == EINPROGRESS;
  524. + }
  525. +#endif
  526. return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS;
  527. }
  528.  
  529. bool
  530. +SocketFd::getsockname(rak::socket_address *sa) {
  531. + check_valid();
  532. +
  533. + socklen_t len = sizeof(rak::socket_address);
  534. + if (::getsockname(m_fd, sa->c_sockaddr(), &len)) {
  535. + return false;
  536. + }
  537. +
  538. +#ifdef RAK_USE_INET6
  539. + if (m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
  540. + *sa = sa->sa_inet6()->normalize_address();
  541. + }
  542. +#endif
  543. +
  544. + return true;
  545. +}
  546. +
  547. +bool
  548. SocketFd::listen(int size) {
  549. check_valid();
  550.  
  551. @@ -182,7 +247,18 @@
  552. check_valid();
  553. socklen_t len = sizeof(rak::socket_address);
  554.  
  555. +#ifdef RAK_USE_INET6
  556. + if (sa == NULL) {
  557. + return SocketFd(::accept(m_fd, NULL, &len));
  558. + }
  559. + int fd = ::accept(m_fd, sa->c_sockaddr(), &len);
  560. + if (fd != -1 && m_ipv6_socket && sa->family() == rak::socket_address::af_inet6) {
  561. + *sa = sa->sa_inet6()->normalize_address();
  562. + }
  563. + return SocketFd(fd);
  564. +#else
  565. return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len));
  566. +#endif
  567. }
  568.  
  569. // unsigned int
  570. --- a/src/utils/socket_fd.h
  571. +++ b/src/utils/socket_fd.h
  572. @@ -80,6 +80,7 @@
  573. bool bind(const rak::socket_address& sa);
  574. bool bind(const rak::socket_address& sa, unsigned int length);
  575. bool connect(const rak::socket_address& sa);
  576. + bool getsockname(rak::socket_address* sa);
  577.  
  578. bool listen(int size);
  579. SocketFd accept(rak::socket_address* sa);
  580. @@ -91,6 +92,9 @@
  581. inline void check_valid() const;
  582.  
  583. int m_fd;
  584. +#ifdef RAK_USE_INET6
  585. + bool m_ipv6_socket;
  586. +#endif
  587. };
  588.  
  589. }
Advertisement
Add Comment
Please, Sign In to add comment