Re: [testsuite patch] race: server-kill.exp: Connection reset by peer [Re: [patch+7.6] Fix 7.5 regression crashing GDB if gdbserver dies]

Pedro Alves
2013-04-09T15:23:10Z

[-- Attachment #1: Type: text/plain, Size: 1770 bytes --]

On 04/06/2013 08:26 PM, Jan Kratochvil wrote:
> On Fri, 22 Mar 2013 20:18:41 +0100, Jan Kratochvil wrote:
>> +set server_pid [exp_pid -i [board_info target fileid]]
>> +remote_exec target "kill -9 $server_pid"
>> +
>> +gdb_test "step" "Remote connection closed"
>
> Getting occasionally randomly:
> Remote communication error. Target disconnected.: Connection reset by peer.
> (gdb) FAIL: gdb.server/server-kill.exp: tstatus
>
> (it was FAILing on "step" before, "tstatus" vs. "step" does not matter)
>
> I even Googled one may get ECONNRESET by writing into a closed TCP socket:
> http://stackoverflow.com/questions/2974021/what-does-econnreset-mean-in-the-context-of-an-af-local-socket
>
> But I was unable to reproduce it myself (kernel-3.8.4-202.fc18.x86_64) with
> the attached testcase:
> sleeping ... done
> write ok
> ssize=0
> read ok
> send: send.c:53: main: Unexpected error: Broken pipe.
> Aborted
> by:
> * nc -l 5000
> * ./send (starts sleeping)
> * kill -9 `pidof ncat` (Fedora nc is ncat)
> * # send resumes sleeping
>
> I get at most EPIPE but never ECONNRESET. send vs. write and recv vs. read
> also make no difference there.

From that url:

"Triggered when there's outstanding outgoing data that has not yet been written to the other side."

ncat is recv'ing the data you send it, so the window that
could trigger is quite small.

I've attached a standalone (no ncat) reproducer that triggers it all
the time for me.

$ ./send
sleeping ... closing ... done
send: send.c:72: main: Unexpected error: Connection reset by peer.
Aborted

> With no answer I will check in this patch as this issue seems unrelated to the
> problem, GDB still works properly even with ECONNRESET. I was just curious.

Looks fine to me.

--
Pedro Alves

[-- Attachment #2: send.c --]
[-- Type: text/x-csrc, Size: 1725 bytes --]

#define _GNU_SOURCE 1
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#define PORT 5000

int
main (void)
{
struct sockaddr_in sockaddr;
socklen_t tmp;
int listen_fd, send_fd, recv_fd;
char charbuf;
ssize_t ssize;
int i;

setbuf (stdout, NULL);

/* bind/listen. */
errno = 0;
listen_fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
assert (listen_fd != -1);

sockaddr.sin_family = PF_INET;
sockaddr.sin_port = htons (PORT);
sockaddr.sin_addr.s_addr = INADDR_ANY;

if (bind (listen_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
|| listen (listen_fd, 1))
perror ("Can't bind address");

/* Connect. */
send_fd = socket (PF_INET,SOCK_STREAM, 0);
assert (send_fd != -1);

memset (&sockaddr, 0, sizeof sockaddr);
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
sockaddr.sin_port = htons (PORT);

i = connect (send_fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));
assert (i == 0);

/* Accept. */
tmp = sizeof (sockaddr);
recv_fd = accept (listen_fd, (struct sockaddr *) &sockaddr, &tmp);
assert (recv_fd != -1);

/* Send. */
charbuf = 'a';
ssize = send (send_fd, &charbuf, 1, 0);
assert (ssize == 1);

/* Now that data has been queued, close the receiving end. */
fputs ("sleeping ...", stdout);
sleep (1);
fputs (" closing ...", stdout);
close (recv_fd);
sleep (1);
puts (" done");

/* Try sending again. */
charbuf = 'b';
errno = 0;
ssize = send (send_fd, &charbuf, 1, 0);
assert_perror (errno);
assert (ssize == 1);
puts ("send ok");

return 0;
}