LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   [C++] Cannot catch SIGPIPE signal (https://www.linuxquestions.org/questions/programming-9/%5Bc-%5D-cannot-catch-sigpipe-signal-871355/)

dwhitney67 03-27-2011 07:56 PM

[C++] Cannot catch SIGPIPE signal
 
I have a Socket library, written in C++, in which the method used to send data never has the opportunity to handle an errno of SIGPIPE. Thus I thought perhaps I should setup a signal handler to receive the signal, but this too is not being called.

Is there something that I am missing or doing that is completely wrong? Below is the relevant code. Note that a SIGPIPE signal is generated when the Server is unable to send data to the Client (e.g. the client has terminated).

Server code:
Code:

#include <TCPServerSocket.hpp>
#include <string>
#include <iostream>
#include <unistd.h>

int main()
{
  using namespace socketpp;
  using namespace std;

  try
  {
      TCPServerSocket server;
      server.bind(9000);
      server.listen();

      TCPSocketPtr client = server.accept();

      client->setNonBlocking();

      string message = "Hello";

      while (true)
      {
        *client << message;  // send data
        sleep(1);
      }
  }
  catch (SocketException& e)
  {
      cerr << "Exception -- " << e.what() << endl;
      return -1;
  }

  return 0;
}

In the constructor for TCPSocket, which above is noted as TCPSocketPtr (a boost shared ptr), I have the following code:
Code:

TCPSocket::TCPSocket(int domain, int type, int protocol)
  : Socket(domain, type, protocol)
{
  struct sigaction act;

  memset(&act, 0, sizeof(act));
  act.sa_handler = sigHandler;

  sigaction(SIGPIPE, &act, NULL);
}

...

void
TCPSocket::sigHandler(int signo)
{
  throw SocketException("TCPSocket: Signal received.", signo);
}

And finally, the code that sends the data:
Code:

TCPSocket&
operator<<(TCPSocket& sock, const std::string& msg)
{
  sock.send(msg.c_str(), msg.size());
  return sock;
}

...

void
TCPSocket::send(const char* msg, size_t msgLen)
{
  size_t bytesSent = 0;

  while (bytesSent != msgLen)
  {
    int rtn = ::send(m_Socket, msg + bytesSent, msgLen - bytesSent, 0);

    if (rtn < 0 && (errno == EAGAIN || errno == EINTR))  // This point never reached when SIGPIPE signal is issued.
    {
      continue;
    }
    if (rtn < 0)
    {
      throw SocketException("Error occurred while attempting to send data", errno);
    }

    bytesSent += rtn;
  }
}


P.S. I assume it is a SIGPIPE signal that is killing my Server, because that is what gdb reported when I was debugging via ddd.

dwhitney67 03-27-2011 08:20 PM

Never mind -- I figured out the issue. I had failed to notice that there are two variants of the TCPSocket constructor; of course I failed to setup the signal handler within the constructor that was actually being called by the accept() method.

Also, I found out that it was not necessary to throw an exception from within the signal handler. Once the signal is properly handled (in my case, with a "no-op"), execution returns to the send() method where the return value and errno are examined. Thus a more useful exception is thrown when the error is detected.


All times are GMT -5. The time now is 01:16 AM.