Unix domain socket problem?

253 views
Skip to first unread message

Tanaka Akira

unread,
Feb 24, 2013, 2:34:19 AM2/24/13
to min...@googlegroups.com
Hi.

I'm trying to use Unix domain socket on Minix but
my test program don't behave as I expected.

I have two questions:

1. Why accept() blocks until client closes socket?
2. Why read() on server blocks even after client exit?

My test program is follows.

$ uname -srvm
Minix 3.2.1 i686
$ cat server.c
/* usage: ./server [socket-filename] */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

int main(int argc, char *argv[])
{
char *socket_filename = NULL;
struct sockaddr_un serv_addr;
struct sockaddr_un acpt_addr;
socklen_t acpt_len;
int serv_socket, acpt_socket;
char buf[4096];
ssize_t ssize;
int ret;

if (1 < argc)
socket_filename = argv[1];
else
socket_filename = "socket-file";

serv_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (serv_socket == -1) { perror("socket"); exit(EXIT_FAILURE); }

memset(&serv_addr, '\0', sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, socket_filename);

ret = bind(serv_socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (ret == -1) { perror("bind"); exit(EXIT_FAILURE); }

ret = listen(serv_socket, 128);
if (ret == -1) { perror("listen"); exit(EXIT_FAILURE); }

fprintf(stderr, "before accept\n");
acpt_len = sizeof(acpt_addr);
acpt_socket = accept(serv_socket, (struct sockaddr *)&acpt_addr, &acpt_len);
if (acpt_socket == -1) { perror("accept"); exit(EXIT_FAILURE); }
fprintf(stderr, "after accept\n");

fprintf(stderr, "before read\n");
ssize = read(acpt_socket, buf, sizeof(buf));
if (ssize == -1) { perror("read"); exit(EXIT_FAILURE); }
fprintf(stderr, "after read\n");

return EXIT_SUCCESS;
}

$ cat client.c
/* usage: ./client [socket-filename] */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

int main(int argc, char *argv[])
{
char *socket_filename = NULL;
struct sockaddr_un conn_addr;
int clnt_socket;
int ret;

if (1 < argc)
socket_filename = argv[1];
else
socket_filename = "socket-file";

clnt_socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (clnt_socket == -1) { perror("socket"); exit(EXIT_FAILURE); }

memset(&conn_addr, '\0', sizeof(conn_addr));
conn_addr.sun_family = AF_UNIX;
strcpy(conn_addr.sun_path, socket_filename);

ret = connect(clnt_socket, (struct sockaddr *)&conn_addr, sizeof(conn_addr));
if (ret == -1) { perror("connect"); exit(EXIT_FAILURE); }

sleep(5);

close(clnt_socket);

return EXIT_SUCCESS;
}

$ gcc -Wall -g server.c -o server
$ gcc -Wall -g client.c -o client

I run ./server and then ./client without arguments in different terminals:
(./client doesn't produce output.)

$ ./server
before accept
(blocks 5 seconds here after ./client run. Why accept() returns immediately?)
after accept
before read
(blocks here even after ./client exit. Why read() deosn't return?)

I think accept() should return just after client calls connect() and
read() should return 0 (EOF) just after client closes socket.
--
Tanaka Akira

Thomas Cort

unread,
Feb 24, 2013, 10:45:06 AM2/24/13
to min...@googlegroups.com
Hi,

The code for unix domain sockets is in /usr/src/servers/pfs. I've looked through it and I think I've spotted what might be causing at least one of the issues (#2). I'll look at coming up with and testing some fixes later today.


> 1. Why accept() blocks until client closes socket?

The code to handle accept/connect is in uds.c, but it's hard to follow just by reading it because there are a lot of moving parts. Though, the bug should reveal itself if pfs is compiled with DEBUG set to 1. I'll investigate this further later today.


> 2. Why read() on server blocks even after client exit?

uds_close() is called when the client calls close(). In uds_close() in dev_uds.c, uds_unsuspend() is called to revive the other process blocked on read(). However, from looking at the code, a process blocked on read() isn't sent a DEV_REVIVE message if there is nothing read. I think the solution is to skip the uds_perform_read() and following if statement near line 991 if fdp->peer == -1. The UDS_SUSPENDED_WRITE case below it should also get similar treatment.

Thanks for such a detailed bug report,
-Thomas

Thomas Cort

unread,
Feb 24, 2013, 10:11:40 PM2/24/13
to min...@googlegroups.com
On Sunday, February 24, 2013 10:45:06 AM UTC-5, Thomas Cort wrote:
I think I've spotted what might be causing at least one of the issues

It appears that I was mistaken. Maybe someone else can take a look at this one? The tests in /usr/src/test/test56.c all pass with Minix-3.2.1-current, but the test cases in the original post fail as described. It looks like the blocked processes aren't unblocking.

-Thomas

Thomas Veerman

unread,
Mar 7, 2013, 5:33:47 AM3/7/13
to min...@googlegroups.com
All,

This has been fixed in current master (1ba514e).

--
Thomas
Reply all
Reply to author
Forward
0 new messages