Complete.Org: Mailing Lists: Archives: freeciv-dev: August 2001:
[Freeciv-Dev] Re: [Patch] Write data if socket allows it
Home

[Freeciv-Dev] Re: [Patch] Write data if socket allows it

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: freeciv development list <freeciv-dev@xxxxxxxxxxx>
Subject: [Freeciv-Dev] Re: [Patch] Write data if socket allows it
From: Raimar Falke <hawk@xxxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 20 Aug 2001 15:30:20 +0200
Reply-to: rf13@xxxxxxxxxxxxxxxxxxxxxx

On Sat, Aug 11, 2001 at 12:49:32PM +0200, Raimar Falke wrote:
> 
> It can happen that in the send_buffer still holds data if something on
> the client send a lot of packets in a short time and than waits for
> data from the server.

Never sent a patch if you are busy. The long description of the above
goes like this:

First the current situation:
 - every send_packet_* method calls send_connection_data
 - send_connection_data will add the data to the buffer and will call
 flush_connection_send_buffer_* which will call write_socket_data
 - write_socket_data will test if the socket is writable:
    * if it is writable it will send as much data as posible till the
    socket becomes unwritable or all data got sent
    * if the socket is not writable it will just return
 - the main loop of the client is in input_from_server and it will
 just read data from the server

Problem: if in a short time a lot of data (it doesn't matter if these
are a lot of small packets or some big ones) is send (via
send_packet_*) and the socket isn't writeable the data is put into the
buffer. If now the client wait for input from the server the data in
the send buffer will never be delivered to the server although the
socket may have become writeable.

Solution: in the main loop check if there is data to be sent. If so
also wait for the socket to become writable and write data if the
socket accepts data.

This problem isn't triggered in normal client operation since the
human player is just too slow. The attribute block however can grow
larger than 64kb and is send in 2kb packets to the server in a very
short time.

        Raimar

> diff -Nurd -X freeciv/diff_ignore freeciv.current/client/clinet.c 
> extra_write1/client/clinet.c
> --- freeciv.current/client/clinet.c   Tue Aug  7 15:53:09 2001
> +++ extra_write1/client/clinet.c      Sat Aug 11 12:38:16 2001
> @@ -20,6 +20,7 @@
>  #include <ctype.h>
>  #include <errno.h>
>  #include <signal.h>
> +#include <assert.h>
>  
>  #ifdef HAVE_UNISTD_H
>  #include <unistd.h>
> @@ -195,12 +196,61 @@
>  }  
>  
>  /**************************************************************************
> +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.
> +**************************************************************************/
> +static int read_from_connection()
> +{
> +  for (;;) {
> +    fd_set readfs, writefs;
> +    int socket_fd = aconnection.sock;
> +    int have_data_for_server = (aconnection.used && aconnection.send_buffer
> +                             && aconnection.send_buffer->ndata);
> +    int n;
> +
> +    MY_FD_ZERO(&readfs);
> +    FD_SET(socket_fd, &readfs);
> +
> +    if (have_data_for_server) {
> +      MY_FD_ZERO(&writefs);
> +      FD_SET(socket_fd, &writefs);
> +      n = select(socket_fd + 1, &readfs, &writefs, NULL, NULL);
> +    } else {
> +      n = select(socket_fd + 1, &readfs, NULL, NULL, NULL);
> +    }
> +
> +    /* no timeout expected */
> +    assert(n != 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, &writefs)) {
> +      flush_connection_send_buffer_all(&aconnection);
> +    }
> +
> +    if (FD_ISSET(socket_fd, &readfs)) {
> +      return read_socket_data(socket_fd, aconnection.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()>=0) {
>      int type, result;
>      char *packet;
>  

-- 
 email: rf13@xxxxxxxxxxxxxxxxx
 "Many of my assistants were fans of Tolkien, who wrote 'Lord of the Rings'
  and a number of other children's stories for adults.  The first character
  alphabet that was programmed for my plotter was Elvish rather than Latin."
    -- from SAIs "life as a computer for a quarter of a century"


[Prev in Thread] Current Thread [Next in Thread]