Freeciv-3.3: /fast/freeciv/nightly/main/client/clinet.c Source File

Freeciv-3.3

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
102 static struct fc_sockaddr_list *list = NULL;
103
104/**********************************************************************/
108 static void close_socket_nomessage(struct connection *pc)
109{
110 connection_common_close(pc);
111 remove_net_input();
112 popdown_races_dialog();
113 close_connection_dialog();
114
115 set_client_state(C_S_DISCONNECTED);
116}
117
118/**********************************************************************/
122 static void client_conn_close_callback(struct connection *pconn)
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
132 close_socket_nomessage(pconn);
133 /* If we lost connection to the internal server - kill it. */
134 client_kill_server(TRUE);
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/**********************************************************************/
148 static 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) {
167 fc_sockaddr_list_destroy(list);
168 }
169
170 /* Any supported family will do */
171 list = net_lookup_service(hostname, port, FC_ADDR_ANY);
172
173 name_count = fc_sockaddr_list_size(list);
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/**********************************************************************/
194 static int try_to_connect(const char *username, char *errbuf, int errbufsize)
195{
196 int sock = -1;
197 fc_errno err = 0;
198
199 connections_set_close_callback(client_conn_close_callback);
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;
209 fc_sockaddr_list_iterate(list, paddr) {
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 }
228 } fc_sockaddr_list_iterate_end;
229
230 client.conn.sock = sock;
231 if (client.conn.sock == -1) {
232 (void) fc_strlcpy(errbuf, fc_strerror(err), errbufsize);
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/**********************************************************************/
249 int 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
264 if (gui_options.use_prev_server) {
265 sz_strlcpy(gui_options.default_server_host, hostname);
266 gui_options.default_server_port = port;
267 }
268
269 return 0;
270}
271
272/**********************************************************************/
275 void make_connection(int sock, const char *username)
276{
277 struct packet_server_join_req req;
278
279 connection_common_init(&client.conn);
280 client.conn.sock = sock;
281 client.conn.client.last_request_id_used = 0;
282 client.conn.client.last_processed_request_id_seen = 0;
283 client.conn.client.request_id_of_currently_handled_packet = 0;
284 client.conn.incoming_packet_notify = notify_about_incoming_packet;
285 client.conn.outgoing_packet_notify = notify_about_outgoing_packet;
286
287 /* call gui-dependent stuff in gui_main.c */
288 add_net_input(client.conn.sock);
289
290 /* now send join_request package */
291
292 req.major_version = MAJOR_VERSION;
293 req.minor_version = MINOR_VERSION;
294 req.patch_version = PATCH_VERSION;
295 sz_strlcpy(req.version_label, VERSION_LABEL);
296 sz_strlcpy(req.capability, our_capability);
297 sz_strlcpy(req.username, username);
298
299 send_packet_server_join_req(&client.conn, &req);
300}
301
302/**********************************************************************/
306 void disconnect_from_server(bool leaving_sound)
307{
308 const bool force = !client.conn.used;
309
310 attribute_flush();
311
312 stop_turn_change_wait();
313
314 /* If it's internal server - kill it
315 * We assume that we are always connected to the internal server */
316 if (!force) {
317 client_kill_server(FALSE);
318 }
319 close_socket_nomessage(&client.conn);
320 if (force) {
321 client_kill_server(TRUE);
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
329 if (gui_options.save_options_on_exit) {
330 options_save(NULL);
331 }
332}
333
334/**********************************************************************/
345 static int read_from_connection(struct connection *pc, bool block)
346{
347 for (;;) {
348 fd_set readfs, writefs, exceptfs;
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;
353 fc_timeval tv;
354
355 tv.tv_sec = 0;
356 tv.tv_usec = 0;
357
358 FC_FD_ZERO(&readfs);
359 FD_SET(socket_fd, &readfs);
360
361 FC_FD_ZERO(&exceptfs);
362 FD_SET(socket_fd, &exceptfs);
363
364 if (have_data_for_server) {
365 FC_FD_ZERO(&writefs);
366 FD_SET(socket_fd, &writefs);
367 n = fc_select(socket_fd + 1, &readfs, &writefs, &exceptfs,
368 block ? NULL : &tv);
369 } else {
370 n = fc_select(socket_fd + 1, &readfs, NULL, &exceptfs,
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)",
389 n, errno, fc_strerror(fc_get_errno()));
390 return -1;
391 }
392
393 if (FD_ISSET(socket_fd, &exceptfs)) {
394 return -1;
395 }
396
397 if (have_data_for_server && FD_ISSET(socket_fd, &writefs)) {
398 flush_connection_send_buffer_all(pc);
399 }
400
401 if (FD_ISSET(socket_fd, &readfs)) {
402 return read_socket_data(socket_fd, pc->buffer);
403 }
404 }
405}
406
407/**********************************************************************/
411 void input_from_server(int fd)
412{
413 int nb;
414
415 fc_assert_ret(fd == client.conn.sock);
416
417 nb = read_from_connection(&client.conn, FALSE);
418 if (0 <= nb) {
419 agents_freeze_hint();
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 packet_destroy(packet, type);
427 } else {
428 break;
429 }
430 }
431 if (client.conn.used) {
432 agents_thaw_hint();
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/**********************************************************************/
447 void input_from_server_till_request_got_processed(int fd,
448 int expected_request_id)
449{
450 fc_assert_ret(expected_request_id);
451 fc_assert_ret(fd == client.conn.sock);
452
453 log_debug("input_from_server_till_request_got_processed("
454 "expected_request_id=%d)", expected_request_id);
455
456 while (TRUE) {
457 int nb = read_from_connection(&client.conn, 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 packet_destroy(packet, type);
471
472 if (type == PACKET_PROCESSING_FINISHED) {
473 log_debug("ifstrgp: expect=%d, seen=%d",
474 expected_request_id,
475 client.conn.client.last_processed_request_id_seen);
476 if (client.conn.client.last_processed_request_id_seen >=
477 expected_request_id) {
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
493 static bool autoconnecting = FALSE;
494/**********************************************************************/
498 double try_to_autoconnect(void)
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"),
515 server_host, server_port, user_name, count);
516 exit(EXIT_FAILURE);
517 }
518
519 switch (try_to_connect(user_name, errbuf, sizeof(errbuf))) {
520 case 0: /* Success! */
521 /* Don't call me again */
522 autoconnecting = FALSE;
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."));
531 warning_shown = TRUE;
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"),
539 server_host, server_port, user_name, errbuf);
540 exit(EXIT_FAILURE);
541 }
542
543 RETURN_VALUE_AFTER_EXIT(1.0);
544}
545
546/**********************************************************************/
553 void start_autoconnecting_to_server(void)
554{
555 char buf[512];
556
557 output_window_printf(ftc_client,
558 _("Auto-connecting to server \"%s\" at port %d "
559 "as \"%s\" every %f second(s) for %d times"),
560 server_host, server_port, user_name,
561 0.001 * AUTOCONNECT_INTERVAL,
562 MAX_AUTOCONNECT_ATTEMPTS);
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"),
567 server_host, server_port, user_name, buf);
568 exit(EXIT_FAILURE);
569 }
570 autoconnecting = TRUE;
571}
agents_thaw_hint
void agents_thaw_hint(void)
Definition agents.c:441
agents_freeze_hint
void agents_freeze_hint(void)
Definition agents.c:432
agents.h
n
#define n
Definition astring.c:77
attribute_flush
void attribute_flush(void)
Definition attribute.c:327
attribute.h
audio_play_sound
void audio_play_sound(const char *const tag, const char *const alt_tag, const char *const alt_tag2)
Definition audio.c:528
audio.h
our_capability
const char *const our_capability
Definition capstr.c:32
capstr.h
output_window_append
void output_window_append(const struct ft_color color, const char *featured_text)
Definition chatline_common.c:104
output_window_printf
void output_window_printf(const struct ft_color color, const char *format,...)
Definition chatline_common.c:153
chatline_g.h
user_name
char user_name[512]
Definition client_main.c:142
client_packet_input
void client_packet_input(void *packet, int type)
Definition client_main.c:774
server_host
char server_host[512]
Definition client_main.c:141
stop_turn_change_wait
void stop_turn_change_wait(void)
Definition client_main.c:1148
client
struct civclient client
Definition client_main.c:150
server_port
int server_port
Definition client_main.c:145
set_client_state
void set_client_state(enum client_states newstate)
Definition client_main.c:844
client_main.h
C_S_DISCONNECTED
@ C_S_DISCONNECTED
Definition client_main.h:45
climisc.h
start_autoconnecting_to_server
void start_autoconnecting_to_server(void)
Definition clinet.c:553
list
static struct fc_sockaddr_list * list
Definition clinet.c:102
connect_to_server
int connect_to_server(const char *username, const char *hostname, int port, char *errbuf, int errbufsize)
Definition clinet.c:249
autoconnecting
static bool autoconnecting
Definition clinet.c:493
disconnect_from_server
void disconnect_from_server(bool leaving_sound)
Definition clinet.c:306
client_conn_close_callback
static void client_conn_close_callback(struct connection *pconn)
Definition clinet.c:122
make_connection
void make_connection(int sock, const char *username)
Definition clinet.c:275
read_from_connection
static int read_from_connection(struct connection *pc, bool block)
Definition clinet.c:345
AUTOCONNECT_INTERVAL
#define AUTOCONNECT_INTERVAL
Definition clinet.c:97
try_to_connect
static int try_to_connect(const char *username, char *errbuf, int errbufsize)
Definition clinet.c:194
try_to_autoconnect
double try_to_autoconnect(void)
Definition clinet.c:498
MAX_AUTOCONNECT_ATTEMPTS
#define MAX_AUTOCONNECT_ATTEMPTS
Definition clinet.c:100
input_from_server_till_request_got_processed
void input_from_server_till_request_got_processed(int fd, int expected_request_id)
Definition clinet.c:447
input_from_server
void input_from_server(int fd)
Definition clinet.c:411
close_socket_nomessage
static void close_socket_nomessage(struct connection *pc)
Definition clinet.c:108
get_server_address
static int get_server_address(const char *hostname, int port, char *errbuf, int errbufsize)
Definition clinet.c:148
clinet.h
incite_cost
char * incite_cost
Definition comments.c:74
client_kill_server
void client_kill_server(bool force)
Definition connectdlg_common.c:153
connectdlg_common.h
connectdlg_g.h
connections_set_close_callback
void connections_set_close_callback(conn_close_fn_t func)
Definition connection.c:80
flush_connection_send_buffer_all
void flush_connection_send_buffer_all(struct connection *pc)
Definition connection.c:230
connection_common_init
void connection_common_init(struct connection *pconn)
Definition connection.c:603
connection_close
void connection_close(struct connection *pconn, const char *reason)
Definition connection.c:88
connection_common_close
void connection_common_close(struct connection *pconn)
Definition connection.c:630
read_socket_data
int read_socket_data(int sock, struct socket_packet_buffer *buffer)
Definition connection.c:129
dataio.h
dialogs_g.h
fc_prehdrs.h
fcintl.h
_
#define _(String)
Definition fcintl.h:67
ftc_client
const struct ft_color ftc_client
Definition featured_text.c:78
game.h
close_connection_dialog
void close_connection_dialog(void)
Definition connectdlg.c:52
popdown_races_dialog
void popdown_races_dialog(void)
Definition dialogs.c:1230
remove_net_input
void remove_net_input(void)
Definition gui_main.c:2333
add_net_input
void add_net_input(int sock)
Definition gui_main.c:2315
type
GType type
Definition repodlgs.c:1313
gui_main_g.h
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_fatal
#define log_fatal(message,...)
Definition log.h:100
log_debug
#define log_debug(message,...)
Definition log.h:115
log_error
#define log_error(message,...)
Definition log.h:103
mapview_common.h
mem.h
menu_g.h
messagewin_g.h
FC_ADDR_ANY
@ FC_ADDR_ANY
Definition net_types.h:64
net_lookup_service
struct fc_sockaddr_list * net_lookup_service(const char *name, int port, enum fc_addr_family family)
Definition netintf.c:411
fc_closesocket
void fc_closesocket(int sock)
Definition netintf.c:186
sockaddr_size
int sockaddr_size(union fc_sockaddr *addr)
Definition netintf.c:305
fc_connect
int fc_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
Definition netintf.c:107
fc_select
int fc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fc_timeval *timeout)
Definition netintf.c:125
netintf.h
fc_timeval
struct timeval fc_timeval
Definition netintf.h:90
fc_sockaddr_list_iterate_end
#define fc_sockaddr_list_iterate_end
Definition netintf.h:85
FC_FD_ZERO
#define FC_FD_ZERO(p)
Definition netintf.h:57
fc_sockaddr_list_iterate
#define fc_sockaddr_list_iterate(sockaddrlist, paddr)
Definition netintf.h:83
options_save
void options_save(option_save_log_callback log_cb)
Definition options.c:6341
gui_options
struct client_options gui_options
Definition options.c:71
options.h
packets.h
get_packet_from_connection
#define get_packet_from_connection(pc, ptype)
Definition packets.h:90
packet_destroy
void packet_destroy(void *packet, enum packet_type type)
Definition packets_gen.c:91173
send_packet_server_join_req
int send_packet_server_join_req(struct connection *pc, const struct packet_server_join_req *packet)
Definition packets_gen.c:1794
packet_type
packet_type
Definition packets_gen.h:1902
PACKET_PROCESSING_FINISHED
@ PACKET_PROCESSING_FINISHED
Definition packets_gen.h:1904
notify_about_incoming_packet
void notify_about_incoming_packet(struct connection *pc, int packet_type, int size)
Definition packhand.c:5331
notify_about_outgoing_packet
void notify_about_outgoing_packet(struct connection *pc, int packet_type, int size, int request_id)
Definition packhand.c:5341
packhand.h
pages_g.h
plrdlg_g.h
registry.h
repodlgs_g.h
FC_INFINITY
#define FC_INFINITY
Definition shared.h:36
civclient::conn
struct connection conn
Definition client_main.h:96
client_options::default_server_port
int default_server_port
Definition options.h:110
client_options::use_prev_server
bool use_prev_server
Definition options.h:111
client_options::default_server_host
char default_server_host[512]
Definition options.h:109
client_options::save_options_on_exit
bool save_options_on_exit
Definition options.h:125
connection
Definition connection.h:136
connection::request_id_of_currently_handled_packet
int request_id_of_currently_handled_packet
Definition connection.h:193
connection::client
struct connection::@58::@63 client
connection::last_request_id_used
int last_request_id_used
Definition connection.h:187
connection::incoming_packet_notify
void(* incoming_packet_notify)(struct connection *pc, int packet_type, int size)
Definition connection.h:251
connection::outgoing_packet_notify
void(* outgoing_packet_notify)(struct connection *pc, int packet_type, int size, int request_id)
Definition connection.h:259
connection::sock
int sock
Definition connection.h:138
connection::last_processed_request_id_seen
int last_processed_request_id_seen
Definition connection.h:190
connection::used
bool used
Definition connection.h:139
packet_server_join_req
Definition packets_gen.h:46
packet_server_join_req::version_label
char version_label[48]
Definition packets_gen.h:49
packet_server_join_req::capability
char capability[512]
Definition packets_gen.h:48
packet_server_join_req::minor_version
int minor_version
Definition packets_gen.h:51
packet_server_join_req::patch_version
int patch_version
Definition packets_gen.h:52
packet_server_join_req::major_version
int major_version
Definition packets_gen.h:50
packet_server_join_req::username
char username[48]
Definition packets_gen.h:47
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:777
fc_strerror
const char * fc_strerror(fc_errno err)
Definition support.c:609
fc_get_errno
fc_errno fc_get_errno(void)
Definition support.c:592
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
RETURN_VALUE_AFTER_EXIT
#define RETURN_VALUE_AFTER_EXIT(_val_)
Definition support.h:146
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
fc_errno
int fc_errno
Definition support.h:140
version.h