Hi,
Looking into the socklog package test errors a bug was found in the
pflocal socket implementation, specifically in connect():
1)
PID1: create a local named socket using a server to receive data
PID2: connect to that socket with a client to send data
everything is fine :)
Terminal1:
./test_socket_server.DGRAM
test_socket_server:main(): Domain = AF_UNIX, Type = SOCK_DGRAM
test_socket_server:main(): Removing old socket: 'test_socket'
test_socket_server:socket_unix(): socket() socket_fd = 3
test_socket_server:read_socket(): Waiting for incoming connections...
Terminal2:
./test_socket_client.DGRAM
test_socket_client:main(): Domain = AF_UNIX, Type = SOCK_DGRAM
test_socket_client:main(): socket_name = 'test_socket'
test_socket_client:write_socket(): connect(): err = '(os/kern)
successful'
test_socket_client:write_socket(): send() err = '(os/kern) successful'
Terminal1:
test_socket_server:read_socket(): read() Message = 'Testing,
testing, ...'
2) kill $PID1 to leave the socket behind
PID2: connect to that socket with a client to send data
On hurd this is not detected:
/test_socket_client.DGRAM
test_socket_client:main(): Domain = AF_UNIX, Type = SOCK_DGRAM
test_socket_client:main(): socket_name = 'test_socket'
test_socket_client:write_socket(): connect(): err = '(os/kern)
successful' <-- BUG IS HERE
test_socket_client:write_socket(): send() err = '(os/kern) successful'
Expected output e.g. on Linux (or with AF_INET):
./test_socket_client.DGRAM
test_socket_client:main(): Domain = AF_UNIX, Type = SOCK_DGRAM
test_socket_client:main(): socket_name = 'test_socket'
test_socket_client:write_socket(): connect(): err = 'Connection refused'
<-- correct ECONNREFUSED is returned
test_socket_client:write_socket(): connect(): Connection refused
test_socket_client:main(): write_socket() SOCK_DGRAM: Connection refused
Programs are attached to cover the following cases selected in defs.inc:
AF_UNIX+SOCK_DGRAM, AF_UNIX+SOCK_STREAM (pflocal is buggy)
AF_INET+SOCK_DGRAM, AF_INET+SOCK_STREAM (pfinet is fine)
I've tried to find out how to detect that the socket server is gone but
not found a solution yet.
Functions tried in pflocal/sock.c:
pipe_acquire_reader(pipe): modifies the reference count and locking
problems
pipe_acquire_writer(pipe): modifies the reference count and locking
problems
pipe_is_readable(pipe, 0/1): always returns false
pipe_wait_readable(pipe, 1, 0/1): always returns EAGAIN, setting noblock
to 0 makes the box freeze :(
pipe_wait_writable(pipe, 0/1): Always returns 0 since
pipe->readable(pipe, 1)=0 and pipe->write_limit=16384 (another bug?)
The test calls were placed in the function: void connect() planned to
return an error code instead.
Hopefully the problem is described detailed enough.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "defs.inc"
#ifdef USE_SOCK_STREAM
#define type SOCK_STREAM
#else
#define type SOCK_DGRAM
#endif
/* FIXME: Support AF_INET */
#ifdef USE_AF_UNIX
#define domain AF_UNIX
#else
#define domain AF_INET
#endif
#define SOCKET_NAME "test_socket"
#define DATA "Testing, testing, ..."
int write_socket(const char* socket_name) {
int err = 0, socket_fd, write_size;
#ifdef USE_AF_UNIX
struct sockaddr_un server;
int c = sizeof(struct sockaddr_un);
#else
struct sockaddr_in server;
int c = sizeof(struct sockaddr_in);
#endif
/* Create socket */
socket_fd = socket (domain, type, 0);
if (socket_fd == -1)
{
perror("test_socket_client:write_socket(): socket()");
return -1;
}
#ifdef USE_AF_UNIX
server.sun_family = domain;
strncpy (server.sun_path, socket_name, sizeof(server.sun_path));
#else
server.sin_family = domain;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_port = htons( );
#endif
/* Connect to socket_fd */
err = connect (socket_fd, (struct sockaddr *)&server, c);
printf("test_socket_client:write_socket(): connect(): err = '%s'\n", strerror(errno));
if (err) {
close(socket_fd);
#ifdef EDESTADDRREQ
if (errno == EDESTADDRREQ) errno = ECONNREFUSED;
#endif
perror("test_socket_client:write_socket(): connect()");
return err;
}
#if 0
write_size = write (socket_fd, DATA, sizeof(DATA));
printf("test_socket_client:write_socket(): write(): err = '%s'\n", strerror(errno));
#else
write_size = send (socket_fd, DATA, sizeof(DATA), 0);
printf("test_socket_client:write_socket(): send() err = '%s'\n", strerror(errno));
#endif
if (write_size == -1)
{
#ifdef USE_SOCK_STREAM
perror("test_socket_client:write_socket(): write(): Sending on stream socket");
#else
perror("test_socket_client:write_socket(): write(): Sending on datagram socket");
#endif
close(socket_fd);
return err;
}
close(socket_fd);
return err;
}
int main(void) {
const char* socket_name = SOCKET_NAME;
int err = 0;
printf ("test_socket_client:main(): Domain = %s, Type = %s\n", (domain == AF_UNIX) ? "AF_UNIX": "AF_INET", (type == S