RigsofRods
Soft-body Physics Simulation
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  m_disconnected_users.push_back(*user); // Copy
321  m_users.erase(user);
322  }
323  }
324  }
325  else if (header.command == MSG2_USER_INFO || header.command == MSG2_USER_JOIN)
326  {
327  if (header.source == m_uid)
328  {
329  std::lock_guard<std::mutex> lock(m_userdata_mutex);
330  memcpy(&m_userdata, buffer, sizeof(RoRnet::UserInfo));
331  m_authlevel = m_userdata.authstatus;
332  m_username = Ogre::UTFString(m_userdata.username);
334  // TODO: Update the global variable 'mp_player_name' in a threadsafe way.
335  }
336  else
337  {
338  RoRnet::UserInfo user_info;
339  if (!GetUserInfo(header.source, user_info)) // Check that user doesn't exist yet.
340  {
341  memcpy(&user_info, buffer, sizeof(RoRnet::UserInfo));
342  Str<300> text;
343  if (user_info.authstatus != 0) // Show nothing for guests (no special authorization)
344  {
345  text << "(" << UserAuthToStringShort(user_info) << ") ";
346  }
347  text << _L("joined the game");
348 
349  // NB: Console is threadsafe
351  user_info.uniqueid, Console::CONSOLE_SYSTEM_NOTICE, text.ToCStr());
353  // Lock and update userlist
354  std::lock_guard<std::mutex> lock(m_users_mutex);
355  m_users.push_back(user_info);
356  } // End of lock scope
357  }
358  continue;
359  }
360  else if (header.command == MSG2_GAME_CMD)
361  {
362 #ifdef USE_ANGELSCRIPT
363  App::GetScriptEngine()->queueStringForExecution(Ogre::String(buffer));
364 #endif // USE_ANGELSCRIPT
365  continue;
366  }
367  //DebugPacket("recv", &header, buffer);
368 
369  QueueStreamData(header, buffer, RORNET_MAX_MESSAGE_LENGTH);
370  }
371 
372  LOG_THREAD("[RoR|Networking] RecvThread stopped");
373 }
374 
375 
376 void Network::CouldNotConnect(std::string const & msg, bool close_socket /*= true*/)
377 {
378  RoR::LogFormat("[RoR|Networking] Failed to connect to server [%s:%d], message: %s", m_net_host.c_str(), m_net_port, msg.c_str());
379  PushNetMessage(MSG_NET_CONNECT_FAILURE, msg);
380 
381  if (close_socket)
382  {
383  m_socket.set_timeout(1, 0);
384  m_socket.disconnect();
385  }
386 }
387 
389 {
390  // Shadow vars for threaded access
391  m_username = App::mp_player_name->getStr();
392  m_token = App::mp_player_token->getStr();
393  m_net_host = App::mp_server_host->getStr();
394  m_net_port = App::mp_server_port->getInt();
395  m_password = App::mp_server_password->getStr();
396 
397  try
398  {
399  m_connect_thread = std::thread(&Network::ConnectThread, this);
400  App::mp_state->setVal((int)MpState::CONNECTING); // Mark connect thread as started
401  PushNetMessage(MSG_NET_CONNECT_STARTED, _LC("Network", "Starting..."));
402  return true;
403  }
404  catch (std::exception& e)
405  {
407  PushNetMessage(MSG_NET_CONNECT_FAILURE, _L("Failed to launch connection thread"));
408  RoR::LogFormat("[RoR|Networking] Failed to launch connection thread, message: %s", e.what());
409  return false;
410  }
411 }
412 
414 {
415  if (m_connect_thread.joinable())
416  m_connect_thread.join(); // Clean up
417 }
418 
420 {
421  RoR::LogFormat("[RoR|Networking] Trying to join server '%s' on port '%d' ...", m_net_host.c_str(), m_net_port);
422 
423  SWBaseSocket::SWBaseError error;
424 
425  PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Estabilishing connection..."));
426  m_socket = SWInetSocket();
427  m_socket.set_timeout(10, 0);
428  m_socket.connect(m_net_port, m_net_host, &error);
429  if (error != SWBaseSocket::ok)
430  {
431  CouldNotConnect(_L("Could not create connection"), false);
432  return false;
433  }
434 
435  PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Getting server info..."));
436  if (!SendNetMessage(MSG2_HELLO, 0, (int)strlen(RORNET_VERSION), (char *)RORNET_VERSION))
437  {
438  CouldNotConnect(_L("Establishing network session: error sending hello"));
439  return false;
440  }
441 
442  RoRnet::Header header;
443  char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
444 
445  // Receive server (rornet protocol) version
446  if (ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH))
447  {
448  CouldNotConnect(_L("Establishing network session: error getting server version"));
449  return false;
450  }
451  if (header.command == MSG2_WRONG_VER_LEGACY) // Pre-RoRnet_2.40 server
452  {
454  memcpy(&info, buffer, sizeof(RoRnet::LegacyServerInfo));
455  Ogre::UTFString format_wstr = _L("Establishing network session: wrong server version, you are using version '%s' and the server is using '%s'");
456  const char* server_ver = (info.protocolversion[0] != 0) ? info.protocolversion : "~ RoRnet_2.38 or earlier (not detected) ~";
457  char msg_buf[500];
458  snprintf(msg_buf, 500, format_wstr.asUTF8_c_str(), RORNET_VERSION, server_ver);
459  CouldNotConnect(msg_buf);
460  return false;
461  }
462  if (header.command == MSG2_WRONG_VER)
463  {
464  CouldNotConnect(_L("server uses a different protocol version"));
465  return false;
466  }
467  if (header.command != MSG2_HELLO)
468  {
469  CouldNotConnect(_L("Establishing network session: error getting server hello"));
470  return false;
471  }
472 
473  // Save server settings
474  memcpy(&m_server_settings, buffer, sizeof(RoRnet::ServerInfo));
475 
476  if (strncmp(m_server_settings.protocolversion, RORNET_VERSION, strlen(RORNET_VERSION)))
477  {
478  wchar_t tmp[512] = L"";
479  Ogre::UTFString tmp2 = _L("Establishing network session: wrong server version, you are using version '%s' and the server is using '%s'");
480  swprintf(tmp, 512, tmp2.asWStr_c_str(), RORNET_VERSION, m_server_settings.protocolversion);
481  CouldNotConnect(MyGUI::UString(tmp).asUTF8_c_str());
482  return false;
483  }
484 
485  PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Authorizing..."));
486 
487  // First handshake done, increase the timeout, important!
488  m_socket.set_timeout(0, 0);
489 
490  // Construct user credentials
491  // Beware of the wchar_t converted to UTF8 for networking
493  memset(&c, 0, sizeof(RoRnet::UserInfo));
494  // Cut off the UTF string on the highest level, otherwise you will break UTF info
495  strncpy((char *)c.username, m_username.substr(0, RORNET_MAX_USERNAME_LEN * 0.5f).asUTF8_c_str(), RORNET_MAX_USERNAME_LEN);
496  strncpy(c.serverpassword, Sha1Hash(m_password).c_str(), size_t(40));
497  strncpy(c.usertoken, Sha1Hash(m_token).c_str(), size_t(40));
499  strncpy(c.clientname, "RoR", 10);
500  std::string language = App::app_language->getStr().substr(0, 2);
501  std::string country = App::app_country->getStr().substr(0, 2);
502  strncpy(c.language, (language + std::string("_") + country).c_str(), 5);
503  strcpy(c.sessiontype, "normal");
504  if (!SendNetMessage(MSG2_USER_INFO, 0, sizeof(RoRnet::UserInfo), (char*)&c))
505  {
506  CouldNotConnect(_L("Establishing network session: error sending user info"));
507  return false;
508  }
509 
510  // Getting authorization
511  if (ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH))
512  {
513  CouldNotConnect(_L("Establishing network session: error getting server authorization"));
514  return false;
515  }
516 
517  if (header.command==MSG2_FULL)
518  {
519  CouldNotConnect(_L("Establishing network session: sorry, server has too many players"));
520  return false;
521  }
522  else if (header.command==MSG2_BANNED)
523  {
524  // Do NOT `disconnect()` the m_socket in this case - causes SocketW to terminate RoR.
525  CouldNotConnect(_L("Establishing network session: sorry, you are banned!"), /*close_socket=*/false);
526  return false;
527  }
528  else if (header.command==MSG2_WRONG_PW)
529  {
530  CouldNotConnect(_L("Establishing network session: sorry, wrong password!"));
531  return false;
532  }
533  else if (header.command==MSG2_WRONG_VER)
534  {
535  CouldNotConnect(_L("Establishing network session: sorry, wrong protocol version!"));
536  return false;
537  }
538 
539  if (header.command!=MSG2_WELCOME)
540  {
541  CouldNotConnect(_L("Establishing network session: sorry, unknown server response"));
542  return false;
543  }
544 
545  PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Finishing..."));
546 
547  m_uid = header.source;
548 
549  // we get our userdata back
550  memcpy(&m_userdata, buffer, std::min<int>(sizeof(RoRnet::UserInfo), header.size));
551 
552  m_shutdown = false;
553 
554  LOG("[RoR|Networking] Connect(): Creating Send/Recv threads");
555  m_send_thread = std::thread(&Network::SendThread, this);
556  m_recv_thread = std::thread(&Network::RecvThread, this);
557  PushNetMessage(MSG_NET_CONNECT_SUCCESS, "");
558 
559  return true;
560 }
561 
563 {
564  LOG("[RoR|Networking] Disconnect() disconnecting...");
565  bool is_clean_disconnect = !m_shutdown; // Hacky detection of invalid network state
566 
567  m_shutdown = true; // Instruct Send/Recv threads to shut down.
568 
569  m_send_packet_available_cv.notify_one();
570 
571  m_send_thread.join();
572  LOG("[RoR|Networking] Disconnect() sender thread cleaned up");
573 
574  m_socket.set_timeout(1, 0);
575 
576  if (is_clean_disconnect)
577  {
578  SendNetMessage(MSG2_USER_LEAVE, 0, 0, 0);
579  }
580 
581  m_recv_thread.join();
582  LOG("[RoR|Networking] Disconnect() receiver thread cleaned up");
583 
584  if (is_clean_disconnect)
585  {
586  m_socket.disconnect();
587  }
588  else
589  {
590  m_socket.close_fd();
591  }
592 
593  SetNetQuality(0);
594  m_users.clear();
595  m_disconnected_users.clear();
596  m_recv_packet_buffer.clear();
597  m_send_packet_buffer.clear();
598  App::GetConsole()->doCommand("clear net");
599 
600  m_shutdown = false;
602 
603  LOG("[RoR|Networking] Disconnect() done");
604 }
605 
606 void Network::AddPacket(int streamid, int type, int len, const char *content)
607 {
608  const auto max_len = RORNET_MAX_MESSAGE_LENGTH - sizeof(RoRnet::Header);
609  if (len > max_len)
610  {
611  LOGSTREAM << "[RoR|Networking] Discarding network packet (StreamID: "
612  <<streamid<<", Type: "<<type<<"), length is " << len << ", max is " << max_len;
613  return;
614  }
615 
616  NetSendPacket packet;
617  memset(&packet, 0, sizeof(NetSendPacket));
618 
619  char *buffer = (char*)(packet.buffer);
620 
621  RoRnet::Header *head = (RoRnet::Header *)buffer;
622  head->command = type;
623  head->source = m_uid;
624  head->size = len;
625  head->streamid = streamid;
626 
627  // then copy the contents
628  char *bufferContent = (char *)(buffer + sizeof(RoRnet::Header));
629  memcpy(bufferContent, content, len);
630 
631  // record the packet size
632  packet.size = len + sizeof(RoRnet::Header);
633 
634  { // Lock scope
635  std::lock_guard<std::mutex> lock(m_send_packetqueue_mutex);
636  if (type == MSG2_STREAM_DATA_DISCARDABLE)
637  {
638  if (m_send_packet_buffer.size() > m_packet_buffer_size)
639  {
640  // buffer full, discard unimportant data packets
641  return;
642  }
643  auto search = std::find_if(m_send_packet_buffer.begin(), m_send_packet_buffer.end(),
644  [&](const NetSendPacket& p) { return !memcmp(packet.buffer, p.buffer, sizeof(RoRnet::Header)); });
645  if (search != m_send_packet_buffer.end())
646  {
647  // Found outdated discardable streamdata -> replace it
648  (*search) = packet;
649  m_send_packet_available_cv.notify_one();
650  return;
651  }
652  }
653  //DebugPacket("send", head, buffer);
654  m_send_packet_buffer.push_back(packet);
655  }
656 
657  m_send_packet_available_cv.notify_one();
658 }
659 
661 {
662  reg->origin_sourceid = m_uid;
663  reg->origin_streamid = m_stream_id;
664  reg->status = 0;
665 
666  AddPacket(m_stream_id, MSG2_STREAM_REGISTER, size, (char*)reg);
667  LOG("adding local stream: " + TOSTRING(m_uid) + ":"+ TOSTRING(m_stream_id) + ", type: " + TOSTRING(reg->type));
668 
669  m_stream_id++;
670 }
671 
672 std::vector<NetRecvPacket> Network::GetIncomingStreamData()
673 {
674  std::lock_guard<std::mutex> lock(m_recv_packetqueue_mutex);
675  std::vector<NetRecvPacket> buf_copy = m_recv_packet_buffer;
676  m_recv_packet_buffer.clear();
677  return buf_copy;
678 }
679 
681 {
682  return m_server_settings.terrain;
683 }
684 
686 {
687  std::lock_guard<std::mutex> lock(m_userdata_mutex);
688  return m_userdata.colournum;
689 }
690 
691 Ogre::UTFString Network::GetUsername()
692 {
693  std::lock_guard<std::mutex> lock(m_userdata_mutex);
694  return m_username;
695 }
696 
698 {
699  std::lock_guard<std::mutex> lock(m_userdata_mutex);
700  return m_userdata;
701 }
702 
703 std::vector<RoRnet::UserInfo> Network::GetUserInfos()
704 {
705  std::lock_guard<std::mutex> lock(m_users_mutex);
706  return m_users;
707 }
708 
710 {
711  std::lock_guard<std::mutex> lock(m_users_mutex);
712  for (RoRnet::UserInfo user : m_users)
713  {
714  if ((int)user.uniqueid == uid)
715  {
716  result = user;
717  return true;
718  }
719  }
720  return false;
721 }
722 
724 {
725  std::lock_guard<std::mutex> lock(m_users_mutex);
726  for (RoRnet::UserInfo user : m_disconnected_users)
727  {
728  if ((int)user.uniqueid == uid)
729  {
730  result = user;
731  return true;
732  }
733  }
734  return false;
735 }
736 
738 {
739  RoRnet::UserInfo tmp;
740 
741  // Try remote users
742  if (GetUserInfo(uid, tmp))
743  {
744  result = tmp;
745  return true;
746  }
747 
748  // Try local user
749  tmp = GetLocalUserData();
750  if (tmp.uniqueid == uid)
751  {
752  result = tmp;
753  return true;
754  }
755 
756  return false;
757 }
758 
759 bool Network::FindUserInfo(std::string const& username, RoRnet::UserInfo &result)
760 {
761  std::lock_guard<std::mutex> lock(m_users_mutex);
762  for (RoRnet::UserInfo user : m_users)
763  {
764  if (user.username == username)
765  {
766  result = user;
767  return true;
768  }
769  }
770  return false;
771 }
772 
773 void Network::BroadcastChatMsg(const char* msg)
774 {
775  AddPacket(m_stream_id, RoRnet::MSG2_UTF8_CHAT, (int)std::strlen(msg), msg);
776 }
777 
778 void Network::WhisperChatMsg(RoRnet::UserInfo const& user, const char* msg)
779 {
780  // Prepare buffer
781  char payload[RORNET_MAX_MESSAGE_LENGTH - sizeof(RoRnet::Header)];
782  size_t payload_len = 0;
783 
784  // Write client ID
785  std::memcpy(payload, &user.uniqueid, sizeof(user.uniqueid));
786  payload_len += sizeof(user.uniqueid);
787 
788  // Write text
789  std::strncpy(payload + payload_len, msg, sizeof(payload) - payload_len);
790  payload_len += std::strlen(msg);
791 
792  // Queue packet
793  AddPacket(m_stream_id, RoRnet::MSG2_UTF8_PRIVCHAT, (int)payload_len, msg);
794 }
795 
797 {
798  if (user.authstatus & AUTH_ADMIN) { return _LC("NetUserAuth", "Admin"); }
799  else if (user.authstatus & AUTH_MOD) { return _LC("NetUserAuth", "Mod"); }
800  else if (user.authstatus & AUTH_BOT) { return _LC("NetUserAuth", "Bot"); }
801  else if (user.authstatus & AUTH_RANKED) { return _LC("NetUserAuth", "Ranked"); }
802  else if (user.authstatus & AUTH_BANNED) { return _LC("NetUserAuth", "Banned"); }
803  else { return _LC("NetUserAuth", "Guest"); }
804 }
805 
807 {
808  if (user.authstatus & AUTH_ADMIN) { return _LC("NetUserAuth","Server Administrator"); }
809  else if (user.authstatus & AUTH_MOD) { return _LC("NetUserAuth","Server Moderator"); }
810  else if (user.authstatus & AUTH_BOT) { return _LC("NetUserAuth","Bot"); }
811  else if (user.authstatus & AUTH_RANKED) { return _LC("NetUserAuth","Ranked user"); }
812  else if (user.authstatus & AUTH_BANNED) { return _LC("NetUserAuth","Banned user"); }
813  else { return _LC("NetUserAuth","Guest"); }
814 }
815 
816 #endif // USE_SOCKETW
GameContext.h
Game state manager and message-queue provider.
RoR::Network::Disconnect
void Disconnect()
Definition: Network.cpp:562
RoRnet::MSG2_STREAM_UNREGISTER
@ MSG2_STREAM_UNREGISTER
remove stream
Definition: RoRnet.h:65
RoR::Network::GetUserInfos
std::vector< RoRnet::UserInfo > GetUserInfos()
Definition: Network.cpp:703
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:388
RoR::Network::ConnectThread
bool ConnectThread()
Definition: Network.cpp:419
RoR::Network::UserAuthToStringShort
std::string UserAuthToStringShort(RoRnet::UserInfo const &user)
Definition: Network.cpp:796
RoRnet::LegacyServerInfo
Definition: RoRnet.h:209
RoR::MSG_NET_USER_DISCONNECT
@ MSG_NET_USER_DISCONNECT
Definition: Application.h:104
RoR::Network::GetUserColor
int GetUserColor()
Definition: Network.cpp:685
m_packet_buffer_size
static const unsigned int m_packet_buffer_size
Definition: Network.cpp:82
RoRnet::UserInfo
Definition: RoRnet.h:168
RoR::Network::GetUID
int GetUID()
Definition: Network.cpp:122
RoRnet::Header::source
int32_t source
source of this command: 0 = server
Definition: RoRnet.h:135
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
port used to send the broadcast announcement in LAN mode
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
RoR::App::app_language
CVar * app_language
Definition: Application.cpp:80
RoR::Network::GetIncomingStreamData
std::vector< NetRecvPacket > GetIncomingStreamData()
Definition: Network.cpp:672
RoR::MSG_NET_CONNECT_STARTED
@ MSG_NET_CONNECT_STARTED
Definition: Application.h:98
RoRnet::Header::command
uint32_t command
the command of this packet: MSG2_*
Definition: RoRnet.h:134
RoR::LogFormat
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
Definition: Application.cpp:424
RoRnet::StreamRegister::origin_sourceid
int32_t origin_sourceid
origin sourceid
Definition: RoRnet.h:144
RoR::HashData
Ogre::String HashData(const char *key, int len)
Definition: Utils.cpp:51
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:200
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:478
Utils.h
RoRnet
Definition: ForwardDeclarations.h:232
RoR::Network::GetAnyUserInfo
bool GetAnyUserInfo(int uid, RoRnet::UserInfo &result)
Also considers local client.
Definition: Network.cpp:737
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:96
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:709
RoR::App::GetScriptEngine
ScriptEngine * GetScriptEngine()
Definition: Application.cpp:279
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:91
RoR::NetSendPacket::buffer
char buffer[RORNET_MAX_MESSAGE_LENGTH]
Definition: Network.h:90
RoR::App::mp_state
CVar * mp_state
Definition: Application.cpp:115
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
RoR::Network::GetUsername
Ogre::UTFString GetUsername()
Definition: Network.cpp:691
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:171
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:680
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
RoRnet::UserInfo::serverpassword
char serverpassword[40]
server password
Definition: RoRnet.h:177
ErrorUtils.h
RoRnet::LegacyServerInfo::protocolversion
char protocolversion[20]
protocol version being used
Definition: RoRnet.h:211
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:137
RoRnet::MSG2_STREAM_REGISTER
@ MSG2_STREAM_REGISTER
create new stream
Definition: RoRnet.h:63
ScriptEngine.h
RoR::GameContext::PushMessage
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
Definition: GameContext.cpp:65
strnlen
#define strnlen(str, len)
Definition: InputEngine.cpp:397
RoR::Network::BroadcastChatMsg
void BroadcastChatMsg(const char *msg)
Definition: Network.cpp:773
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:723
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::Network::CouldNotConnect
void CouldNotConnect(std::string const &msg, bool close_socket=true)
Definition: Network.cpp:376
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:270
RoRnet::Header
< Common header for every packet
Definition: RoRnet.h:132
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:697
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:280
RoRnet::Header::streamid
uint32_t streamid
streamid for this command
Definition: RoRnet.h:136
RoR::Console::doCommand
void doCommand(std::string msg)
Identify and execute any console line.
Definition: ConsoleCmd.cpp:678
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:182
RoRVersion.h
RoRnet::UserInfo::clientversion
char clientversion[25]
a version number of the client. For example 1 for RoR 0.35
Definition: RoRnet.h:180
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:179
_LC
#define _LC(ctx, str)
Definition: Language.h:42
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:143
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:88
RoRnet::MSG2_WRONG_VER
@ MSG2_WRONG_VER
wrong version
Definition: RoRnet.h:44
RoRnet::StreamRegister::type
int32_t type
stream type
Definition: RoRnet.h:142
RoR::Sha1Hash
std::string Sha1Hash(std::string const &data)
Definition: Utils.cpp:138
RoR::Network::FindUserInfo
bool FindUserInfo(std::string const &username, RoRnet::UserInfo &result)
Definition: Network.cpp:759
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:175
RoRnet::UserInfo::uniqueid
uint32_t uniqueid
user unique id
Definition: RoRnet.h:170
RoR::Network::SetNetQuality
void SetNetQuality(int quality)
Definition: Network.cpp:112
RoR::App::mp_server_port
CVar * mp_server_port
Definition: Application.cpp:122
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:34
RoR::Console::putNetMessage
void putNetMessage(int user_id, MessageType type, const char *text)
Definition: Console.cpp:102
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:145
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:97
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:806
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:660
RoR::NetRecvPacket
Definition: Network.h:94
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:606
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:178
RoRnet::MSG2_USER_LEAVE
@ MSG2_USER_LEAVE
user leaves
Definition: RoRnet.h:58
RoRnet::UserInfo::usertoken
char usertoken[40]
user token
Definition: RoRnet.h:176
RoR::Network::SendThread
void SendThread()
Definition: Network.cpp:214
RoRnet::Header::size
uint32_t size
size of the attached data block
Definition: RoRnet.h:137
RoR::MpState::CONNECTING
@ CONNECTING
RoR::Network::WhisperChatMsg
void WhisperChatMsg(RoRnet::UserInfo const &user, const char *msg)
Definition: Network.cpp:778
RoRnet::StreamRegister
< Sent from the client to server and vice versa, to broadcast a new stream
Definition: RoRnet.h:140
LOG_THREAD
#define LOG_THREAD(_MSG_)
Definition: Network.cpp:84
RoR::Network::StopConnecting
void StopConnecting()
Definition: Network.cpp:413