Date: Mon, 10 Jan 2005 16:59:04 +0200 From: Maxim Sobolev <sobomax@portaone.com> To: hackers@freebsd.org Cc: current@freebsd.org Subject: Re: Attempt to invoke connect(2) on already connected unix domain datagram socket fails with ECONNRESET Message-ID: <41E29838.9020805@portaone.com> In-Reply-To: <41E27076.8080904@portaone.com> References: <41E27076.8080904@portaone.com>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------040309000406060207060002 Content-Type: text/plain; charset=KOI8-U; format=flowed Content-Transfer-Encoding: 7bit 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 --------------040309000406060207060002 Content-Type: text/plain; name="socket_test1.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="socket_test1.c" #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); } --------------040309000406060207060002--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?41E29838.9020805>