diff -X freeciv/diff_ignore -Nurd freeciv/client/civclient.c autoconnect/client/civclient.c --- freeciv/client/civclient.c Fri Feb 23 14:15:03 2001 +++ autoconnect/client/civclient.c Sat Feb 24 16:09:54 2001 @@ -67,9 +67,14 @@ char metaserver[256]; char server_host[512]; -char name[512]; +char connect_name[512]; int server_port; +/* + * Non-zero = skip "Connect to Freeciv Server" dialog + */ +int auto_connect = 0; + enum client_states client_state=CLIENT_BOOT_STATE; static char *tile_set_name = NULL; @@ -101,7 +106,7 @@ server_port=DEFAULT_SOCK_PORT; sz_strlcpy(server_host, "localhost"); sz_strlcpy(metaserver, METALIST_ADDR); - name[0] = '\0'; + connect_name[0] = '\0'; i = 1; @@ -113,6 +118,7 @@ fprintf(stderr, _(" -n, --name NAME\tUse NAME as name\n")); fprintf(stderr, _(" -p, --port PORT\tConnect to server port PORT\n")); fprintf(stderr, _(" -s, --server HOST\tConnect to the server at HOST\n")); + fprintf(stderr, _(" -a, --autoconnect\tAutomatically connect to server\n")); fprintf(stderr, _(" -t, --tiles FILE\tUse data file FILE.tilespec for tiles\n")); #ifdef SOUND fprintf(stderr, _(" -s, --sound FILE\tRead sound information from FILE\n")); @@ -131,13 +137,15 @@ } else if ((option = get_option("--log",argv,&i,argc)) != NULL) logfile = mystrdup(option); /* never free()d */ else if ((option = get_option("--name",argv,&i,argc)) != NULL) - sz_strlcpy(name, option); + sz_strlcpy(connect_name, option); else if ((option = get_option("--meta",argv,&i,argc)) != NULL) sz_strlcpy(metaserver, option); else if ((option = get_option("--port",argv,&i,argc)) != NULL) server_port=atoi(option); else if ((option = get_option("--server",argv,&i,argc)) != NULL) sz_strlcpy(server_host, option); + else if (is_option("--autoconnect",argv[i])) + auto_connect = 1; else if ((option = get_option("--debug",argv,&i,argc)) != NULL) { loglevel=log_parse_level_str(option); if (loglevel==-1) { @@ -155,8 +163,8 @@ log_init(logfile, loglevel, NULL); /* after log_init: */ - if (name[0] == '\0') { - sz_strlcpy(name, user_username()); + if (connect_name[0] == '\0') { + sz_strlcpy(connect_name, user_username()); } /* initialization */ @@ -499,8 +507,13 @@ } update_menus(); } - if(client_state==CLIENT_PRE_GAME_STATE) - gui_server_connect(); + if (client_state == CLIENT_PRE_GAME_STATE) { + if (auto_connect) { + server_autoconnect(); + } else { + gui_server_connect(); + } + } } diff -X freeciv/diff_ignore -Nurd freeciv/client/civclient.h autoconnect/client/civclient.h --- freeciv/client/civclient.h Mon Jan 15 01:30:17 2001 +++ autoconnect/client/civclient.h Sat Feb 24 13:49:59 2001 @@ -37,7 +37,7 @@ extern char metaserver[256]; extern char server_host[512]; -extern char name[512]; +extern char connect_name[512]; extern int server_port; #endif /* FC__CIVCLIENT_H */ diff -X freeciv/diff_ignore -Nurd freeciv/client/clinet.c autoconnect/client/clinet.c --- freeciv/client/clinet.c Fri Feb 23 14:15:03 2001 +++ autoconnect/client/clinet.c Sat Feb 24 16:46:03 2001 @@ -67,6 +67,7 @@ #include "clinet.h" struct connection aconnection; +static struct sockaddr_in server_addr; /************************************************************************** Close socket and cleanup. This one doesn't print a message, so should @@ -100,76 +101,117 @@ } /************************************************************************** -... + Connect to a civserver instance -- or at least try to. On sucess, + return 0; on failure, put an error message in ERRBUF and return -1. **************************************************************************/ int connect_to_server(char *name, char *hostname, int port, - char *errbuf, int n_errbuf) + char *errbuf, int errbufsize) +{ + int outcome; + + outcome = get_server_address(hostname, port, errbuf, errbufsize); + if (outcome == 0) { + outcome = try_to_connect(name, errbuf, errbufsize); + if (outcome != 0) + outcome = -1; + } + return outcome; +} + + +/************************************************************************** + Get ready to [try to] connect to a server: + - translate HOSTNAME and PORT (with defaults of "localhost" and + DEFAULT_SOCK_PORT respectively) to a raw IP address and port number, and + store them in the `server_addr' variable + - return 0 on success + or put an error message in ERRBUF and return -1 on failure +**************************************************************************/ +int get_server_address(char *hostname, int port, char *errbuf, + int errbufsize) { + if (port == 0) + port = DEFAULT_SOCK_PORT; + /* use name to find TCP/IP address of server */ - struct sockaddr_in src; - struct packet_req_join_game req; + if (!hostname) + hostname = "localhost"; - if(port==0) - port=DEFAULT_SOCK_PORT; - - if(!hostname) - hostname="localhost"; - - if (!fc_lookup_host(hostname, &src)) { - mystrlcpy(errbuf, _("Failed looking up host"), n_errbuf); + if (!fc_lookup_host(hostname, &server_addr)) { + mystrlcpy(errbuf, _("Failed looking up host"), errbufsize); return -1; } - - src.sin_port = htons(port); + + server_addr.sin_port = htons(port); #ifdef HAVE_SIGPIPE /* ignore broken pipes */ - signal (SIGPIPE, SIG_IGN); + signal(SIGPIPE, SIG_IGN); #endif - - if((aconnection.sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) { - mystrlcpy(errbuf, mystrerror(errno), n_errbuf); + + return 0; +} + +/************************************************************************** + Try to connect to a server (get_server_address() must be called first!): + - try to create a TCP socket and connect it to `server_addr' + - if successful: + - start monitoring the socket for packets from the server + - send a "join game request" packet to the server + and - return 0 + - if unable to create the connection, close the socket, put an error + message in ERRBUF and return the Unix error code (ie., errno, which + will be non-zero). +**************************************************************************/ +int try_to_connect(char *connect_name, char *errbuf, int errbufsize) +{ + int outcome; + + if ((aconnection.sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + mystrlcpy(errbuf, mystrerror(errno), errbufsize); return -1; } - - if(connect(aconnection.sock, (struct sockaddr *) &src, sizeof (src)) < 0) { - mystrlcpy(errbuf, mystrerror(errno), n_errbuf); + + outcome = connect(aconnection.sock, + (struct sockaddr *) &server_addr, sizeof(server_addr)); + if (outcome < 0) { + outcome = errno; + mystrlcpy(errbuf, mystrerror(outcome), errbufsize); my_closesocket(aconnection.sock); aconnection.sock = -1; - return -1; - } + return outcome; + } else { + struct packet_req_join_game req; - if (aconnection.buffer) { - /* didn't close cleanly previously? */ - freelog(LOG_ERROR, "Unexpected buffers in connect_to_server()"); - /* get newly initialized ones instead */ - free_socket_packet_buffer(aconnection.buffer); - free_socket_packet_buffer(aconnection.send_buffer); - } - aconnection.buffer = new_socket_packet_buffer(); - aconnection.send_buffer = new_socket_packet_buffer(); - aconnection.last_write = 0; - - aconnection.used = 1; + if (aconnection.buffer) { + /* didn't close cleanly previously? */ + /* get newly initialized ones instead */ + free_socket_packet_buffer(aconnection.buffer); + free_socket_packet_buffer(aconnection.send_buffer); + } + aconnection.buffer = new_socket_packet_buffer(); + aconnection.send_buffer = new_socket_packet_buffer(); + aconnection.last_write = 0; - /* gui-dependent details now in gui_main.c: */ - add_net_input(aconnection.sock); - - close_socket_set_callback(close_socket_callback); + aconnection.used = 1; - /* now send join_request package */ + /* gui-dependent details now in gui_main.c: */ + add_net_input(aconnection.sock); - mystrlcpy(req.short_name, name, MAX_LEN_USERNAME); - req.major_version=MAJOR_VERSION; - req.minor_version=MINOR_VERSION; - req.patch_version=PATCH_VERSION; - sz_strlcpy(req.version_label, VERSION_LABEL); - sz_strlcpy(req.capability, our_capability); - sz_strlcpy(req.name, name); + /* now send join_request package */ - send_packet_req_join_game(&aconnection, &req); - - return 0; + mystrlcpy(req.short_name, connect_name, MAX_LEN_USERNAME); + req.major_version = MAJOR_VERSION; + req.minor_version = MINOR_VERSION; + req.patch_version = PATCH_VERSION; + sz_strlcpy(req.version_label, VERSION_LABEL); + sz_strlcpy(req.capability, our_capability); + sz_strlcpy(req.name, connect_name); + + send_packet_req_join_game(&aconnection, &req); + + return 0; + } } /************************************************************************** diff -X freeciv/diff_ignore -Nurd freeciv/client/clinet.h autoconnect/client/clinet.h --- freeciv/client/clinet.h Sun Jan 2 12:55:22 2000 +++ autoconnect/client/clinet.h Sat Feb 24 16:53:38 2001 @@ -16,10 +16,15 @@ #define DEFAULT_SOCK_PORT 5555 #define METALIST_ADDR "http://meta.freeciv.org/metaserver/" +/* In autoconnect mode, try to connect to server four times a second */ +#define AUTOCONNECT_INTERVAL 250 + struct connection; int connect_to_server(char *name, char *hostname, int port, - char *errbuf, int n_errbuf); + char *errbuf, int errbufsize); +int get_server_address(char *hostname, int port, char *errbuf, int errbufsize); +int try_to_connect(char *connect_name, char *errbuf, int errbufsize); void input_from_server(int fd); void disconnect_from_server(void); diff -X freeciv/diff_ignore -Nurd freeciv/client/gui-gtk/connectdlg.c autoconnect/client/gui-gtk/connectdlg.c --- freeciv/client/gui-gtk/connectdlg.c Fri Feb 23 14:15:05 2001 +++ autoconnect/client/gui-gtk/connectdlg.c Sat Feb 24 16:59:03 2001 @@ -14,12 +14,14 @@ #include #endif +#include #include #include #include #include "fcintl.h" +#include "log.h" #include "support.h" #include "version.h" @@ -45,6 +47,8 @@ static int get_meta_list(GtkWidget *list, char *errbuf, int n_errbuf); +static int try_to_autoconnect(); + /************************************************************************** ... **************************************************************************/ @@ -52,11 +56,11 @@ { char errbuf [512]; - sz_strlcpy(name, gtk_entry_get_text(GTK_ENTRY(iname))); + sz_strlcpy(connect_name, gtk_entry_get_text(GTK_ENTRY(iname))); sz_strlcpy(server_host, gtk_entry_get_text(GTK_ENTRY(ihost))); server_port=atoi(gtk_entry_get_text(GTK_ENTRY(iport))); - if(connect_to_server(name, server_host, server_port, + if(connect_to_server(connect_name, server_host, server_port, errbuf, sizeof(errbuf))!=-1) { gtk_widget_destroy(dialog); gtk_widget_set_sensitive(toplevel,TRUE); @@ -161,7 +165,7 @@ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); iname=gtk_entry_new(); - gtk_entry_set_text(GTK_ENTRY(iname), name); + gtk_entry_set_text(GTK_ENTRY(iname), connect_name); gtk_table_attach_defaults (GTK_TABLE (table), iname, 1, 2, 0, 1); label=gtk_label_new(_("Host:")); @@ -288,4 +292,71 @@ gtk_clist_thaw(GTK_CLIST(list)); return 0; +} + +/************************************************************************** + Start trying to autoconnect to civserver. Calls + get_server_address(), then arranges for try_to_autoconnect(), which + calls try_to_connect(), to be called roughly every + AUTOCONNECT_INTERVAL milliseconds, until success, fatal error or + user intervention. (Doesn't use widgets, but is GTK-specific + because it calls gtk_timeout_add().) +**************************************************************************/ +void server_autoconnect() +{ + char buf[512]; + int outcome; + + my_snprintf(buf, sizeof(buf), + _("Auto-connecting to server \"%s\" at port %d as \"%s\""), + server_host, server_port, connect_name); + append_output_window(buf); + outcome = get_server_address(server_host, server_port, buf, sizeof(buf)); + if (outcome < 0) { + freelog(LOG_FATAL, + _("Error contacting server \"%s\" at port %d " + "as \"%s\":\n %s\n"), + server_host, server_port, connect_name, buf); + gtk_exit(1); + } + if (try_to_autoconnect()) { + gtk_timeout_add(AUTOCONNECT_INTERVAL, try_to_autoconnect, NULL); + } +} + +/************************************************************************** + Make an attempt to autoconnect to the server. + (server_autoconnect() gets GTK to call this function every so often.) +**************************************************************************/ +static int try_to_autoconnect() +{ + char errbuf[512]; + static int count = 0; + + count++; + + /* abort if after 10 seconds the server couldn't be reached */ + + if (AUTOCONNECT_INTERVAL*count >= 10000) { + freelog(LOG_FATAL, + _("Failed to contact server \"%s\" at port " + "%d as \"%s\" after %d attempts"), + server_host, server_port, connect_name, count); + gtk_exit(1); + } + + switch (try_to_connect(connect_name, errbuf, sizeof(errbuf))) { + case 0: /* Success! */ + return FALSE; /* Tells GTK not to call this + function again */ + case ECONNREFUSED: /* Server not available (yet) */ + return TRUE; /* Tells GTK to keep calling this function */ + default: /* All other errors are fatal */ + freelog(LOG_FATAL, + _("Error contacting server \"%s\" at port %d " + "as \"%s\":\n %s\n"), + server_host, server_port, connect_name, errbuf); + gtk_exit(1); + exit(1); /* Suppresses a gcc warning */ + } } diff -X freeciv/diff_ignore -Nurd freeciv/client/gui-stub/connectdlg.c autoconnect/client/gui-stub/connectdlg.c --- freeciv/client/gui-stub/connectdlg.c Mon Dec 27 18:25:06 1999 +++ autoconnect/client/gui-stub/connectdlg.c Sat Feb 24 17:00:52 2001 @@ -1,10 +1,82 @@ /* connectdlg.c -- PLACEHOLDER */ +#include + +#include "log.h" + #include "connectdlg.h" +static void try_to_autoconnect(); + void gui_server_connect(void) { /* PORTME */ +} + + +/************************************************************************** + Start trying to autoconnect to civserver. + Calls get_server_address(), then arranges for + autoconnect_callback(), which calls try_to_connect(), to be called + roughly every AUTOCONNECT_INTERVAL milliseconds, until success, + fatal error or user intervention. +**************************************************************************/ +void server_autoconnect() +{ + char buf[512]; + int outcome; + + my_snprintf(buf, sizeof(buf), + _("Auto-connecting to server \"%s\" at port %d as \"%s\""), + server_host, server_port, connect_name); + append_output_window(buf); + outcome = get_server_address(server_host, server_port, buf, sizeof(buf)); + if (outcome < 0) { + freelog(LOG_FATAL, + _("Error contacting server \"%s\" at port %d " + "as \"%s\":\n %s\n"), + server_host, server_port, connect_name, buf); + exit(1); + } + try_to_autoconnect(); +} + +/************************************************************************** + Make an attempt to autoconnect to the server. If the server isn't + there yet, arrange for this routine to be called again in about + AUTOCONNECT_INTERVAL milliseconds. If anything else goes wrong, log + a fatal error. +**************************************************************************/ +static int try_to_autoconnect() +{ + char errbuf[512]; + static int count = 0; + + count++; + + /* abort if after 10 seconds the server couldn't be reached */ + + if (AUTOCONNECT_INTERVAL * count >= 10000) { + freelog(LOG_FATAL, + _("Failed to contact server \"%s\" at port " + "%d as \"%s\" after %d attempts"), + server_host, server_port, connect_name, count); + gtk_exit(1); + } + + switch (try_to_connect(connect_name, errbuf, sizeof(errbuf))) { + case 0: /* Success! */ + return; + case ECONNREFUSED: /* Server not available (yet) - wait & retry */ + /*PORTME*/ schedule_timer + (AUTOCONNECT_INTERVAL, try_to_autoconnect, NULL); + default: /* All other errors are fatal */ + freelog(LOG_FATAL, + _("Error contacting server \"%s\" at port %d " + "as \"%s\":\n %s\n"), + server_host, server_port, connect_name, errbuf); + /*PORTME*/ exit_application(error code); + } } diff -X freeciv/diff_ignore -Nurd freeciv/client/gui-xaw/connectdlg.c autoconnect/client/gui-xaw/connectdlg.c --- freeciv/client/gui-xaw/connectdlg.c Wed Jan 31 00:38:52 2001 +++ autoconnect/client/gui-xaw/connectdlg.c Sat Feb 24 16:58:57 2001 @@ -14,6 +14,7 @@ #include #endif +#include #include #include @@ -27,6 +28,7 @@ #include #include "fcintl.h" +#include "log.h" #include "mem.h" /* mystrdup() */ #include "support.h" #include "version.h" @@ -49,6 +51,7 @@ void quit_callback(Widget w, XtPointer client_data, XtPointer call_data); void connect_callback(Widget w, XtPointer client_data, XtPointer call_data); void connect_meta_callback(Widget w, XtPointer client_data, XtPointer call_data); +void try_to_autoconnect(); /****************************************************************/ @@ -85,7 +88,7 @@ I_L(XtVaCreateManagedWidget("cnamel", labelWidgetClass, form, NULL)); iname=XtVaCreateManagedWidget("cnamei", asciiTextWidgetClass, form, - XtNstring, name, NULL); + XtNstring, connect_name, NULL); I_L(XtVaCreateManagedWidget("chostl", labelWidgetClass, form, NULL)); ihost=XtVaCreateManagedWidget("chosti", asciiTextWidgetClass, form, @@ -145,13 +148,13 @@ char errbuf[512]; XtVaGetValues(iname, XtNstring, &dp, NULL); - sz_strlcpy(name, (char*)dp); + sz_strlcpy(connect_name, (char*)dp); XtVaGetValues(ihost, XtNstring, &dp, NULL); sz_strlcpy(server_host, (char*)dp); XtVaGetValues(iport, XtNstring, &dp, NULL); sscanf((char*)dp, "%d", &server_port); - if(connect_to_server(name, server_host, server_port, + if(connect_to_server(connect_name, server_host, server_port, errbuf, sizeof(errbuf))!=-1) { XtDestroyWidget(XtParent(XtParent(w))); if(meta_dialog_shell) { @@ -298,4 +301,67 @@ delete_server_list(server_list); *list=NULL; return 0; +} + + +/************************************************************************** + Start trying to autoconnect to civserver. + Calls get_server_address() then try_to_autoconnect(). +**************************************************************************/ +void server_autoconnect() +{ + char buf[512]; + int outcome; + + my_snprintf(buf, sizeof(buf), + _("Auto-connecting to server \"%s\" at port %d as \"%s\""), + server_host, server_port, connect_name); + append_output_window(buf); + outcome = get_server_address(server_host, server_port, buf, sizeof(buf)); + if (outcome < 0) { + freelog(LOG_FATAL, + _("Error contacting server \"%s\" at port %d " + "as \"%s\":\n %s\n"), + server_host, server_port, connect_name, buf); + exit(1); + } + try_to_autoconnect(); +} + +/************************************************************************** + Make an attempt to autoconnect to the server. If the server isn't + there yet, get the Xt kit to call this routine again about + AUTOCONNECT_INTERVAL milliseconds. If anything else goes wrong, log + a fatal error. +**************************************************************************/ +void try_to_autoconnect() +{ + char errbuf[512]; + static int count = 0; + + count++; + + /* abort if after 10 seconds the server couldn't be reached */ + + if (AUTOCONNECT_INTERVAL*count >= 10000) { + freelog(LOG_FATAL, + _("Failed to contact server \"%s\" at port " + "%d as \"%s\" after %d attempts"), + server_host, server_port, connect_name, count); + exit(1); + } + + switch (try_to_connect(connect_name, errbuf, sizeof(errbuf))) { + case 0: /* Success! */ + return; + case ECONNREFUSED: /* Server not available (yet) - wait & retry */ + XtAppAddTimeOut(app_context, + AUTOCONNECT_INTERVAL, try_to_autoconnect, NULL); + default: /* All other errors are fatal */ + freelog(LOG_FATAL, + _("Error contacting server \"%s\" at port %d " + "as \"%s\":\n %s\n"), + server_host, server_port, connect_name, errbuf); + exit(1); /* Same as gui_main.c::main_quit_freeciv() */ + } } diff -X freeciv/diff_ignore -Nurd freeciv/client/include/connectdlg_g.h autoconnect/client/include/connectdlg_g.h --- freeciv/client/include/connectdlg_g.h Wed Jul 14 13:15:52 1999 +++ autoconnect/client/include/connectdlg_g.h Sat Feb 24 13:46:38 2001 @@ -14,5 +14,6 @@ #define FC__CONNECTDLG_G_H void gui_server_connect(void); +void server_autoconnect(void); #endif /* FC__CONNECTDLG_G_H */ diff -X freeciv/diff_ignore -Nurd freeciv/client/packhand.c autoconnect/client/packhand.c --- freeciv/client/packhand.c Fri Feb 23 14:15:04 2001 +++ autoconnect/client/packhand.c Sat Feb 24 13:46:38 2001 @@ -1101,7 +1101,7 @@ /* Remove to here */ if(get_client_state()==CLIENT_GAME_RUNNING_STATE && pplayer==game.player_ptr) { - sz_strlcpy(name, pplayer->name); + sz_strlcpy(connect_name, pplayer->name); if(poptechup) { if(!game.player_ptr->ai.control || ai_popup_windows) popup_science_dialog(1);