Freeciv-3.1: /fast/freeciv/nightly/S3_1/server/connecthand.c Source File

Freeciv-3.1

Loading...
Searching...
No Matches
connecthand.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <string.h>
19
20/* utility */
21#include "capability.h"
22#include "fcintl.h"
23#include "log.h"
24#include "mem.h"
25#include "support.h"
26
27/* common */
28#include "capstr.h"
29#include "events.h"
30#include "game.h"
31#include "packets.h"
32#include "player.h"
33#include "version.h"
34
35/* server */
36#include "aiiface.h"
37#include "auth.h"
38#include "diplhand.h"
39#include "edithand.h"
40#include "gamehand.h"
41#include "maphand.h"
42#include "meta.h"
43#include "notify.h"
44#include "plrhand.h"
45#include "report.h"
46#include "ruleset.h"
47#include "sernet.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
56static bool connection_attach_real(struct connection *pconn,
57 struct player *pplayer,
58 bool observing, bool connecting);
59
60/**********************************************************************/
68 void conn_set_access(struct connection *pconn, enum cmdlevel new_level,
69 bool granted)
70{
71 enum cmdlevel old_level = conn_get_access(pconn);
72
73 pconn->access_level = new_level;
74 if (granted) {
75 pconn->server.granted_access_level = new_level;
76 }
77
78 if (old_level != new_level) {
79 send_server_access_level_settings(pconn->self, old_level, new_level);
80 }
81}
82
83/**********************************************************************/
90 static void restore_access_level(struct connection *pconn)
91{
92 /* Restore previous privileges. */
93 enum cmdlevel level = pconn->server.granted_access_level;
94
95 /* Detached connections must have at most the same privileges
96 * as observers, unless they were granted something higher than
97 * ALLOW_BASIC in the first place. */
98 if ((pconn->observer || !pconn->playing) && level == ALLOW_BASIC) {
99 level = ALLOW_INFO;
100 }
101
102 conn_set_access(pconn, level, FALSE);
103}
104
105/**********************************************************************/
123 void establish_new_connection(struct connection *pconn)
124{
125 struct conn_list *dest = pconn->self;
126 struct player *pplayer;
127 struct packet_server_join_reply packet;
128 struct packet_chat_msg connect_info;
129 char hostname[512];
130 bool delegation_error = FALSE;
131 struct packet_set_topology topo_packet;
132
133 /* zero out the password */
134 memset(pconn->server.password, 0, sizeof(pconn->server.password));
135
136 /* send join_reply packet */
137 packet.you_can_join = TRUE;
138 sz_strlcpy(packet.capability, our_capability);
139 fc_snprintf(packet.message, sizeof(packet.message), _("%s Welcome"),
140 pconn->username);
141 sz_strlcpy(packet.challenge_file, new_challenge_filename(pconn));
142 packet.conn_id = pconn->id;
143 send_packet_server_join_reply(pconn, &packet);
144
145 /* "establish" the connection */
146 pconn->established = TRUE;
147 pconn->server.status = AS_ESTABLISHED;
148
149 pconn->server.delegation.status = FALSE;
150 pconn->server.delegation.playing = NULL;
151 pconn->server.delegation.observer = FALSE;
152
153 conn_list_append(game.est_connections, pconn);
154 if (conn_list_size(game.est_connections) == 1) {
155 /* First connection
156 * Replace "restarting in x seconds" meta message */
157 maybe_automatic_meta_message(default_meta_message_string());
158 (void) send_server_info_to_metaserver(META_INFO);
159 }
160
161 /* introduce the server to the connection */
162 if (fc_gethostname(hostname, sizeof(hostname)) == 0) {
163 notify_conn(dest, NULL, E_CONNECTION, ftc_any,
164 _("Welcome to the %s Server running at %s port %d."),
165 freeciv_name_version(), hostname, srvarg.port);
166 } else {
167 notify_conn(dest, NULL, E_CONNECTION, ftc_any,
168 _("Welcome to the %s Server at port %d."),
169 freeciv_name_version(), srvarg.port);
170 }
171
172 /* FIXME: this (getting messages about others logging on) should be a
173 * message option for the client with event */
174
175 /* Notify the console that you're here. */
176 log_normal(_("%s has connected from %s."), pconn->username, pconn->addr);
177
178 conn_compression_freeze(pconn);
179 send_rulesets(dest);
180 send_server_setting_control(pconn);
181 send_server_settings(dest);
182 send_scenario_info(dest);
183 send_scenario_description(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) != NULL);
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, NULL, E_CONNECTION, ftc_server,
199 _("Your delegate %s was controlling your player '%s'; "
200 "now detached."), pdelegate->username,
201 player_name(pplayer));
202 notify_conn(pdelegate->self, NULL, E_CONNECTION, ftc_server,
203 _("%s reconnected, ending your delegated control of "
204 "player '%s'."), pconn->username, player_name(pplayer));
205 } else {
206 fc_assert(pdelegate);
207 /* This really shouldn't happen. */
208 log_error("Failed to revoke delegate %s's control of %s, so owner %s "
209 "can't regain control.", pdelegate->username,
210 player_name(pplayer), pconn->username);
211 notify_conn(dest, NULL, E_CONNECTION, ftc_server,
212 _("Couldn't get control of '%s' from delegation to %s."),
213 player_name(pplayer), pdelegate->username);
214 delegation_error = TRUE;
215 pplayer = NULL;
216 }
217 }
218
219 if (!delegation_error) {
220 if ((pplayer = player_by_user(pconn->username))
221 && connection_attach_real(pconn, pplayer, FALSE, TRUE)) {
222 /* a player has already been created for this user, reconnect */
223
224 if (S_S_INITIAL == server_state()) {
225 send_player_info_c(NULL, dest);
226 }
227 } else {
228 if (!game_was_started()) {
229 if (connection_attach_real(pconn, NULL, FALSE, TRUE)) {
230 pplayer = conn_get_player(pconn);
231 fc_assert(pplayer != NULL);
232 } else {
233 notify_conn(dest, NULL, E_CONNECTION, ftc_server,
234 _("Couldn't attach your connection to new player."));
235 log_verbose("%s is not attached to a player", pconn->username);
236 }
237 }
238 send_player_info_c(NULL, dest);
239 }
240 }
241
242 send_conn_info(game.est_connections, dest);
243
244 if (NULL == pplayer) {
245 /* Else this has already been done in connection_attach_real(). */
246 send_pending_events(pconn, TRUE);
247 send_running_votes(pconn, FALSE);
248 restore_access_level(pconn);
249 send_conn_info(dest, game.est_connections);
250
251 notify_conn(dest, NULL, E_CONNECTION, ftc_server,
252 _("You are logged in as '%s' connected to no player."),
253 pconn->username);
254 } else {
255 notify_conn(dest, NULL, E_CONNECTION, ftc_server,
256 _("You are logged in as '%s' connected to %s."),
257 pconn->username,
258 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 if (game.server.ip_hide) {
270 package_event(&connect_info, NULL, E_CONNECTION, ftc_server,
271 _("%s has connected (player %s)."),
272 pconn->username,
273 player_name(conn_get_player(pconn)));
274 } else {
275 package_event(&connect_info, NULL, E_CONNECTION, ftc_server,
276 _("%s has connected from %s (player %s)."),
277 pconn->username, pconn->addr,
278 player_name(conn_get_player(pconn)));
279 }
280 } else {
281 if (game.server.ip_hide) {
282 package_event(&connect_info, NULL, E_CONNECTION, ftc_server,
283 _("%s has connected."),
284 pconn->username);
285 } else {
286 package_event(&connect_info, NULL, E_CONNECTION, ftc_server,
287 _("%s has connected from %s."),
288 pconn->username, pconn->addr);
289 }
290 }
291 conn_list_iterate(game.est_connections, aconn) {
292 if (aconn != pconn) {
293 send_packet_chat_msg(aconn, &connect_info);
294 }
295 } conn_list_iterate_end;
296 event_cache_add_for_all(&connect_info);
297
298 /* if need be, tell who we're waiting on to end the game.info.turn */
299 if (S_S_RUNNING == server_state() && game.server.turnblock) {
300 players_iterate_alive(cplayer) {
301 if (is_human(cplayer)
302 && !cplayer->phase_done
303 && cplayer != pconn->playing) { /* skip current player */
304 notify_conn(dest, NULL, E_CONNECTION, ftc_any,
305 _("Turn-blocking game play: "
306 "waiting on %s to finish turn..."),
307 player_name(cplayer));
308 }
309 } players_iterate_alive_end;
310 }
311
312 if (game.info.is_edit_mode) {
313 notify_conn(dest, NULL, E_SETTING, ftc_editor,
314 _(" *** Server is in edit mode. *** "));
315 }
316
317 if (NULL != pplayer) {
318 /* Else, no need to do anything. */
319 reset_all_start_commands(TRUE);
320 (void) send_server_info_to_metaserver(META_INFO);
321 }
322
323 send_current_history_report(pconn->self);
324
325 conn_compression_thaw(pconn);
326}
327
328/**********************************************************************/
331 void reject_new_connection(const char *msg, struct connection *pconn)
332{
333 struct packet_server_join_reply packet;
334
335 /* zero out the password */
336 memset(pconn->server.password, 0, sizeof(pconn->server.password));
337
338 packet.you_can_join = FALSE;
339 sz_strlcpy(packet.capability, our_capability);
340 sz_strlcpy(packet.message, msg);
341 packet.challenge_file[0] = '\0';
342 packet.conn_id = -1;
343 send_packet_server_join_reply(pconn, &packet);
344 log_normal(_("Client rejected: %s."), conn_description(pconn));
345 flush_connection_send_buffer_all(pconn);
346}
347
348/**********************************************************************/
352 bool handle_login_request(struct connection *pconn,
353 struct packet_server_join_req *req)
354{
355 char msg[MAX_LEN_MSG];
356 int kick_time_remaining;
357
358 if (pconn->established || pconn->server.status != AS_NOT_ESTABLISHED) {
359 /* We read the PACKET_SERVER_JOIN_REQ twice from this connection,
360 * this is probably not a Freeciv client. */
361 return FALSE;
362 }
363
364 log_normal(_("Connection request from %s from %s"),
365 req->username, pconn->addr);
366
367 /* print server and client capabilities to console */
368 log_normal(_("%s has client version %d.%d.%d%s"),
369 pconn->username, req->major_version, req->minor_version,
370 req->patch_version, req->version_label);
371 log_verbose("Client caps: %s", req->capability);
372 log_verbose("Server caps: %s", our_capability);
373 conn_set_capability(pconn, req->capability);
374
375 /* Make sure the server has every capability the client needs */
376 if (!has_capabilities(our_capability, req->capability)) {
377 fc_snprintf(msg, sizeof(msg),
378 _("The client is missing a capability that this server needs.\n"
379 "Server version: %d.%d.%d%s Client version: %d.%d.%d%s."
380 " Upgrading may help!"),
381 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL,
382 req->major_version, req->minor_version,
383 req->patch_version, req->version_label);
384 reject_new_connection(msg, pconn);
385 log_normal(_("%s was rejected: Mismatched capabilities."),
386 req->username);
387 return FALSE;
388 }
389
390 /* Make sure the client has every capability the server needs */
391 if (!has_capabilities(req->capability, our_capability)) {
392 fc_snprintf(msg, sizeof(msg),
393 _("The server is missing a capability that the client needs.\n"
394 "Server version: %d.%d.%d%s Client version: %d.%d.%d%s."
395 " Upgrading may help!"),
396 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL,
397 req->major_version, req->minor_version,
398 req->patch_version, req->version_label);
399 reject_new_connection(msg, pconn);
400 log_normal(_("%s was rejected: Mismatched capabilities."),
401 req->username);
402 return FALSE;
403 }
404
405 {
406 /* Client is compatible. That includes ability to receive server info.
407 * Send it. */
408 struct packet_server_info info;
409
410 info.major_version = MAJOR_VERSION;
411 info.minor_version = MINOR_VERSION;
412 info.patch_version = PATCH_VERSION;
413#ifdef EMERGENCY_VERSION
414 info.emerg_version = EMERGENCY_VERSION;
415#else
416 info.emerg_version = 0;
417#endif
418 sz_strlcpy(info.version_label, VERSION_LABEL);
419 send_packet_server_info(pconn, &info);
420 }
421
422 remove_leading_trailing_spaces(req->username);
423
424 /* Name-sanity check: could add more checks? */
425 if (!is_valid_username(req->username)) {
426 fc_snprintf(msg, sizeof(msg), _("Invalid username '%s'"), req->username);
427 reject_new_connection(msg, pconn);
428 log_normal(_("%s was rejected: Invalid name [%s]."),
429 req->username, pconn->addr);
430 return FALSE;
431 }
432
433 if (conn_is_kicked(pconn, &kick_time_remaining)) {
434 fc_snprintf(msg, sizeof(msg), _("You have been kicked from this server "
435 "and cannot reconnect for %d seconds."),
436 kick_time_remaining);
437 reject_new_connection(msg, pconn);
438 log_normal(_("%s was rejected: Connection kicked "
439 "(%d seconds remaining)."),
440 req->username, kick_time_remaining);
441 return FALSE;
442 }
443
444 /* don't allow duplicate logins */
445 conn_list_iterate(game.all_connections, aconn) {
446 if (fc_strcasecmp(req->username, aconn->username) == 0) {
447 fc_snprintf(msg, sizeof(msg), _("'%s' already connected."),
448 req->username);
449 reject_new_connection(msg, pconn);
450 log_normal(_("%s was rejected: Duplicate login name [%s]."),
451 req->username, pconn->addr);
452 return FALSE;
453 }
454 } conn_list_iterate_end;
455
456 /* Remove the ping timeout given in sernet.c:server_make_connection(). */
457 fc_assert_msg(1 == timer_list_size(pconn->server.ping_timers),
458 "Ping timer list size %d, should be 1. Have we sent "
459 "a ping to unestablished connection %s?",
460 timer_list_size(pconn->server.ping_timers),
461 conn_description(pconn));
462 timer_list_pop_front(pconn->server.ping_timers);
463
464 if (game.server.connectmsg[0] != '\0') {
465 log_debug("Sending connectmsg: %s", game.server.connectmsg);
466 dsend_packet_connect_msg(pconn, game.server.connectmsg);
467 }
468
469 if (srvarg.auth_enabled) {
470 return auth_user(pconn, req->username);
471 } else {
472 sz_strlcpy(pconn->username, req->username);
473 establish_new_connection(pconn);
474 return TRUE;
475 }
476}
477
478/**********************************************************************/
486 void lost_connection_to_client(struct connection *pconn)
487{
488 const char *desc = conn_description(pconn);
489
490 fc_assert_ret(pconn->server.is_closing);
491
492 log_normal(_("Lost connection: %s."), desc);
493
494 /* Special color (white on black) for player loss */
495 notify_conn(game.est_connections, NULL, E_CONNECTION,
496 conn_controls_player(pconn) ? ftc_player_lost : ftc_server,
497 _("Lost connection: %s."), desc);
498
499 connection_detach(pconn, TRUE);
500 send_conn_info_remove(pconn->self, game.est_connections);
501 notify_if_first_access_level_is_available();
502
503 check_for_full_turn_done();
504}
505
506/**********************************************************************/
509 static void package_conn_info(struct connection *pconn,
510 struct packet_conn_info *packet)
511{
512 packet->id = pconn->id;
513 packet->used = pconn->used;
514 packet->established = pconn->established;
515 packet->player_num = (NULL != pconn->playing)
516 ? player_number(pconn->playing)
517 : player_slot_count();
518 packet->observer = pconn->observer;
519 packet->access_level = pconn->access_level;
520
521 sz_strlcpy(packet->username, pconn->username);
522 if (game.server.ip_hide) {
523 sz_strlcpy(packet->addr, Q_("?IP:Hidden"));
524 } else {
525 sz_strlcpy(packet->addr, pconn->addr);
526 }
527 sz_strlcpy(packet->capability, pconn->capability);
528}
529
530/**********************************************************************/
535 static void send_conn_info_arg(struct conn_list *src,
536 struct conn_list *dest, bool remove_conn)
537{
538 struct packet_conn_info packet;
539
540 if (!dest) {
541 dest = game.est_connections;
542 }
543
544 conn_list_iterate(src, psrc) {
545 package_conn_info(psrc, &packet);
546 if (remove_conn) {
547 packet.used = FALSE;
548 }
549 lsend_packet_conn_info(dest, &packet);
550 } conn_list_iterate_end;
551}
552
553/**********************************************************************/
557 void send_conn_info(struct conn_list *src, struct conn_list *dest)
558{
559 send_conn_info_arg(src, dest, FALSE);
560}
561
562/**********************************************************************/
566 void send_conn_info_remove(struct conn_list *src, struct conn_list *dest)
567{
568 send_conn_info_arg(src, dest, TRUE);
569}
570
571/**********************************************************************/
574 struct player *find_uncontrolled_player(void)
575{
576 players_iterate(played) {
577 if (!played->is_connected && !played->was_created) {
578 return played;
579 }
580 } players_iterate_end;
581
582 return NULL;
583}
584
585/**********************************************************************/
601 static bool connection_attach_real(struct connection *pconn,
602 struct player *pplayer,
603 bool observing, bool connecting)
604{
605 fc_assert_ret_val(pconn != NULL, FALSE);
606 fc_assert_ret_val_msg(!pconn->observer && pconn->playing == NULL, FALSE,
607 "connections must be detached with "
608 "connection_detach() before calling this!");
609
610 if (!observing) {
611 if (NULL == pplayer) {
612 /* search for uncontrolled player */
613 pplayer = find_uncontrolled_player();
614
615 if (NULL == pplayer) {
616 /* no uncontrolled player found */
617 if (player_count() >= game.server.max_players
618 || normal_player_count() >= server.playable_nations) {
619 return FALSE;
620 }
621 /* add new player, or not */
622 /* Should only be called in such a way as to create a new player
623 * in the pregame */
624 fc_assert_ret_val(!game_was_started(), FALSE);
625 pplayer = server_create_player(-1, default_ai_type_name(),
626 NULL, FALSE);
627 /* Pregame => no need to assign_player_colors() */
628 if (!pplayer) {
629 return FALSE;
630 }
631 } else {
632 team_remove_player(pplayer);
633 }
634 server_player_init(pplayer, FALSE, TRUE);
635
636 /* Make it human! */
637 set_as_human(pplayer);
638 }
639
640 sz_strlcpy(pplayer->username, pconn->username);
641 pplayer->unassigned_user = FALSE;
642 pplayer->user_turns = 0; /* reset for a new user */
643 pplayer->is_connected = TRUE;
644
645 if (!game_was_started()) {
646 if (!pplayer->was_created && NULL == pplayer->nation) {
647 /* Temporarily set player_name() to username. */
648 server_player_set_name(pplayer, pconn->username);
649 }
650 (void) aifill(game.info.aifill);
651 }
652
653 if (game.server.auto_ai_toggle && !is_human(pplayer)) {
654 toggle_ai_player_direct(NULL, pplayer);
655 }
656
657 send_player_info_c(pplayer, game.est_connections);
658
659 /* Remove from global observers list, if was there */
660 conn_list_remove(game.glob_observers, pconn);
661 } else if (pplayer == NULL) {
662 /* Global observer */
663 bool already = FALSE;
664
665 fc_assert(observing);
666
667 conn_list_iterate(game.glob_observers, pconn2) {
668 if (pconn2 == pconn) {
669 already = TRUE;
670 break;
671 }
672 } conn_list_iterate_end;
673
674 if (!already) {
675 conn_list_append(game.glob_observers, pconn);
676 }
677 }
678
679 /* We don't want the connection's username on another player. */
680 players_iterate(aplayer) {
681 if (aplayer != pplayer
682 && 0 == strncmp(aplayer->username, pconn->username, MAX_LEN_NAME)) {
683 sz_strlcpy(aplayer->username, _(ANON_USER_NAME));
684 aplayer->unassigned_user = TRUE;
685 send_player_info_c(aplayer, NULL);
686 }
687 } players_iterate_end;
688
689 pconn->observer = observing;
690 pconn->playing = pplayer;
691 if (pplayer) {
692 conn_list_append(pplayer->connections, pconn);
693 }
694
695 restore_access_level(pconn);
696
697 /* Reset the delta-state. */
698 send_conn_info(pconn->self, game.est_connections); /* Client side. */
699 conn_reset_delta_state(pconn); /* Server side. */
700
701 /* Initial packets don't need to be resent. See comment for
702 * connecthand.c::establish_new_connection(). */
703 switch (server_state()) {
704 case S_S_INITIAL:
705 send_pending_events(pconn, connecting);
706 send_running_votes(pconn, !connecting);
707 break;
708
709 case S_S_RUNNING:
710 conn_compression_freeze(pconn);
711 send_all_info(pconn->self);
712 if (game.info.is_edit_mode && can_conn_edit(pconn)) {
713 edithand_send_initial_packets(pconn->self);
714 }
715 conn_compression_thaw(pconn);
716 /* Enter C_S_RUNNING client state. */
717 dsend_packet_start_phase(pconn, game.info.phase);
718 /* Must be after C_S_RUNNING client state to be effective. */
719 send_diplomatic_meetings(pconn);
720 send_pending_events(pconn, connecting);
721 send_running_votes(pconn, !connecting);
722 break;
723
724 case S_S_OVER:
725 conn_compression_freeze(pconn);
726 send_all_info(pconn->self);
727 if (game.info.is_edit_mode && can_conn_edit(pconn)) {
728 edithand_send_initial_packets(pconn->self);
729 }
730 conn_compression_thaw(pconn);
731 report_final_scores(pconn->self);
732 send_pending_events(pconn, connecting);
733 send_running_votes(pconn, !connecting);
734 if (!connecting) {
735 /* Send information about delegation(s). */
736 send_delegation_info(pconn);
737 }
738 break;
739 }
740
741 send_updated_vote_totals(NULL);
742
743 return TRUE;
744}
745
746/**********************************************************************/
749 bool connection_attach(struct connection *pconn, struct player *pplayer,
750 bool observing)
751{
752 return connection_attach_real(pconn, pplayer, observing, FALSE);
753}
754
755/**********************************************************************/
765 void connection_detach(struct connection *pconn, bool remove_unused_player)
766{
767 struct player *pplayer;
768
769 fc_assert_ret(pconn != NULL);
770
771 if (NULL != (pplayer = pconn->playing)) {
772 bool was_connected = pplayer->is_connected;
773
774 send_remove_team_votes(pconn);
775 conn_list_remove(pplayer->connections, pconn);
776 pconn->playing = NULL;
777 pconn->observer = FALSE;
778 restore_access_level(pconn);
779 cancel_connection_votes(pconn);
780 send_updated_vote_totals(NULL);
781 send_conn_info(pconn->self, game.est_connections);
782
783 /* If any other (non-observing) conn is attached to this player, the
784 * player is still connected. */
785 pplayer->is_connected = FALSE;
786 conn_list_iterate(pplayer->connections, aconn) {
787 if (!aconn->observer) {
788 pplayer->is_connected = TRUE;
789 break;
790 }
791 } conn_list_iterate_end;
792
793 if (was_connected && !pplayer->is_connected) {
794 /* Player just lost its controlling connection. */
795 if (remove_unused_player
796 && !pplayer->was_created && !game_was_started()) {
797 /* Remove player. */
798 conn_list_iterate(pplayer->connections, aconn) {
799 /* Detach all. */
800 fc_assert_action(aconn != pconn, continue);
801 notify_conn(aconn->self, NULL, E_CONNECTION, ftc_server,
802 _("Detaching from %s."), player_name(pplayer));
803 /* Recursive... but shouldn't be a problem, as this can only
804 * be a non-controlling connection so can't get back here. */
805 connection_detach(aconn, TRUE);
806 } conn_list_iterate_end;
807
808 /* Actually do the removal. */
809 server_remove_player(pplayer);
810 (void) aifill(game.info.aifill);
811 reset_all_start_commands(TRUE);
812 } else {
813 /* Aitoggle the player if no longer connected. */
814 if (game.server.auto_ai_toggle && is_human(pplayer)) {
815 toggle_ai_player_direct(NULL, pplayer);
816 /* send_player_info_c() was formerly updated by
817 * toggle_ai_player_direct(), so it must be safe to send here now?
818 *
819 * At other times, data from send_conn_info() is used by the
820 * client to display player information.
821 * See establish_new_connection().
822 */
823 log_verbose("connection_detach() calls send_player_info_c()");
824 send_player_info_c(pplayer, NULL);
825
826 reset_all_start_commands(TRUE);
827 }
828 }
829 }
830 } else {
831 pconn->observer = FALSE;
832 restore_access_level(pconn);
833 send_conn_info(pconn->self, game.est_connections);
834 }
835}
836
837/**********************************************************************/
840 bool connection_delegate_take(struct connection *pconn,
841 struct player *dplayer)
842{
843 fc_assert_ret_val(!pconn->server.delegation.status, FALSE);
844
845 /* Save the original player of this connection and the original username of
846 * the player. */
847 pconn->server.delegation.status = TRUE;
848 pconn->server.delegation.playing = conn_get_player(pconn);
849 pconn->server.delegation.observer = pconn->observer;
850 if (conn_controls_player(pconn)) {
851 /* Setting orig_username in the player we're about to put aside is
852 * a flag that no-one should be allowed to mess with it (e.g. /take). */
853 struct player *oplayer = conn_get_player(pconn);
854
855 fc_assert_ret_val(oplayer != dplayer, FALSE);
856 fc_assert_ret_val(strlen(oplayer->server.orig_username) == 0, FALSE);
857 sz_strlcpy(oplayer->server.orig_username, oplayer->username);
858 }
859 fc_assert_ret_val(strlen(dplayer->server.orig_username) == 0, FALSE);
860 sz_strlcpy(dplayer->server.orig_username, dplayer->username);
861
862 /* Detach the current connection. */
863 if (NULL != pconn->playing || pconn->observer) {
864 connection_detach(pconn, FALSE);
865 }
866
867 /* Try to attach to the new player */
868 if (!connection_attach(pconn, dplayer, FALSE)) {
869
870 /* Restore original connection. */
871#ifndef FREECIV_NDEBUG
872 bool success =
873#endif
874 connection_attach(pconn,
875 pconn->server.delegation.playing,
876 pconn->server.delegation.observer);
877 fc_assert_ret_val(success, FALSE);
878
879 /* Reset all changes done above. */
880 pconn->server.delegation.status = FALSE;
881 pconn->server.delegation.playing = NULL;
882 pconn->server.delegation.observer = FALSE;
883 if (conn_controls_player(pconn)) {
884 struct player *oplayer = conn_get_player(pconn);
885 oplayer->server.orig_username[0] = '\0';
886 }
887 dplayer->server.orig_username[0] = '\0';
888
889 return FALSE;
890 }
891
892 return TRUE;
893}
894
895/**********************************************************************/
901 bool connection_delegate_restore(struct connection *pconn)
902{
903 struct player *dplayer;
904
905 if (!pconn->server.delegation.status) {
906 return FALSE;
907 }
908
909 if (pconn->server.delegation.playing
910 && !pconn->server.delegation.observer) {
911 /* If restoring to controlling another player, and we're not the
912 * original controller of that player, something's gone wrong. */
913 fc_assert_ret_val(
914 strcmp(pconn->server.delegation.playing->server.orig_username,
915 pconn->username) == 0, FALSE);
916 }
917
918 /* Save the current (delegated) player. */
919 dplayer = conn_get_player(pconn);
920
921 /* There should be a delegated player connected to pconn. */
922 fc_assert_ret_val(dplayer, FALSE);
923
924 /* Detach the current (delegate) connection from the delegated player. */
925 if (NULL != pconn->playing || pconn->observer) {
926 connection_detach(pconn, FALSE);
927 }
928
929 /* Try to attach to the delegate's original player */
930 if ((NULL != pconn->server.delegation.playing
931 || pconn->server.delegation.observer)
932 && !connection_attach(pconn, pconn->server.delegation.playing,
933 pconn->server.delegation.observer)) {
934 return FALSE;
935 }
936
937 /* Reset data. */
938 pconn->server.delegation.status = FALSE;
939 pconn->server.delegation.playing = NULL;
940 pconn->server.delegation.observer = FALSE;
941 if (conn_controls_player(pconn) && conn_get_player(pconn) != NULL) {
942 /* Remove flag that we had 'put aside' our original player. */
943 struct player *oplayer = conn_get_player(pconn);
944 fc_assert_ret_val(oplayer != dplayer, FALSE);
945 oplayer->server.orig_username[0] = '\0';
946 }
947
948 /* Restore the username of the original controller in the previously-
949 * delegated player. */
950 sz_strlcpy(dplayer->username, dplayer->server.orig_username);
951 dplayer->server.orig_username[0] = '\0';
952 /* Send updated username to all connections. */
953 send_player_info_c(dplayer, NULL);
954
955 return TRUE;
956}
957
958/**********************************************************************/
962 void connection_close_server(struct connection *pconn, const char *reason)
963{
964 /* Restore possible delegations before the connection is closed. */
965 connection_delegate_restore(pconn);
966 connection_close(pconn, reason);
967}
default_ai_type_name
const char * default_ai_type_name(void)
Definition aiiface.c:262
aiiface.h
auth_user
bool auth_user(struct connection *pconn, char *username)
Definition auth.c:73
auth.h
has_capabilities
bool has_capabilities(const char *us, const char *them)
Definition capability.c:86
capability.h
our_capability
const char *const our_capability
Definition capstr.c:32
capstr.h
connection_attach_real
static bool connection_attach_real(struct connection *pconn, struct player *pplayer, bool observing, bool connecting)
Definition connecthand.c:601
send_conn_info
void send_conn_info(struct conn_list *src, struct conn_list *dest)
Definition connecthand.c:557
connection_attach
bool connection_attach(struct connection *pconn, struct player *pplayer, bool observing)
Definition connecthand.c:749
package_conn_info
static void package_conn_info(struct connection *pconn, struct packet_conn_info *packet)
Definition connecthand.c:509
reject_new_connection
void reject_new_connection(const char *msg, struct connection *pconn)
Definition connecthand.c:331
send_conn_info_arg
static void send_conn_info_arg(struct conn_list *src, struct conn_list *dest, bool remove_conn)
Definition connecthand.c:535
connection_delegate_take
bool connection_delegate_take(struct connection *pconn, struct player *dplayer)
Definition connecthand.c:840
handle_login_request
bool handle_login_request(struct connection *pconn, struct packet_server_join_req *req)
Definition connecthand.c:352
find_uncontrolled_player
struct player * find_uncontrolled_player(void)
Definition connecthand.c:574
restore_access_level
static void restore_access_level(struct connection *pconn)
Definition connecthand.c:90
lost_connection_to_client
void lost_connection_to_client(struct connection *pconn)
Definition connecthand.c:486
connection_close_server
void connection_close_server(struct connection *pconn, const char *reason)
Definition connecthand.c:962
connection_detach
void connection_detach(struct connection *pconn, bool remove_unused_player)
Definition connecthand.c:765
conn_set_access
void conn_set_access(struct connection *pconn, enum cmdlevel new_level, bool granted)
Definition connecthand.c:68
connection_delegate_restore
bool connection_delegate_restore(struct connection *pconn)
Definition connecthand.c:901
send_conn_info_remove
void send_conn_info_remove(struct conn_list *src, struct conn_list *dest)
Definition connecthand.c:566
establish_new_connection
void establish_new_connection(struct connection *pconn)
Definition connecthand.c:123
connecthand.h
conn_get_player
struct player * conn_get_player(const struct connection *pconn)
Definition connection.c:760
can_conn_edit
bool can_conn_edit(const struct connection *pconn)
Definition connection.c:510
conn_by_user
struct connection * conn_by_user(const char *user_name)
Definition connection.c:376
flush_connection_send_buffer_all
void flush_connection_send_buffer_all(struct connection *pc)
Definition connection.c:229
conn_set_capability
void conn_set_capability(struct connection *pconn, const char *capability)
Definition connection.c:658
conn_reset_delta_state
void conn_reset_delta_state(struct connection *pc)
Definition connection.c:670
connection_close
void connection_close(struct connection *pconn, const char *reason)
Definition connection.c:88
conn_controls_player
bool conn_controls_player(const struct connection *pconn)
Definition connection.c:742
conn_description
const char * conn_description(const struct connection *pconn)
Definition connection.c:473
conn_compression_freeze
void conn_compression_freeze(struct connection *pconn)
Definition connection.c:691
conn_get_access
enum cmdlevel conn_get_access(const struct connection *pconn)
Definition connection.c:772
AS_NOT_ESTABLISHED
@ AS_NOT_ESTABLISHED
Definition connection.h:98
AS_ESTABLISHED
@ AS_ESTABLISHED
Definition connection.h:102
conn_compression_thaw
bool conn_compression_thaw(struct connection *pconn)
Definition packets.c:194
conn_list_iterate
#define conn_list_iterate(connlist, pconn)
Definition connection.h:113
conn_list_iterate_end
#define conn_list_iterate_end
Definition connection.h:115
send_diplomatic_meetings
void send_diplomatic_meetings(struct connection *dest)
Definition diplhand.c:912
diplhand.h
edithand_send_initial_packets
void edithand_send_initial_packets(struct conn_list *dest)
Definition edithand.c:113
edithand.h
events.h
MAX_LEN_NAME
#define MAX_LEN_NAME
Definition fc_types.h:66
fcintl.h
Q_
#define Q_(String)
Definition fcintl.h:70
_
#define _(String)
Definition fcintl.h:67
ftc_player_lost
const struct ft_color ftc_player_lost
Definition featured_text.c:83
ftc_server
const struct ft_color ftc_server
Definition featured_text.c:77
ftc_editor
const struct ft_color ftc_editor
Definition featured_text.c:79
ftc_any
const struct ft_color ftc_any
Definition featured_text.c:73
game
struct civ_game game
Definition game.c:57
wld
struct world wld
Definition game.c:58
game.h
send_scenario_description
void send_scenario_description(struct conn_list *dest)
Definition gamehand.c:962
send_scenario_info
void send_scenario_info(struct conn_list *dest)
Definition gamehand.c:948
send_game_info
void send_game_info(struct conn_list *dest)
Definition gamehand.c:905
new_challenge_filename
const char * new_challenge_filename(struct connection *pc)
Definition gamehand.c:1094
gamehand.h
log.h
fc_assert_msg
#define fc_assert_msg(condition, message,...)
Definition log.h:181
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
fc_assert_action
#define fc_assert_action(condition, action)
Definition log.h:187
log_debug
#define log_debug(message,...)
Definition log.h:115
log_normal
#define log_normal(message,...)
Definition log.h:107
log_error
#define log_error(message,...)
Definition log.h:103
fc_assert_ret_val_msg
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:208
maphand.h
mem.h
maybe_automatic_meta_message
void maybe_automatic_meta_message(const char *automatic)
Definition meta.c:151
default_meta_message_string
const char * default_meta_message_string(void)
Definition meta.c:90
send_server_info_to_metaserver
bool send_server_info_to_metaserver(enum meta_flag flag)
Definition meta.c:490
meta.h
META_INFO
@ META_INFO
Definition meta.h:26
send_pending_events
void send_pending_events(struct connection *pconn, bool include_public)
Definition notify.c:754
notify_conn
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:239
package_event
void package_event(struct packet_chat_msg *packet, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:168
event_cache_add_for_all
void event_cache_add_for_all(const struct packet_chat_msg *packet)
Definition notify.c:620
notify.h
packets.h
MAX_LEN_MSG
#define MAX_LEN_MSG
Definition packets.h:43
dsend_packet_connect_msg
int dsend_packet_connect_msg(struct connection *pc, const char *message)
Definition packets_gen.c:11437
lsend_packet_conn_info
void lsend_packet_conn_info(struct conn_list *dest, const struct packet_conn_info *packet)
Definition packets_gen.c:51586
send_packet_server_info
int send_packet_server_info(struct connection *pc, const struct packet_server_info *packet)
Definition packets_gen.c:11712
send_packet_chat_msg
int send_packet_chat_msg(struct connection *pc, const struct packet_chat_msg *packet)
Definition packets_gen.c:10775
send_packet_set_topology
int send_packet_set_topology(struct connection *pc, const struct packet_set_topology *packet)
Definition packets_gen.c:82608
dsend_packet_start_phase
int dsend_packet_start_phase(struct connection *pc, int phase)
Definition packets_gen.c:52552
send_packet_server_join_reply
int send_packet_server_join_reply(struct connection *pc, const struct packet_server_join_reply *packet)
Definition packets_gen.c:2105
is_valid_username
bool is_valid_username(const char *name)
Definition player.c:1872
player_count
int player_count(void)
Definition player.c:808
player_slot_count
int player_slot_count(void)
Definition player.c:411
player_number
int player_number(const struct player *pplayer)
Definition player.c:828
player_name
const char * player_name(const struct player *pplayer)
Definition player.c:886
player_by_user
struct player * player_by_user(const char *name)
Definition player.c:931
player.h
players_iterate_end
#define players_iterate_end
Definition player.h:535
players_iterate
#define players_iterate(_pplayer)
Definition player.h:530
ANON_USER_NAME
#define ANON_USER_NAME
Definition player.h:48
set_as_human
#define set_as_human(plr)
Definition player.h:235
players_iterate_alive_end
#define players_iterate_alive_end
Definition player.h:545
is_human
#define is_human(plr)
Definition player.h:233
players_iterate_alive
#define players_iterate_alive(_pplayer)
Definition player.h:540
server_player_set_name
void server_player_set_name(struct player *pplayer, const char *name)
Definition plrhand.c:2097
server_create_player
struct player * server_create_player(int player_id, const char *ai_tname, struct rgbcolor *prgbcolor, bool allow_ai_type_fallbacking)
Definition plrhand.c:1723
normal_player_count
int normal_player_count(void)
Definition plrhand.c:3034
player_by_user_delegated
struct player * player_by_user_delegated(const char *name)
Definition plrhand.c:3147
send_player_info_c
void send_player_info_c(struct player *src, struct conn_list *dest)
Definition plrhand.c:1000
send_delegation_info
void send_delegation_info(const struct connection *pconn)
Definition plrhand.c:3104
server_remove_player
void server_remove_player(struct player *pplayer)
Definition plrhand.c:1772
server_player_init
void server_player_init(struct player *pplayer, bool initmap, bool needs_team)
Definition plrhand.c:1450
player_delegation_get
const char * player_delegation_get(const struct player *pplayer)
Definition plrhand.c:3067
reset_all_start_commands
void reset_all_start_commands(bool plrchange)
Definition plrhand.c:2553
plrhand.h
report_final_scores
void report_final_scores(struct conn_list *dest)
Definition report.c:1555
send_current_history_report
void send_current_history_report(struct conn_list *dest)
Definition report.c:298
report.h
send_rulesets
void send_rulesets(struct conn_list *dest)
Definition ruleset.c:9592
ruleset.h
sernet.h
level
struct setting_list * level[OLEVELS_NUM]
Definition settings.c:183
send_server_setting_control
void send_server_setting_control(struct connection *pconn)
Definition settings.c:5177
send_server_settings
void send_server_settings(struct conn_list *dest)
Definition settings.c:5133
send_server_access_level_settings
void send_server_access_level_settings(struct conn_list *dest, enum cmdlevel old_level, enum cmdlevel new_level)
Definition settings.c:5145
settings.h
remove_leading_trailing_spaces
void remove_leading_trailing_spaces(char *s)
Definition shared.c:443
aifill
const char * aifill(int amount)
Definition srv_main.c:2395
game_was_started
bool game_was_started(void)
Definition srv_main.c:339
srvarg
struct server_arguments srvarg
Definition srv_main.c:173
check_for_full_turn_done
void check_for_full_turn_done(void)
Definition srv_main.c:2145
send_all_info
void send_all_info(struct conn_list *dest)
Definition srv_main.c:682
server_state
enum server_states server_state(void)
Definition srv_main.c:323
srv_main.h
notify_if_first_access_level_is_available
void notify_if_first_access_level_is_available(void)
Definition stdinhand.c:1449
conn_is_kicked
bool conn_is_kicked(struct connection *pconn, int *time_remaining)
Definition stdinhand.c:6208
toggle_ai_player_direct
void toggle_ai_player_direct(struct connection *caller, struct player *pplayer)
Definition stdinhand.c:704
stdinhand.h
civ_game::server
struct civ_game::@30::@34 server
civ_game::connectmsg
char connectmsg[MAX_LEN_MSG]
Definition game.h:218
civ_game::glob_observers
struct conn_list * glob_observers
Definition game.h:98
civ_game::est_connections
struct conn_list * est_connections
Definition game.h:97
civ_game::info
struct packet_game_info info
Definition game.h:89
civ_game::ip_hide
bool ip_hide
Definition game.h:173
civ_game::all_connections
struct conn_list * all_connections
Definition game.h:96
civ_game::max_players
int max_players
Definition game.h:155
civ_game::auto_ai_toggle
bool auto_ai_toggle
Definition game.h:129
civ_game::turnblock
bool turnblock
Definition game.h:196
civ_map::topology_id
int topology_id
Definition map_types.h:72
connection
Definition connection.h:141
connection::established
bool established
Definition connection.h:145
connection::playing
struct player * playing
Definition connection.h:156
connection::delegation
struct connection::@57::@63::@64 delegation
connection::access_level
enum cmdlevel access_level
Definition connection.h:182
connection::self
struct conn_list * self
Definition connection.h:168
connection::ping_timers
struct timer_list * ping_timers
Definition connection.h:210
connection::is_closing
bool is_closing
Definition connection.h:236
connection::observer
bool observer
Definition connection.h:152
connection::username
char username[MAX_LEN_NAME]
Definition connection.h:169
connection::server
struct connection::@57::@63 server
connection::status
enum auth_status status
Definition connection.h:222
connection::capability
char capability[MAX_LEN_CAPSTR]
Definition connection.h:176
connection::addr
char addr[MAX_LEN_ADDR]
Definition connection.h:170
connection::id
int id
Definition connection.h:142
connection::password
char password[MAX_LEN_PASSWORD]
Definition connection.h:223
connection::granted_access_level
enum cmdlevel granted_access_level
Definition connection.h:229
connection::used
bool used
Definition connection.h:144
packet_chat_msg
Definition packets_gen.h:287
packet_conn_info
Definition packets_gen.h:876
packet_conn_info::capability
char capability[MAX_LEN_CAPSTR]
Definition packets_gen.h:885
packet_conn_info::established
bool established
Definition packets_gen.h:879
packet_conn_info::observer
bool observer
Definition packets_gen.h:880
packet_conn_info::used
bool used
Definition packets_gen.h:878
packet_conn_info::addr
char addr[MAX_LEN_ADDR]
Definition packets_gen.h:884
packet_conn_info::player_num
int player_num
Definition packets_gen.h:881
packet_conn_info::username
char username[MAX_LEN_NAME]
Definition packets_gen.h:883
packet_conn_info::id
int id
Definition packets_gen.h:877
packet_conn_info::access_level
enum cmdlevel access_level
Definition packets_gen.h:882
packet_game_info::aifill
int aifill
Definition packets_gen.h:121
packet_game_info::is_edit_mode
bool is_edit_mode
Definition packets_gen.h:185
packet_game_info::phase
int phase
Definition packets_gen.h:206
packet_server_info
Definition packets_gen.h:313
packet_server_info::major_version
int major_version
Definition packets_gen.h:315
packet_server_info::version_label
char version_label[48]
Definition packets_gen.h:314
packet_server_info::patch_version
int patch_version
Definition packets_gen.h:317
packet_server_info::minor_version
int minor_version
Definition packets_gen.h:316
packet_server_info::emerg_version
int emerg_version
Definition packets_gen.h:318
packet_server_join_reply
Definition packets_gen.h:54
packet_server_join_reply::challenge_file
char challenge_file[4095]
Definition packets_gen.h:58
packet_server_join_reply::you_can_join
bool you_can_join
Definition packets_gen.h:55
packet_server_join_reply::conn_id
int conn_id
Definition packets_gen.h:59
packet_server_join_reply::capability
char capability[512]
Definition packets_gen.h:57
packet_server_join_reply::message
char message[1536]
Definition packets_gen.h:56
packet_server_join_req
Definition packets_gen.h:45
packet_server_join_req::version_label
char version_label[48]
Definition packets_gen.h:48
packet_server_join_req::capability
char capability[512]
Definition packets_gen.h:47
packet_server_join_req::minor_version
int minor_version
Definition packets_gen.h:50
packet_server_join_req::patch_version
int patch_version
Definition packets_gen.h:51
packet_server_join_req::major_version
int major_version
Definition packets_gen.h:49
packet_server_join_req::username
char username[48]
Definition packets_gen.h:46
packet_set_topology
Definition packets_gen.h:1586
packet_set_topology::topology_id
int topology_id
Definition packets_gen.h:1587
player
Definition player.h:249
player::username
char username[MAX_LEN_NAME]
Definition player.h:252
player::is_connected
bool is_connected
Definition player.h:296
player::was_created
bool was_created
Definition player.h:294
player::connections
struct conn_list * connections
Definition player.h:298
player::nation
struct nation_type * nation
Definition player.h:260
player::server
struct player::@69::@71 server
player::user_turns
int user_turns
Definition player.h:256
player::orig_username
char orig_username[MAX_LEN_NAME]
Definition player.h:347
player::unassigned_user
bool unassigned_user
Definition player.h:253
server_arguments::auth_enabled
bool auth_enabled
Definition srv_main.h:57
server_arguments::port
int port
Definition srv_main.h:36
server
Definition servers.h:29
world::map
struct civ_map map
Definition world_object.h:38
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
fc_gethostname
int fc_gethostname(char *buf, size_t len)
Definition support.c:1016
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:161
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
team_remove_player
void team_remove_player(struct player *pplayer)
Definition team.c:502
freeciv_name_version
const char * freeciv_name_version(void)
Definition version.c:35
version.h
send_running_votes
void send_running_votes(struct connection *pconn, bool only_team_votes)
Definition voting.c:810
send_remove_team_votes
void send_remove_team_votes(struct connection *pconn)
Definition voting.c:841
cancel_connection_votes
void cancel_connection_votes(struct connection *pconn)
Definition voting.c:691
send_updated_vote_totals
void send_updated_vote_totals(struct conn_list *dest)
Definition voting.c:866
voting.h