diff -ur freeciv-1.11.4/client/clinet.c freeciv-1.11.4-patched/client/clinet.c --- freeciv-1.11.4/client/clinet.c Fri Jun 23 18:37:32 2000 +++ freeciv-1.11.4-patched/client/clinet.c Wed Aug 9 02:14:24 2000 @@ -63,6 +63,7 @@ #include "game.h" #include "log.h" #include "mem.h" +#include "netintf.h" #include "packets.h" #include "support.h" #include "version.h" @@ -145,7 +146,10 @@ return -1; } + my_nodelay(aconnection.sock); + aconnection.buffer.ndata=0; + aconnection.lastwrite=0; /* gui-dependent details now in gui_main.c: */ add_net_input(aconnection.sock); diff -ur freeciv-1.11.4/common/game.h freeciv-1.11.4-patched/common/game.h --- freeciv-1.11.4/common/game.h Sat Jul 15 18:45:47 2000 +++ freeciv-1.11.4-patched/common/game.h Wed Aug 9 01:29:20 2000 @@ -57,6 +57,8 @@ int tech; int skill_level; int timeout; + int tcptimeout; + int netwait; time_t turn_start; int end_year; int year; @@ -311,6 +313,14 @@ #define GAME_DEFAULT_TIMEOUT 0 #define GAME_MIN_TIMEOUT 0 #define GAME_MAX_TIMEOUT 8639999 + +#define GAME_DEFAULT_TCPTIMEOUT 10 +#define GAME_MIN_TCPTIMEOUT 0 +#define GAME_MAX_TCPTIMEOUT 120 + +#define GAME_DEFAULT_NETWAIT 5 +#define GAME_MIN_NETWAIT 0 +#define GAME_MAX_NETWAIT 10 #define GAME_DEFAULT_BARBARIANRATE 2 #define GAME_MIN_BARBARIANRATE 0 diff -ur freeciv-1.11.4/common/netintf.c freeciv-1.11.4-patched/common/netintf.c --- freeciv-1.11.4/common/netintf.c Mon Jun 26 15:21:06 2000 +++ freeciv-1.11.4-patched/common/netintf.c Wed Aug 9 02:18:22 2000 @@ -28,10 +28,18 @@ #include #endif +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_TCP_H +#include +#endif + #include "log.h" +#include "netintf.h" #include "support.h" -#include "netintf.h" /*************************************************************** ... @@ -62,5 +70,28 @@ #endif #else freelog(LOG_DEBUG, "NONBLOCKING_SOCKETS not available"); +#endif +} + + +/*************************************************************** +... +***************************************************************/ +void my_nodelay(int sockfd) +{ +#ifdef TCP_NODELAY + struct protoent* pent; + int val; + + pent = getprotobyname("tcp"); + + if ( pent == NULL ) + return; + + val = 1; + + ret = setsockopt(sockfd,pent->p_proto,TCP_NODELAY,(char*)&val,sizeof(val)); +#else + return; #endif } diff -ur freeciv-1.11.4/common/netintf.h freeciv-1.11.4-patched/common/netintf.h --- freeciv-1.11.4/common/netintf.h Mon Jun 26 15:21:07 2000 +++ freeciv-1.11.4-patched/common/netintf.h Tue Aug 8 20:46:35 2000 @@ -42,5 +42,6 @@ #endif void my_nonblock(int sockfd); +void my_nodelay(int sockfd); #endif /* FC__NETINTF_H */ diff -ur freeciv-1.11.4/common/packets.c freeciv-1.11.4-patched/common/packets.c --- freeciv-1.11.4/common/packets.c Mon Jul 10 07:42:36 2000 +++ freeciv-1.11.4-patched/common/packets.c Wed Aug 9 01:37:08 2000 @@ -3682,58 +3682,97 @@ /******************************************************************** + write_socket_data() attempts to flush the socket_packet_buffer buf + to the connection "pc". write wrapper function -vasc + ********************************************************************/ static int write_socket_data(struct connection *pc, - struct socket_packet_buffer *buf) + struct socket_packet_buffer* buf) { - int start, nput, nblock; - - for (start=0; startndata;) { - fd_set writefs, exceptfs; - struct timeval tv; - - MY_FD_ZERO(&writefs); - MY_FD_ZERO(&exceptfs); - FD_SET(pc->sock, &writefs); - FD_SET(pc->sock, &exceptfs); - - tv.tv_sec = 2; tv.tv_usec = 0; - - if (select(pc->sock+1, NULL, &writefs, &exceptfs, &tv) <= 0) { - buf->ndata -= start; - memmove(buf->data, buf->data+start, buf->ndata); - return -1; - } + int nput,offset,ret,nblock; +#ifndef NONBLOCKING_SOCKETS + fd_set writefs, exceptfs; + struct timeval tv; +#endif + + offset = 0; + ret = 0; + nput = 1; + + while ( nput > 0 && offset < buf->ndata ) { + + /* Some sillyness to support really really obscure platforms? + ++ltarkkal */ + +#ifndef NONBLOCKING_SOCKETS + + /* Avoid calling select() if the socket is in blocking mode. This + requires that the socket_packet_buffer is always flushed in + blocking mode */ + + if ( pc->lastwrite != 0 ) { + { + MY_FD_ZERO(&writefs); + MY_FD_ZERO(&exceptfs); + FD_SET(pc->sock,&writefs); + FD_SET(pc->sock,&exceptfs); + + tv.tv_sec = 0; tv.tv_usec = 0; + + if ( select(pc->sock+1,NULL,&writefs,&exceptfs,&tv) < 0 ) { + nput = -1; + break; + } - if (FD_ISSET(pc->sock, &exceptfs)) { - if (close_callback) { - (*close_callback)(pc); + if (FD_ISSET(pc->sock, &exceptfs)) { + nput = -1; + break; + } + + if (!(FD_ISSET(pc->sock,&writefs))) /* Still blocking */ + break; } - return -1; - } - if (FD_ISSET(pc->sock, &writefs)) { - nblock=MIN(buf->ndata-start, 4096); - if((nput=write(pc->sock, (const char *)buf->data+start, nblock)) == -1) { -#ifdef NONBLOCKING_SOCKETS - if (errno == EWOULDBLOCK || errno == EAGAIN) { - continue; - } + nblock = MIN(4096,buf->ndata-offset); +#else + nblock = buf->ndata-offset; #endif - if (close_callback) { - (*close_callback)(pc); - } - return -1; - } - start += nput; - } + nput = write(pc->sock, (const char*)buf->data+offset, nblock); + + if ( nput > 0 ) + offset += nput; } - buf->ndata=0; - return 0; -} + if ( offset < buf->ndata && offset > 0 ) { + memmove(buf->data,buf->data+offset,buf->ndata-offset); + } + + buf->ndata -= offset; + + if ( buf->ndata > 0 && (offset > 0 || pc->lastwrite == 0 )) { + time(&pc->lastwrite); + } + /* freeciv currently uses O_NONBLOCK, not O_NDELAY*/ + + if ( nput == -1 ) { +#ifdef NONBLOCKING_SOCKETS + if ( errno != EAGAIN && errno != EWOULDBLOCK ) { + if ( close_callback ) { + (*close_callback)(pc); + ret = -1; + } + } +#else + if ( close_callback ) { + (*close_callback)(pc); + ret = -1; + } +#endif + } + return ret; +} /******************************************************************** flush'em diff -ur freeciv-1.11.4/common/packets.h freeciv-1.11.4-patched/common/packets.h --- freeciv-1.11.4/common/packets.h Mon Jul 10 04:49:06 2000 +++ freeciv-1.11.4-patched/common/packets.h Wed Aug 9 01:36:45 2000 @@ -819,6 +819,7 @@ char *player; struct socket_packet_buffer buffer; struct socket_packet_buffer send_buffer; + time_t lastwrite; char addr[MAX_LEN_ADDR]; char capability[MAX_LEN_CAPSTR]; /* "capability" gives the capability string of the executable (be it diff -ur freeciv-1.11.4/configure freeciv-1.11.4-patched/configure --- freeciv-1.11.4/configure Thu Jul 20 20:26:32 2000 +++ freeciv-1.11.4-patched/configure Tue Aug 8 20:50:18 2000 @@ -1071,7 +1071,7 @@ fi -for ac_prog in mawk gawk nawk awk +for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -6357,7 +6357,7 @@ for ac_hdr in arpa/inet.h netdb.h netinet/in.h pwd.h sys/ioctl.h \ sys/select.h sys/signal.h sys/socket.h sys/termio.h \ - sys/time.h sys/types.h sys/uio.h termios.h unistd.h fcntl.h + sys/time.h sys/types.h sys/uio.h termios.h unistd.h fcntl.h netinet/tcp.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 diff -ur freeciv-1.11.4/configure.in freeciv-1.11.4-patched/configure.in --- freeciv-1.11.4/configure.in Thu Jul 20 20:26:32 2000 +++ freeciv-1.11.4-patched/configure.in Tue Aug 8 20:48:16 2000 @@ -418,7 +418,7 @@ AC_HEADER_STDC AC_CHECK_HEADERS(arpa/inet.h netdb.h netinet/in.h pwd.h sys/ioctl.h \ sys/select.h sys/signal.h sys/socket.h sys/termio.h \ - sys/time.h sys/types.h sys/uio.h termios.h unistd.h fcntl.h) + sys/time.h sys/types.h sys/uio.h termios.h unistd.h fcntl.h netinet/tcp.h) if test x$client = xxaw; then dnl Want to get appropriate -I flags: fc_save_CPPFLAGS="$CPPFLAGS" diff -ur freeciv-1.11.4/server/civserver.c freeciv-1.11.4-patched/server/civserver.c --- freeciv-1.11.4/server/civserver.c Sat Jul 15 18:45:47 2000 +++ freeciv-1.11.4-patched/server/civserver.c Wed Aug 9 02:16:58 2000 @@ -335,7 +335,7 @@ server_state=PRE_GAME_STATE; while(server_state==PRE_GAME_STATE) - sniff_packets(); + io_handler(1); send_server_info_to_metaserver(1,0); @@ -379,7 +379,7 @@ } while(server_state==SELECT_RACES_STATE) { - sniff_packets(); + io_handler(1); for(i=0; igame.end_year || is_game_over()) server_state=GAME_OVER_STATE; + + io_handler(2); /* flush output buffers */ } show_ending(); @@ -549,7 +551,7 @@ while(server_state==GAME_OVER_STATE) { force_end_of_sniff=0; - sniff_packets(); + io_handler(1); } server_close_udp(); @@ -1443,11 +1445,11 @@ return; if (gethostname(hostname, 512)==0) { - notify_player(pplayer, _("Welcome to the %s Server running at %s."), - FREECIV_NAME_VERSION, hostname); + notify_player(pplayer, _("Welcome to the %s Server running at %s port %d."), + FREECIV_NAME_VERSION, hostname, port); } else { - notify_player(pplayer, _("Welcome to the %s Server."), - FREECIV_NAME_VERSION); + notify_player(pplayer, _("Welcome to the %s Server at port %d."), + FREECIV_NAME_VERSION,port); } /* tell who we're waiting on to end the game turn */ diff -ur freeciv-1.11.4/server/console.c freeciv-1.11.4-patched/server/console.c --- freeciv-1.11.4/server/console.c Mon Jul 17 17:50:39 2000 +++ freeciv-1.11.4-patched/server/console.c Wed Aug 9 00:38:31 2000 @@ -33,6 +33,7 @@ static int console_show_prompt=0; static int console_prompt_is_showing=0; static int console_rfcstyle=0; + #ifdef HAVE_LIBREADLINE static int readline_received_enter = 1; #endif diff -ur freeciv-1.11.4/server/sernet.c freeciv-1.11.4-patched/server/sernet.c --- freeciv-1.11.4/server/sernet.c Wed Jul 19 15:18:11 2000 +++ freeciv-1.11.4-patched/server/sernet.c Wed Aug 9 02:36:47 2000 @@ -167,10 +167,97 @@ } /***************************************************************************** +Initialize all state relevant to the server console i/o +*****************************************************************************/ +void +io_console_init(void) +{ +#ifdef HAVE_LIBREADLINE + static int readline_initialized = 0; +#endif + + con_prompt_init(); + +#ifdef HAVE_LIBREADLINE + + if (!readline_initialized) { + char *home_dir = user_home_dir(); + if (home_dir) { + history_file = + fc_malloc(strlen(home_dir) + 1 + strlen(HISTORY_FILENAME) + 1); + if (history_file) { + strcpy(history_file, home_dir); + strcat(history_file, "/"); + strcat(history_file, HISTORY_FILENAME); + using_history(); + read_history(history_file); + } + } + + rl_initialize(); + rl_callback_handler_install("> ", handle_readline_input_callback); + + readline_initialized = 1; + } +#endif +} + +/***************************************************************************** +Read the present as input from the server console. This assumes there +actually is input present. +*****************************************************************************/ +void +io_console_input(void) +{ +#ifdef SOCKET_ZERO_ISNT_STDIN + char buf[BUF_SIZE+1]; + char *bufptr = buf; +#else +#ifndef HAVE_LIBREADLINE + char buf[BUF_SIZE+1]; + int didget; +#endif +#endif + +#ifndef SOCKET_ZERO_ISNT_STDIN +#ifdef HAVE_LIBREADLINE + rl_callback_read_char(); + if (readline_handled_input) { + readline_handled_input = 0; + con_prompt_enter_clear(); + } +#else + if((didget=read(0, buf, BUF_SIZE))==-1) { + freelog(LOG_FATAL, "read from stdin failed"); + exit(1); + } + *(buf+didget)='\0'; + con_prompt_enter(); /* will need a new prompt, regardless */ + handle_stdin_input((struct player *)NULL, buf); +#endif +#else + /* fetch chars until \n or run out of space in buffer */ + while ((*bufptr=fgetc(stdin)) != EOF) { + if (*bufptr == '\n') *bufptr = '\0'; + if (*bufptr == '\0') { + bufptr = buf; + con_prompt_enter(); /* will need a new prompt, regardless */ + handle_stdin_input((struct player *)NULL, buf); + break; + } + if ((bufptr-buf) <= BUF_SIZE) bufptr++; /* prevent overrun */ + } +#endif +} + +/***************************************************************************** Get and handle: - new connections, - input from connections, - input from server operator in stdin +Mode parameter: + 1 for cmd line i/o and client i/o + 2 for cmd line i/o and client output only (see game.netwait parameter) Returns: 0 if went past end-of-turn timeout 2 if force_end_of_sniff found to be set @@ -178,88 +265,98 @@ This function also handles prompt printing, via the con_prompt_* functions. That is, other functions should not need to do so. --dwp *****************************************************************************/ -int sniff_packets(void) +int io_handler(int mode) { - int i; + int i,ret,nflush; int max_desc; - fd_set readfs, exceptfs; + fd_set readfs, exceptfs, writefs; struct timeval tv; + time_t entrytime; static int year; -#ifdef SOCKET_ZERO_ISNT_STDIN - char buf[BUF_SIZE+1]; - char *bufptr = buf; -#endif - - con_prompt_init(); - -#ifdef HAVE_LIBREADLINE - { - static int readline_initialized = 0; - - if (!readline_initialized) { - char *home_dir = user_home_dir(); - if (home_dir) { - history_file = - fc_malloc(strlen(home_dir) + 1 + strlen(HISTORY_FILENAME) + 1); - if (history_file) { - strcpy(history_file, home_dir); - strcat(history_file, "/"); - strcat(history_file, HISTORY_FILENAME); - using_history(); - read_history(history_file); - } - } - rl_initialize(); - rl_callback_handler_install("> ", handle_readline_input_callback); - - readline_initialized = 1; - } - } -#endif + io_console_init(); if(year!=game.year) { if (server_state == RUN_GAME_STATE) year=game.year; } + if (!game.timeout) game.turn_start = time(NULL); + time(&entrytime); + while(1) { - con_prompt_on(); /* accepting new input */ - if(force_end_of_sniff) { + if( force_end_of_sniff || + (mode == 2 && time(NULL) >= entrytime + game.netwait)) { force_end_of_sniff=0; - con_prompt_off(); return 2; } - + tv.tv_sec=1; tv.tv_usec=0; MY_FD_ZERO(&readfs); MY_FD_ZERO(&exceptfs); + MY_FD_ZERO(&writefs); + #ifndef SOCKET_ZERO_ISNT_STDIN FD_SET(0, &readfs); #endif - FD_SET(sock, &readfs); + + if ( mode != 2 ) + FD_SET(sock, &readfs); + FD_SET(sock, &exceptfs); max_desc=sock; + + nflush = 0; for(i=0; i 0) && + time(NULL) > connections[i].lastwrite + game.tcptimeout ) { + freelog(LOG_VERBOSE,"Cutting lagging client connection"); + close_socket_callback(&connections[i]); + } + } + + if ( ret == 0) { /* timeout */ send_server_info_to_metaserver(0,0); - if((game.timeout) - && (time(NULL)>game.turn_start + game.timeout) - && (server_state == RUN_GAME_STATE)){ - con_prompt_off(); + + if(game.timeout && (mode != 2) + && (time(NULL) > game.turn_start + game.timeout) + && (server_state == RUN_GAME_STATE)){ return 0; } #ifdef __VMS @@ -281,6 +378,7 @@ continue; #endif } + if (!game.timeout) game.turn_start = time(NULL); @@ -292,72 +390,55 @@ if(server_accept_connection(sock)==-1) freelog(LOG_NORMAL, "failed accepting connection"); } - for(i=0; i=0) { - char *packet; - int type; - while((packet=get_packet_from_connection(&connections[i], &type))) - handle_packet_input(&connections[i], packet, type); - } - else { - close_socket_callback(&connections[i]); - } + + /* input from a player */ + + for(i=0; i=0) { + char *packet; + int type; + while((packet=get_packet_from_connection(&connections[i], &type))) + handle_packet_input(&connections[i], packet, type); + } + else { + close_socket_callback(&connections[i]); } } } break; } - con_prompt_off(); if((game.timeout) - && (time(NULL)>game.turn_start + game.timeout)) + && (time(NULL)>game.turn_start + game.timeout) + && (mode != 2)) return 0; + return 1; } @@ -381,6 +462,7 @@ } my_nonblock(new_sock); + my_nodelay(new_sock); from=gethostbyaddr((char*)&fromend.sin_addr, sizeof(fromend.sin_addr), AF_INET); @@ -391,6 +473,7 @@ connections[i].sock=new_sock; connections[i].player=NULL; connections[i].buffer.ndata=0; + connections[i].lastwrite=0; connections[i].first_packet=1; connections[i].byte_swap=0; connections[i].access_level=(i?default_access_level:first_access_level); @@ -465,6 +548,7 @@ int i; for(i=0; i