Note that there are some explanatory texts on larger screens.

plurals
  1. POWriting to a closed, local TCP socket not failing
    primarykey
    data
    text
    <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>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload