Re: Attempt to invoke connect(2) on already connected unix domain datagram socket fails with ECONNRESET

From: Maxim Sobolev <sobomax_at_portaone.com>
Date: Mon, 10 Jan 2005 16:59:04 +0200
Further investigation revealed that the said problem only happens when 
the program is trying to re-connect() socket object which previously has 
been connected to the unix domain socket closed on the server side at 
the time when the second connect() is called. Attached please find more 
simple testcase.

-Maxim

Maxim Sobolev wrote:
> Folks,
> 
> I've discovered very strange behaviour of the connect(2) system call 
> when it's called on already connected unix domain datagram socket. In 
> this case connect(2) fails with ECONNRESET, which is weird. ECONNRESET 
> is not even listed among possible return values of connect(2). I've 
> confirmed this behaviour at 4.10 and 5.3 systems. Linux doesn't exhibit 
> this (mis?)behaviour.
> 
> As long as I can tell, this behaviour contradicts documentation, 
> connect(2) manpage says:
> 
>      Generally, stream sockets may successfully connect() only
>      once; datagram sockets may use connect() multiple times to change
>      their association.
> 
> Attached please find small test program which illustrates the problem. 
> It forks itsels at the start, child becomes a server, while parent a 
> client. After each transaction server closes unix domain socket and 
> opens its again, while the client attempts to re-connect() to that unix 
> domain socket using already created socket object.
> 
> This mimics real-world scenario in which I've encountered the problem. 
> In this scenarion, there are two distinct processes communicating using 
> unix domain socket. Client uses connect() on already connected socket 
> object for performance reasons to avoid calling socket(2) for each 
> transaction. Everything works just fine until server is restarted. After 
> that any attempts to send command from the client to the server fails 
> with ECONNRESET until the client is restarted as well.
> 
> -Maxim


#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

#define	UDS_NAME1	"/tmp/uds_test.sock1"
#define	UDS_NAME2	"/tmp/uds_test.sock2"

#define	sstosa(ss)	((struct sockaddr *)(ss))

void
prepare_ifsun(struct sockaddr_un *ifsun, const char *path)
{

    memset(ifsun, '\0', sizeof(*ifsun));
#if !defined(__linux__) && !defined(__solaris__)
    ifsun->sun_len = strlen(path);
#endif
    ifsun->sun_family = AF_LOCAL;
    strcpy(ifsun->sun_path, path);
}

int
create_uds_server(const char *path)
{
    struct sockaddr_un ifsun;
    int sock;

    prepare_ifsun(&ifsun, path);

    unlink(ifsun.sun_path);

    sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
    if (sock == -1)
        err(1, "server: can't create socket");
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sock, sizeof(sock));
    if (bind(sock, sstosa(&ifsun), sizeof(ifsun)) < 0)
        err(1, "server: can't bind to a socket");

    return sock;
}

void
connect_uds_server(int sock, const char *path)
{
    struct sockaddr_un ifsun;
    int e;

    prepare_ifsun(&ifsun, path);

    e = connect(sock, sstosa(&ifsun), sizeof(ifsun));
    if (e < 0)
        err(1, "client: can't connect to a socket");
}

int
main()
{
    int s_sock1, s_sock2, c_sock;

    s_sock1 = create_uds_server(UDS_NAME1);
    s_sock2 = create_uds_server(UDS_NAME2);

    c_sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
    if (c_sock < 0)
        err(1, "client: can't create socket");

    connect_uds_server(c_sock, UDS_NAME1);
    close(s_sock1);
    connect_uds_server(c_sock, UDS_NAME2);

    exit (0);
}
Received on Mon Jan 10 2005 - 13:59:12 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:25 UTC