stonier / ecl_core

A set of tools and interfaces extending the capabilities of c++ to provide a lightweight, consistent interface with a focus for control programming.
Other
84 stars 68 forks source link

Client connections sending SIGPIPE #34

Closed stonier closed 10 years ago

stonier commented 10 years ago

@jakan2 says that the ecl socket server is getting killed when the client connection breaks. The relevant ecl code:

long SocketServer::write(const char *s, unsigned long n) ecl_debug_throw_decl(StandardException) {
    int bytes_written = ::send(client_socket_fd,s,n,0);
    if ( bytes_written < 0 ) {
        switch(errno) {
            case ( EPIPE ) : {
                close();
                return ConnectionHungUp;
            }
            default : {
                ecl_debug_throw( devices::send_exception(LOC) );
                error_handler = devices::send_error();
                return ConnectionProblem;
            }
        }
    }
}

So it seems we already had handling for exactly this in our old use cases, but this no longer works. Look up the man pages:

   EPIPE  The  local  end  has been shut down on a connection oriented socket.  In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set.

So SIGPIPE is getting sent which kills the server. The 'fix' would be to do this:

  int bytes_written = ::send(client_socket_fd,s,n,0);
  int bytes_written = ::send(client_socket_fd,s,n,MSG_NOSIGNAL);

The question is....why is this code falling over now and not before? If we know this, then we can know that we're not introducing another problem.

stonier commented 10 years ago

@jakan2 - I think I found the reason. From the man pages:

POSIX.1-2001 only describes the MSG_OOB and MSG_EOR flags.  POSIX.1-2008 adds a specification of MSG_NOSIGNAL.

Probably the linux operating systems we were using did not have POSIX.1-2008 implementations.

stonier commented 10 years ago

We should handle cases where the signal is not defined - I updated the server code appropriately.

#ifdef MSG_NOSIGNAL
    int bytes_written = ::send(client_socket_fd,s,n,0|MSG_NOSIGNAL);
#else
    int bytes_written = ::send(client_socket_fd,s,n,0);
#endif