Freeciv21
Develop your civilization from humble roots to a global empire
connecthand.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 #include <fc_config.h>
15 
16 #include <cstring>
17 
18 // utility
19 #include "capability.h"
20 #include "fcintl.h"
21 #include "log.h"
22 #include "registry_ini.h"
23 #include "support.h"
24 
25 // generated
26 #include "fc_version.h"
27 
28 // common
29 #include "capstr.h"
30 #include "events.h"
31 #include "game.h"
32 #include "packets.h"
33 #include "player.h"
34 #include "version.h"
35 
36 // server
37 #include "aiiface.h"
38 #include "auth.h"
39 #include "diplhand.h"
40 #include "edithand.h"
41 #include "gamehand.h"
42 #include "maphand.h"
43 #include "meta.h"
44 #include "notify.h"
45 #include "plrhand.h"
46 #include "report.h"
47 #include "ruleset.h"
48 #include "settings.h"
49 #include "srv_main.h"
50 #include "stdinhand.h"
51 #include "voting.h"
52 
53 #include "connecthand.h"
54 
55 static bool connection_attach_real(struct connection *pconn,
56  struct player *pplayer, bool observing,
57  bool connecting);
58 
67 void conn_set_access(struct connection *pconn, enum cmdlevel new_level,
68  bool granted)
69 {
70  enum cmdlevel old_level = conn_get_access(pconn);
71 
72  pconn->access_level = new_level;
73  if (granted) {
74  pconn->server.granted_access_level = new_level;
75  }
76 
77  if (old_level != new_level) {
78  send_server_access_level_settings(pconn->self, old_level, new_level);
79  }
80 }
81 
89 static void restore_access_level(struct connection *pconn)
90 {
91  // Restore previous privileges.
92  enum cmdlevel level = pconn->server.granted_access_level;
93 
94  /* Detached connections must have at most the same privileges
95  * as observers, unless they were granted something higher than
96  * ALLOW_BASIC in the first place. */
97  if ((pconn->observer || !pconn->playing) && level == ALLOW_BASIC) {
98  level = ALLOW_INFO;
99  }
100 
101  conn_set_access(pconn, level, false);
102 }
103 
123 {
124  struct conn_list *dest = pconn->self;
125  struct player *pplayer;
126  struct packet_server_join_reply packet;
127  struct packet_chat_msg connect_info;
128  char hostname[512];
129  bool delegation_error = false;
130  struct packet_set_topology topo_packet;
131 
132  // zero out the password
133  memset(pconn->server.password, 0, sizeof(pconn->server.password));
134 
135  // send join_reply packet
136  packet.you_can_join = true;
137  sz_strlcpy(packet.capability, our_capability);
138  fc_snprintf(packet.message, sizeof(packet.message), _("%s Welcome"),
139  pconn->username);
140  sz_strlcpy(packet.challenge_file, new_challenge_filename(pconn));
141  packet.conn_id = pconn->id;
142  send_packet_server_join_reply(pconn, &packet);
143 
144  // "establish" the connection
145  pconn->established = true;
146  pconn->server.status = AS_ESTABLISHED;
147 
148  pconn->server.delegation.status = false;
149  pconn->server.delegation.playing = nullptr;
150  pconn->server.delegation.observer = false;
151 
152  conn_list_append(game.est_connections, pconn);
153  if (conn_list_size(game.est_connections) == 1) {
154  /* First connection
155  * Replace "restarting in x seconds" meta message */
158  }
159 
160  // introduce the server to the connection
161  if (fc_gethostname(hostname, sizeof(hostname)) == 0) {
162  notify_conn(dest, nullptr, E_CONNECTION, ftc_any,
163  _("Welcome to the %s Server running at %s port %d."),
164  freeciv_name_version(), hostname, srvarg.port);
165  } else {
166  notify_conn(dest, nullptr, E_CONNECTION, ftc_any,
167  _("Welcome to the %s Server at port %d."),
169  }
170 
171  /* FIXME: this (getting messages about others logging on) should be a
172  * message option for the client with event */
173 
174  // Notify the console that you're here.
175  qInfo(_("%s has connected from %s."), pconn->username,
176  qUtf8Printable(pconn->addr));
177 
179  send_rulesets(dest);
181  send_server_settings(dest);
182  send_scenario_info(dest);
184  send_game_info(dest);
185  topo_packet.topology_id = wld.map.topology_id;
186  send_packet_set_topology(pconn, &topo_packet);
187 
188  // Do we have a player that a delegate is currently controlling?
189  if ((pplayer = player_by_user_delegated(pconn->username))) {
190  // Reassert our control over the player.
191  struct connection *pdelegate;
192  fc_assert_ret(player_delegation_get(pplayer) != nullptr);
193  pdelegate = conn_by_user(player_delegation_get(pplayer));
194 
195  if (pdelegate && connection_delegate_restore(pdelegate)) {
196  /* Delegate now detached from our player. We will restore control
197  * over them as normal below. */
198  notify_conn(pconn->self, nullptr, E_CONNECTION, ftc_server,
199  _("Your delegate %s was controlling your player '%s'; "
200  "now detached."),
201  pdelegate->username, player_name(pplayer));
202  notify_conn(pdelegate->self, nullptr, E_CONNECTION, ftc_server,
203  _("%s reconnected, ending your delegated control of "
204  "player '%s'."),
205  pconn->username, player_name(pplayer));
206  } else {
207  fc_assert(pdelegate);
208  // This really shouldn't happen.
209  qCritical("Failed to revoke delegate %s's control of %s, so owner %s "
210  "can't regain control.",
211  pdelegate->username, player_name(pplayer), pconn->username);
212  notify_conn(dest, nullptr, E_CONNECTION, ftc_server,
213  _("Couldn't get control of '%s' from delegation to %s."),
214  player_name(pplayer), pdelegate->username);
215  delegation_error = true;
216  pplayer = nullptr;
217  }
218  }
219 
220  if (!delegation_error) {
221  if ((pplayer = player_by_user(pconn->username))
222  && connection_attach_real(pconn, pplayer, false, true)) {
223  // a player has already been created for this user, reconnect
224 
225  if (S_S_INITIAL == server_state()) {
226  send_player_info_c(nullptr, dest);
227  }
228  } else {
229  if (!game_was_started()) {
230  if (connection_attach_real(pconn, nullptr, false, true)) {
231  pplayer = conn_get_player(pconn);
232  fc_assert(pplayer != nullptr);
233  } else {
234  notify_conn(dest, nullptr, E_CONNECTION, ftc_server,
235  _("Couldn't attach your connection to new player."));
236  qDebug("%s is not attached to a player", pconn->username);
237  }
238  }
239  send_player_info_c(nullptr, dest);
240  }
241  }
242 
244 
245  if (nullptr == pplayer) {
246  // Else this has already been done in connection_attach_real().
247  send_pending_events(pconn, true);
248  send_running_votes(pconn, false);
249  restore_access_level(pconn);
251 
252  notify_conn(dest, nullptr, E_CONNECTION, ftc_server,
253  _("You are logged in as '%s' connected to no player."),
254  pconn->username);
255  } else {
256  notify_conn(dest, nullptr, E_CONNECTION, ftc_server,
257  _("You are logged in as '%s' connected to %s."),
258  pconn->username, player_name(pconn->playing));
259  }
260 
261  // Send information about delegation(s).
262  send_delegation_info(pconn);
263 
264  /* Notify the *other* established connections that you are connected, and
265  * add the info for all in event cache. Note we must to do it after we
266  * sent the pending events to pconn (from this function and also
267  * connection_attach()), otherwise pconn will receive it too. */
268  if (conn_controls_player(pconn)) {
269  package_event(&connect_info, nullptr, E_CONNECTION, ftc_server,
270  _("%s has connected (player %s)."), pconn->username,
271  player_name(conn_get_player(pconn)));
272  } else {
273  package_event(&connect_info, nullptr, E_CONNECTION, ftc_server,
274  _("%s has connected."), pconn->username);
275  }
277  {
278  if (aconn != pconn) {
279  send_packet_chat_msg(aconn, &connect_info);
280  }
281  }
283  event_cache_add_for_all(&connect_info);
284 
285  // if need be, tell who we're waiting on to end the game.info.turn
286  if (S_S_RUNNING == server_state() && game.server.turnblock
287  && !game.server.fixedlength) {
288  players_iterate_alive(cplayer)
289  {
290  if (is_human(cplayer) && !cplayer->phase_done
291  && cplayer != pconn->playing) { // skip current player
292  notify_conn(dest, nullptr, E_CONNECTION, ftc_any,
293  _("Turn-blocking game play: "
294  "waiting on %s to finish turn..."),
295  player_name(cplayer));
296  }
297  }
299  }
300 
301  if (game.info.is_edit_mode) {
302  notify_conn(dest, nullptr, E_SETTING, ftc_editor,
303  _(" *** Server is in edit mode. *** "));
304  }
305 
306  if (nullptr != pplayer) {
307  // Else, no need to do anything.
310  }
311 
313 
314  conn_compression_thaw(pconn);
315 }
316 
320 void reject_new_connection(const char *msg, struct connection *pconn)
321 {
322  struct packet_server_join_reply packet;
323 
324  // zero out the password
325  memset(pconn->server.password, 0, sizeof(pconn->server.password));
326 
327  packet.you_can_join = false;
328  sz_strlcpy(packet.capability, our_capability);
329  sz_strlcpy(packet.message, msg);
330  packet.challenge_file[0] = '\0';
331  packet.conn_id = -1;
332  send_packet_server_join_reply(pconn, &packet);
333  qInfo(_("Client rejected: %s."), conn_description(pconn));
335 }
336 
341 bool handle_login_request(struct connection *pconn,
342  struct packet_server_join_req *req)
343 {
344  char msg[MAX_LEN_MSG];
345  int kick_time_remaining;
346 
347  if (pconn->established || pconn->server.status != AS_NOT_ESTABLISHED) {
348  /* We read the PACKET_SERVER_JOIN_REQ twice from this connection,
349  * this is probably not a Freeciv21 client. */
350  return false;
351  }
352 
353  qInfo(_("Connection request from %s from %s"), req->username,
354  qUtf8Printable(pconn->addr));
355 
356  // print server and client capabilities to console
357  qInfo(_("%s has client version %d.%d.%d%s"), pconn->username,
358  req->major_version, req->minor_version, req->patch_version,
359  req->version_label);
360  qDebug("Client caps: %s", req->capability);
361  qDebug("Server caps: %s", our_capability);
362  conn_set_capability(pconn, req->capability);
363 
364  // Make sure the server has every capability the client needs
365  if (!has_capabilities(our_capability, req->capability)) {
366  fc_snprintf(
367  msg, sizeof(msg),
368  _("The client is missing a capability that this server needs.\n"
369  "Server version: %d.%d.%d%s Client version: %d.%d.%d%s."
370  " Upgrading may help!"),
371  MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL,
372  req->major_version, req->minor_version, req->patch_version,
373  req->version_label);
374  reject_new_connection(msg, pconn);
375  qInfo(_("%s was rejected: Mismatched capabilities."), req->username);
376  return false;
377  }
378 
379  // Make sure the client has every capability the server needs
380  if (!has_capabilities(req->capability, our_capability)) {
381  fc_snprintf(
382  msg, sizeof(msg),
383  _("The server is missing a capability that the client needs.\n"
384  "Server version: %d.%d.%d%s Client version: %d.%d.%d%s."
385  " Upgrading may help!"),
386  MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL,
387  req->major_version, req->minor_version, req->patch_version,
388  req->version_label);
389  reject_new_connection(msg, pconn);
390  qInfo(_("%s was rejected: Mismatched capabilities."), req->username);
391  return false;
392  }
393 
394  {
395  /* Client is compatible. That includes ability to receive server info.
396  * Send it. */
397  struct packet_server_info info;
398 
399  info.major_version = MAJOR_VERSION;
400  info.minor_version = MINOR_VERSION;
401  info.patch_version = PATCH_VERSION;
402  info._obsolete = 0;
403  sz_strlcpy(info.version_label, VERSION_LABEL);
404  send_packet_server_info(pconn, &info);
405  }
406 
407  remove_leading_trailing_spaces(req->username);
408 
409  // Name-sanity check: could add more checks?
410  if (!is_valid_username(req->username)) {
411  fc_snprintf(msg, sizeof(msg), _("Invalid username '%s'"), req->username);
412  reject_new_connection(msg, pconn);
413  qInfo(_("%s was rejected: Invalid name [%s]."), req->username,
414  qUtf8Printable(pconn->addr));
415  return false;
416  }
417 
418  if (conn_is_kicked(pconn, &kick_time_remaining)) {
419  fc_snprintf(msg, sizeof(msg),
420  _("You have been kicked from this server "
421  "and cannot reconnect for %d seconds."),
422  kick_time_remaining);
423  reject_new_connection(msg, pconn);
424  qInfo(_("%s was rejected: Connection kicked "
425  "(%d seconds remaining)."),
426  req->username, kick_time_remaining);
427  return false;
428  }
429 
430  // don't allow duplicate logins
432  {
433  if (fc_strcasecmp(req->username, aconn->username) == 0) {
434  fc_snprintf(msg, sizeof(msg), _("'%s' already connected."),
435  req->username);
436  reject_new_connection(msg, pconn);
437  qInfo(_("%s was rejected: Duplicate login name [%s]."), req->username,
438  qUtf8Printable(pconn->addr));
439  return false;
440  }
441  }
443 
444  // Remove the ping timeout given in sernet.c:server_make_connection().
445  fc_assert_msg(1 == pconn->server.ping_timers->size(),
446  "Ping timer list size %d, should be 1. Have we sent "
447  "a ping to unestablished connection %s?",
448  pconn->server.ping_timers->size(), conn_description(pconn));
449 
450  civtimer *deltimer = pconn->server.ping_timers->takeFirst();
451  timer_destroy(deltimer);
452 
453  if (game.server.connectmsg[0] != '\0') {
454  log_debug("Sending connectmsg: %s", game.server.connectmsg);
455  dsend_packet_connect_msg(pconn, game.server.connectmsg);
456  }
457 
458  if (srvarg.auth_enabled) {
459  return auth_user(pconn, req->username);
460  } else {
461  sz_strlcpy(pconn->username, req->username);
463  return true;
464  }
465 }
466 
476 {
477  fc_assert_ret(true == pconn->server.is_closing);
478 
479  qInfo(_("Lost connection: %s."), conn_description(pconn, true));
480 
481  // Special color (white on black) for player loss
482  notify_conn(game.est_connections, nullptr, E_CONNECTION,
484  _("Lost connection: %s."), conn_description(pconn, false));
485 
486  connection_detach(pconn, true);
489 
491 }
492 
496 static void package_conn_info(struct connection *pconn,
497  struct packet_conn_info *packet)
498 {
499  packet->id = pconn->id;
500  packet->used = pconn->used;
501  packet->established = pconn->established;
502  packet->player_num = (nullptr != pconn->playing)
503  ? player_number(pconn->playing)
505  packet->observer = pconn->observer;
506  packet->access_level = pconn->access_level;
507 
508  sz_strlcpy(packet->username, pconn->username);
509  sz_strlcpy(packet->addr, "");
510  sz_strlcpy(packet->capability, pconn->capability);
511 }
512 
518 static void send_conn_info_arg(struct conn_list *src, struct conn_list *dest,
519  bool remove_conn)
520 {
521  struct packet_conn_info packet;
522 
523  if (!dest) {
524  dest = game.est_connections;
525  }
526 
527  conn_list_iterate(src, psrc)
528  {
529  package_conn_info(psrc, &packet);
530  if (remove_conn) {
531  packet.used = false;
532  }
533  lsend_packet_conn_info(dest, &packet);
534  }
536 }
537 
542 void send_conn_info(struct conn_list *src, struct conn_list *dest)
543 {
544  send_conn_info_arg(src, dest, false);
545 }
546 
551 void send_conn_info_remove(struct conn_list *src, struct conn_list *dest)
552 {
553  send_conn_info_arg(src, dest, true);
554 }
555 
560 {
561  players_iterate(played)
562  {
563  if (!played->is_connected && !played->was_created) {
564  return played;
565  }
566  }
568 
569  return nullptr;
570 }
571 
588 static bool connection_attach_real(struct connection *pconn,
589  struct player *pplayer, bool observing,
590  bool connecting)
591 {
592  fc_assert_ret_val(pconn != nullptr, false);
593  fc_assert_ret_val_msg(!pconn->observer && pconn->playing == nullptr, false,
594  "connections must be detached with "
595  "connection_detach() before calling this!");
596 
597  if (!observing) {
598  if (nullptr == pplayer) {
599  // search for uncontrolled player
600  pplayer = find_uncontrolled_player();
601 
602  if (nullptr == pplayer) {
603  // no uncontrolled player found
604  if (player_count() >= game.server.max_players
605  || normal_player_count() >= server.playable_nations) {
606  return false;
607  }
608  // add new player, or not
609  /* Should only be called in such a way as to create a new player
610  * in the pregame */
612  pplayer =
613  server_create_player(-1, default_ai_type_name(), nullptr, false);
614  // Pregame => no need to assign_player_colors()
615  if (!pplayer) {
616  return false;
617  }
618  } else {
619  team_remove_player(pplayer);
620  }
621  server_player_init(pplayer, false, true);
622 
623  // Make it human!
624  set_as_human(pplayer);
625  }
626 
627  sz_strlcpy(pplayer->username, pconn->username);
628  pplayer->unassigned_user = false;
629  pplayer->user_turns = 0; // reset for a new user
630  pplayer->is_connected = true;
631 
632  if (!game_was_started()) {
633  if (!pplayer->was_created && nullptr == pplayer->nation) {
634  // Temporarily set player_name() to username.
635  server_player_set_name(pplayer, pconn->username);
636  }
637  (void) aifill(game.info.aifill);
638  }
639 
640  if (game.server.auto_ai_toggle && !is_human(pplayer)) {
641  toggle_ai_player_direct(nullptr, pplayer);
642  }
643 
645 
646  // Remove from global observers list, if was there
647  conn_list_remove(game.glob_observers, pconn);
648  } else if (pplayer == nullptr) {
649  // Global observer
650  bool already = false;
651 
652  fc_assert(observing);
653 
655  {
656  if (pconn2 == pconn) {
657  already = true;
658  break;
659  }
660  }
662 
663  if (!already) {
664  conn_list_append(game.glob_observers, pconn);
665  }
666  }
667 
668  // We don't want the connection's username on another player.
669  players_iterate(aplayer)
670  {
671  if (aplayer != pplayer
672  && 0 == strncmp(aplayer->username, pconn->username, MAX_LEN_NAME)) {
673  sz_strlcpy(aplayer->username, _(ANON_USER_NAME));
674  aplayer->unassigned_user = true;
675  send_player_info_c(aplayer, nullptr);
676  }
677  }
679 
680  pconn->observer = observing;
681  pconn->playing = pplayer;
682  if (pplayer) {
683  conn_list_append(pplayer->connections, pconn);
684  }
685 
686  restore_access_level(pconn);
687 
688  // Reset the delta-state.
689  send_conn_info(pconn->self, game.est_connections); // Client side.
690  conn_reset_delta_state(pconn); // Server side.
691 
692  /* Initial packets don't need to be resent. See comment for
693  * connecthand.c::establish_new_connection(). */
694  switch (server_state()) {
695  case S_S_INITIAL:
696  send_pending_events(pconn, connecting);
697  send_running_votes(pconn, !connecting);
698  break;
699 
700  case S_S_RUNNING:
702  send_all_info(pconn->self);
703  if (game.info.is_edit_mode && can_conn_edit(pconn)) {
705  }
706  conn_compression_thaw(pconn);
707  // Enter C_S_RUNNING client state.
708  dsend_packet_start_phase(pconn, game.info.phase);
709  // Must be after C_S_RUNNING client state to be effective.
711  send_pending_events(pconn, connecting);
712  send_running_votes(pconn, !connecting);
713  break;
714 
715  case S_S_OVER:
717  send_all_info(pconn->self);
718  if (game.info.is_edit_mode && can_conn_edit(pconn)) {
720  }
721  conn_compression_thaw(pconn);
722  report_final_scores(pconn->self);
723  send_pending_events(pconn, connecting);
724  send_running_votes(pconn, !connecting);
725  if (!connecting) {
726  // Send information about delegation(s).
727  send_delegation_info(pconn);
728  }
729  break;
730  }
731 
732  send_updated_vote_totals(nullptr);
733 
734  return true;
735 }
736 
740 bool connection_attach(struct connection *pconn, struct player *pplayer,
741  bool observing)
742 {
743  return connection_attach_real(pconn, pplayer, observing, false);
744 }
745 
756 void connection_detach(struct connection *pconn, bool remove_unused_player)
757 {
758  struct player *pplayer;
759 
760  fc_assert_ret(pconn != nullptr);
761 
762  if (nullptr != (pplayer = pconn->playing)) {
763  bool was_connected = pplayer->is_connected;
764 
765  send_remove_team_votes(pconn);
766  conn_list_remove(pplayer->connections, pconn);
767  pconn->playing = nullptr;
768  pconn->observer = false;
769  restore_access_level(pconn);
771  send_updated_vote_totals(nullptr);
773 
774  /* If any other (non-observing) conn is attached to this player, the
775  * player is still connected. */
776  pplayer->is_connected = false;
777  conn_list_iterate(pplayer->connections, aconn)
778  {
779  if (!aconn->observer) {
780  pplayer->is_connected = true;
781  break;
782  }
783  }
785 
786  if (was_connected && !pplayer->is_connected) {
787  // Player just lost its controlling connection.
788  if (remove_unused_player && !pplayer->was_created
789  && !game_was_started()) {
790  // Remove player.
791  conn_list_iterate(pplayer->connections, aconn)
792  {
793  // Detach all.
794  fc_assert_action(aconn != pconn, continue);
795  notify_conn(aconn->self, nullptr, E_CONNECTION, ftc_server,
796  _("Detaching from %s."), player_name(pplayer));
797  /* Recursive... but shouldn't be a problem, as this can only
798  * be a non-controlling connection so can't get back here. */
799  connection_detach(aconn, true);
800  }
802 
803  // Actually do the removal.
804  server_remove_player(pplayer);
805  (void) aifill(game.info.aifill);
807  } else {
808  // Aitoggle the player if no longer connected.
809  if (game.server.auto_ai_toggle && is_human(pplayer)) {
810  toggle_ai_player_direct(nullptr, pplayer);
811  /* send_player_info_c() was formerly updated by
812  * toggle_ai_player_direct(), so it must be safe to send here now?
813  *
814  * At other times, data from send_conn_info() is used by the
815  * client to display player information.
816  * See establish_new_connection().
817  */
818  qDebug("connection_detach() calls send_player_info_c()");
819  send_player_info_c(pplayer, nullptr);
820 
822  } else {
823  // is_connected has changed
824  send_player_info_c(pplayer, nullptr);
825  }
826  }
827  }
828  } else {
829  pconn->observer = false;
830  restore_access_level(pconn);
832  }
833 }
834 
839  struct player *dplayer)
840 {
841  fc_assert_ret_val(pconn->server.delegation.status == false, false);
842 
843  /* Save the original player of this connection and the original username of
844  * the player. */
845  pconn->server.delegation.status = true;
846  pconn->server.delegation.playing = conn_get_player(pconn);
847  pconn->server.delegation.observer = pconn->observer;
848  if (conn_controls_player(pconn)) {
849  /* Setting orig_username in the player we're about to put aside is
850  * a flag that no-one should be allowed to mess with it (e.g. /take). */
851  struct player *oplayer = conn_get_player(pconn);
852 
853  fc_assert_ret_val(oplayer != dplayer, false);
854  fc_assert_ret_val(strlen(oplayer->server.orig_username) == 0, false);
855  sz_strlcpy(oplayer->server.orig_username, oplayer->username);
856  }
857  fc_assert_ret_val(strlen(dplayer->server.orig_username) == 0, false);
858  sz_strlcpy(dplayer->server.orig_username, dplayer->username);
859 
860  // Detach the current connection.
861  if (nullptr != pconn->playing || pconn->observer) {
862  connection_detach(pconn, false);
863  }
864 
865  // Try to attach to the new player
866  if (!connection_attach(pconn, dplayer, false)) {
867  // Restore original connection.
868  bool success = connection_attach(pconn, pconn->server.delegation.playing,
869  pconn->server.delegation.observer);
870  fc_assert_ret_val(success, false);
871 
872  // Reset all changes done above.
873  pconn->server.delegation.status = false;
874  pconn->server.delegation.playing = nullptr;
875  pconn->server.delegation.observer = false;
876  if (conn_controls_player(pconn)) {
877  struct player *oplayer = conn_get_player(pconn);
878  oplayer->server.orig_username[0] = '\0';
879  }
880  dplayer->server.orig_username[0] = '\0';
881 
882  return false;
883  }
884 
885  return true;
886 }
887 
895 {
896  struct player *dplayer;
897 
898  if (!pconn->server.delegation.status) {
899  return false;
900  }
901 
902  if (pconn->server.delegation.playing
903  && !pconn->server.delegation.observer) {
904  /* If restoring to controlling another player, and we're not the
905  * original controller of that player, something's gone wrong. */
907  strcmp(pconn->server.delegation.playing->server.orig_username,
908  pconn->username)
909  == 0,
910  false);
911  }
912 
913  // Save the current (delegated) player.
914  dplayer = conn_get_player(pconn);
915 
916  // There should be a delegated player connected to pconn.
917  fc_assert_ret_val(dplayer, false);
918 
919  // Detach the current (delegate) connection from the delegated player.
920  if (nullptr != pconn->playing || pconn->observer) {
921  connection_detach(pconn, false);
922  }
923 
924  // Try to attach to the delegate's original player
925  if ((nullptr != pconn->server.delegation.playing
926  || pconn->server.delegation.observer)
927  && !connection_attach(pconn, pconn->server.delegation.playing,
928  pconn->server.delegation.observer)) {
929  return false;
930  }
931 
932  // Reset data.
933  pconn->server.delegation.status = false;
934  pconn->server.delegation.playing = nullptr;
935  pconn->server.delegation.observer = false;
936  if (conn_controls_player(pconn) && conn_get_player(pconn) != nullptr) {
937  // Remove flag that we had 'put aside' our original player.
938  struct player *oplayer = conn_get_player(pconn);
939  fc_assert_ret_val(oplayer != dplayer, false);
940  oplayer->server.orig_username[0] = '\0';
941  }
942 
943  /* Restore the username of the original controller in the previously-
944  * delegated player. */
945  sz_strlcpy(dplayer->username, dplayer->server.orig_username);
946  dplayer->server.orig_username[0] = '\0';
947  // Send updated username to all connections.
948  send_player_info_c(dplayer, nullptr);
949 
950  return true;
951 }
952 
957 void connection_close_server(struct connection *pconn, const QString &reason)
958 {
959  // Restore possible delegations before the connection is closed.
961  connection_close(pconn, reason);
962 }
const char * default_ai_type_name()
Return name of default ai type.
Definition: aiiface.cpp:265
bool auth_user(struct connection *pconn, char *username)
Handle authentication of a user; called by handle_login_request() if authentication is enabled.
Definition: auth.cpp:56
bool has_capabilities(const char *us, const char *them)
This routine returns true if all the mandatory capabilities in us appear in them.
Definition: capability.cpp:80
const char *const our_capability
Definition: capstr.cpp:28
static bool connection_attach_real(struct connection *pconn, struct player *pplayer, bool observing, bool connecting)
Setup pconn as a client connected to pplayer or observer: Updates pconn->playing, pplayer->connection...
void send_conn_info(struct conn_list *src, struct conn_list *dest)
Send conn_info packets to tell 'dest' connections all about 'src' connections.
bool connection_attach(struct connection *pconn, struct player *pplayer, bool observing)
Setup pconn as a client connected to pplayer or observer.
static void package_conn_info(struct connection *pconn, struct packet_conn_info *packet)
Fill in packet_conn_info from full connection struct.
void reject_new_connection(const char *msg, struct connection *pconn)
send the rejection packet to the client.
static void send_conn_info_arg(struct conn_list *src, struct conn_list *dest, bool remove_conn)
Handle both send_conn_info() and send_conn_info_removed(), depending on 'remove' arg.
bool connection_delegate_take(struct connection *pconn, struct player *dplayer)
Use a delegation to get control over another player.
bool handle_login_request(struct connection *pconn, struct packet_server_join_req *req)
Returns FALSE if the clients gets rejected and the connection should be closed.
static void restore_access_level(struct connection *pconn)
Restore access level for the given connection (user).
Definition: connecthand.cpp:89
void lost_connection_to_client(struct connection *pconn)
High-level server stuff when connection to client is closed or lost.
struct player * find_uncontrolled_player()
Search for first uncontrolled player.
void connection_close_server(struct connection *pconn, const QString &reason)
Close a connection.
void connection_detach(struct connection *pconn, bool remove_unused_player)
Remove pconn as a client connected to pplayer: Updates pconn->playing, pconn->playing->connections,...
void conn_set_access(struct connection *pconn, enum cmdlevel new_level, bool granted)
Set the access level of a connection, and re-send some needed info.
Definition: connecthand.cpp:67
bool connection_delegate_restore(struct connection *pconn)
Restore the original status of a delegate connection pconn after potentially using a delegation.
void send_conn_info_remove(struct conn_list *src, struct conn_list *dest)
Like send_conn_info(), but turn off the 'used' bits to tell clients to remove info about these connec...
void establish_new_connection(struct connection *pconn)
This is used when a new player joins a server, before the game has started.
bool can_conn_edit(const struct connection *pconn)
Return TRUE iff the connection is currently allowed to edit.
Definition: connection.cpp:472
void flush_connection_send_buffer_all(struct connection *pc)
Flush'em.
Definition: connection.cpp:177
struct player * conn_get_player(const struct connection *pconn)
Returns the player that this connection is attached to, or nullptr.
Definition: connection.cpp:693
const char * conn_description(const struct connection *pconn, bool is_private)
° Return pointer to static string containing a description for this ° connection, based on pconn->nam...
Definition: connection.cpp:431
void conn_set_capability(struct connection *pconn, const char *capability)
Set the network capability string for 'pconn'.
Definition: connection.cpp:603
void conn_reset_delta_state(struct connection *pc)
Remove all is-game-info cached packets from the connection.
Definition: connection.cpp:615
bool conn_controls_player(const struct connection *pconn)
Returns TRUE if the given connection is attached to a player which it also controls (i....
Definition: connection.cpp:675
void connection_close(struct connection *pconn, const QString &reason)
Call the conn_close_callback.
Definition: connection.cpp:69
void conn_compression_freeze(struct connection *pconn)
Freeze the connection.
Definition: connection.cpp:636
struct connection * conn_by_user(const char *user_name)
Find connection by exact user name, from game.all_connections, case-insensitve.
Definition: connection.cpp:329
enum cmdlevel conn_get_access(const struct connection *pconn)
Returns the current access level of the given connection.
Definition: connection.cpp:705
@ AS_NOT_ESTABLISHED
Definition: connection.h:84
@ AS_ESTABLISHED
Definition: connection.h:88
bool conn_compression_thaw(struct connection *pconn)
Thaw the connection.
Definition: packets.cpp:160
#define conn_list_iterate(connlist, pconn)
Definition: connection.h:99
#define conn_list_iterate_end
Definition: connection.h:101
void send_diplomatic_meetings(struct connection *dest)
Send information on any on-going diplomatic meetings for connection's player.
Definition: diplhand.cpp:859
void edithand_send_initial_packets(struct conn_list *dest)
Send the needed packets for connections entering in the editing mode.
Definition: edithand.cpp:94
#define MAX_NUM_PLAYER_SLOTS
Definition: fc_types.h:24
#define MAX_LEN_NAME
Definition: fc_types.h:61
#define _(String)
Definition: fcintl.h:50
const struct ft_color ftc_player_lost
const struct ft_color ftc_server
const struct ft_color ftc_editor
const struct ft_color ftc_any
struct civ_game game
Definition: game.cpp:47
struct world wld
Definition: game.cpp:48
const char * new_challenge_filename(struct connection *pc)
Find a file that we can write too, and return it's name.
Definition: gamehand.cpp:1099
void send_scenario_description(struct conn_list *dest)
Send description of the current scenario.
Definition: gamehand.cpp:967
void send_scenario_info(struct conn_list *dest)
Send current scenario info.
Definition: gamehand.cpp:950
void send_game_info(struct conn_list *dest)
Send game_info packet; some server options and various stuff...
Definition: gamehand.cpp:905
#define fc_assert_msg(condition, message,...)
Definition: log.h:96
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert(condition)
Definition: log.h:89
#define fc_assert_ret_val(condition, val)
Definition: log.h:114
#define fc_assert_action(condition, action)
Definition: log.h:104
#define log_debug(message,...)
Definition: log.h:65
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition: log.h:132
void maybe_automatic_meta_message(const char *automatic)
Update meta message.
Definition: meta.cpp:112
const char * default_meta_message_string()
Return static string with default info line to send to metaserver.
Definition: meta.cpp:63
bool send_server_info_to_metaserver(enum meta_flag flag)
Control when we send info to the metaserver.
Definition: meta.cpp:469
@ META_INFO
Definition: meta.h:25
void send_pending_events(struct connection *pconn, bool include_public)
Send all available events.
Definition: notify.cpp:742
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
See notify_conn_packet - this is just the "non-v" version, with varargs.
Definition: notify.cpp:235
void package_event(struct packet_chat_msg *packet, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Fill a packet_chat_msg structure for common server event.
Definition: notify.cpp:164
void event_cache_add_for_all(const struct packet_chat_msg *packet)
Add an event to the cache for all connections.
Definition: notify.cpp:609
#define MAX_LEN_MSG
Definition: packets.h:37
bool is_valid_username(const char *name)
Returns whether this is a valid username.
Definition: player.cpp:1793
int player_number(const struct player *pplayer)
Return the player index/number/id.
Definition: player.cpp:756
int player_count()
Return the number of players.
Definition: player.cpp:739
const char * player_name(const struct player *pplayer)
Return the leader name of the player.
Definition: player.cpp:816
struct player * player_by_user(const char *name)
Find player by its user name (not player/leader name)
Definition: player.cpp:860
#define players_iterate_end
Definition: player.h:520
#define players_iterate(_pplayer)
Definition: player.h:514
#define ANON_USER_NAME
Definition: player.h:31
#define set_as_human(plr)
Definition: player.h:228
#define players_iterate_alive_end
Definition: player.h:532
#define is_human(plr)
Definition: player.h:226
#define players_iterate_alive(_pplayer)
Definition: player.h:526
void server_player_set_name(struct player *pplayer, const char *name)
Try to set the player name to 'name'.
Definition: plrhand.cpp:2159
struct player * server_create_player(int player_id, const char *ai_tname, struct rgbcolor *prgbcolor, bool allow_ai_type_fallbacking)
Creates a new, uninitialized, used player slot.
Definition: plrhand.cpp:1776
struct player * player_by_user_delegated(const char *name)
For a given user, if there is some player that the user originally controlled but is currently delega...
Definition: plrhand.cpp:3252
void send_player_info_c(struct player *src, struct conn_list *dest)
Send information about player slot 'src', or all valid (i.e.
Definition: plrhand.cpp:1048
void send_delegation_info(const struct connection *pconn)
Send information about delegations to reconnecting users.
Definition: plrhand.cpp:3207
void server_remove_player(struct player *pplayer)
This function does not close any connections attached to this player.
Definition: plrhand.cpp:1825
void server_player_init(struct player *pplayer, bool initmap, bool needs_team)
Initialize ANY newly-created player on the server.
Definition: plrhand.cpp:1494
int normal_player_count()
Return the number of non-barbarian players.
Definition: plrhand.cpp:3140
const char * player_delegation_get(const struct player *pplayer)
Returns the username that control of the player is delegated to, if any.
Definition: plrhand.cpp:3170
void reset_all_start_commands(bool plrchange)
Called when something is changed; this resets everyone's readiness.
Definition: plrhand.cpp:2658
void report_final_scores(struct conn_list *dest)
Inform clients about player scores and statistics when the game ends.
Definition: report.cpp:1741
void send_current_history_report(struct conn_list *dest)
Send history report of this turn.
Definition: report.cpp:323
void send_rulesets(struct conn_list *dest)
Send all ruleset information to the specified connections.
Definition: ruleset.cpp:8890
struct setting_list * level[OLEVELS_NUM]
Definition: settings.cpp:167
void send_server_setting_control(struct connection *pconn)
Tell the client about all server settings.
Definition: settings.cpp:4986
void send_server_settings(struct conn_list *dest)
Tell the client about all server settings.
Definition: settings.cpp:4941
void send_server_access_level_settings(struct conn_list *dest, enum cmdlevel old_level, enum cmdlevel new_level)
Send the server settings that got a different visibility or changability after a connection access le...
Definition: settings.cpp:4952
void remove_leading_trailing_spaces(char *s)
Removes leading and trailing spaces in string pointed to by 's'.
Definition: shared.cpp:353
const char * aifill(int amount)
Fill or remove players to meet the given aifill.
Definition: srv_main.cpp:2440
void check_for_full_turn_done()
Check if turn is really done.
Definition: srv_main.cpp:2179
struct server_arguments srvarg
Definition: srv_main.cpp:118
bool game_was_started()
Returns iff the game was started once upon a time.
Definition: srv_main.cpp:251
enum server_states server_state()
Return current server state.
Definition: srv_main.cpp:238
void send_all_info(struct conn_list *dest)
Send all information for when game starts or client reconnects.
Definition: srv_main.cpp:607
void notify_if_first_access_level_is_available()
Check if first access level is available and if it is, notify connections about it.
Definition: stdinhand.cpp:1382
bool conn_is_kicked(struct connection *pconn, int *time_remaining)
Returns FALSE if the connection isn't kicked and can connect the server normally.
Definition: stdinhand.cpp:6280
void toggle_ai_player_direct(struct connection *caller, struct player *pplayer)
Handle ai player ai toggling.
Definition: stdinhand.cpp:676
struct civ_game::@28::@32 server
struct conn_list * glob_observers
Definition: game.h:89
struct conn_list * est_connections
Definition: game.h:88
struct packet_game_info info
Definition: game.h:80
struct conn_list * all_connections
Definition: game.h:87
int topology_id
Definition: map_types.h:68
bool established
Definition: connection.h:131
struct player * playing
Definition: connection.h:142
enum cmdlevel access_level
Definition: connection.h:164
struct conn_list * self
Definition: connection.h:150
struct connection::@55::@61 server
bool observer
Definition: connection.h:138
char username[MAX_LEN_NAME]
Definition: connection.h:151
char capability[MAX_LEN_CAPSTR]
Definition: connection.h:158
QString addr
Definition: connection.h:152
Definition: player.h:231
char username[MAX_LEN_NAME]
Definition: player.h:234
bool is_connected
Definition: player.h:278
struct player::@65::@67 server
bool was_created
Definition: player.h:276
struct conn_list * connections
Definition: player.h:280
struct nation_type * nation
Definition: player.h:242
int user_turns
Definition: player.h:238
bool unassigned_user
Definition: player.h:235
bool auth_enabled
Definition: srv_main.h:61
Definition: servers.h:55
struct civ_map map
Definition: world_object.h:21
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
int fc_gethostname(char *buf, size_t len)
Call gethostname() if supported, else just returns -1.
Definition: support.cpp:586
int fc_strcasecmp(const char *str0, const char *str1)
Compare strings like strcmp(), but ignoring case.
Definition: support.cpp:89
#define sz_strlcpy(dest, src)
Definition: support.h:140
void team_remove_player(struct player *pplayer)
Remove the player from the team.
Definition: team.cpp:471
void timer_destroy(civtimer *t)
Deletes timer.
Definition: timing.cpp:66
const char * freeciv_name_version()
Return string containing both name of Freeciv21 and version.
Definition: version.cpp:34
void send_running_votes(struct connection *pconn, bool only_team_votes)
Sends a packet_vote_new to pconn for every currently running votes.
Definition: voting.cpp:827
void send_remove_team_votes(struct connection *pconn)
Sends a packet_vote_remove to pconn for every currently running team vote 'pconn' can see.
Definition: voting.cpp:859
void cancel_connection_votes(struct connection *pconn)
Cancel the votes of a lost or a detached connection.
Definition: voting.cpp:702
void send_updated_vote_totals(struct conn_list *dest)
Sends a packet_vote_update to every conn in dest.
Definition: voting.cpp:884