title: Writing to a closed, local TCP socket not failing
body: <p>I seem to be having a problem with my sockets.  Below, you will see some code which forks a server and a client.  The server opens a TCP socket, and the client connects to it and then closes it.  Sleeps are used to coordinate the timing.  After the client-side close(), the server tries to write() to its own end of the TCP connection.  According to the write(2) man page, this <em>should</em> give me a SIGPIPE and an EPIPE errno.  However, I don't see this.  From the server's point of view, the write to a local, closed socket <em>succeeds</em>, and absent the EPIPE I can't see how the server should be detecting that the client has closed the socket.</p>
  
  <p>In the gap between the client closing its end and the server attempting to write, a call to netstat will show that the connection is in a CLOSE_WAIT/FIN_WAIT2 state, so the server end should definitely be able to reject the write.</p>
  
  <p>For reference, I'm on Debian Squeeze, uname -r is 2.6.39-bpo.2-amd64.</p>
  
  <p>What's going on here?</p>
  
  <hr>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/wait.h&gt;
  #include &lt;sys/socket.h&gt;
  #include &lt;sys/select.h&gt;
  #include &lt;netinet/tcp.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;fcntl.h&gt;
  
  #include &lt;netdb.h&gt;
  
  #define SERVER_ADDRESS "127.0.0.7"
  #define SERVER_PORT 4777
  
  
  #define myfail_if( test, msg ) do { if((test)){ fprintf(stderr, msg "\n"); exit(1); } } while (0)
  #define myfail_unless( test, msg ) myfail_if( !(test), msg )
  
  int connect_client( char *addr, int actual_port )
  {
      int client_fd;
  
      struct addrinfo hint;
      struct addrinfo *ailist, *aip;
  
  
      memset( &amp;hint, '\0', sizeof( struct addrinfo ) );
      hint.ai_socktype = SOCK_STREAM;
  
      myfail_if( getaddrinfo( addr, NULL, &amp;hint, &amp;ailist ) != 0, "getaddrinfo failed." );
  
      int connected = 0;
      for( aip = ailist; aip; aip = aip-&gt;ai_next ) {
          ((struct sockaddr_in *)aip-&gt;ai_addr)-&gt;sin_port = htons( actual_port );
          client_fd = socket( aip-&gt;ai_family, aip-&gt;ai_socktype, aip-&gt;ai_protocol );
  
          if( client_fd == -1) { continue; }
          if( connect( client_fd, aip-&gt;ai_addr, aip-&gt;ai_addrlen) == 0 ) {
              connected = 1;
              break;
          }
          close( client_fd );
      }
  
      freeaddrinfo( ailist );
  
      myfail_unless( connected, "Didn't connect." );
      return client_fd;
  }
  
  
  void client(){
      sleep(1);
      int client_fd = connect_client( SERVER_ADDRESS, SERVER_PORT );
  
      printf("Client closing its fd... ");
      myfail_unless( 0 == close( client_fd ), "close failed" );
      fprintf(stdout, "Client exiting.\n");
      exit(0);
  }
  
  
  int init_server( struct sockaddr * saddr, socklen_t saddr_len )
  {
      int sock_fd;
  
      sock_fd = socket( saddr-&gt;sa_family, SOCK_STREAM, 0 );
      if ( sock_fd &lt; 0 ){
          return sock_fd;
      }
  
      myfail_unless( bind( sock_fd, saddr, saddr_len ) == 0, "Failed to bind." );
      return sock_fd;
  }
  
  int start_server( const char * addr, int port )
  {
      struct addrinfo *ailist, *aip;
      struct addrinfo hint;
      int sock_fd;
  
      memset( &amp;hint, '\0', sizeof( struct addrinfo ) );
      hint.ai_socktype = SOCK_STREAM;
      myfail_if( getaddrinfo( addr, NULL, &amp;hint, &amp;ailist ) != 0, "getaddrinfo failed." );
  
      for( aip = ailist; aip; aip = aip-&gt;ai_next ){
          ((struct sockaddr_in *)aip-&gt;ai_addr)-&gt;sin_port = htons( port );
          sock_fd = init_server( aip-&gt;ai_addr, aip-&gt;ai_addrlen );
          if ( sock_fd &gt; 0 ){
              break;
          } 
      }
      freeaddrinfo( aip );
  
      myfail_unless( listen( sock_fd, 2 ) == 0, "Failed to listen" );
      return sock_fd;
  }
  
  
  int server_accept( int server_fd )
  {
      printf("Accepting\n");
      int client_fd = accept( server_fd, NULL, NULL );
      myfail_unless( client_fd &gt; 0, "Failed to accept" );
      return client_fd;
  }
  
  
  void server() {
      int server_fd = start_server(SERVER_ADDRESS, SERVER_PORT);
      int client_fd = server_accept( server_fd );
  
      printf("Server sleeping\n");
      sleep(60);
  
      printf( "Errno before: %s\n", strerror( errno ) );
      printf( "Write result: %d\n", write( client_fd, "123", 3 ) );
      printf( "Errno after:  %s\n", strerror( errno ) );
  
      close( client_fd );
  }
  
  
  int main(void){
      pid_t clientpid;
      pid_t serverpid;
  
      clientpid = fork();
  
      if ( clientpid == 0 ) {
          client();
      } else {
          serverpid = fork();
  
          if ( serverpid == 0 ) {
              server();
          }
          else {
              int clientstatus;
              int serverstatus;
  
              waitpid( clientpid, &amp;clientstatus, 0 );
              waitpid( serverpid, &amp;serverstatus, 0 );
  
              printf( "Client status is %d, server status is %d\n", 
                      clientstatus, serverstatus );
          }
      }
  
      return 0;
  }
  </code></pre>