RigsofRods
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Network.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5  Copyright 2013-2016 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #ifdef USE_SOCKETW
23 
24 #include "Network.h"
25 
26 #include "Application.h"
27 #include "ChatSystem.h"
28 #include "Console.h"
29 #include "ErrorUtils.h"
30 #include "GameContext.h"
31 #include "GUIManager.h"
32 #include "GUI_TopMenubar.h"
33 #include "Language.h"
34 #include "RoRVersion.h"
35 #include "ScriptEngine.h"
36 #include "Utils.h"
37 
38 #include <Ogre.h>
39 #include <SocketW.h>
40 
41 #include <algorithm>
42 #include <chrono>
43 #include <cstring>
44 
45 using namespace RoR;
46 
47 static Ogre::ColourValue MP_COLORS[] = // Classic RoR multiplayer colors
48 {
49  Ogre::ColourValue(0.0, 0.8, 0.0),
50  Ogre::ColourValue(0.0, 0.4, 0.701960784314),
51  Ogre::ColourValue(1.0, 0.501960784314, 0.0),
52  Ogre::ColourValue(1.0, 0.8, 0.0),
53  //Ogre::ColourValue(0.2, 0.0, 0.6),
54  //Ogre::ColourValue(0.6, 0.0, 0.6),
55  Ogre::ColourValue(0.8, 1.0, 0.0),
56  Ogre::ColourValue(1.0, 0.0, 0.0),
57  Ogre::ColourValue(0.501960784314, 0.501960784314, 0.501960784314),
58  Ogre::ColourValue(0.0, 0.560784313725, 0.0),
59  //Ogre::ColourValue(0.0, 0.282352941176, 0.490196078431),
60  Ogre::ColourValue(0.701960784314, 0.352941176471, 0.0),
61  Ogre::ColourValue(0.701960784314, 0.560784313725, 0.0),
62  //Ogre::ColourValue(0.419607843137, 0.0, 0.419607843137),
63  Ogre::ColourValue(0.560784313725, 0.701960784314, 0.0),
64  Ogre::ColourValue(0.701960784314, 0.0, 0.0),
65  Ogre::ColourValue(0.745098039216, 0.745098039216, 0.745098039216),
66  Ogre::ColourValue(0.501960784314, 1.0, 0.501960784314),
67  Ogre::ColourValue(0.501960784314, 0.788235294118, 1.0),
68  Ogre::ColourValue(1.0, 0.752941176471, 0.501960784314),
69  Ogre::ColourValue(1.0, 0.901960784314, 0.501960784314),
70  Ogre::ColourValue(0.666666666667, 0.501960784314, 1.0),
71  Ogre::ColourValue(0.933333333333, 0.0, 0.8),
72  Ogre::ColourValue(1.0, 0.501960784314, 0.501960784314),
73  Ogre::ColourValue(0.4, 0.4, 0.0),
74  Ogre::ColourValue(1.0, 0.749019607843, 1.0),
75  Ogre::ColourValue(0.0, 1.0, 0.8),
76  Ogre::ColourValue(0.8, 0.4, 0.6),
77  Ogre::ColourValue(0.6, 0.6, 0.0),
78 };
79 
80 using namespace RoRnet;
81 
82 static const unsigned int m_packet_buffer_size = 20;
83 
84 #define LOG_THREAD(_MSG_) { std::stringstream s; s << _MSG_ << " (Thread ID: " << std::this_thread::get_id() << ")"; LOG(s.str()); }
85 #define LOGSTREAM Ogre::LogManager().getSingleton().stream()
86 
87 void Network::PushNetMessage(MsgType type, std::string const & message)
88 {
89  Message m(type);
90  m.description = message;
92 }
93 
94 Ogre::ColourValue Network::GetPlayerColor(int color_num)
95 {
96  int numColours = sizeof(MP_COLORS) / sizeof(Ogre::ColourValue);
97  if (color_num < 0 || color_num >= numColours)
98  return Ogre::ColourValue::White;
99 
100  return MP_COLORS[color_num];
101 }
102 
103 // Internal helper
104 void DebugPacket(const char *name, RoRnet::Header *header, char *buffer)
105 {
106  std::stringstream msg;
107  msg << "++ " << name << ": " << header->source << ", " << header->streamid
108  << ", "<< header->command << ", " << header->size << ", hash: " << HashData(buffer, header->size);
109  LOG(msg.str());
110 }
111 
112 void Network::SetNetQuality(int quality)
113 {
114  m_net_quality = quality;
115 }
116 
118 {
119  return m_net_quality;
120 }
121 
123 {
124  return m_uid;
125 }
126 
127 bool Network::SendMessageRaw(char *buffer, int msgsize)
128 {
129  SWBaseSocket::SWBaseError error;
130 
131  if (m_socket.fsend(buffer, msgsize, &error) < msgsize)
132  {
133  LOG("NET send error: " + error.get_error());
134  return false;
135  }
136 
137  return true;
138 }
139 
140 bool Network::SendNetMessage(int type, unsigned int streamid, int len, char* content)
141 {
142  RoRnet::Header head;
143  memset(&head, 0, sizeof(RoRnet::Header));
144  head.command = type;
145  head.source = m_uid;
146  head.size = len;
147  head.streamid = streamid;
148 
149  const int msgsize = sizeof(RoRnet::Header) + len;
150 
151  if (msgsize >= RORNET_MAX_MESSAGE_LENGTH)
152  {
153  return false;
154  }
155 
156  char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
157  memcpy(buffer, (char *)&head, sizeof(RoRnet::Header));
158  memcpy(buffer + sizeof(RoRnet::Header), content, len);
159 
160  return SendMessageRaw(buffer, msgsize);
161 }
162 
163 void Network::QueueStreamData(RoRnet::Header &header, char *buffer, size_t buffer_len)
164 {
165  NetRecvPacket packet;
166  packet.header = header;
167  memcpy(packet.buffer, buffer, std::min(buffer_len, size_t(RORNET_MAX_MESSAGE_LENGTH)));
168 
169  std::lock_guard<std::mutex> lock(m_recv_packetqueue_mutex);
170  m_recv_packet_buffer.push_back(packet);
171 }
172 
173 int Network::ReceiveMessage(RoRnet::Header *head, char* content, int bufferlen)
174 {
175  SWBaseSocket::SWBaseError error;
176 
177 #ifdef DEBUG
178  LOG_THREAD("[RoR|Networking] ReceiveMessage() waiting...");
179 #endif //DEBUG
180 
181  if (m_socket.frecv((char*)head, sizeof(RoRnet::Header), &error) < sizeof(RoRnet::Header))
182  {
183  LOG("NET receive error 1: " + error.get_error());
184  return -1;
185  }
186 
187 #ifdef DEBUG
188  LOG_THREAD("[RoR|Networking] ReceiveMessage() header received");
189 #endif //DEBUG
190 
191  if (head->size > uint32_t(bufferlen))
192  {
193  return -3;
194  }
195 
196  if (head->size > 0)
197  {
198  // Read the packet content
199  std::memset(content, 0, bufferlen);
200  if (m_socket.frecv(content, head->size, &error) < static_cast<int>(head->size))
201  {
202  LOG_THREAD("NET receive error 2: "+ error.get_error());
203  return -1;
204  }
205  }
206 
207 #ifdef DEBUG
208  LOG_THREAD("[RoR|Networking] ReceiveMessage() body received");
209 #endif //DEBUG
210 
211  return 0;
212 }
213 
215 {
216  LOG("[RoR|Networking] SendThread started");
217  while (!m_shutdown)
218  {
219  NetSendPacket packet;
220  {
221  std::unique_lock<std::mutex> queue_lock(m_send_packetqueue_mutex);
222  while (m_send_packet_buffer.empty() && !m_shutdown)
223  {
224  m_send_packet_available_cv.wait(queue_lock);
225  }
226  if (m_shutdown)
227  {
228  break;
229  }
230  packet = m_send_packet_buffer.front();
231  m_send_packet_buffer.pop_front();
232  }
233  SendMessageRaw(packet.buffer, packet.size);
234  }
235  LOG("[RoR|Networking] SendThread stopped");
236 }
237 
239 {
240  LOG_THREAD("[RoR|Networking] RecvThread starting...");
241 
242  RoRnet::Header header;
243 
244  char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
245 
246  while (!m_shutdown)
247  {
248  int err = ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH);
249  //LOG("Received data: " + TOSTRING(header.command) + ", source: " + TOSTRING(header.source) + ":" + TOSTRING(header.streamid) + ", size: " + TOSTRING(header.size));
250  if (err != 0)
251  {
252  LOG_THREAD("[RoR|Networking] RecvThread: Error while receiving data: " + TOSTRING(err));
253  m_shutdown = true; // Atomic; instruct sender thread to stop
254  PushNetMessage(MSG_NET_RECV_ERROR, _LC("Network", "Error receiving data from network"));
255  continue; // Stop receiving data
256  }
257 
258  if (header.command == MSG2_STREAM_REGISTER)
259  {
260  if (header.source == m_uid)
261  continue;
262 
264 
265  LOG(" * received stream registration: " + TOSTRING(header.source) + ": " + TOSTRING(header.streamid) + ", type: " + TOSTRING(reg->type));
266  }
267  else if (header.command == MSG2_STREAM_REGISTER_RESULT)
268  {
270  LOG(" * received stream registration result: " + TOSTRING(header.source) + ": " + TOSTRING(header.streamid) + ", status: " + TOSTRING(reg->status));
271  }
272  else if (header.command == MSG2_STREAM_UNREGISTER)
273  {
274  LOG(" * received stream deregistration: " + TOSTRING(header.source) + ": " + TOSTRING(header.streamid));
275  }
276  else if (header.command == MSG2_UTF8_CHAT || header.command == MSG2_UTF8_PRIVCHAT)
277  {
278  // Chat message
279  }
280  else if (header.command == MSG2_NETQUALITY && header.source == -1)
281  {
282  if (header.size != sizeof(int))
283  {
284  continue;
285  }
286  int quality = *(int *)buffer;
287  SetNetQuality(quality);
288  continue;
289  }
290  else if (header.command == MSG2_USER_LEAVE)
291  {
292  if (header.source == m_uid)
293  {
294  m_shutdown = true; // Atomic; stop sending/receiving data - server closes the connection quickly after kick.
295 
296  std::stringstream msg;
297  msg << _L("disconnected: remote side closed the connection");
298  msg << " ** ";
299  msg << buffer;
300 
301  bool was_kick = (std::strstr(buffer, "disconnected on request") == nullptr); // FIXME: Add a reason code to MSG2_USER_LEAVE, this is ugly!
302  PushNetMessage((was_kick) ? MSG_NET_SERVER_KICK : MSG_NET_USER_DISCONNECT, msg.str());
304 
306  }
307  else
308  {
309  std::lock_guard<std::mutex> lock(m_users_mutex);
310  auto user = std::find_if(m_users.begin(), m_users.end(), [header](const RoRnet::UserInfo& u) { return static_cast<int>(u.uniqueid) == header.source; });
311  if (user != m_users.end())
312  {
313  // Console is now threadsafe, no need to send fake chatmessages to ourselves
314  Str<300> text;
315  text << _L("left the game");
318  LOG_THREAD(text);
319 
320  // Erase matching peer options
321  int peeropt_offset = (int)std::distance(m_users.begin(), user);
322  auto peeropt_itor = m_users_peeropts.begin() + peeropt_offset;
323  m_users_peeropts.erase(peeropt_itor);
324 
325  m_disconnected_users.push_back(*user); // Copy
326  m_users.erase(user);
327  }
328  }
329  }
330  else if (header.command == MSG2_USER_INFO || header.command == MSG2_USER_JOIN)
331  {
332  if (header.source == m_uid)
333  {
334  std::lock_guard<std::mutex> lock(m_userdata_mutex);
335  memcpy(&m_userdata, buffer, sizeof(RoRnet::UserInfo));
336  m_authlevel = m_userdata.authstatus;
337  m_username = std::string(m_userdata.username);
339  // TODO: Update the global variable 'mp_player_name' in a threadsafe way.
340  }
341  else
342  {
343  RoRnet::UserInfo user_info;
344  if (!GetUserInfo(header.source, user_info)) // Check that user doesn't exist yet.
345  {
346  memcpy(&user_info, buffer, sizeof(RoRnet::UserInfo));
347  Str<300> text;
348  if (user_info.authstatus != 0) // Show nothing for guests (no special authorization)
349  {
350  text << "(" << UserAuthToStringShort(user_info) << ") ";
351  }
352  text << _L("joined the game");
353 
354  // NB: Console is threadsafe
356  user_info.uniqueid, Console::CONSOLE_SYSTEM_NOTICE, text.ToCStr());
358  // Lock and update userlist
359  std::lock_guard<std::mutex> lock(m_users_mutex);
360  m_users.push_back(user_info);
361  m_users_peeropts.push_back(BitMask_t(0));
362  } // End of lock scope
363  }
364  continue;
365  }
366  else if (header.command == MSG2_GAME_CMD)
367  {
368 #ifdef USE_ANGELSCRIPT
369  App::GetScriptEngine()->queueStringForExecution(Ogre::String(buffer));
370 #endif // USE_ANGELSCRIPT
371  continue;
372  }
373  //DebugPacket("recv", &header, buffer);
374 
375  QueueStreamData(header, buffer, RORNET_MAX_MESSAGE_LENGTH);
376  }
377 
378  LOG_THREAD("[RoR|Networking] RecvThread stopped");
379 }
380 
381 
382 void Network::CouldNotConnect(std::string const & msg, bool close_socket /*= true*/)
383 {
384  RoR::LogFormat("[RoR|Networking] Failed to connect to server [%s:%d], message: %s", m_net_host.c_str(), m_net_port, msg.c_str());
385  PushNetMessage(MSG_NET_CONNECT_FAILURE, msg);
386 
387  if (close_socket)
388  {
389  m_socket.set_timeout(1, 0);
390  m_socket.disconnect();
391  }
392 }
393 
395 {
396  // Shadow vars for threaded access
397  m_username = App::mp_player_name->getStr();
398  m_token = App::mp_player_token->getStr();
399  m_net_host = App::mp_server_host->getStr();
400  m_net_port = App::mp_server_port->getInt();
401  m_password = App::mp_server_password->getStr();
402 
403  try
404  {
405  m_connect_thread = std::thread(&Network::ConnectThread, this);
406  App::mp_state->setVal((int)MpState::CONNECTING); // Mark connect thread as started
407  PushNetMessage(MSG_NET_CONNECT_STARTED, _LC("Network", "Starting..."));
408  return true;
409  }
410  catch (std::exception& e)
411  {
413  PushNetMessage(MSG_NET_CONNECT_FAILURE, _L("Failed to launch connection thread"));
414  RoR::LogFormat("[RoR|Networking] Failed to launch connection thread, message: %s", e.what());
415  return false;
416  }
417 }
418 
420 {
422 
423  if (m_connect_thread.joinable())
424  m_connect_thread.join(); // Clean up
425 }
426 
428 {
429  RoR::LogFormat("[RoR|Networking] Trying to join server '%s' on port '%d' ...", m_net_host.c_str(), m_net_port);
430 
431  SWBaseSocket::SWBaseError error;
432 
433  PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Estabilishing connection..."));
434  m_socket = SWInetSocket();
435  m_socket.set_timeout(10, 0);
436  m_socket.connect(m_net_port, m_net_host, &error);
437  if (error != SWBaseSocket::ok)
438  {
439  CouldNotConnect(_L("Could not create connection"), false);
440  return false;
441  }
442 
443  PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Getting server info..."));
444  if (!SendNetMessage(MSG2_HELLO, 0, (int)strlen(RORNET_VERSION), (char *)RORNET_VERSION))
445  {
446  CouldNotConnect(_L("Establishing network session: error sending hello"));
447  return false;
448  }
449 
450  RoRnet::Header header;
451  char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
452 
453  // Receive server (rornet protocol) version
454  if (ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH))
455  {
456  CouldNotConnect(_L("Establishing network session: error getting server version"));
457  return false;
458  }
459  if (header.command == MSG2_WRONG_VER_LEGACY) // Pre-RoRnet_2.40 server
460  {
462  memcpy(&info, buffer, sizeof(RoRnet::LegacyServerInfo));
463  std::string format_str = _L("Establishing network session: wrong server version, you are using version '%s' and the server is using '%s'");
464  const char* server_ver = (info.protocolversion[0] != 0) ? info.protocolversion : "~ RoRnet_2.38 or earlier (not detected) ~";
465  CouldNotConnect(fmt::format(format_str.c_str(), RORNET_VERSION, server_ver));
466  return false;
467  }
468  if (header.command == MSG2_WRONG_VER)
469  {
470  CouldNotConnect(_L("server uses a different protocol version"));
471  return false;
472  }
473  if (header.command != MSG2_HELLO)
474  {
475  CouldNotConnect(_L("Establishing network session: error getting server hello"));
476  return false;
477  }
478 
479  // Save server settings
480  memcpy(&m_server_settings, buffer, sizeof(RoRnet::ServerInfo));
481 
482  if (strncmp(m_server_settings.protocolversion, RORNET_VERSION, strlen(RORNET_VERSION)))
483  {
484  std::string formatstr = _L("Establishing network session: wrong server version, you are using version '%s' and the server is using '%s'");
485  CouldNotConnect(fmt::format(formatstr, RORNET_VERSION, m_server_settings.protocolversion));
486  return false;
487  }
488 
489  PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Authorizing..."));
490 
491  // First handshake done, increase the timeout, important!
492  m_socket.set_timeout(0, 0);
493 
494  // Construct user credentials
496  memset(&c, 0, sizeof(RoRnet::UserInfo));
497  // Cut off the UTF string on the highest level, otherwise you will break UTF info
498  strncpy(c.username, m_username.substr(0, RORNET_MAX_USERNAME_LEN).c_str(), RORNET_MAX_USERNAME_LEN);
499  strncpy(c.serverpassword, Sha1Hash(m_password).c_str(), size_t(40));
500  strncpy(c.usertoken, Sha1Hash(m_token).c_str(), size_t(40));
502  strncpy(c.clientname, "RoR", 10);
503  std::string language = App::app_language->getStr().substr(0, 2);
504  std::string country = App::app_country->getStr().substr(0, 2);
505  strncpy(c.language, (language + std::string("_") + country).c_str(), 5);
506  strcpy(c.sessiontype, "normal");
507  if (!SendNetMessage(MSG2_USER_INFO, 0, sizeof(RoRnet::UserInfo), (char*)&c))
508  {
509  CouldNotConnect(_L("Establishing network session: error sending user info"));
510  return false;
511  }
512 
513  // Getting authorization
514  if (ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH))
515  {
516  CouldNotConnect(_L("Establishing network session: error getting server authorization"));
517  return false;
518  }
519 
520  if (header.command==MSG2_FULL)
521  {
522  CouldNotConnect(_L("Establishing network session: sorry, server has too many players"));
523  return false;
524  }
525  else if (header.command==MSG2_BANNED)
526  {
527  // Do NOT `disconnect()` the m_socket in this case - causes SocketW to terminate RoR.
528  CouldNotConnect(_L("Establishing network session: sorry, you are banned!"), /*close_socket=*/false);
529  return false;
530  }
531  else if (header.command==MSG2_WRONG_PW)
532  {
533  CouldNotConnect(_L("Establishing network session: sorry, wrong password!"));
534  return false;
535  }
536  else if (header.command==MSG2_WRONG_VER)
537  {
538  CouldNotConnect(_L("Establishing network session: sorry, wrong protocol version!"));
539  return false;
540  }
541 
542  if (header.command!=MSG2_WELCOME)
543  {
544  CouldNotConnect(_L("Establishing network session: sorry, unknown server response"));
545  return false;
546  }
547 
548  PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Finishing..."));
549 
550  m_uid = header.source;
551 
552  // we get our userdata back
553  memcpy(&m_userdata, buffer, std::min<int>(sizeof(RoRnet::UserInfo), header.size));
554 
555  m_shutdown = false;
556 
557  LOG("[RoR|Networking] Connect(): Creating Send/Recv threads");
558  m_send_thread = std::thread(&Network::SendThread, this);
559  m_recv_thread = std::thread(&Network::RecvThread, this);
560  PushNetMessage(MSG_NET_CONNECT_SUCCESS, "");
561 
562  return true;
563 }
564 
566 {
567  LOG("[RoR|Networking] Disconnect() disconnecting...");
568  bool is_clean_disconnect = !m_shutdown; // Hacky detection of invalid network state
569 
570  m_shutdown = true; // Instruct Send/Recv threads to shut down.
571 
572  m_send_packet_available_cv.notify_one();
573 
574  m_send_thread.join();
575  LOG("[RoR|Networking] Disconnect() sender thread cleaned up");
576 
577  m_socket.set_timeout(1, 0);
578 
579  if (is_clean_disconnect)
580  {
581  SendNetMessage(MSG2_USER_LEAVE, 0, 0, 0);
582  }
583 
584  m_recv_thread.join();
585  LOG("[RoR|Networking] Disconnect() receiver thread cleaned up");
586 
587  if (is_clean_disconnect)
588  {
589  m_socket.disconnect();
590  }
591  else
592  {
593  m_socket.close_fd();
594  }
595 
596  SetNetQuality(0);
597  m_users.clear();
598  m_disconnected_users.clear();
599  m_recv_packet_buffer.clear();
600  m_send_packet_buffer.clear();
601  App::GetConsole()->doCommand("clear net");
602 
603  m_shutdown = false;
605 
606  LOG("[RoR|Networking] Disconnect() done");
607 }
608 
609 void Network::AddPacket(int streamid, int type, int len, const char *content)
610 {
611  const auto max_len = RORNET_MAX_MESSAGE_LENGTH - sizeof(RoRnet::Header);
612  if (len > max_len)
613  {
614  LOGSTREAM << "[RoR|Networking] Discarding network packet (StreamID: "
615  <<streamid<<", Type: "<<type<<"), length is " << len << ", max is " << max_len;
616  return;
617  }
618 
619  NetSendPacket packet;
620  memset(&packet, 0, sizeof(NetSendPacket));
621 
622  char *buffer = (char*)(packet.buffer);
623 
624  RoRnet::Header *head = (RoRnet::Header *)buffer;
625  head->command = type;
626  head->source = m_uid;
627  head->size = len;
628  head->streamid = streamid;
629 
630  // then copy the contents
631  char *bufferContent = (char *)(buffer + sizeof(RoRnet::Header));
632  memcpy(bufferContent, content, len);
633 
634  // record the packet size
635  packet.size = len + sizeof(RoRnet::Header);
636 
637  { // Lock scope
638  std::lock_guard<std::mutex> lock(m_send_packetqueue_mutex);
639  if (type == MSG2_STREAM_DATA_DISCARDABLE)
640  {
641  if (m_send_packet_buffer.size() > m_packet_buffer_size)
642  {
643  // buffer full, discard unimportant data packets
644  return;
645  }
646  auto search = std::find_if(m_send_packet_buffer.begin(), m_send_packet_buffer.end(),
647  [&](const NetSendPacket& p) { return !memcmp(packet.buffer, p.buffer, sizeof(RoRnet::Header)); });
648  if (search != m_send_packet_buffer.end())
649  {
650  // Found outdated discardable streamdata -> replace it
651  (*search) = packet;
652  m_send_packet_available_cv.notify_one();
653  return;
654  }
655  }
656  //DebugPacket("send", head, buffer);
657  m_send_packet_buffer.push_back(packet);
658  }
659 
660  m_send_packet_available_cv.notify_one();
661 }
662 
664 {
665  reg->origin_sourceid = m_uid;
666  reg->origin_streamid = m_stream_id;
667  reg->status = 0;
668 
669  AddPacket(m_stream_id, MSG2_STREAM_REGISTER, size, (char*)reg);
670  LOG("adding local stream: " + TOSTRING(m_uid) + ":"+ TOSTRING(m_stream_id) + ", type: " + TOSTRING(reg->type));
671 
672  m_stream_id++;
673 }
674 
675 std::vector<NetRecvPacket> Network::GetIncomingStreamData()
676 {
677  std::lock_guard<std::mutex> lock(m_recv_packetqueue_mutex);
678  std::vector<NetRecvPacket> buf_copy = m_recv_packet_buffer;
679  m_recv_packet_buffer.clear();
680  return buf_copy;
681 }
682 
684 {
685  return m_server_settings.terrain;
686 }
687 
689 {
690  std::lock_guard<std::mutex> lock(m_userdata_mutex);
691  return m_userdata.colournum;
692 }
693 
694 std::string Network::GetUsername()
695 {
696  std::lock_guard<std::mutex> lock(m_userdata_mutex);
697  return m_username;
698 }
699 
701 {
702  std::lock_guard<std::mutex> lock(m_userdata_mutex);
703  return m_userdata;
704 }
705 
706 std::vector<RoRnet::UserInfo> Network::GetUserInfos()
707 {
708  std::lock_guard<std::mutex> lock(m_users_mutex);
709  return m_users;
710 }
711 
712 std::vector<BitMask_t> Network::GetAllUsersPeerOpts()
713 {
714  std::lock_guard<std::mutex> lock(m_users_mutex);
715  return m_users_peeropts;
716 }
717 
719 {
720  std::lock_guard<std::mutex> lock(m_users_mutex);
721  for (RoRnet::UserInfo user : m_users)
722  {
723  if ((int)user.uniqueid == uid)
724  {
725  result = user;
726  return true;
727  }
728  }
729  return false;
730 }
731 
732 bool Network::GetUserPeerOpts(int uid, BitMask_t& result)
733 {
734  std::lock_guard<std::mutex> lock(m_users_mutex);
735  for (size_t i = 0; i < m_users.size(); i++)
736  {
737  if (static_cast<int>(m_users[i].uniqueid) == uid)
738  {
739  result = m_users_peeropts[i];
740  return true;
741  }
742  }
743  return false;
744 }
745 
747 {
748  std::lock_guard<std::mutex> lock(m_users_mutex);
749  for (RoRnet::UserInfo user : m_disconnected_users)
750  {
751  if ((int)user.uniqueid == uid)
752  {
753  result = user;
754  return true;
755  }
756  }
757  return false;
758 }
759 
761 {
762  RoRnet::UserInfo tmp;
763 
764  // Try remote users
765  if (GetUserInfo(uid, tmp))
766  {
767  result = tmp;
768  return true;
769  }
770 
771  // Try local user
772  tmp = GetLocalUserData();
773  if (tmp.uniqueid == uid)
774  {
775  result = tmp;
776  return true;
777  }
778 
779  return false;
780 }
781 
782 bool Network::FindUserInfo(std::string const& username, RoRnet::UserInfo &result)
783 {
784  std::lock_guard<std::mutex> lock(m_users_mutex);
785  for (RoRnet::UserInfo user : m_users)
786  {
787  if (user.username == username)
788  {
789  result = user;
790  return true;
791  }
792  }
793  return false;
794 }
795 
796 
798 {
799  std::lock_guard<std::mutex> lock(m_users_mutex);
800 
801  const bool peeropts_sane = m_users.size() == m_users_peeropts.size();
802  ROR_ASSERT(peeropts_sane);
803  if (!peeropts_sane) return;
804 
805  for (size_t i = 0; i < m_users.size(); i++)
806  {
807  if (static_cast<int>(m_users[i].uniqueid) == rq->por_uid)
808  {
809  BITMASK_SET_1(m_users_peeropts[i], rq->por_peeropts);
810  }
811  }
812 }
813 
815 {
816  std::lock_guard<std::mutex> lock(m_users_mutex);
817 
818  const bool peeropts_sane = m_users.size() == m_users_peeropts.size();
819  ROR_ASSERT(peeropts_sane);
820  if (!peeropts_sane) return;
821 
822  for (size_t i = 0; i < m_users.size(); i++)
823  {
824  if (static_cast<int>(m_users[i].uniqueid) == rq->por_uid)
825  {
826  BITMASK_SET_0(m_users_peeropts[i], rq->por_peeropts);
827  }
828  }
829 }
830 
831 void Network::BroadcastChatMsg(const char* msg)
832 {
833  AddPacket(m_stream_id, RoRnet::MSG2_UTF8_CHAT, (int)std::strlen(msg), msg);
834 }
835 
836 void Network::WhisperChatMsg(RoRnet::UserInfo const& user, const char* msg)
837 {
838  // Prepare buffer
839  char payload[RORNET_MAX_MESSAGE_LENGTH - sizeof(RoRnet::Header)];
840  size_t payload_len = 0;
841 
842  // Write client ID
843  std::memcpy(payload, &user.uniqueid, sizeof(user.uniqueid));
844  payload_len += sizeof(user.uniqueid);
845 
846  // Write text
847  std::strncpy(payload + payload_len, msg, sizeof(payload) - payload_len);
848  payload_len += std::strlen(msg);
849 
850  // Queue packet
851  AddPacket(m_stream_id, RoRnet::MSG2_UTF8_PRIVCHAT, (int)payload_len, msg);
852 }
853 
855 {
856  if (user.authstatus & AUTH_ADMIN) { return _LC("NetUserAuth", "Admin"); }
857  else if (user.authstatus & AUTH_MOD) { return _LC("NetUserAuth", "Mod"); }
858  else if (user.authstatus & AUTH_BOT) { return _LC("NetUserAuth", "Bot"); }
859  else if (user.authstatus & AUTH_RANKED) { return _LC("NetUserAuth", "Ranked"); }
860  else if (user.authstatus & AUTH_BANNED) { return _LC("NetUserAuth", "Banned"); }
861  else { return _LC("NetUserAuth", "Guest"); }
862 }
863 
865 {
866  if (user.authstatus & AUTH_ADMIN) { return _LC("NetUserAuth","Server Administrator"); }
867  else if (user.authstatus & AUTH_MOD) { return _LC("NetUserAuth","Server Moderator"); }
868  else if (user.authstatus & AUTH_BOT) { return _LC("NetUserAuth","Bot"); }
869  else if (user.authstatus & AUTH_RANKED) { return _LC("NetUserAuth","Ranked user"); }
870  else if (user.authstatus & AUTH_BANNED) { return _LC("NetUserAuth","Banned user"); }
871  else { return _LC("NetUserAuth","Guest"); }
872 }
873 
874 #endif // USE_SOCKETW
ROR_ASSERT
#define ROR_ASSERT(_EXPR)
Definition: Application.h:40
GameContext.h
Game state manager and message-queue provider.
RoR::Network::Disconnect
void Disconnect()
Definition: Network.cpp:565
RoRnet::MSG2_STREAM_UNREGISTER
@ MSG2_STREAM_UNREGISTER
remove stream
Definition: RoRnet.h:65
RoR::Network::GetUserInfos
std::vector< RoRnet::UserInfo > GetUserInfos()
Definition: Network.cpp:706
RoR::Network::PushNetMessage
void PushNetMessage(MsgType type, std::string const &message)
Definition: Network.cpp:87
RoR::Network::StartConnecting
bool StartConnecting()
Launches connecting on background.
Definition: Network.cpp:394
RoR::Network::ConnectThread
bool ConnectThread()
Definition: Network.cpp:427
RoR::Network::UserAuthToStringShort
std::string UserAuthToStringShort(RoRnet::UserInfo const &user)
Definition: Network.cpp:854
RoRnet::LegacyServerInfo
Definition: RoRnet.h:219
RoR::MSG_NET_USER_DISCONNECT
@ MSG_NET_USER_DISCONNECT
Definition: Application.h:104
RoR::Network::GetUserColor
int GetUserColor()
Definition: Network.cpp:688
m_packet_buffer_size
static const unsigned int m_packet_buffer_size
Definition: Network.cpp:82
RoRnet::UserInfo
Definition: RoRnet.h:178
RoR::Network::GetUID
int GetUID()
Definition: Network.cpp:122
RoRnet::Header::source
int32_t source
source of this command: 0 = server
Definition: RoRnet.h:143
RoRnet::MSG2_WRONG_PW
@ MSG2_WRONG_PW
server send that on wrong pw
Definition: RoRnet.h:43
DebugPacket
void DebugPacket(const char *name, RoRnet::Header *header, char *buffer)
Definition: Network.cpp:104
RoR::App::mp_player_name
CVar * mp_player_name
Definition: Application.cpp:124
RORNET_MAX_USERNAME_LEN
#define RORNET_MAX_USERNAME_LEN
bytes.
Definition: RoRnet.h:33
RoR::App::mp_player_token
CVar * mp_player_token
Definition: Application.cpp:125
RORNET_VERSION
#define RORNET_VERSION
Definition: RoRnet.h:35
GUI_TopMenubar.h
RoR::Network::QueueStreamData
void QueueStreamData(RoRnet::Header &header, char *buffer, size_t buffer_len)
Definition: Network.cpp:163
format
Truck file format(technical spec)
RoR::App::app_language
CVar * app_language
Definition: Application.cpp:80
RoR::Network::GetIncomingStreamData
std::vector< NetRecvPacket > GetIncomingStreamData()
Definition: Network.cpp:675
RoR::MSG_NET_CONNECT_STARTED
@ MSG_NET_CONNECT_STARTED
Definition: Application.h:98
RoR::PeerOptionsRequest::por_uid
int por_uid
RoRnet unique user ID.
Definition: Network.h:106
RoRnet::Header::command
uint32_t command
the command of this packet: MSG2_*
Definition: RoRnet.h:142
RoR::LogFormat
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
Definition: Application.cpp:440
RoRnet::StreamRegister::origin_sourceid
int32_t origin_sourceid
origin sourceid
Definition: RoRnet.h:152
RoR::HashData
Ogre::String HashData(const char *key, int len)
Definition: Utils.cpp:54
RoRnet::AUTH_ADMIN
@ AUTH_ADMIN
admin on the server
Definition: RoRnet.h:76
Console.h
RoR::MSG_NET_RECV_ERROR
@ MSG_NET_RECV_ERROR
Definition: Application.h:105
RoRnet::ServerInfo
Definition: RoRnet.h:210
RoR::App::app_country
CVar * app_country
Definition: Application.cpp:81
RoR::ScriptEngine::queueStringForExecution
void queueStringForExecution(const Ogre::String command)
Queues a string for execution.
Definition: ScriptEngine.cpp:497
Utils.h
RoRnet
Definition: ForwardDeclarations.h:269
RoR::Network::GetAnyUserInfo
bool GetAnyUserInfo(int uid, RoRnet::UserInfo &result)
Also considers local client.
Definition: Network.cpp:760
RoR::Network::GetUserPeerOpts
bool GetUserPeerOpts(int uid, BitMask_t &result)
Definition: Network.cpp:732
RoRnet::AUTH_BANNED
@ AUTH_BANNED
banned
Definition: RoRnet.h:80
RoRnet::MSG2_FULL
@ MSG2_FULL
no more slots for us
Definition: RoRnet.h:42
RoRnet::MSG2_BANNED
@ MSG2_BANNED
client not allowed to join
Definition: RoRnet.h:45
Language.h
RoR::NetRecvPacket::header
RoRnet::Header header
Definition: Network.h:95
RoRnet::MSG2_USER_JOIN
@ MSG2_USER_JOIN
new user joined
Definition: RoRnet.h:57
RoRnet::MSG2_WRONG_VER_LEGACY
@ MSG2_WRONG_VER_LEGACY
Wrong version.
Definition: RoRnet.h:70
RoR::MSG_NET_SERVER_KICK
@ MSG_NET_SERVER_KICK
Definition: Application.h:102
GUIManager.h
RoR::Network::GetUserInfo
bool GetUserInfo(int uid, RoRnet::UserInfo &result)
Definition: Network.cpp:718
RoR::App::GetScriptEngine
ScriptEngine * GetScriptEngine()
Definition: Application.cpp:295
RoR::Console::CONSOLE_SYSTEM_NOTICE
@ CONSOLE_SYSTEM_NOTICE
Definition: Console.h:51
RoRnet::MSG2_UTF8_CHAT
@ MSG2_UTF8_CHAT
broadcast chat line in UTF8 encoding; Payload: const char*(text)
Definition: RoRnet.h:59
RoR::NetSendPacket::size
int size
Definition: Network.h:90
RoR::NetSendPacket::buffer
char buffer[RORNET_MAX_MESSAGE_LENGTH]
Definition: Network.h:89
RoR::App::mp_state
CVar * mp_state
Definition: Application.cpp:115
BITMASK_SET_0
#define BITMASK_SET_0(VAR, FLAGS)
Definition: BitFlags.h:16
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
RoRnet::MSG2_GAME_CMD
@ MSG2_GAME_CMD
Script message. Can be sent in both directions.
Definition: RoRnet.h:56
RoRnet::UserInfo::authstatus
int32_t authstatus
auth status set by server: AUTH_*
Definition: RoRnet.h:181
RoRnet::MSG2_UTF8_PRIVCHAT
@ MSG2_UTF8_PRIVCHAT
private chat line in UTF8 encoding; Payload: uint32_t(uniqueid), const char*(text)
Definition: RoRnet.h:60
RoR::Network::GetTerrainName
Ogre::String GetTerrainName()
Definition: Network.cpp:683
RoR::CVar::getStr
std::string const & getStr() const
Definition: CVar.h:95
RoR::Str
Wrapper for classic c-string (local buffer) Refresher: strlen() excludes '\0' terminator; strncat() A...
Definition: Str.h:35
RoR::Network::GetAllUsersPeerOpts
std::vector< BitMask_t > GetAllUsersPeerOpts()
Definition: Network.cpp:712
RoRnet::UserInfo::serverpassword
char serverpassword[40]
server password
Definition: RoRnet.h:187
ErrorUtils.h
RoRnet::LegacyServerInfo::protocolversion
char protocolversion[20]
protocol version being used
Definition: RoRnet.h:221
RoRnet::AUTH_MOD
@ AUTH_MOD
moderator status
Definition: RoRnet.h:78
RoR::MSG_GUI_MP_CLIENTS_REFRESH
@ MSG_GUI_MP_CLIENTS_REFRESH
Definition: Application.h:141
RoRnet::MSG2_STREAM_REGISTER
@ MSG2_STREAM_REGISTER
create new stream
Definition: RoRnet.h:63
ScriptEngine.h
BITMASK_SET_1
#define BITMASK_SET_1(VAR, FLAGS)
Definition: BitFlags.h:17
RoR::GameContext::PushMessage
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
Definition: GameContext.cpp:66
strnlen
#define strnlen(str, len)
Definition: InputEngine.cpp:400
RoR::Network::BroadcastChatMsg
void BroadcastChatMsg(const char *msg)
Definition: Network.cpp:831
RoR::App::mp_server_password
CVar * mp_server_password
Definition: Application.cpp:123
RoR::Network::GetDisconnectedUserInfo
bool GetDisconnectedUserInfo(int uid, RoRnet::UserInfo &result)
Definition: Network.cpp:746
RoR::Network::GetNetQuality
int GetNetQuality()
Definition: Network.cpp:117
ChatSystem.h
RoR::Str::ToCStr
const char * ToCStr() const
Definition: Str.h:46
RORNET_MAX_MESSAGE_LENGTH
#define RORNET_MAX_MESSAGE_LENGTH
maximum size of a RoR message. 8192 bytes = 8 kibibytes
Definition: RoRnet.h:31
RoR::Network::SendNetMessage
bool SendNetMessage(int type, unsigned int streamid, int len, char *content)
Definition: Network.cpp:140
RoR::PeerOptionsRequest::por_peeropts
BitMask_t por_peeropts
See RoRnet::PeerOptions.
Definition: Network.h:107
RoR::Network::CouldNotConnect
void CouldNotConnect(std::string const &msg, bool close_socket=true)
Definition: Network.cpp:382
RoR::Network::AddPeerOptions
void AddPeerOptions(PeerOptionsRequest *rq)
Definition: Network.cpp:797
RoR::MsgType
MsgType
Global gameplay message loop, see struct Message in GameContext.h.
Definition: Application.h:74
Application.h
Central state/object manager and communications hub.
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:286
RoRnet::Header
< Common header for every packet
Definition: RoRnet.h:140
RoRnet::MSG2_STREAM_REGISTER_RESULT
@ MSG2_STREAM_REGISTER_RESULT
result of a stream creation
Definition: RoRnet.h:64
RoR::Network::GetLocalUserData
RoRnet::UserInfo GetLocalUserData()
Definition: Network.cpp:700
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:296
RoRnet::Header::streamid
uint32_t streamid
streamid for this command
Definition: RoRnet.h:144
RoR::Console::doCommand
void doCommand(std::string msg)
Identify and execute any console line.
Definition: ConsoleCmd.cpp:707
RoR::Network::ReceiveMessage
int ReceiveMessage(RoRnet::Header *head, char *content, int bufferlen)
Definition: Network.cpp:173
RoRnet::UserInfo::sessiontype
char sessiontype[10]
the requested session type. For example "normal", "bot", "rcon"
Definition: RoRnet.h:192
RoRVersion.h
RoRnet::UserInfo::clientversion
char clientversion[25]
a version number of the client. For example 1 for RoR 0.35
Definition: RoRnet.h:190
RoRnet::AUTH_RANKED
@ AUTH_RANKED
ranked status
Definition: RoRnet.h:77
ROR_VERSION_STRING
const char *const ROR_VERSION_STRING
RoR::Message::description
std::string description
Definition: GameContext.h:58
RoRnet::UserInfo::clientname
char clientname[10]
the name and version of the client. For exmaple: "ror" or "gamebot"
Definition: RoRnet.h:189
_LC
#define _LC(ctx, str)
Definition: Language.h:38
RoR::Network::SendMessageRaw
bool SendMessageRaw(char *buffer, int msgsize)
Definition: Network.cpp:127
RoRnet::StreamRegister::status
int32_t status
initial stream status
Definition: RoRnet.h:151
RoR::Network::GetPlayerColor
Ogre::ColourValue GetPlayerColor(int color_num)
Definition: Network.cpp:94
RoR::MSG_NET_CONNECT_SUCCESS
@ MSG_NET_CONNECT_SUCCESS
Definition: Application.h:100
RoR::NetSendPacket
Definition: Network.h:87
RoRnet::MSG2_WRONG_VER
@ MSG2_WRONG_VER
wrong version
Definition: RoRnet.h:44
RoRnet::StreamRegister::type
int32_t type
0 = Actor, 1 = Character, 3 = ChatSystem
Definition: RoRnet.h:150
RoR::Sha1Hash
std::string Sha1Hash(std::string const &data)
Definition: Utils.cpp:141
RoR::Network::FindUserInfo
bool FindUserInfo(std::string const &username, RoRnet::UserInfo &result)
Definition: Network.cpp:782
RoR::Network::RecvThread
void RecvThread()
Definition: Network.cpp:238
RoRnet::UserInfo::username
char username[RORNET_MAX_USERNAME_LEN]
the nickname of the user (UTF-8)
Definition: RoRnet.h:185
RoRnet::UserInfo::uniqueid
uint32_t uniqueid
user unique id
Definition: RoRnet.h:180
RoR::Network::RemovePeerOptions
void RemovePeerOptions(PeerOptionsRequest *rq)
Definition: Network.cpp:814
RoR::Network::SetNetQuality
void SetNetQuality(int quality)
Definition: Network.cpp:112
RoR::Network::GetUsername
std::string GetUsername()
Definition: Network.cpp:694
RoR::App::mp_server_port
CVar * mp_server_port
Definition: Application.cpp:122
RoR::PeerOptionsRequest
Payload of MSG_NET_{ADD/REMOVE}_PEEROPTIONS_REQUESTED.
Definition: Network.h:104
RoR::Message
Unified game event system - all requests and state changes are reported using a message.
Definition: GameContext.h:51
RoR::App::mp_server_host
CVar * mp_server_host
Definition: Application.cpp:121
RoRnet::MSG2_STREAM_DATA_DISCARDABLE
@ MSG2_STREAM_DATA_DISCARDABLE
stream data that is allowed to be discarded
Definition: RoRnet.h:67
RoR::CVar::setVal
void setVal(T val)
Definition: CVar.h:72
_L
#define _L
Definition: ErrorUtils.cpp:35
RoR::Console::putNetMessage
void putNetMessage(int user_id, MessageType type, const char *text)
Definition: Console.cpp:108
RoR::MpState::DISABLED
@ DISABLED
Not connected for whatever reason.
RoRnet::AUTH_BOT
@ AUTH_BOT
bot status
Definition: RoRnet.h:79
RoRnet::StreamRegister::origin_streamid
int32_t origin_streamid
origin streamid
Definition: RoRnet.h:153
MP_COLORS
static Ogre::ColourValue MP_COLORS[]
Definition: Network.cpp:47
RoR::MSG_NET_CONNECT_FAILURE
@ MSG_NET_CONNECT_FAILURE
Definition: Application.h:101
RoR::NetRecvPacket::buffer
char buffer[RORNET_MAX_MESSAGE_LENGTH]
Definition: Network.h:96
BitMask_t
uint32_t BitMask_t
Definition: BitFlags.h:7
RoRnet::MSG2_NETQUALITY
@ MSG2_NETQUALITY
network quality information
Definition: RoRnet.h:53
RoR::Network::UserAuthToStringLong
std::string UserAuthToStringLong(RoRnet::UserInfo const &user)
Definition: Network.cpp:864
RoRnet::MSG2_HELLO
@ MSG2_HELLO
client sends its version as first message
Definition: RoRnet.h:39
RoR::CVar::getInt
int getInt() const
Definition: CVar.h:97
RoR::MSG_NET_CONNECT_PROGRESS
@ MSG_NET_CONNECT_PROGRESS
Definition: Application.h:99
RoRnet::MSG2_USER_INFO
@ MSG2_USER_INFO
user data that is sent from the server to the clients
Definition: RoRnet.h:51
RoR::Network::AddLocalStream
void AddLocalStream(RoRnet::StreamRegister *reg, int size)
Definition: Network.cpp:663
RoR::NetRecvPacket
Definition: Network.h:93
LOGSTREAM
#define LOGSTREAM
Definition: Network.cpp:85
RoRnet::MSG2_WELCOME
@ MSG2_WELCOME
we can proceed
Definition: RoRnet.h:46
RoR::Network::AddPacket
void AddPacket(int streamid, int type, int len, const char *content)
Definition: Network.cpp:609
RoR
Definition: AppContext.h:36
Network.h
RoRnet::UserInfo::language
char language[10]
user's language. For example "de-DE" or "en-US"
Definition: RoRnet.h:188
RoRnet::MSG2_USER_LEAVE
@ MSG2_USER_LEAVE
user leaves
Definition: RoRnet.h:58
RoRnet::UserInfo::usertoken
char usertoken[40]
user token
Definition: RoRnet.h:186
RoR::Network::SendThread
void SendThread()
Definition: Network.cpp:214
RoRnet::Header::size
uint32_t size
size of the attached data block
Definition: RoRnet.h:145
RoR::MpState::CONNECTING
@ CONNECTING
RoR::Network::WhisperChatMsg
void WhisperChatMsg(RoRnet::UserInfo const &user, const char *msg)
Definition: Network.cpp:836
RoRnet::StreamRegister
< Sent from the client to server and vice versa, to broadcast a new stream
Definition: RoRnet.h:148
LOG_THREAD
#define LOG_THREAD(_MSG_)
Definition: Network.cpp:84
RoR::Network::StopConnecting
void StopConnecting()
Definition: Network.cpp:419