Freeciv-3.2
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 "audio.h"
78#include "chatline_g.h"
79#include "client_main.h"
80#include "climisc.h"
81#include "connectdlg_common.h"
82#include "connectdlg_g.h"
83#include "dialogs_g.h" /* popdown_races_dialog() */
84#include "gui_main_g.h" /* add_net_input(), remove_net_input() */
85#include "mapview_common.h" /* unqueue_mapview_update */
86#include "menu_g.h"
87#include "messagewin_g.h"
88#include "options.h"
89#include "packhand.h"
90#include "pages_g.h"
91#include "plrdlg_g.h"
92#include "repodlgs_g.h"
93
94#include "clinet.h"
95
96/* In autoconnect mode, try to connect to once a second */
97#define AUTOCONNECT_INTERVAL 500
98
99/* In autoconnect mode, try to connect 100 times */
100#define MAX_AUTOCONNECT_ATTEMPTS 100
101
102static struct fc_sockaddr_list *list = NULL;
103
104/**********************************************************************/
117
118/**********************************************************************/
123{
124 char reason[256];
125
126 if (NULL != pconn->closing_reason) {
127 fc_strlcpy(reason, pconn->closing_reason, sizeof(reason));
128 } else {
129 fc_strlcpy(reason, _("unknown reason"), sizeof(reason));
130 }
131
133 /* If we lost connection to the internal server - kill it. */
135 log_error("Lost connection to server: %s.", reason);
136 output_window_printf(ftc_client, _("Lost connection to server (%s)!"),
137 reason);
138}
139
140/**********************************************************************/
148static int get_server_address(const char *hostname, int port,
149 char *errbuf, int errbufsize)
150{
151 int name_count;
152
153 if (port == 0) {
154#ifdef FREECIV_JSON_CONNECTION
155 port = FREECIV_JSON_PORT;
156#else /* FREECIV_JSON_CONNECTION */
157 port = DEFAULT_SOCK_PORT;
158#endif /* FREECIV_JSON_CONNECTION */
159 }
160
161 /* use name to find TCP/IP address of server */
162 if (!hostname) {
163 hostname = "localhost";
164 }
165
166 if (list != NULL) {
168 }
169
170 /* Any supported family will do */
172
174
175 if (name_count <= 0) {
176 (void) fc_strlcpy(errbuf, _("Failed looking up host."), errbufsize);
177 return -1;
178 }
179
180 return 0;
181}
182
183/**********************************************************************/
194static int try_to_connect(const char *username, char *errbuf, int errbufsize)
195{
196 int sock = -1;
197 fc_errno err = 0;
198
200
201 /* connection in progress? wait. */
202 if (client.conn.used) {
203 (void) fc_strlcpy(errbuf, _("Connection in progress."), errbufsize);
204 return -1;
205 }
206
207 /* Try all (IPv4, IPv6, ...) addresses until we have a connection. */
208 sock = -1;
210 if ((sock = socket(paddr->saddr.sa_family, SOCK_STREAM, 0)) == -1) {
211 if (err == 0) {
212 err = fc_get_errno();
213 }
214 /* Probably EAFNOSUPPORT or EPROTONOSUPPORT. */
215 continue;
216 }
217
218 if (fc_connect(sock, &paddr->saddr,
219 sockaddr_size(paddr)) == -1) {
220 err = fc_get_errno(); /* Save errno value before calling anything */
221 fc_closesocket(sock);
222 sock = -1;
223 continue;
224 } else {
225 /* We have a connection! */
226 break;
227 }
229
230 client.conn.sock = sock;
231 if (client.conn.sock == -1) {
233#ifdef FREECIV_HAVE_WINSOCK
234 return -1;
235#else
236 return err;
237#endif /* FREECIV_HAVE_WINSOCK */
238 }
239
240 make_connection(client.conn.sock, username);
241
242 return 0;
243}
244
245/**********************************************************************/
249int connect_to_server(const char *username, const char *hostname, int port,
250 char *errbuf, int errbufsize)
251{
252 if (errbufsize > 0 && errbuf != NULL) {
253 errbuf[0] = '\0';
254 }
255
256 if (0 != get_server_address(hostname, port, errbuf, errbufsize)) {
257 return -1;
258 }
259
260 if (0 != try_to_connect(username, errbuf, errbufsize)) {
261 return -1;
262 }
263
267 }
268
269 return 0;
270}
271
272/**********************************************************************/
301
302/**********************************************************************/
307{
308 const bool force = !client.conn.used;
309
311
313
314 /* If it's internal server - kill it
315 * We assume that we are always connected to the internal server */
316 if (!force) {
318 }
320 if (force) {
322 }
323 output_window_append(ftc_client, _("Disconnected from server."));
324
325 if (leaving_sound) {
326 audio_play_sound("e_leave_game", NULL, NULL);
327 }
328
331 }
332}
333
334/**********************************************************************/
345static int read_from_connection(struct connection *pc, bool block)
346{
347 for (;;) {
349 int socket_fd = pc->sock;
350 bool have_data_for_server = (pc->used && pc->send_buffer
351 && 0 < pc->send_buffer->ndata);
352 int n;
354
355 tv.tv_sec = 0;
356 tv.tv_usec = 0;
357
360
363
368 block ? NULL : &tv);
369 } else {
371 block ? NULL : &tv);
372 }
373
374 /* the socket is neither readable, writeable nor got an
375 * exception */
376 if (n == 0) {
377 return 0;
378 }
379
380 if (n == -1) {
381 if (errno == EINTR) {
382 /* EINTR can happen sometimes, especially when compiling with -pg.
383 * Generally we just want to run select again. */
384 log_debug("select() returned EINTR");
385 continue;
386 }
387
388 log_error("select() return=%d errno=%d (%s)",
390 return -1;
391 }
392
393 if (FD_ISSET(socket_fd, &exceptfs)) {
394 return -1;
395 }
396
399 }
400
401 if (FD_ISSET(socket_fd, &readfs)) {
402 return read_socket_data(socket_fd, pc->buffer);
403 }
404 }
405}
406
407/**********************************************************************/
412{
413 int nb;
414
416
418 if (0 <= nb) {
420 while (client.conn.used) {
421 enum packet_type type;
422 void *packet = get_packet_from_connection(&client.conn, &type);
423
424 if (NULL != packet) {
425 client_packet_input(packet, type);
426 free(packet);
427 } else {
428 break;
429 }
430 }
431 if (client.conn.used) {
433 }
434 } else if (-2 == nb) {
435 connection_close(&client.conn, _("server disconnected"));
436 } else {
437 connection_close(&client.conn, _("read error"));
438 }
439}
440
441/**********************************************************************/
449{
452
453 log_debug("input_from_server_till_request_got_processed("
454 "expected_request_id=%d)", expected_request_id);
455
456 while (TRUE) {
458
459 if (0 <= nb) {
460 enum packet_type type;
461
462 while (TRUE) {
463 void *packet = get_packet_from_connection(&client.conn, &type);
464
465 if (NULL == packet) {
466 break;
467 }
468
469 client_packet_input(packet, type);
470 free(packet);
471
473 log_debug("ifstrgp: expect=%d, seen=%d",
478 log_debug("ifstrgp: got it; returning");
479 return;
480 }
481 }
482 }
483 } else if (-2 == nb) {
484 connection_close(&client.conn, _("server disconnected"));
485 break;
486 } else {
487 connection_close(&client.conn, _("read error"));
488 break;
489 }
490 }
491}
492
493static bool autoconnecting = FALSE;
494/**********************************************************************/
499{
500 char errbuf[512];
501 static int count = 0;
502#ifndef FREECIV_MSWINDOWS
503 static bool warning_shown = FALSE;
504#endif
505
506 if (!autoconnecting) {
507 return FC_INFINITY;
508 }
509
510 count++;
511
512 if (count >= MAX_AUTOCONNECT_ATTEMPTS) {
513 log_fatal(_("Failed to contact server \"%s\" at port "
514 "%d as \"%s\" after %d attempts"),
517 }
518
519 switch (try_to_connect(user_name, errbuf, sizeof(errbuf))) {
520 case 0: /* Success! */
521 /* Don't call me again */
523 return FC_INFINITY;
524#ifndef FREECIV_MSWINDOWS
525 /* See PR#4042 for more info on issues with try_to_connect() and errno. */
526 case ECONNREFUSED: /* Server not available (yet) */
527 if (!warning_shown) {
528 log_error("Connection to server refused. Please start the server.");
529 output_window_append(ftc_client, _("Connection to server refused. "
530 "Please start the server."));
532 }
533 /* Try again in 0.5 seconds */
534 return 0.001 * AUTOCONNECT_INTERVAL;
535#endif /* FREECIV_MSWINDOWS */
536 default: /* All other errors are fatal */
537 log_fatal(_("Error contacting server \"%s\" at port %d "
538 "as \"%s\":\n %s\n"),
541 }
542
544}
545
546/**********************************************************************/
554{
555 char buf[512];
556
558 _("Auto-connecting to server \"%s\" at port %d "
559 "as \"%s\" every %f second(s) for %d times"),
561 0.001 * AUTOCONNECT_INTERVAL,
563
564 if (get_server_address(server_host, server_port, buf, sizeof(buf)) < 0) {
565 log_fatal(_("Error contacting server \"%s\" at port %d "
566 "as \"%s\":\n %s\n"),
569 }
571}
void agents_thaw_hint(void)
Definition agents.c:440
void agents_freeze_hint(void)
Definition agents.c:431
#define n
Definition astring.c:77
void attribute_flush(void)
Definition attribute.c:327
void audio_play_sound(const char *const tag, const char *const alt_tag, const char *const alt_tag2)
Definition audio.c:528
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:553
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:249
static bool autoconnecting
Definition clinet.c:493
void disconnect_from_server(bool leaving_sound)
Definition clinet.c:306
static void client_conn_close_callback(struct connection *pconn)
Definition clinet.c:122
void make_connection(int sock, const char *username)
Definition clinet.c:275
static int read_from_connection(struct connection *pc, bool block)
Definition clinet.c:345
#define AUTOCONNECT_INTERVAL
Definition clinet.c:97
static int try_to_connect(const char *username, char *errbuf, int errbufsize)
Definition clinet.c:194
double try_to_autoconnect(void)
Definition clinet.c:498
#define MAX_AUTOCONNECT_ATTEMPTS
Definition clinet.c:100
void input_from_server_till_request_got_processed(int fd, int expected_request_id)
Definition clinet.c:447
void input_from_server(int fd)
Definition clinet.c:411
static void close_socket_nomessage(struct connection *pc)
Definition clinet.c:108
static int get_server_address(const char *hostname, int port, char *errbuf, int errbufsize)
Definition clinet.c:148
char * incite_cost
Definition comments.c:75
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:230
void connection_common_init(struct connection *pconn)
Definition connection.c:603
void connection_close(struct connection *pconn, const char *reason)
Definition connection.c:88
void connection_common_close(struct connection *pconn)
Definition connection.c:630
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:52
void popdown_races_dialog(void)
Definition dialogs.c:1230
void remove_net_input(void)
Definition gui_main.c:2311
void add_net_input(int sock)
Definition gui_main.c:2293
GType type
Definition repodlgs.c:1313
#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:6089
struct client_options gui_options
Definition options.c:71
#define get_packet_from_connection(pc, ptype)
Definition packets.h:90
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:5318
void notify_about_outgoing_packet(struct connection *pc, int packet_type, int size, int request_id)
Definition packhand.c:5328
#define FC_INFINITY
Definition shared.h:36
struct connection conn
Definition client_main.h:96
int default_server_port
Definition options.h:110
bool use_prev_server
Definition options.h:111
char default_server_host[512]
Definition options.h:109
bool save_options_on_exit
Definition options.h:125
int request_id_of_currently_handled_packet
Definition connection.h:193
struct connection::@58::@63 client
int last_request_id_used
Definition connection.h:187
void(* incoming_packet_notify)(struct connection *pc, int packet_type, int size)
Definition connection.h:251
void(* outgoing_packet_notify)(struct connection *pc, int packet_type, int size, int request_id)
Definition connection.h:259
int last_processed_request_id_seen
Definition connection.h:190
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
const char * fc_strerror(fc_errno err)
Definition support.c:611
fc_errno fc_get_errno(void)
Definition support.c:594
#define sz_strlcpy(dest, src)
Definition support.h:195
#define RETURN_VALUE_AFTER_EXIT(_val_)
Definition support.h:146
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
int fc_errno
Definition support.h:140