Freeciv-3.1
Loading...
Searching...
No Matches
clinet.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 "fc_prehdrs.h"
19
20#include <errno.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#ifdef FREECIV_HAVE_SYS_TYPES_H
26#include <sys/types.h>
27#endif
28#ifdef HAVE_SYS_SOCKET_H
29#include <sys/socket.h>
30#endif
31#ifdef HAVE_NETINET_IN_H
32#include <netinet/in.h>
33#endif
34#ifdef HAVE_ARPA_INET_H
35#include <arpa/inet.h>
36#endif
37#ifdef HAVE_NETDB_H
38#include <netdb.h>
39#endif
40#ifdef HAVE_PWD_H
41#include <pwd.h>
42#endif
43#ifdef HAVE_SYS_SELECT_H
44#include <sys/select.h>
45#endif
46#ifdef HAVE_SYS_TIME_H
47#include <sys/time.h>
48#endif
49#ifdef HAVE_SYS_UIO_H
50#include <sys/uio.h>
51#endif
52#ifdef HAVE_SYS_UTSNAME_H
53#include <sys/utsname.h>
54#endif
55#ifdef HAVE_UNISTD_H
56#include <unistd.h>
57#endif
58
59/* utility */
60#include "capstr.h"
61#include "dataio.h"
62#include "fcintl.h"
63#include "log.h"
64#include "mem.h"
65#include "netintf.h"
66#include "registry.h"
67#include "support.h"
68
69/* common */
70#include "game.h"
71#include "packets.h"
72#include "version.h"
73
74/* client */
75#include "agents.h"
76#include "attribute.h"
77#include "chatline_g.h"
78#include "client_main.h"
79#include "climisc.h"
80#include "connectdlg_common.h"
81#include "connectdlg_g.h"
82#include "dialogs_g.h" /* popdown_races_dialog() */
83#include "gui_main_g.h" /* add_net_input(), remove_net_input() */
84#include "mapview_common.h" /* unqueue_mapview_update */
85#include "menu_g.h"
86#include "messagewin_g.h"
87#include "options.h"
88#include "packhand.h"
89#include "pages_g.h"
90#include "plrdlg_g.h"
91#include "repodlgs_g.h"
92
93#include "clinet.h"
94
95/* In autoconnect mode, try to connect to once a second */
96#define AUTOCONNECT_INTERVAL 500
97
98/* In autoconnect mode, try to connect 100 times */
99#define MAX_AUTOCONNECT_ATTEMPTS 100
100
101extern char forced_tileset_name[512];
102static struct fc_sockaddr_list *list = NULL;
103static int name_count;
104
105/**********************************************************************/
118
119/**********************************************************************/
123static void client_conn_close_callback(struct connection *pconn)
124{
125 char reason[256];
126
127 if (NULL != pconn->closing_reason) {
128 fc_strlcpy(reason, pconn->closing_reason, sizeof(reason));
129 } else {
130 fc_strlcpy(reason, _("unknown reason"), sizeof(reason));
131 }
132
134 /* If we lost connection to the internal server - kill it. */
136 log_error("Lost connection to server: %s.", reason);
137 output_window_printf(ftc_client, _("Lost connection to server (%s)!"),
138 reason);
139}
140
141/**********************************************************************/
149static int get_server_address(const char *hostname, int port,
150 char *errbuf, int errbufsize)
151{
152 if (port == 0) {
153#ifdef FREECIV_JSON_CONNECTION
154 port = FREECIV_JSON_PORT;
155#else /* FREECIV_JSON_CONNECTION */
156 port = DEFAULT_SOCK_PORT;
157#endif /* FREECIV_JSON_CONNECTION */
158 }
159
160 /* use name to find TCP/IP address of server */
161 if (!hostname) {
162 hostname = "localhost";
163 }
164
165 if (list != NULL) {
166 fc_sockaddr_list_destroy(list);
167 }
168
169 /* Any supported family will do */
170 list = net_lookup_service(hostname, port, FC_ADDR_ANY);
171
172 name_count = fc_sockaddr_list_size(list);
173
174 if (name_count <= 0) {
175 (void) fc_strlcpy(errbuf, _("Failed looking up host."), errbufsize);
176 return -1;
177 }
178
179 return 0;
180}
181
182/**********************************************************************/
193static int try_to_connect(const char *username, char *errbuf, int errbufsize)
194{
195 int sock = -1;
196 fc_errno err = 0;
197
199
200 /* connection in progress? wait. */
201 if (client.conn.used) {
202 (void) fc_strlcpy(errbuf, _("Connection in progress."), errbufsize);
203 return -1;
204 }
205
206 /* Try all (IPv4, IPv6, ...) addresses until we have a connection. */
207 sock = -1;
209 if ((sock = socket(paddr->saddr.sa_family, SOCK_STREAM, 0)) == -1) {
210 if (err == 0) {
211 err = fc_get_errno();
212 }
213 /* Probably EAFNOSUPPORT or EPROTONOSUPPORT. */
214 continue;
215 }
216
217 if (fc_connect(sock, &paddr->saddr,
218 sockaddr_size(paddr)) == -1) {
219 err = fc_get_errno(); /* Save errno value before calling anything */
220 fc_closesocket(sock);
221 sock = -1;
222 continue;
223 } else {
224 /* We have a connection! */
225 break;
226 }
228
229 client.conn.sock = sock;
230 if (client.conn.sock == -1) {
231 (void) fc_strlcpy(errbuf, fc_strerror(err), errbufsize);
232#ifdef FREECIV_HAVE_WINSOCK
233 return -1;
234#else
235 return err;
236#endif /* FREECIV_HAVE_WINSOCK */
237 }
238
239 make_connection(client.conn.sock, username);
240
241 return 0;
242}
243
244/**********************************************************************/
248int connect_to_server(const char *username, const char *hostname, int port,
249 char *errbuf, int errbufsize)
250{
251 if (errbufsize > 0 && errbuf != NULL) {
252 errbuf[0] = '\0';
253 }
254
255 if (0 != get_server_address(hostname, port, errbuf, errbufsize)) {
256 return -1;
257 }
258
259 if (0 != try_to_connect(username, errbuf, errbufsize)) {
260 return -1;
261 }
262
266 }
267
268 return 0;
269}
270
271/**********************************************************************/
274void make_connection(int sock, const char *username)
275{
276 struct packet_server_join_req req;
277
279 client.conn.sock = sock;
285
286 /* call gui-dependent stuff in gui_main.c */
288
289 /* now send join_request package */
290
291 req.major_version = MAJOR_VERSION;
292 req.minor_version = MINOR_VERSION;
293 req.patch_version = PATCH_VERSION;
294 sz_strlcpy(req.version_label, VERSION_LABEL);
297
299}
300
301/**********************************************************************/
306{
307 const bool force = !client.conn.used;
308
310
312
313 /* If it's internal server - kill it
314 * We assume that we are always connected to the internal server */
315 if (!force) {
317 }
319 if (force) {
321 }
322 output_window_append(ftc_client, _("Disconnected from server."));
323
325 options_save(NULL);
326 }
327}
328
329/**********************************************************************/
340static int read_from_connection(struct connection *pc, bool block)
341{
342 for (;;) {
343 fd_set readfs, writefs, exceptfs;
344 int socket_fd = pc->sock;
345 bool have_data_for_server = (pc->used && pc->send_buffer
346 && 0 < pc->send_buffer->ndata);
347 int n;
348 fc_timeval tv;
349
350 tv.tv_sec = 0;
351 tv.tv_usec = 0;
352
353 FC_FD_ZERO(&readfs);
354 FD_SET(socket_fd, &readfs);
355
356 FC_FD_ZERO(&exceptfs);
357 FD_SET(socket_fd, &exceptfs);
358
359 if (have_data_for_server) {
360 FC_FD_ZERO(&writefs);
361 FD_SET(socket_fd, &writefs);
362 n = fc_select(socket_fd + 1, &readfs, &writefs, &exceptfs,
363 block ? NULL : &tv);
364 } else {
365 n = fc_select(socket_fd + 1, &readfs, NULL, &exceptfs,
366 block ? NULL : &tv);
367 }
368
369 /* the socket is neither readable, writeable nor got an
370 * exception */
371 if (n == 0) {
372 return 0;
373 }
374
375 if (n == -1) {
376 if (errno == EINTR) {
377 /* EINTR can happen sometimes, especially when compiling with -pg.
378 * Generally we just want to run select again. */
379 log_debug("select() returned EINTR");
380 continue;
381 }
382
383 log_error("select() return=%d errno=%d (%s)",
384 n, errno, fc_strerror(fc_get_errno()));
385 return -1;
386 }
387
388 if (FD_ISSET(socket_fd, &exceptfs)) {
389 return -1;
390 }
391
392 if (have_data_for_server && FD_ISSET(socket_fd, &writefs)) {
394 }
395
396 if (FD_ISSET(socket_fd, &readfs)) {
397 return read_socket_data(socket_fd, pc->buffer);
398 }
399 }
400}
401
402/**********************************************************************/
407{
408 int nb;
409
411
413 if (0 <= nb) {
415 while (client.conn.used) {
416 enum packet_type type;
417 void *packet = get_packet_from_connection(&client.conn, &type);
418
419 if (NULL != packet) {
420 client_packet_input(packet, type);
421 free(packet);
422 } else {
423 break;
424 }
425 }
426 if (client.conn.used) {
428 }
429 } else if (-2 == nb) {
430 connection_close(&client.conn, _("server disconnected"));
431 } else {
432 connection_close(&client.conn, _("read error"));
433 }
434}
435
436/**********************************************************************/
443 int expected_request_id)
444{
445 fc_assert_ret(expected_request_id);
447
448 log_debug("input_from_server_till_request_got_processed("
449 "expected_request_id=%d)", expected_request_id);
450
451 while (TRUE) {
453
454 if (0 <= nb) {
455 enum packet_type type;
456
457 while (TRUE) {
458 void *packet = get_packet_from_connection(&client.conn, &type);
459 if (NULL == packet) {
460 break;
461 }
462
463 client_packet_input(packet, type);
464 free(packet);
465
467 log_debug("ifstrgp: expect=%d, seen=%d",
468 expected_request_id,
471 expected_request_id) {
472 log_debug("ifstrgp: got it; returning");
473 return;
474 }
475 }
476 }
477 } else if (-2 == nb) {
478 connection_close(&client.conn, _("server disconnected"));
479 break;
480 } else {
481 connection_close(&client.conn, _("read error"));
482 break;
483 }
484 }
485}
486
487static bool autoconnecting = FALSE;
488/**********************************************************************/
493{
494 char errbuf[512];
495 static int count = 0;
496#ifndef FREECIV_MSWINDOWS
497 static int warning_shown = 0;
498#endif
499
500 if (!autoconnecting) {
501 return FC_INFINITY;
502 }
503
504 count++;
505
506 if (count >= MAX_AUTOCONNECT_ATTEMPTS) {
507 log_fatal(_("Failed to contact server \"%s\" at port "
508 "%d as \"%s\" after %d attempts"),
510 exit(EXIT_FAILURE);
511 }
512
513 switch (try_to_connect(user_name, errbuf, sizeof(errbuf))) {
514 case 0: /* Success! */
515 /* Don't call me again */
517 return FC_INFINITY;
518#ifndef FREECIV_MSWINDOWS
519 /* See PR#4042 for more info on issues with try_to_connect() and errno. */
520 case ECONNREFUSED: /* Server not available (yet) */
521 if (!warning_shown) {
522 log_error("Connection to server refused. Please start the server.");
523 output_window_append(ftc_client, _("Connection to server refused. "
524 "Please start the server."));
525 warning_shown = 1;
526 }
527 /* Try again in 0.5 seconds */
528 return 0.001 * AUTOCONNECT_INTERVAL;
529#endif /* FREECIV_MSWINDOWS */
530 default: /* All other errors are fatal */
531 log_fatal(_("Error contacting server \"%s\" at port %d "
532 "as \"%s\":\n %s\n"),
534 exit(EXIT_FAILURE);
535 }
536
538}
539
540/**********************************************************************/
548{
549 char buf[512];
550
552 _("Auto-connecting to server \"%s\" at port %d "
553 "as \"%s\" every %f second(s) for %d times"),
555 0.001 * AUTOCONNECT_INTERVAL,
557
558 if (get_server_address(server_host, server_port, buf, sizeof(buf)) < 0) {
559 log_fatal(_("Error contacting server \"%s\" at port %d "
560 "as \"%s\":\n %s\n"),
562 exit(EXIT_FAILURE);
563 }
565}
void agents_thaw_hint(void)
Definition agents.c:436
void agents_freeze_hint(void)
Definition agents.c:427
#define n
Definition astring.c:77
void attribute_flush(void)
Definition attribute.c:327
const char *const our_capability
Definition capstr.c:32
void output_window_append(const struct ft_color color, const char *featured_text)
void output_window_printf(const struct ft_color color, const char *format,...)
char user_name[512]
void client_packet_input(void *packet, int type)
char server_host[512]
void stop_turn_change_wait(void)
struct civclient client
int server_port
void set_client_state(enum client_states newstate)
@ C_S_DISCONNECTED
Definition client_main.h:45
void start_autoconnecting_to_server(void)
Definition clinet.c:547
char forced_tileset_name[512]
static struct fc_sockaddr_list * list
Definition clinet.c:102
int connect_to_server(const char *username, const char *hostname, int port, char *errbuf, int errbufsize)
Definition clinet.c:248
static bool autoconnecting
Definition clinet.c:487
static void client_conn_close_callback(struct connection *pconn)
Definition clinet.c:123
void make_connection(int sock, const char *username)
Definition clinet.c:274
static int read_from_connection(struct connection *pc, bool block)
Definition clinet.c:340
#define AUTOCONNECT_INTERVAL
Definition clinet.c:96
static int name_count
Definition clinet.c:103
static int try_to_connect(const char *username, char *errbuf, int errbufsize)
Definition clinet.c:193
double try_to_autoconnect(void)
Definition clinet.c:492
#define MAX_AUTOCONNECT_ATTEMPTS
Definition clinet.c:99
void input_from_server_till_request_got_processed(int fd, int expected_request_id)
Definition clinet.c:442
void input_from_server(int fd)
Definition clinet.c:406
void disconnect_from_server(void)
Definition clinet.c:305
static void close_socket_nomessage(struct connection *pc)
Definition clinet.c:109
static int get_server_address(const char *hostname, int port, char *errbuf, int errbufsize)
Definition clinet.c:149
void client_kill_server(bool force)
void connections_set_close_callback(conn_close_fn_t func)
Definition connection.c:80
void flush_connection_send_buffer_all(struct connection *pc)
Definition connection.c:229
void connection_common_init(struct connection *pconn)
Definition connection.c:602
void connection_close(struct connection *pconn, const char *reason)
Definition connection.c:88
void connection_common_close(struct connection *pconn)
Definition connection.c:627
int read_socket_data(int sock, struct socket_packet_buffer *buffer)
Definition connection.c:129
#define _(String)
Definition fcintl.h:67
const struct ft_color ftc_client
void close_connection_dialog(void)
Definition connectdlg.c:50
void popdown_races_dialog(void)
Definition dialogs.c:1238
void remove_net_input(void)
Definition gui_main.c:2116
void add_net_input(int sock)
Definition gui_main.c:2098
GType type
Definition repodlgs.c:1312
#define fc_assert_ret(condition)
Definition log.h:191
#define log_fatal(message,...)
Definition log.h:100
#define log_debug(message,...)
Definition log.h:115
#define log_error(message,...)
Definition log.h:103
@ FC_ADDR_ANY
Definition net_types.h:64
struct fc_sockaddr_list * net_lookup_service(const char *name, int port, enum fc_addr_family family)
Definition netintf.c:411
void fc_closesocket(int sock)
Definition netintf.c:186
int sockaddr_size(union fc_sockaddr *addr)
Definition netintf.c:305
int fc_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
Definition netintf.c:107
int fc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fc_timeval *timeout)
Definition netintf.c:125
struct timeval fc_timeval
Definition netintf.h:90
#define fc_sockaddr_list_iterate_end
Definition netintf.h:85
#define FC_FD_ZERO(p)
Definition netintf.h:57
#define fc_sockaddr_list_iterate(sockaddrlist, paddr)
Definition netintf.h:83
void options_save(option_save_log_callback log_cb)
Definition options.c:6053
struct client_options gui_options
Definition options.c:71
#define get_packet_from_connection(pc, ptype)
Definition packets.h:113
int send_packet_server_join_req(struct connection *pc, const struct packet_server_join_req *packet)
packet_type
@ PACKET_PROCESSING_FINISHED
void notify_about_incoming_packet(struct connection *pc, int packet_type, int size)
Definition packhand.c:5479
void notify_about_outgoing_packet(struct connection *pc, int packet_type, int size, int request_id)
Definition packhand.c:5489
#define FC_INFINITY
Definition shared.h:36
struct connection conn
Definition client_main.h:96
int default_server_port
Definition options.h:109
bool use_prev_server
Definition options.h:110
char default_server_host[512]
Definition options.h:108
bool save_options_on_exit
Definition options.h:121
char * closing_reason
Definition connection.h:147
struct connection::@57::@62 client
int request_id_of_currently_handled_packet
Definition connection.h:198
int last_request_id_used
Definition connection.h:192
void(* incoming_packet_notify)(struct connection *pc, int packet_type, int size)
Definition connection.h:253
void(* outgoing_packet_notify)(struct connection *pc, int packet_type, int size, int request_id)
Definition connection.h:261
struct socket_packet_buffer * send_buffer
Definition connection.h:159
int last_processed_request_id_seen
Definition connection.h:195
struct socket_packet_buffer * buffer
Definition connection.h:158
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:787
const char * fc_strerror(fc_errno err)
Definition support.c:610
fc_errno fc_get_errno(void)
Definition support.c:593
#define sz_strlcpy(dest, src)
Definition support.h:167
#define RETURN_VALUE_AFTER_EXIT(_val_)
Definition support.h:121
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
int fc_errno
Definition support.h:115