Date: Thu, 17 Dec 2009 17:46:55 +0200 From: Mikolaj Golub <to.my.trociny@gmail.com> To: FreeBSD-NET <freebsd-net@freebsd.org> Subject: close: Socket is not connected Message-ID: <86aaxhfvrk.fsf@zhuzha.ua1>
next in thread | raw e-mail | index | archive | help
Hi, We have an application that consists of two processes communicating via unix socket (client connects, sends requests, reads response and close the connection). Sometimes the error 'Socket is not connected' is observed when client closes the socket. We observed this problem on FreeBSD6.X and now have been observing it on 7.1. To model the behaviour of the application I have written a simple test program (see below) based on relevant parts from the application code. Using this test program it requires from an a half of hour to several hours to reproduce the error. It might fail on close() both in the parent (server) and the children (client). $ date; ./unixsocket ; date Thu Dec 17 09:38:35 UTC 2009 unixsocket: parent: close error: 57 Thu Dec 17 14:13:07 UTC 2009 unixsocket: child: connect error 61 $ ./unixsocket unixsocket: child: close error: 57 I can reproduce the error running the test on 8.0 too. Does this indicate some bug in FreeBSD or may be just something is wrong with our code? #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <strings.h> #include <string.h> #include <unistd.h> #include <sys/select.h> #include <err.h> #define UNIXSTR_PATH "/tmp/mytest.socket" #define BUFSIZE 557 #define USLEEP 10000 #define timeout 10 int waitData(int handle, int reading, int writing) { struct timeval tv; int result; fd_set rset; fd_set wset; fd_set eset; FD_ZERO(&rset); FD_SET(handle, &rset); FD_ZERO(&wset); FD_SET(handle, &wset); FD_ZERO(&eset); FD_SET(handle, &eset); tv.tv_sec = timeout; tv.tv_usec = 0; for (;;) { if (reading && !writing) result = select(handle + 1, &rset, 0, &eset, &tv); else if (!reading && writing) result = select(handle + 1, 0, &wset, &eset, &tv); else result = select(handle + 1, &rset, &wset, &eset, &tv); if (result == 0) /* timeout */ return 0; if (result < 0) { if (errno == EINTR) { continue; } errx(1, "select: %d", errno); } if (FD_ISSET(handle, &rset) || FD_ISSET(handle, &wset)) { int err = 0; socklen_t err_size = sizeof(err); if (getsockopt(handle, SOL_SOCKET, SO_ERROR, (char*)&err, &err_size) != 0) { errx(1, "getsockopts: %d", errno); } if (err != 0) { errx(1, "getsockopts: err: %d", err); } } else { errx(1, "select problems"); } return 1; /* OK */ } } void Write(int handle, const char* buf, size_t size) { size_t left = size; while (left > 0) { while (1) { int sent = send(handle, buf, size, 0); if (sent <= 0) { if (errno == EAGAIN) { if (!waitData(handle, 0, 1)) errx(1, "Write: timeout"); continue; } errx(1, "Write: error: %d", errno); } left -= sent; buf += sent; break; } } } void Read(int handle, char* buf, size_t size) { while (size > 0) { int blockSize; if (!waitData(handle, 1, 0)) errx(1, "Read: timeout"); blockSize = recv(handle, buf, size, 0); if (blockSize <= 0) { errx(1, "Read: error: blockSize: %d", blockSize); } buf += blockSize; size -= blockSize; } } int main(int argc, char **argv) { int listenfd, connfd, pid; struct sockaddr_un servaddr; char buf[BUFSIZE]; memset(buf, 'X', sizeof(buf)); pid = fork(); if (-1 == pid) errx(1, "fork(): %d", errno); if (0 != pid) { /* parent */ if ((listenfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) errx(1, "parent: socket error: %d", errno); unlink(UNIXSTR_PATH); bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strcpy(servaddr.sun_path, UNIXSTR_PATH); if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) errx(1, "parent: bind error: %d", errno); if (listen(listenfd, 1024) < 0) errx(1, "parent: listen error: %d", errno); for ( ; ; ) { if ((connfd = accept(listenfd, (struct sockaddr *) NULL, NULL)) < 0) errx(1, "parent: accept error: %d", errno); if (fcntl(connfd, F_SETFL, O_NONBLOCK) == -1) errx(1, "parent: fcntl error: %d", errno); Read(connfd, buf, sizeof(buf)); Write(connfd, buf, sizeof(buf)); if (close(connfd) < 0) errx(1, "parent: close error: %d", errno); } } else { /* child */ /* wait some time while parent has created socket */ sleep(1); for ( ; ; ) { if ((connfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) errx(1, "child: socket error: %d", errno); if (fcntl(connfd, F_SETFL, O_NONBLOCK) == -1) errx(1, "child: fcntl error: %d", errno); bzero(&servaddr, sizeof(servaddr)); servaddr.sun_family = AF_LOCAL; strcpy(servaddr.sun_path, UNIXSTR_PATH); if (connect(connfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) errx(1, "child: connect error %d", errno); Write(connfd, buf, sizeof(buf)); Read(connfd, buf, sizeof(buf)); if (close(connfd) != 0) errx(1, "child: close error: %d", errno); usleep(USLEEP); } } return 0; } -- Mikolaj Golub
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?86aaxhfvrk.fsf>