Dmitry V. Levin
da66e25779
Implement additional synchronization between parent and child processes to guarantee that the child starts closing connected socket only after exiting of the parent's accept() syscall. This guarantee seems to be necessary to reliably receive UNIX_DIAG_PEER messages from NETLINK_SOCK_DIAG interface. * tests/net-accept-connect.c: Implement additional synchronization between parent and child processes. * tests/unix-yy-connect.awk: Update.
75 lines
1.5 KiB
C
75 lines
1.5 KiB
C
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
|
|
static void
|
|
handler(int sig)
|
|
{
|
|
assert(close(1) == 0);
|
|
_exit(0);
|
|
}
|
|
|
|
int
|
|
main(int ac, const char **av)
|
|
{
|
|
struct sockaddr_un addr = {
|
|
.sun_family = AF_UNIX,
|
|
};
|
|
socklen_t len;
|
|
|
|
assert(ac == 2);
|
|
assert(strlen(av[1]) > 0);
|
|
|
|
strncpy(addr.sun_path, av[1], sizeof(addr.sun_path));
|
|
len = offsetof(struct sockaddr_un, sun_path) + strlen(av[1]) + 1;
|
|
if (len > sizeof(addr))
|
|
len = sizeof(addr);
|
|
|
|
unlink(av[1]);
|
|
close(0);
|
|
close(1);
|
|
|
|
assert(socket(PF_LOCAL, SOCK_STREAM, 0) == 0);
|
|
assert(bind(0, (struct sockaddr *) &addr, len) == 0);
|
|
assert(listen(0, 5) == 0);
|
|
|
|
memset(&addr, 0, sizeof addr);
|
|
assert(getsockname(0, (struct sockaddr *) &addr, &len) == 0);
|
|
if (len > sizeof(addr))
|
|
len = sizeof(addr);
|
|
|
|
pid_t pid = fork();
|
|
assert(pid >= 0);
|
|
|
|
if (pid) {
|
|
assert(accept(0, (struct sockaddr *) &addr, &len) == 1);
|
|
assert(close(0) == 0);
|
|
assert(kill(pid, SIGUSR1) == 0);
|
|
int status;
|
|
assert(waitpid(pid, &status, 0) == pid);
|
|
assert(status == 0);
|
|
assert(close(1) == 0);
|
|
} else {
|
|
sigset_t set;
|
|
sigemptyset(&set);
|
|
sigaddset(&set, SIGUSR1);
|
|
|
|
assert(sigprocmask(SIG_BLOCK, &set, NULL) == 0);
|
|
assert(signal(SIGUSR1, handler) != SIG_ERR);
|
|
assert(socket(PF_LOCAL, SOCK_STREAM, 0) == 1);
|
|
assert(close(0) == 0);
|
|
assert(connect(1, (struct sockaddr *) &addr, len) == 0);
|
|
assert(sigprocmask(SIG_UNBLOCK, &set, NULL) == 0);
|
|
assert(pause() == 99);
|
|
return 1;
|
|
}
|
|
|
|
unlink(av[1]);
|
|
return 0;
|
|
}
|