librats 1.0.2 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/README.md +137 -332
  2. package/binding.gyp +16 -3
  3. package/lib/index.d.ts +271 -696
  4. package/lib/index.js +383 -44
  5. package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
  6. package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
  7. package/native-src/CMakeLists.txt +396 -179
  8. package/native-src/LICENSE +1 -1
  9. package/native-src/src/librats/bindings/rats.cpp +731 -0
  10. package/native-src/src/librats/bindings/rats.h +352 -0
  11. package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
  12. package/native-src/src/librats/bittorrent/bencode.h +176 -0
  13. package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
  14. package/native-src/src/librats/bittorrent/bitfield.h +76 -0
  15. package/native-src/src/librats/bittorrent/byte_io.h +58 -0
  16. package/native-src/src/librats/bittorrent/choker.cpp +25 -0
  17. package/native-src/src/librats/bittorrent/choker.h +46 -0
  18. package/native-src/src/librats/bittorrent/client.cpp +413 -0
  19. package/native-src/src/librats/bittorrent/client.h +227 -0
  20. package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
  21. package/native-src/src/librats/bittorrent/disk_io.h +150 -0
  22. package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
  23. package/native-src/src/librats/bittorrent/extensions.h +94 -0
  24. package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
  25. package/native-src/src/librats/bittorrent/file_storage.h +79 -0
  26. package/native-src/src/librats/bittorrent/log.h +42 -0
  27. package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
  28. package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
  29. package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
  30. package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
  31. package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
  32. package/native-src/src/librats/bittorrent/peer_list.h +75 -0
  33. package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
  34. package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
  35. package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
  36. package/native-src/src/librats/bittorrent/reactor.h +89 -0
  37. package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
  38. package/native-src/src/librats/bittorrent/resume_data.h +41 -0
  39. package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
  40. package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
  41. package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
  42. package/native-src/src/librats/bittorrent/torrent.h +260 -0
  43. package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
  44. package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
  45. package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
  46. package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
  47. package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
  48. package/native-src/src/librats/bittorrent/tracker.h +108 -0
  49. package/native-src/src/librats/bittorrent/types.cpp +206 -0
  50. package/native-src/src/librats/bittorrent/types.h +86 -0
  51. package/native-src/src/librats/core/address.cpp +35 -0
  52. package/native-src/src/librats/core/address.h +78 -0
  53. package/native-src/src/librats/core/bytes.h +69 -0
  54. package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
  55. package/native-src/src/librats/core/chained_send_buffer.h +183 -0
  56. package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
  57. package/native-src/src/librats/core/endpoint_parse.h +31 -0
  58. package/native-src/src/librats/core/event_bus.h +70 -0
  59. package/native-src/src/librats/core/host_endpoint.h +56 -0
  60. package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
  61. package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
  62. package/native-src/src/librats/core/ip_address.cpp +120 -0
  63. package/native-src/src/librats/core/ip_address.h +109 -0
  64. package/native-src/src/librats/core/mpsc_queue.h +47 -0
  65. package/native-src/src/librats/core/notifier.h +74 -0
  66. package/native-src/src/librats/core/receive_buffer.cpp +219 -0
  67. package/native-src/src/librats/core/receive_buffer.h +171 -0
  68. package/native-src/src/librats/core/service_registry.h +58 -0
  69. package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
  70. package/native-src/src/librats/core/socket.h +496 -0
  71. package/native-src/src/librats/core/timer_queue.h +105 -0
  72. package/native-src/src/librats/core/types.cpp +42 -0
  73. package/native-src/src/librats/core/types.h +93 -0
  74. package/native-src/src/librats/core/wakeup_pipe.h +83 -0
  75. package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
  76. package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
  77. package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
  78. package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
  79. package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
  80. package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
  81. package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
  82. package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
  83. package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
  84. package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
  85. package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
  86. package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
  87. package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
  88. package/native-src/src/librats/crypto/hkdf.c +266 -0
  89. package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
  90. package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
  91. package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
  92. package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
  93. package/native-src/src/librats/crypto/poly1305.h +37 -0
  94. package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
  95. package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
  96. package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
  97. package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
  98. package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
  99. package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
  100. package/native-src/src/librats/dht/announce.cpp +37 -0
  101. package/native-src/src/librats/dht/announce.h +41 -0
  102. package/native-src/src/librats/dht/bep42.cpp +109 -0
  103. package/native-src/src/librats/dht/bep42.h +48 -0
  104. package/native-src/src/librats/dht/dht.cpp +501 -0
  105. package/native-src/src/librats/dht/dht.h +119 -0
  106. package/native-src/src/librats/dht/dht_runner.cpp +103 -0
  107. package/native-src/src/librats/dht/dht_runner.h +71 -0
  108. package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
  109. package/native-src/src/librats/dht/dos_blocker.h +47 -0
  110. package/native-src/src/librats/dht/find_peers.cpp +52 -0
  111. package/native-src/src/librats/dht/find_peers.h +73 -0
  112. package/native-src/src/librats/dht/id.h +167 -0
  113. package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
  114. package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
  115. package/native-src/src/librats/dht/log.h +38 -0
  116. package/native-src/src/librats/dht/node.cpp +473 -0
  117. package/native-src/src/librats/dht/node.h +164 -0
  118. package/native-src/src/librats/dht/node_entry.h +81 -0
  119. package/native-src/src/librats/dht/observer.h +72 -0
  120. package/native-src/src/librats/dht/persistence.cpp +90 -0
  121. package/native-src/src/librats/dht/persistence.h +32 -0
  122. package/native-src/src/librats/dht/routing_table.cpp +559 -0
  123. package/native-src/src/librats/dht/routing_table.h +185 -0
  124. package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
  125. package/native-src/src/librats/dht/rpc_manager.h +77 -0
  126. package/native-src/src/librats/dht/storage.cpp +92 -0
  127. package/native-src/src/librats/dht/storage.h +74 -0
  128. package/native-src/src/librats/dht/transport.h +27 -0
  129. package/native-src/src/librats/dht/traversal.cpp +326 -0
  130. package/native-src/src/librats/dht/traversal.h +120 -0
  131. package/native-src/src/librats/dht/udp_transport.cpp +49 -0
  132. package/native-src/src/librats/dht/udp_transport.h +51 -0
  133. package/native-src/src/librats/mdns/log.h +22 -0
  134. package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
  135. package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
  136. package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
  137. package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
  138. package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
  139. package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
  140. package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
  141. package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
  142. package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
  143. package/native-src/src/librats/node/config.h +110 -0
  144. package/native-src/src/librats/node/dial_service.h +54 -0
  145. package/native-src/src/librats/node/dialer.cpp +264 -0
  146. package/native-src/src/librats/node/dialer.h +188 -0
  147. package/native-src/src/librats/node/host_events.h +26 -0
  148. package/native-src/src/librats/node/identify.cpp +130 -0
  149. package/native-src/src/librats/node/identify.h +71 -0
  150. package/native-src/src/librats/node/nat_status.cpp +103 -0
  151. package/native-src/src/librats/node/nat_status.h +118 -0
  152. package/native-src/src/librats/node/node.cpp +826 -0
  153. package/native-src/src/librats/node/node.h +333 -0
  154. package/native-src/src/librats/node/node_context.h +33 -0
  155. package/native-src/src/librats/node/peer_network.h +91 -0
  156. package/native-src/src/librats/peer/peer.h +49 -0
  157. package/native-src/src/librats/peer/peer_book.cpp +181 -0
  158. package/native-src/src/librats/peer/peer_book.h +88 -0
  159. package/native-src/src/librats/peer/peer_id.cpp +72 -0
  160. package/native-src/src/librats/peer/peer_id.h +62 -0
  161. package/native-src/src/librats/peer/peer_info.h +37 -0
  162. package/native-src/src/librats/peer/peer_table.cpp +137 -0
  163. package/native-src/src/librats/peer/peer_table.h +148 -0
  164. package/native-src/src/librats/security/handshaker.h +66 -0
  165. package/native-src/src/librats/security/identity.h +43 -0
  166. package/native-src/src/librats/security/noise_security.cpp +122 -0
  167. package/native-src/src/librats/security/noise_security.h +37 -0
  168. package/native-src/src/librats/security/plaintext_security.h +106 -0
  169. package/native-src/src/librats/security/session.h +37 -0
  170. package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
  171. package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
  172. package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
  173. package/native-src/src/librats/subsystems/bittorrent.h +136 -0
  174. package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
  175. package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
  176. package/native-src/src/librats/subsystems/dht_service.h +36 -0
  177. package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
  178. package/native-src/src/librats/subsystems/file_transfer.h +367 -0
  179. package/native-src/src/librats/subsystems/hole_punch.cpp +532 -0
  180. package/native-src/src/librats/subsystems/hole_punch.h +266 -0
  181. package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
  182. package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
  183. package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
  184. package/native-src/src/librats/subsystems/message_json.cpp +112 -0
  185. package/native-src/src/librats/subsystems/message_json.h +88 -0
  186. package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
  187. package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
  188. package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
  189. package/native-src/src/librats/subsystems/ping_service.h +66 -0
  190. package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
  191. package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
  192. package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
  193. package/native-src/src/librats/subsystems/pubsub.h +175 -0
  194. package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
  195. package/native-src/src/librats/subsystems/reconnection.h +126 -0
  196. package/native-src/src/librats/transport/connection.cpp +343 -0
  197. package/native-src/src/librats/transport/connection.h +283 -0
  198. package/native-src/src/librats/transport/link.h +96 -0
  199. package/native-src/src/librats/transport/reactor.cpp +540 -0
  200. package/native-src/src/librats/transport/reactor.h +224 -0
  201. package/native-src/src/librats/transport/reactor_pool.h +81 -0
  202. package/native-src/src/librats/transport/tcp_link.cpp +49 -0
  203. package/native-src/src/librats/transport/tcp_link.h +43 -0
  204. package/native-src/src/librats/transport/udp_mux.cpp +617 -0
  205. package/native-src/src/librats/transport/udp_mux.h +363 -0
  206. package/native-src/src/librats/transport/udp_packet.cpp +121 -0
  207. package/native-src/src/librats/transport/udp_packet.h +190 -0
  208. package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
  209. package/native-src/src/librats/transport/udp_stream.h +614 -0
  210. package/native-src/src/librats/util/features.h.in +51 -0
  211. package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
  212. package/native-src/src/librats/util/fs.h +136 -0
  213. package/native-src/src/librats/util/json.cpp +1002 -0
  214. package/native-src/src/librats/util/json.h +444 -0
  215. package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
  216. package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
  217. package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
  218. package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
  219. package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
  220. package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
  221. package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
  222. package/native-src/src/librats/util/rats_export.h +69 -0
  223. package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
  224. package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
  225. package/native-src/src/librats/wire/frame.cpp +76 -0
  226. package/native-src/src/librats/wire/frame.h +110 -0
  227. package/native-src/src/librats/wire/message_router.cpp +45 -0
  228. package/native-src/src/librats/wire/message_router.h +47 -0
  229. package/package.json +5 -4
  230. package/scripts/build-librats.js +1 -0
  231. package/scripts/postinstall.js +3 -3
  232. package/scripts/prepare-package.js +4 -4
  233. package/scripts/verify-installation.js +63 -105
  234. package/src/librats_node.cpp +1042 -1324
  235. package/native-src/src/bencode.cpp +0 -485
  236. package/native-src/src/bencode.h +0 -145
  237. package/native-src/src/bittorrent.cpp +0 -14
  238. package/native-src/src/bittorrent.h +0 -74
  239. package/native-src/src/bt_bitfield.cpp +0 -372
  240. package/native-src/src/bt_bitfield.h +0 -316
  241. package/native-src/src/bt_choker.cpp +0 -228
  242. package/native-src/src/bt_choker.h +0 -147
  243. package/native-src/src/bt_client.cpp +0 -1047
  244. package/native-src/src/bt_client.h +0 -445
  245. package/native-src/src/bt_create_torrent.cpp +0 -677
  246. package/native-src/src/bt_create_torrent.h +0 -473
  247. package/native-src/src/bt_extension.cpp +0 -469
  248. package/native-src/src/bt_extension.h +0 -309
  249. package/native-src/src/bt_file_storage.cpp +0 -261
  250. package/native-src/src/bt_file_storage.h +0 -298
  251. package/native-src/src/bt_handshake.cpp +0 -134
  252. package/native-src/src/bt_handshake.h +0 -157
  253. package/native-src/src/bt_messages.cpp +0 -364
  254. package/native-src/src/bt_messages.h +0 -324
  255. package/native-src/src/bt_network.cpp +0 -1007
  256. package/native-src/src/bt_network.h +0 -417
  257. package/native-src/src/bt_peer_connection.cpp +0 -742
  258. package/native-src/src/bt_peer_connection.h +0 -592
  259. package/native-src/src/bt_piece_picker.cpp +0 -786
  260. package/native-src/src/bt_piece_picker.h +0 -473
  261. package/native-src/src/bt_resume_data.cpp +0 -410
  262. package/native-src/src/bt_resume_data.h +0 -249
  263. package/native-src/src/bt_torrent.cpp +0 -2120
  264. package/native-src/src/bt_torrent.h +0 -641
  265. package/native-src/src/bt_torrent_info.cpp +0 -659
  266. package/native-src/src/bt_torrent_info.h +0 -418
  267. package/native-src/src/bt_types.h +0 -621
  268. package/native-src/src/chained_send_buffer.cpp +0 -75
  269. package/native-src/src/chained_send_buffer.h +0 -137
  270. package/native-src/src/crypto/hkdf.c +0 -266
  271. package/native-src/src/crypto/poly1305.h +0 -36
  272. package/native-src/src/dht.cpp +0 -3311
  273. package/native-src/src/dht.h +0 -717
  274. package/native-src/src/disk_io.cpp +0 -632
  275. package/native-src/src/disk_io.h +0 -315
  276. package/native-src/src/file_transfer.cpp +0 -1415
  277. package/native-src/src/file_transfer.h +0 -286
  278. package/native-src/src/fs.h +0 -108
  279. package/native-src/src/gossipsub.cpp +0 -1139
  280. package/native-src/src/gossipsub.h +0 -403
  281. package/native-src/src/ice.cpp +0 -893
  282. package/native-src/src/ice.h +0 -559
  283. package/native-src/src/json.hpp +0 -25526
  284. package/native-src/src/librats.cpp +0 -2378
  285. package/native-src/src/librats.h +0 -2324
  286. package/native-src/src/librats_bittorrent.cpp +0 -601
  287. package/native-src/src/librats_c.cpp +0 -1557
  288. package/native-src/src/librats_c.h +0 -323
  289. package/native-src/src/librats_discovery.cpp +0 -402
  290. package/native-src/src/librats_encryption.cpp +0 -275
  291. package/native-src/src/librats_file_transfer.cpp +0 -144
  292. package/native-src/src/librats_gossipsub.cpp +0 -289
  293. package/native-src/src/librats_ice.cpp +0 -213
  294. package/native-src/src/librats_log_macros.h +0 -36
  295. package/native-src/src/librats_logging.cpp +0 -173
  296. package/native-src/src/librats_mdns.cpp +0 -166
  297. package/native-src/src/librats_persistence.cpp +0 -796
  298. package/native-src/src/librats_portmap.cpp +0 -419
  299. package/native-src/src/librats_reconnection.cpp +0 -218
  300. package/native-src/src/librats_statistic.cpp +0 -105
  301. package/native-src/src/librats_storage.cpp +0 -189
  302. package/native-src/src/rats_export.h +0 -17
  303. package/native-src/src/receive_buffer.cpp +0 -82
  304. package/native-src/src/receive_buffer.h +0 -127
  305. package/native-src/src/socket.h +0 -228
  306. package/native-src/src/threadmanager.cpp +0 -105
  307. package/native-src/src/threadmanager.h +0 -53
  308. package/native-src/src/tracker.cpp +0 -1264
  309. package/native-src/src/tracker.h +0 -319
  310. package/native-src/src/turn.cpp +0 -762
  311. package/native-src/src/turn.h +0 -460
  312. package/native-src/src/wakeup_pipe.h +0 -60
  313. /package/native-src/src/{os.h → librats/util/os.h} +0 -0
