webrtc_multiplayer_peer.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /**************************************************************************/
  2. /* webrtc_multiplayer_peer.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "webrtc_multiplayer_peer.h"
  31. void WebRTCMultiplayerPeer::_bind_methods() {
  32. ClassDB::bind_method(D_METHOD("create_server", "channels_config"), &WebRTCMultiplayerPeer::create_server, DEFVAL(Array()));
  33. ClassDB::bind_method(D_METHOD("create_client", "peer_id", "channels_config"), &WebRTCMultiplayerPeer::create_client, DEFVAL(Array()));
  34. ClassDB::bind_method(D_METHOD("create_mesh", "peer_id", "channels_config"), &WebRTCMultiplayerPeer::create_mesh, DEFVAL(Array()));
  35. ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayerPeer::add_peer, DEFVAL(1));
  36. ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayerPeer::remove_peer);
  37. ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayerPeer::has_peer);
  38. ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebRTCMultiplayerPeer::get_peer);
  39. ClassDB::bind_method(D_METHOD("get_peers"), &WebRTCMultiplayerPeer::get_peers);
  40. }
  41. void WebRTCMultiplayerPeer::set_target_peer(int p_peer_id) {
  42. target_peer = p_peer_id;
  43. }
  44. /* Returns the ID of the MultiplayerPeer who sent the most recent packet: */
  45. int WebRTCMultiplayerPeer::get_packet_peer() const {
  46. return next_packet_peer;
  47. }
  48. int WebRTCMultiplayerPeer::get_packet_channel() const {
  49. return next_packet_channel < CH_RESERVED_MAX ? 0 : next_packet_channel - CH_RESERVED_MAX + 1;
  50. }
  51. MultiplayerPeer::TransferMode WebRTCMultiplayerPeer::get_packet_mode() const {
  52. ERR_FAIL_INDEX_V(next_packet_channel, channels_modes.size(), TRANSFER_MODE_RELIABLE);
  53. return channels_modes.get(next_packet_channel);
  54. }
  55. bool WebRTCMultiplayerPeer::is_server() const {
  56. return unique_id == TARGET_PEER_SERVER;
  57. }
  58. void WebRTCMultiplayerPeer::poll() {
  59. if (peer_map.size() == 0) {
  60. return;
  61. }
  62. List<int> remove;
  63. List<int> add;
  64. for (KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) {
  65. Ref<ConnectedPeer> peer = E.value;
  66. peer->connection->poll();
  67. // Check peer state
  68. switch (peer->connection->get_connection_state()) {
  69. case WebRTCPeerConnection::STATE_NEW:
  70. case WebRTCPeerConnection::STATE_CONNECTING:
  71. // Go to next peer, not ready yet.
  72. continue;
  73. case WebRTCPeerConnection::STATE_CONNECTED:
  74. // Good to go, go ahead and check channel state.
  75. break;
  76. default:
  77. // Peer is closed or in error state. Got to next peer.
  78. remove.push_back(E.key);
  79. continue;
  80. }
  81. // Check channels state
  82. int ready = 0;
  83. for (List<Ref<WebRTCDataChannel>>::Element *C = peer->channels.front(); C && C->get().is_valid(); C = C->next()) {
  84. Ref<WebRTCDataChannel> ch = C->get();
  85. switch (ch->get_ready_state()) {
  86. case WebRTCDataChannel::STATE_CONNECTING:
  87. continue;
  88. case WebRTCDataChannel::STATE_OPEN:
  89. ready++;
  90. continue;
  91. default:
  92. // Channel was closed or in error state, remove peer id.
  93. remove.push_back(E.key);
  94. }
  95. // We got a closed channel break out, the peer will be removed.
  96. break;
  97. }
  98. // This peer has newly connected, and all channels are now open.
  99. if (ready == peer->channels.size() && !peer->connected) {
  100. peer->connected = true;
  101. add.push_back(E.key);
  102. }
  103. }
  104. // Remove disconnected peers
  105. for (int &E : remove) {
  106. remove_peer(E);
  107. if (next_packet_peer == E) {
  108. next_packet_peer = 0;
  109. }
  110. }
  111. // Signal newly connected peers
  112. for (int &E : add) {
  113. // Already connected to server: simply notify new peer.
  114. if (network_mode == MODE_CLIENT) {
  115. ERR_CONTINUE(E != TARGET_PEER_SERVER); // Bug.
  116. // Server connected.
  117. connection_status = CONNECTION_CONNECTED;
  118. emit_signal(SNAME("peer_connected"), TARGET_PEER_SERVER);
  119. } else {
  120. emit_signal(SNAME("peer_connected"), E);
  121. }
  122. }
  123. // Fetch next packet
  124. if (next_packet_peer == 0) {
  125. _find_next_peer();
  126. }
  127. }
  128. void WebRTCMultiplayerPeer::_find_next_peer() {
  129. HashMap<int, Ref<ConnectedPeer>>::Iterator E = peer_map.find(next_packet_peer);
  130. if (E) {
  131. ++E;
  132. }
  133. // After last.
  134. while (E) {
  135. if (!E->value->connected) {
  136. ++E;
  137. continue;
  138. }
  139. int idx = 0;
  140. for (const Ref<WebRTCDataChannel> &F : E->value->channels) {
  141. if (F->get_available_packet_count()) {
  142. next_packet_channel = idx;
  143. next_packet_peer = E->key;
  144. return;
  145. }
  146. idx++;
  147. }
  148. ++E;
  149. }
  150. E = peer_map.begin();
  151. // Before last
  152. while (E) {
  153. if (!E->value->connected) {
  154. ++E;
  155. continue;
  156. }
  157. int idx = 0;
  158. for (const Ref<WebRTCDataChannel> &F : E->value->channels) {
  159. if (F->get_available_packet_count()) {
  160. next_packet_channel = idx;
  161. next_packet_peer = E->key;
  162. return;
  163. }
  164. idx++;
  165. }
  166. if (E->key == (int)next_packet_peer) {
  167. break;
  168. }
  169. ++E;
  170. }
  171. // No packet found
  172. next_packet_channel = 0;
  173. next_packet_peer = 0;
  174. }
  175. MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status() const {
  176. return connection_status;
  177. }
  178. Error WebRTCMultiplayerPeer::create_server(Array p_channels_config) {
  179. return _initialize(1, MODE_SERVER, p_channels_config);
  180. }
  181. Error WebRTCMultiplayerPeer::create_client(int p_self_id, Array p_channels_config) {
  182. ERR_FAIL_COND_V_MSG(p_self_id == 1, ERR_INVALID_PARAMETER, "Clients cannot have ID 1.");
  183. return _initialize(p_self_id, MODE_CLIENT, p_channels_config);
  184. }
  185. Error WebRTCMultiplayerPeer::create_mesh(int p_self_id, Array p_channels_config) {
  186. return _initialize(p_self_id, MODE_MESH, p_channels_config);
  187. }
  188. Error WebRTCMultiplayerPeer::_initialize(int p_self_id, NetworkMode p_mode, Array p_channels_config) {
  189. ERR_FAIL_COND_V(p_self_id < 1 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER);
  190. channels_config.clear();
  191. channels_modes.clear();
  192. channels_modes.push_back(TRANSFER_MODE_RELIABLE);
  193. channels_modes.push_back(TRANSFER_MODE_UNRELIABLE_ORDERED);
  194. channels_modes.push_back(TRANSFER_MODE_UNRELIABLE);
  195. for (int i = 0; i < p_channels_config.size(); i++) {
  196. ERR_FAIL_COND_V_MSG(p_channels_config[i].get_type() != Variant::INT, ERR_INVALID_PARAMETER, "The 'channels_config' array must contain only enum values from 'MultiplayerPeer.TransferMode'");
  197. int mode = p_channels_config[i].operator int();
  198. // Initialize data channel configurations.
  199. Dictionary cfg;
  200. cfg["id"] = CH_RESERVED_MAX + i + 1;
  201. cfg["negotiated"] = true;
  202. cfg["ordered"] = true;
  203. switch (mode) {
  204. case TRANSFER_MODE_UNRELIABLE_ORDERED:
  205. cfg["maxPacketLifetime"] = 1;
  206. break;
  207. case TRANSFER_MODE_UNRELIABLE:
  208. cfg["maxPacketLifetime"] = 1;
  209. cfg["ordered"] = false;
  210. break;
  211. case TRANSFER_MODE_RELIABLE:
  212. break;
  213. default:
  214. ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, vformat("The 'channels_config' array must contain only enum values from 'MultiplayerPeer.TransferMode'. Got: %d", mode));
  215. }
  216. channels_config.push_back(cfg);
  217. channels_modes.push_back((TransferMode)mode);
  218. }
  219. unique_id = p_self_id;
  220. network_mode = p_mode;
  221. // Mesh and server are always connected
  222. if (p_mode != MODE_CLIENT) {
  223. connection_status = CONNECTION_CONNECTED;
  224. } else {
  225. connection_status = CONNECTION_CONNECTING;
  226. }
  227. return OK;
  228. }
  229. bool WebRTCMultiplayerPeer::is_server_relay_supported() const {
  230. return network_mode == MODE_SERVER || network_mode == MODE_CLIENT;
  231. }
  232. int WebRTCMultiplayerPeer::get_unique_id() const {
  233. ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, 1);
  234. return unique_id;
  235. }
  236. void WebRTCMultiplayerPeer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict) {
  237. Array channels;
  238. for (Ref<WebRTCDataChannel> &F : p_connected_peer->channels) {
  239. channels.push_back(F);
  240. }
  241. r_dict["connection"] = p_connected_peer->connection;
  242. r_dict["connected"] = p_connected_peer->connected;
  243. r_dict["channels"] = channels;
  244. }
  245. bool WebRTCMultiplayerPeer::has_peer(int p_peer_id) {
  246. return peer_map.has(p_peer_id);
  247. }
  248. Dictionary WebRTCMultiplayerPeer::get_peer(int p_peer_id) {
  249. ERR_FAIL_COND_V(!peer_map.has(p_peer_id), Dictionary());
  250. Dictionary out;
  251. _peer_to_dict(peer_map[p_peer_id], out);
  252. return out;
  253. }
  254. Dictionary WebRTCMultiplayerPeer::get_peers() {
  255. Dictionary out;
  256. for (const KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) {
  257. Dictionary d;
  258. _peer_to_dict(E.value, d);
  259. out[E.key] = d;
  260. }
  261. return out;
  262. }
  263. Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) {
  264. ERR_FAIL_COND_V(network_mode == MODE_NONE, ERR_UNCONFIGURED);
  265. ERR_FAIL_COND_V(network_mode == MODE_CLIENT && p_peer_id != 1, ERR_INVALID_PARAMETER);
  266. ERR_FAIL_COND_V(network_mode == MODE_SERVER && p_peer_id == 1, ERR_INVALID_PARAMETER);
  267. ERR_FAIL_COND_V(p_peer_id < 1 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER);
  268. ERR_FAIL_COND_V(p_unreliable_lifetime < 0, ERR_INVALID_PARAMETER);
  269. ERR_FAIL_COND_V(is_refusing_new_connections(), ERR_UNAUTHORIZED);
  270. // Peer must be valid, and in new state (to create data channels)
  271. ERR_FAIL_COND_V(p_peer.is_null(), ERR_INVALID_PARAMETER);
  272. ERR_FAIL_COND_V(p_peer->get_connection_state() != WebRTCPeerConnection::STATE_NEW, ERR_INVALID_PARAMETER);
  273. Ref<ConnectedPeer> peer = memnew(ConnectedPeer);
  274. peer->connection = p_peer;
  275. // Initialize data channels
  276. Dictionary cfg;
  277. cfg["negotiated"] = true;
  278. cfg["ordered"] = true;
  279. cfg["id"] = 1;
  280. peer->channels.get(CH_RELIABLE) = p_peer->create_data_channel("reliable", cfg);
  281. ERR_FAIL_COND_V(peer->channels.get(CH_RELIABLE).is_null(), FAILED);
  282. cfg["id"] = 2;
  283. cfg["maxPacketLifetime"] = p_unreliable_lifetime;
  284. peer->channels.get(CH_ORDERED) = p_peer->create_data_channel("ordered", cfg);
  285. ERR_FAIL_COND_V(peer->channels.get(CH_ORDERED).is_null(), FAILED);
  286. cfg["id"] = 3;
  287. cfg["ordered"] = false;
  288. peer->channels.get(CH_UNRELIABLE) = p_peer->create_data_channel("unreliable", cfg);
  289. ERR_FAIL_COND_V(peer->channels.get(CH_UNRELIABLE).is_null(), FAILED);
  290. for (const Dictionary &dict : channels_config) {
  291. Ref<WebRTCDataChannel> ch = p_peer->create_data_channel(String::num_int64(dict["id"]), dict);
  292. ERR_FAIL_COND_V(ch.is_null(), FAILED);
  293. peer->channels.push_back(ch);
  294. }
  295. peer_map[p_peer_id] = peer; // add the new peer connection to the peer_map
  296. return OK;
  297. }
  298. void WebRTCMultiplayerPeer::remove_peer(int p_peer_id) {
  299. ERR_FAIL_COND(!peer_map.has(p_peer_id));
  300. Ref<ConnectedPeer> peer = peer_map[p_peer_id];
  301. peer_map.erase(p_peer_id);
  302. if (peer->connected) {
  303. peer->connected = false;
  304. emit_signal(SNAME("peer_disconnected"), p_peer_id);
  305. if (network_mode == MODE_CLIENT && p_peer_id == TARGET_PEER_SERVER) {
  306. connection_status = CONNECTION_DISCONNECTED;
  307. }
  308. }
  309. }
  310. void WebRTCMultiplayerPeer::disconnect_peer(int p_peer_id, bool p_force) {
  311. ERR_FAIL_COND(!peer_map.has(p_peer_id));
  312. if (p_force) {
  313. peer_map.erase(p_peer_id);
  314. if (network_mode == MODE_CLIENT && p_peer_id == TARGET_PEER_SERVER) {
  315. connection_status = CONNECTION_DISCONNECTED;
  316. }
  317. } else {
  318. peer_map[p_peer_id]->connection->close(); // Will be removed during next poll.
  319. }
  320. }
  321. Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
  322. // Peer not available
  323. if (next_packet_peer == 0 || !peer_map.has(next_packet_peer)) {
  324. _find_next_peer();
  325. ERR_FAIL_V(ERR_UNAVAILABLE);
  326. }
  327. for (Ref<WebRTCDataChannel> &E : peer_map[next_packet_peer]->channels) {
  328. if (E->get_available_packet_count()) {
  329. Error err = E->get_packet(r_buffer, r_buffer_size);
  330. _find_next_peer();
  331. return err;
  332. }
  333. }
  334. // Channels for that peer were empty. Bug?
  335. _find_next_peer();
  336. ERR_FAIL_V(ERR_BUG);
  337. }
  338. Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
  339. ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, ERR_UNCONFIGURED);
  340. int ch = get_transfer_channel();
  341. if (ch == 0) {
  342. switch (get_transfer_mode()) {
  343. case TRANSFER_MODE_RELIABLE:
  344. ch = CH_RELIABLE;
  345. break;
  346. case TRANSFER_MODE_UNRELIABLE_ORDERED:
  347. ch = CH_ORDERED;
  348. break;
  349. case TRANSFER_MODE_UNRELIABLE:
  350. ch = CH_UNRELIABLE;
  351. break;
  352. }
  353. } else {
  354. ch += CH_RESERVED_MAX - 1;
  355. }
  356. if (target_peer > 0) {
  357. HashMap<int, Ref<ConnectedPeer>>::Iterator E = peer_map.find(target_peer);
  358. ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, "Invalid target peer: " + itos(target_peer) + ".");
  359. ERR_FAIL_COND_V_MSG(E->value->channels.size() <= ch, ERR_INVALID_PARAMETER, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value->channels.size()));
  360. ERR_FAIL_COND_V(E->value->channels.get(ch).is_null(), ERR_BUG);
  361. return E->value->channels.get(ch)->put_packet(p_buffer, p_buffer_size);
  362. } else {
  363. int exclude = -target_peer;
  364. for (KeyValue<int, Ref<ConnectedPeer>> &F : peer_map) {
  365. // Exclude packet. If target_peer == 0 then don't exclude any packets
  366. if (target_peer != 0 && F.key == exclude) {
  367. continue;
  368. }
  369. ERR_CONTINUE_MSG(F.value->channels.size() <= ch, vformat("Unable to send packet on channel %d, max channels: %d", ch, F.value->channels.size()));
  370. ERR_CONTINUE(F.value->channels.get(ch).is_null());
  371. F.value->channels.get(ch)->put_packet(p_buffer, p_buffer_size);
  372. }
  373. }
  374. return OK;
  375. }
  376. int WebRTCMultiplayerPeer::get_available_packet_count() const {
  377. if (next_packet_peer == 0) {
  378. return 0; // To be sure next call to get_packet works if size > 0 .
  379. }
  380. int size = 0;
  381. for (const KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) {
  382. if (!E.value->connected) {
  383. continue;
  384. }
  385. for (const Ref<WebRTCDataChannel> &F : E.value->channels) {
  386. size += F->get_available_packet_count();
  387. }
  388. }
  389. return size;
  390. }
  391. int WebRTCMultiplayerPeer::get_max_packet_size() const {
  392. return 1200;
  393. }
  394. void WebRTCMultiplayerPeer::close() {
  395. peer_map.clear();
  396. channels_config.clear();
  397. unique_id = 0;
  398. next_packet_peer = 0;
  399. next_packet_channel = 0;
  400. target_peer = 0;
  401. network_mode = MODE_NONE;
  402. connection_status = CONNECTION_DISCONNECTED;
  403. }
  404. WebRTCMultiplayerPeer::~WebRTCMultiplayerPeer() {
  405. close();
  406. }