diff -Nurd -X freeciv.current/diff_ignore freeciv.current/client/clinet.c work/client/clinet.c --- freeciv.current/client/clinet.c Mon Aug 20 09:18:08 2001 +++ work/client/clinet.c Wed Aug 22 17:15:29 2001 @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef HAVE_UNISTD_H #include @@ -195,12 +196,84 @@ } /************************************************************************** - This function is called when the client received a - new input from the server +A wrapper around read_socket_data() which also handles the case the +socket becomes writeable and there is still data which should be sent +to the server. + +Returns: + -1 : an error occured - you should close the socket + >0 : number of bytes read + =0 : no data read, would block +**************************************************************************/ +static int read_from_connection(struct connection *pc) +{ + for (;;) { + fd_set readfs, writefs, exceptfs; + int socket_fd = pc->sock; + int have_data_for_server = (pc->used && pc->send_buffer + && pc->send_buffer->ndata); + int n; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + MY_FD_ZERO(&readfs); + FD_SET(socket_fd, &readfs); + + MY_FD_ZERO(&exceptfs); + FD_SET(socket_fd, &exceptfs); + + if (have_data_for_server) { + MY_FD_ZERO(&writefs); + FD_SET(socket_fd, &writefs); + n = select(socket_fd + 1, &readfs, &writefs, &exceptfs, &tv); + } else { + n = select(socket_fd + 1, &readfs, NULL, &exceptfs, &tv); + } + + /* the socket is neither readable, writeable nor got an + exception */ + if (n == 0) { + return 0; + } + + if (n == -1) { + if (errno == EINTR) { + freelog(LOG_DEBUG, "select() returned EINTR"); + continue; + } + + freelog(LOG_NORMAL, "error in select() return=%d errno=%d (%s)", + n, errno, strerror(errno)); + return -1; + } + + if (FD_ISSET(socket_fd, &exceptfs)) { + return -1; + } + + if (have_data_for_server && FD_ISSET(socket_fd, &writefs)) { + flush_connection_send_buffer_all(pc); + if (pc->notify_of_writable_data) { + pc->notify_of_writable_data(pc, pc->send_buffer + && pc->send_buffer->ndata); + } + } + + if (FD_ISSET(socket_fd, &readfs)) { + return read_socket_data(socket_fd, pc->buffer); + } + } +} + +/************************************************************************** + This function is called when the client received a new input from the + server. **************************************************************************/ void input_from_server(int fid) { - if(read_socket_data(fid, aconnection.buffer)>=0) { + if (read_from_connection(&aconnection) >= 0) { int type, result; char *packet; @@ -212,8 +285,7 @@ break; } } - } - else { + } else { close_socket_callback(&aconnection); } } diff -Nurd -X freeciv.current/diff_ignore freeciv.current/client/gui-gtk/gui_main.c work/client/gui-gtk/gui_main.c --- freeciv.current/client/gui-gtk/gui_main.c Mon Aug 20 09:18:09 2001 +++ work/client/gui-gtk/gui_main.c Wed Aug 22 17:14:09 2001 @@ -839,13 +839,35 @@ } /************************************************************************** +... +**************************************************************************/ +static void set_wait_for_writable_socket(struct connection *pc, + int socket_writable) +{ + static int previous_state = 0; + + if (previous_state == socket_writable) + return; + freelog(LOG_DEBUG, "set_wait_for_writable_socket(%d)", socket_writable); + gdk_input_remove(gdk_input_id); + gdk_input_id = + gdk_input_add(aconnection.sock, + GDK_INPUT_READ | (socket_writable ? GDK_INPUT_WRITE : + 0) | GDK_INPUT_EXCEPTION, + get_net_input, NULL); + previous_state = socket_writable; +} + +/************************************************************************** This function is called after the client succesfully has connected to the server **************************************************************************/ void add_net_input(int sock) { gdk_input_id = gdk_input_add(sock, - GDK_INPUT_READ|GDK_INPUT_EXCEPTION, get_net_input, NULL); + GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + get_net_input, NULL); + aconnection.notify_of_writable_data = set_wait_for_writable_socket; } /************************************************************************** diff -Nurd -X freeciv.current/diff_ignore freeciv.current/client/gui-xaw/gui_main.c work/client/gui-xaw/gui_main.c --- freeciv.current/client/gui-xaw/gui_main.c Mon Aug 20 09:18:10 2001 +++ work/client/gui-xaw/gui_main.c Wed Aug 22 17:14:09 2001 @@ -753,14 +753,37 @@ } /************************************************************************** +... +**************************************************************************/ +static void set_wait_for_writable_socket(struct connection *pc, + int socket_writable) +{ + static int previous_state = 0; + + if (previous_state == socket_writable) + return; + freelog(LOG_DEBUG, "set_wait_for_writable_socket(%d)", socket_writable); + XtRemoveInput(x_input_id); + x_input_id = XtAppAddInput(app_context, aconnection.sock, + (XtPointer) (XtInputReadMask | + (socket_writable ? + XtInputWriteMask : 0) | + XtInputExceptMask), + (XtInputCallbackProc) get_net_input, NULL); + previous_state = socket_writable; +} + +/************************************************************************** This function is called after the client succesfully has connected to the server **************************************************************************/ void add_net_input(int sock) { - x_input_id=XtAppAddInput(app_context, sock, - (XtPointer) XtInputReadMask, - (XtInputCallbackProc) get_net_input, NULL); + x_input_id = XtAppAddInput(app_context, sock, + (XtPointer) (XtInputReadMask | + XtInputExceptMask), + (XtInputCallbackProc) get_net_input, NULL); + aconnection.notify_of_writable_data = set_wait_for_writable_socket; } /************************************************************************** diff -Nurd -X freeciv.current/diff_ignore freeciv.current/common/connection.c work/common/connection.c --- freeciv.current/common/connection.c Mon Jul 23 21:45:38 2001 +++ work/common/connection.c Wed Aug 22 17:14:09 2001 @@ -331,6 +331,10 @@ } flush_connection_send_buffer_all(pc); } + if (pc->notify_of_writable_data) { + pc->notify_of_writable_data(pc, pc->send_buffer + && pc->send_buffer->ndata); + } } return 0; } diff -Nurd -X freeciv.current/diff_ignore freeciv.current/common/connection.h work/common/connection.h --- freeciv.current/common/connection.h Mon Jul 23 21:45:38 2001 +++ work/common/connection.h Wed Aug 22 17:14:09 2001 @@ -115,6 +115,8 @@ int delayed_disconnect; /* Something has occured that means the connection should be closed, but the closing has been postponed. */ + void (*notify_of_writable_data) (struct connection * pc, + int data_available_and_socket_full); }; diff -Nurd -X freeciv.current/diff_ignore freeciv.current/common/packets.c work/common/packets.c --- freeciv.current/common/packets.c Fri Jun 29 21:39:04 2001 +++ work/common/packets.c Wed Aug 22 17:16:31 2001 @@ -189,15 +189,17 @@ len = swab_uint16(len); } - if(len > pc->buffer->ndata) - return NULL; /* not all data has been read */ + if (len > pc->buffer->ndata) { + return NULL; /* not all data has been read */ + } /* so the packet gets processed (removed etc) properly: */ if(pc->byte_swap) { put_uint16(pc->buffer->data, len); } - freelog(LOG_DEBUG, "packet type %d len %d", type, len); + freelog(LOG_DEBUG, "packet type=%d len=%d buffer=%d", type, len, + pc->buffer->ndata); *ptype=type; *presult = 1; @@ -376,7 +378,6 @@ freelog(LOG_ERROR, "unknown packet type %d received from %s", type, conn_description(pc)); remove_packet_from_buffer(pc->buffer); - *presult = 0; return NULL; }; } diff -Nurd -X freeciv.current/diff_ignore freeciv.current/server/sernet.c work/server/sernet.c --- freeciv.current/server/sernet.c Mon Aug 20 09:18:13 2001 +++ work/server/sernet.c Wed Aug 22 17:14:09 2001 @@ -634,6 +634,7 @@ pconn->capability[0] = '\0'; pconn->access_level = access_level_for_next_connection(); pconn->delayed_disconnect = 0; + pconn->notify_of_writable_data = NULL; sz_strlcpy(pconn->name, makeup_connection_name(&pconn->id)); sz_strlcpy(pconn->addr,