@@ -1,762 +0,0 @@
1
- /**
2
- * @file turn.cpp
3
- * @brief TURN (Traversal Using Relays around NAT) Client Implementation
4
- *
5
- * Implements RFC 5766 - TURN protocol for NAT traversal via relay.
6
- */
7
-
8
- #include "turn.h"
9
- #include "logger.h"
10
- #include "network_utils.h"
11
- #include <cstring>
12
- #include <algorithm>
13
-
14
- namespace librats {
15
-
16
- // ============================================================================
17
- // Logging Macros
18
- // ============================================================================
19
-
20
- #define LOG_TURN_DEBUG(msg) LOG_DEBUG("turn", msg)
21
- #define LOG_TURN_INFO(msg) LOG_INFO("turn", msg)
22
- #define LOG_TURN_WARN(msg) LOG_WARN("turn", msg)
23
- #define LOG_TURN_ERROR(msg) LOG_ERROR("turn", msg)
24
-
25
- // ============================================================================
26
- // TurnClient Implementation
27
- // ============================================================================
28
-
29
- TurnClient::TurnClient() = default;
30
-
31
- TurnClient::TurnClient(const TurnClientConfig& config) : config_(config) {}
32
-
33
- TurnClient::~TurnClient() {
34
- close();
35
- }
36
-
37
- TurnClient::TurnClient(TurnClient&& other) noexcept
38
- : config_(std::move(other.config_)),
39
- socket_(other.socket_),
40
- stun_client_(std::move(other.stun_client_)),
41
- state_(other.state_),
42
- allocation_(std::move(other.allocation_)),
43
- nonce_(std::move(other.nonce_)),
44
- realm_(std::move(other.realm_)),
45
- permissions_(std::move(other.permissions_)),
46
- channels_(std::move(other.channels_)),
47
- peer_to_channel_(std::move(other.peer_to_channel_)),
48
- next_channel_(other.next_channel_),
49
- data_callback_(std::move(other.data_callback_)),
50
- state_callback_(std::move(other.state_callback_)) {
51
- other.socket_ = INVALID_SOCKET_VALUE;
52
- other.state_ = TurnAllocationState::None;
53
- }
54
-
55
- TurnClient& TurnClient::operator=(TurnClient&& other) noexcept {
56
- if (this != &other) {
57
- close();
58
- config_ = std::move(other.config_);
59
- socket_ = other.socket_;
60
- stun_client_ = std::move(other.stun_client_);
61
- state_ = other.state_;
62
- allocation_ = std::move(other.allocation_);
63
- nonce_ = std::move(other.nonce_);
64
- realm_ = std::move(other.realm_);
65
- permissions_ = std::move(other.permissions_);
66
- channels_ = std::move(other.channels_);
67
- peer_to_channel_ = std::move(other.peer_to_channel_);
68
- next_channel_ = other.next_channel_;
69
- data_callback_ = std::move(other.data_callback_);
70
- state_callback_ = std::move(other.state_callback_);
71
- other.socket_ = INVALID_SOCKET_VALUE;
72
- other.state_ = TurnAllocationState::None;
73
- }
74
- return *this;
75
- }
76
-
77
- void TurnClient::set_config(const TurnClientConfig& config) {
78
- config_ = config;
79
- }
80
-
81
- void TurnClient::close() {
82
- stop_refresh_thread();
83
-
84
- if (is_allocated()) {
85
- release();
86
- }
87
-
88
- if (is_valid_socket(socket_)) {
89
- close_socket(socket_);
90
- socket_ = INVALID_SOCKET_VALUE;
91
- }
92
-
93
- set_state(TurnAllocationState::None);
94
- }
95
-
96
- bool TurnClient::ensure_socket() {
97
- if (is_valid_socket(socket_)) {
98
- return true;
99
- }
100
-
101
- socket_ = create_udp_socket(0);
102
- if (!is_valid_socket(socket_)) {
103
- LOG_TURN_ERROR("Failed to create UDP socket");
104
- return false;
105
- }
106
-
107
- return true;
108
- }
109
-
110
- std::vector<uint8_t> TurnClient::compute_message_integrity_key() const {
111
- std::string effective_realm = realm_.empty() ? config_.realm : realm_;
112
- return stun_compute_long_term_key(config_.username, effective_realm, config_.password);
113
- }
114
-
115
- void TurnClient::set_state(TurnAllocationState new_state) {
116
- if (state_ != new_state) {
117
- state_ = new_state;
118
- if (state_callback_) {
119
- state_callback_(new_state);
120
- }
121
- }
122
- }
123
-
124
- std::string TurnClient::peer_key(const StunMappedAddress& peer) const {
125
- return peer.address + ":" + std::to_string(peer.port);
126
- }
127
-
128
- // ============================================================================
129
- // Allocation Management
130
- // ============================================================================
131
-
132
- TurnResult TurnClient::allocate() {
133
- LOG_TURN_INFO("Requesting TURN allocation from " << config_.server << ":" << config_.port);
134
-
135
- if (!ensure_socket()) {
136
- return TurnResult::Error("Failed to create socket");
137
- }
138
-
139
- set_state(TurnAllocationState::Allocating);
140
-
141
- // First request without credentials to get nonce and realm
142
- auto result = send_allocate_request(false);
143
-
144
- if (!result.success && result.error) {
145
- if (result.error->code == StunErrorCode::Unauthorized) {
146
- // Expected - server sends 401 with nonce and realm
147
- // Retry with credentials
148
- LOG_TURN_DEBUG("Got 401 response, retrying with credentials");
149
- result = send_allocate_request(true);
150
- }
151
- }
152
-
153
- if (result.success) {
154
- set_state(TurnAllocationState::Allocated);
155
- LOG_TURN_INFO("TURN allocation successful: " << allocation_.relay_address.to_string());
156
-
157
- if (config_.auto_refresh) {
158
- start_refresh_thread();
159
- }
160
- } else {
161
- set_state(TurnAllocationState::Failed);
162
- LOG_TURN_ERROR("TURN allocation failed: " << result.error_message);
163
- }
164
-
165
- return result;
166
- }
167
-
168
- TurnResult TurnClient::send_allocate_request(bool with_credentials) {
169
- StunMessage request(StunMessageType::AllocateRequest);
170
- request.add_requested_transport(TURN_TRANSPORT_UDP);
171
- request.add_lifetime(config_.requested_lifetime);
172
-
173
- if (!config_.software.empty()) {
174
- request.add_software(config_.software);
175
- }
176
-
177
- if (with_credentials && !config_.username.empty()) {
178
- request.add_username(config_.username);
179
- std::string effective_realm = realm_.empty() ? config_.realm : realm_;
180
- if (!effective_realm.empty()) {
181
- request.add_realm(effective_realm);
182
- }
183
- if (!nonce_.empty()) {
184
- request.add_nonce(nonce_);
185
- }
186
- }
187
-
188
- std::vector<uint8_t> data;
189
- if (with_credentials && !config_.password.empty()) {
190
- auto key = compute_message_integrity_key();
191
- data = request.serialize_with_integrity(std::string(key.begin(), key.end()));
192
- } else {
193
- data = request.serialize();
194
- }
195
-
196
- auto response = stun_client_.send_request(socket_, request, config_.server,
197
- config_.port, config_.timeout_ms);
198
-
199
- if (!response) {
200
- return TurnResult::Error("Request timed out");
201
- }
202
-
203
- // Extract nonce and realm from any response
204
- if (auto new_nonce = response->get_nonce()) {
205
- nonce_ = *new_nonce;
206
- }
207
- if (auto new_realm = response->get_realm()) {
208
- realm_ = *new_realm;
209
- }
210
-
211
- if (response->is_error_response()) {
212
- auto error = response->get_error();
213
- if (error) {
214
- return TurnResult::Error(error->code, error->reason);
215
- }
216
- return TurnResult::Error("Unknown error");
217
- }
218
-
219
- if (response->is_success_response()) {
220
- // Parse allocation response
221
- auto relay_addr = response->get_xor_relayed_address();
222
- auto mapped_addr = response->get_xor_mapped_address();
223
- auto lifetime = response->get_lifetime();
224
-
225
- if (!relay_addr || !lifetime) {
226
- return TurnResult::Error("Invalid allocation response");
227
- }
228
-
229
- allocation_.relay_address = *relay_addr;
230
- if (mapped_addr) {
231
- allocation_.mapped_address = *mapped_addr;
232
- }
233
- allocation_.lifetime = *lifetime;
234
- allocation_.allocated_at = std::chrono::steady_clock::now();
235
- allocation_.expires_at = allocation_.allocated_at +
236
- std::chrono::seconds(allocation_.lifetime);
237
-
238
- return TurnResult::Success();
239
- }
240
-
241
- return TurnResult::Error("Unexpected response type");
242
- }
243
-
244
- TurnResult TurnClient::refresh(uint32_t lifetime) {
245
- if (!is_allocated()) {
246
- return TurnResult::Error("No active allocation");
247
- }
248
-
249
- LOG_TURN_DEBUG("Refreshing TURN allocation");
250
- set_state(TurnAllocationState::Refreshing);
251
-
252
- auto result = send_refresh_request(lifetime == 0 ? config_.requested_lifetime : lifetime);
253
-
254
- if (result.success) {
255
- set_state(TurnAllocationState::Allocated);
256
- } else {
257
- set_state(TurnAllocationState::Failed);
258
- }
259
-
260
- return result;
261
- }
262
-
263
- TurnResult TurnClient::send_refresh_request(uint32_t lifetime) {
264
- StunMessage request(StunMessageType::RefreshRequest);
265
- request.add_lifetime(lifetime);
266
- request.add_username(config_.username);
267
-
268
- std::string effective_realm = realm_.empty() ? config_.realm : realm_;
269
- if (!effective_realm.empty()) {
270
- request.add_realm(effective_realm);
271
- }
272
- if (!nonce_.empty()) {
273
- request.add_nonce(nonce_);
274
- }
275
-
276
- auto key = compute_message_integrity_key();
277
- auto data = request.serialize_with_integrity(std::string(key.begin(), key.end()));
278
-
279
- auto response = stun_client_.send_request(socket_, request, config_.server,
280
- config_.port, config_.timeout_ms);
281
-
282
- if (!response) {
283
- return TurnResult::Error("Refresh request timed out");
284
- }
285
-
286
- // Update nonce if changed
287
- if (auto new_nonce = response->get_nonce()) {
288
- nonce_ = *new_nonce;
289
- }
290
-
291
- if (response->is_error_response()) {
292
- auto error = response->get_error();
293
- if (error) {
294
- if (error->code == StunErrorCode::StaleNonce) {
295
- // Retry with new nonce
296
- return send_refresh_request(lifetime);
297
- }
298
- return TurnResult::Error(error->code, error->reason);
299
- }
300
- return TurnResult::Error("Unknown error");
301
- }
302
-
303
- if (response->is_success_response()) {
304
- auto new_lifetime = response->get_lifetime();
305
- if (new_lifetime) {
306
- allocation_.lifetime = *new_lifetime;
307
- allocation_.expires_at = std::chrono::steady_clock::now() +
308
- std::chrono::seconds(allocation_.lifetime);
309
- LOG_TURN_DEBUG("Allocation refreshed, new lifetime: " << allocation_.lifetime);
310
- }
311
- return TurnResult::Success();
312
- }
313
-
314
- return TurnResult::Error("Unexpected response type");
315
- }
316
-
317
- TurnResult TurnClient::release() {
318
- if (!is_allocated()) {
319
- return TurnResult::Success(); // Already released
320
- }
321
-
322
- LOG_TURN_INFO("Releasing TURN allocation");
323
- stop_refresh_thread();
324
-
325
- auto result = send_refresh_request(0); // Lifetime 0 = release
326
-
327
- allocation_ = TurnAllocation();
328
- set_state(TurnAllocationState::None);
329
-
330
- return result;
331
- }
332
-
333
- // ============================================================================
334
- // Permission Management
335
- // ============================================================================
336
-
337
- TurnResult TurnClient::create_permission(const std::string& peer_address) {
338
- StunMappedAddress peer(StunAddressFamily::IPv4, peer_address, 0);
339
- return create_permission(peer);
340
- }
341
-
342
- TurnResult TurnClient::create_permission(const StunMappedAddress& peer) {
343
- return create_permissions({peer.address});
344
- }
345
-
346
- TurnResult TurnClient::create_permissions(const std::vector<std::string>& peer_addresses) {
347
- if (!is_allocated()) {
348
- return TurnResult::Error("No active allocation");
349
- }
350
-
351
- std::vector<StunMappedAddress> peers;
352
- for (const auto& addr : peer_addresses) {
353
- peers.emplace_back(StunAddressFamily::IPv4, addr, 0);
354
- }
355
-
356
- return send_create_permission_request(peers);
357
- }
358
-
359
- TurnResult TurnClient::send_create_permission_request(const std::vector<StunMappedAddress>& peers) {
360
- StunMessage request(StunMessageType::CreatePermissionRequest);
361
-
362
- for (const auto& peer : peers) {
363
- request.add_xor_peer_address(peer);
364
- }
365
-
366
- request.add_username(config_.username);
367
- std::string effective_realm = realm_.empty() ? config_.realm : realm_;
368
- if (!effective_realm.empty()) {
369
- request.add_realm(effective_realm);
370
- }
371
- if (!nonce_.empty()) {
372
- request.add_nonce(nonce_);
373
- }
374
-
375
- auto key = compute_message_integrity_key();
376
- auto data = request.serialize_with_integrity(std::string(key.begin(), key.end()));
377
-
378
- auto response = stun_client_.send_request(socket_, request, config_.server,
379
- config_.port, config_.timeout_ms);
380
-
381
- if (!response) {
382
- return TurnResult::Error("CreatePermission request timed out");
383
- }
384
-
385
- if (auto new_nonce = response->get_nonce()) {
386
- nonce_ = *new_nonce;
387
- }
388
-
389
- if (response->is_error_response()) {
390
- auto error = response->get_error();
391
- if (error) {
392
- if (error->code == StunErrorCode::StaleNonce) {
393
- return send_create_permission_request(peers);
394
- }
395
- return TurnResult::Error(error->code, error->reason);
396
- }
397
- return TurnResult::Error("Unknown error");
398
- }
399
-
400
- if (response->is_success_response()) {
401
- std::lock_guard<std::mutex> lock(mutex_);
402
- auto expires_at = std::chrono::steady_clock::now() + std::chrono::minutes(5);
403
-
404
- for (const auto& peer : peers) {
405
- TurnPermission perm;
406
- perm.peer_address = peer.address;
407
- perm.expires_at = expires_at;
408
- permissions_[peer.address] = perm;
409
- }
410
-
411
- LOG_TURN_DEBUG("Created permissions for " << peers.size() << " peers");
412
- return TurnResult::Success();
413
- }
414
-
415
- return TurnResult::Error("Unexpected response type");
416
- }
417
-
418
- bool TurnClient::has_permission(const std::string& peer_address) const {
419
- std::lock_guard<std::mutex> lock(mutex_);
420
- auto it = permissions_.find(peer_address);
421
- if (it == permissions_.end()) return false;
422
- return !it->second.is_expired();
423
- }
424
-
425
- // ============================================================================
426
- // Channel Binding
427
- // ============================================================================
428
-
429
- uint16_t TurnClient::bind_channel(const StunMappedAddress& peer) {
430
- if (!is_allocated()) {
431
- return 0;
432
- }
433
-
434
- std::string key = peer_key(peer);
435
-
436
- {
437
- std::lock_guard<std::mutex> lock(mutex_);
438
- auto it = peer_to_channel_.find(key);
439
- if (it != peer_to_channel_.end()) {
440
- auto& binding = channels_[it->second];
441
- if (!binding.is_expired()) {
442
- return it->second; // Already bound
443
- }
444
- }
445
- }
446
-
447
- uint16_t channel;
448
- {
449
- std::lock_guard<std::mutex> lock(mutex_);
450
- channel = next_channel_++;
451
- if (next_channel_ > TURN_CHANNEL_MAX) {
452
- next_channel_ = TURN_CHANNEL_MIN;
453
- }
454
- }
455
-
456
- auto result = send_channel_bind_request(channel, peer);
457
- if (!result.success) {
458
- LOG_TURN_ERROR("Channel binding failed: " << result.error_message);
459
- return 0;
460
- }
461
-
462
- {
463
- std::lock_guard<std::mutex> lock(mutex_);
464
- TurnChannelBinding binding;
465
- binding.channel_number = channel;
466
- binding.peer_address = peer;
467
- binding.expires_at = std::chrono::steady_clock::now() + std::chrono::minutes(10);
468
-
469
- channels_[channel] = binding;
470
- peer_to_channel_[key] = channel;
471
- }
472
-
473
- LOG_TURN_DEBUG("Bound channel " << channel << " to " << peer.to_string());
474
- return channel;
475
- }
476
-
477
- TurnResult TurnClient::send_channel_bind_request(uint16_t channel, const StunMappedAddress& peer) {
478
- StunMessage request(StunMessageType::ChannelBindRequest);
479
- request.add_channel_number(channel);
480
- request.add_xor_peer_address(peer);
481
-
482
- request.add_username(config_.username);
483
- std::string effective_realm = realm_.empty() ? config_.realm : realm_;
484
- if (!effective_realm.empty()) {
485
- request.add_realm(effective_realm);
486
- }
487
- if (!nonce_.empty()) {
488
- request.add_nonce(nonce_);
489
- }
490
-
491
- auto key = compute_message_integrity_key();
492
- auto data = request.serialize_with_integrity(std::string(key.begin(), key.end()));
493
-
494
- auto response = stun_client_.send_request(socket_, request, config_.server,
495
- config_.port, config_.timeout_ms);
496
-
497
- if (!response) {
498
- return TurnResult::Error("ChannelBind request timed out");
499
- }
500
-
501
- if (auto new_nonce = response->get_nonce()) {
502
- nonce_ = *new_nonce;
503
- }
504
-
505
- if (response->is_error_response()) {
506
- auto error = response->get_error();
507
- if (error) {
508
- if (error->code == StunErrorCode::StaleNonce) {
509
- return send_channel_bind_request(channel, peer);
510
- }
511
- return TurnResult::Error(error->code, error->reason);
512
- }
513
- return TurnResult::Error("Unknown error");
514
- }
515
-
516
- if (response->is_success_response()) {
517
- return TurnResult::Success();
518
- }
519
-
520
- return TurnResult::Error("Unexpected response type");
521
- }
522
-
523
- uint16_t TurnClient::get_channel(const StunMappedAddress& peer) const {
524
- std::lock_guard<std::mutex> lock(mutex_);
525
- std::string key = peer_key(peer);
526
- auto it = peer_to_channel_.find(key);
527
- if (it == peer_to_channel_.end()) return 0;
528
-
529
- auto ch_it = channels_.find(it->second);
530
- if (ch_it == channels_.end() || ch_it->second.is_expired()) return 0;
531
-
532
- return it->second;
533
- }
534
-
535
- std::optional<StunMappedAddress> TurnClient::get_channel_peer(uint16_t channel) const {
536
- std::lock_guard<std::mutex> lock(mutex_);
537
- auto it = channels_.find(channel);
538
- if (it == channels_.end() || it->second.is_expired()) {
539
- return std::nullopt;
540
- }
541
- return it->second.peer_address;
542
- }
543
-
544
- TurnResult TurnClient::refresh_channel(uint16_t channel) {
545
- std::optional<StunMappedAddress> peer;
546
- {
547
- std::lock_guard<std::mutex> lock(mutex_);
548
- auto it = channels_.find(channel);
549
- if (it != channels_.end()) {
550
- peer = it->second.peer_address;
551
- }
552
- }
553
-
554
- if (!peer) {
555
- return TurnResult::Error("Channel not found");
556
- }
557
-
558
- auto result = send_channel_bind_request(channel, *peer);
559
- if (result.success) {
560
- std::lock_guard<std::mutex> lock(mutex_);
561
- auto it = channels_.find(channel);
562
- if (it != channels_.end()) {
563
- it->second.expires_at = std::chrono::steady_clock::now() + std::chrono::minutes(10);
564
- }
565
- }
566
-
567
- return result;
568
- }
569
-
570
- // ============================================================================
571
- // Data Transfer
572
- // ============================================================================
573
-
574
- bool TurnClient::send_data(const StunMappedAddress& peer, const std::vector<uint8_t>& data) {
575
- uint16_t channel = get_channel(peer);
576
- if (channel != 0) {
577
- return send_channel_data(channel, data);
578
- }
579
- return send_indication(peer, data);
580
- }
581
-
582
- bool TurnClient::send_indication(const StunMappedAddress& peer, const std::vector<uint8_t>& data) {
583
- if (!is_allocated()) {
584
- return false;
585
- }
586
-
587
- // Ensure permission exists
588
- if (!has_permission(peer.address)) {
589
- auto result = create_permission(peer);
590
- if (!result.success) {
591
- LOG_TURN_ERROR("Failed to create permission for " << peer.address);
592
- return false;
593
- }
594
- }
595
-
596
- StunMessage indication;
597
- indication.type = StunMessageType::SendIndication;
598
- indication.generate_transaction_id();
599
- indication.add_xor_peer_address(peer);
600
- indication.add_data(data);
601
-
602
- auto msg_data = indication.serialize();
603
- int sent = send_udp_data(socket_, msg_data, config_.server, config_.port);
604
-
605
- return sent > 0;
606
- }
607
-
608
- bool TurnClient::send_channel_data(uint16_t channel, const std::vector<uint8_t>& data) {
609
- if (!is_allocated()) {
610
- return false;
611
- }
612
-
613
- // Channel data format: 2-byte channel + 2-byte length + data (padded to 4 bytes)
614
- std::vector<uint8_t> msg;
615
- msg.reserve(TURN_CHANNEL_HEADER_SIZE + data.size() + 3);
616
-
617
- msg.push_back(static_cast<uint8_t>(channel >> 8));
618
- msg.push_back(static_cast<uint8_t>(channel));
619
- msg.push_back(static_cast<uint8_t>(data.size() >> 8));
620
- msg.push_back(static_cast<uint8_t>(data.size()));
621
- msg.insert(msg.end(), data.begin(), data.end());
622
-
623
- // Pad to 4-byte boundary
624
- while (msg.size() % 4 != 0) {
625
- msg.push_back(0);
626
- }
627
-
628
- int sent = send_udp_data(socket_, msg, config_.server, config_.port);
629
- return sent > 0;
630
- }
631
-
632
- std::optional<std::pair<StunMappedAddress, std::vector<uint8_t>>> TurnClient::receive_data(int timeout_ms) {
633
- if (!is_valid_socket(socket_)) {
634
- return std::nullopt;
635
- }
636
-
637
- Peer sender;
638
- auto data = receive_udp_data(socket_, STUN_MAX_MESSAGE_SIZE, sender, timeout_ms);
639
-
640
- if (data.empty()) {
641
- return std::nullopt;
642
- }
643
-
644
- // Check if it's a STUN message (Data indication)
645
- if (StunMessage::is_stun_message(data)) {
646
- auto msg = StunMessage::deserialize(data);
647
- if (msg && msg->type == StunMessageType::DataIndication) {
648
- auto peer_addr = msg->get_xor_peer_address();
649
- auto payload = msg->get_data();
650
-
651
- if (peer_addr && payload) {
652
- return std::make_pair(*peer_addr, *payload);
653
- }
654
- }
655
- return std::nullopt;
656
- }
657
-
658
- // Check if it's channel data
659
- if (data.size() >= TURN_CHANNEL_HEADER_SIZE) {
660
- uint16_t channel = (static_cast<uint16_t>(data[0]) << 8) | data[1];
661
-
662
- if (channel >= TURN_CHANNEL_MIN && channel <= TURN_CHANNEL_MAX) {
663
- uint16_t length = (static_cast<uint16_t>(data[2]) << 8) | data[3];
664
-
665
- if (data.size() >= TURN_CHANNEL_HEADER_SIZE + length) {
666
- auto peer = get_channel_peer(channel);
667
- if (peer) {
668
- std::vector<uint8_t> payload(data.begin() + TURN_CHANNEL_HEADER_SIZE,
669
- data.begin() + TURN_CHANNEL_HEADER_SIZE + length);
670
- return std::make_pair(*peer, payload);
671
- }
672
- }
673
- }
674
- }
675
-
676
- return std::nullopt;
677
- }
678
-
679
- void TurnClient::set_data_callback(TurnDataCallback callback) {
680
- data_callback_ = std::move(callback);
681
- }
682
-
683
- void TurnClient::set_state_callback(TurnStateCallback callback) {
684
- state_callback_ = std::move(callback);
685
- }
686
-
687
- void TurnClient::process_incoming() {
688
- auto result = receive_data(0); // Non-blocking
689
- if (result && data_callback_) {
690
- data_callback_(result->first, result->second);
691
- }
692
- }
693
-
694
- // ============================================================================
695
- // Refresh Thread
696
- // ============================================================================
697
-
698
- void TurnClient::start_refresh_thread() {
699
- if (refresh_running_) return;
700
-
701
- refresh_running_ = true;
702
- refresh_thread_ = std::thread(&TurnClient::refresh_loop, this);
703
- }
704
-
705
- void TurnClient::stop_refresh_thread() {
706
- refresh_running_ = false;
707
- if (refresh_thread_.joinable()) {
708
- refresh_thread_.join();
709
- }
710
- }
711
-
712
- void TurnClient::refresh_loop() {
713
- LOG_TURN_DEBUG("Refresh thread started");
714
-
715
- while (refresh_running_) {
716
- // Sleep for a bit
717
- for (int i = 0; i < 10 && refresh_running_; i++) {
718
- std::this_thread::sleep_for(std::chrono::seconds(1));
719
- }
720
-
721
- if (!refresh_running_) break;
722
-
723
- // Check if allocation needs refresh (refresh at 80% of lifetime)
724
- if (is_allocated()) {
725
- auto remaining = allocation_.remaining_lifetime();
726
- auto threshold = allocation_.lifetime * 0.2; // Refresh when 20% remaining
727
-
728
- if (remaining <= threshold) {
729
- LOG_TURN_DEBUG("Allocation lifetime low (" << remaining << "s), refreshing");
730
- refresh();
731
- }
732
- }
733
-
734
- // Refresh permissions and channels
735
- {
736
- std::lock_guard<std::mutex> lock(mutex_);
737
-
738
- // Clean up expired permissions
739
- for (auto it = permissions_.begin(); it != permissions_.end();) {
740
- if (it->second.is_expired()) {
741
- it = permissions_.erase(it);
742
- } else {
743
- ++it;
744
- }
745
- }
746
-
747
- // Clean up expired channels
748
- for (auto it = channels_.begin(); it != channels_.end();) {
749
- if (it->second.is_expired()) {
750
- peer_to_channel_.erase(peer_key(it->second.peer_address));
751
- it = channels_.erase(it);
752
- } else {
753
- ++it;
754
- }
755
- }
756
- }
757
- }
758
-
759
- LOG_TURN_DEBUG("Refresh thread stopped");
760
- }
761
-
762
- } // namespace librats