lkml.org 
[lkml]   [2002]   [Jan]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] removed socket buffer in unix domain socket

Hi,

I found a problem to unix domain socket.

The unix_gc function removes socket buffers of the socket
which is connectted but not acceptted yet.

After one process executes "Mark phase" of unix_gc function,
another process registers socket buffer by using sendmsg with SCM_RIGHTS.
At the next moment, the socket buffer is removed.

I attached the test program.
When I execute one server and two clients on SMP machine
(kernel 2.4.16 and PentiumIII x 2), I can reporduce this problem.

Following is a patch to avoid this problem.

--- kernel-2.4.16/net/unix/garbage.c.sv Mon Jan 7 15:46:22 2002
+++ kernel-2.4.16/net/unix/garbage.c Mon Jan 7 15:51:22 2002
@@ -279,7 +279,7 @@
/*
* Do we have file descriptors ?
*/
- if(UNIXCB(skb).fp)
+ if(s->dead && UNIXCB(skb).fp)
{
__skb_unlink(skb, skb->list);
__skb_queue_tail(&hitlist,skb);

Regards,

Yasuma Takeda


#include <stdio.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>

main(int argc,char ** argv)
{

struct sockaddr_un sockaddr;
char line[128];
char reply[128];
int socket_errno;
int i, err, n;
int s;
int ret;
int fd[2];
struct cmsghdr *cmsg;
int *fdptr;
char cmsgbuf[CMSG_SPACE(sizeof (int))];
struct iovec vec;
struct msghdr msghdr;

if ( socketpair( AF_UNIX, SOCK_STREAM, 0, fd ) == -1 ) {
fprintf(stderr, "socketpait error\n");
}
close(fd[1]);

n = 0;
while (1) {
if ((s=socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
socket_errno = errno;
fprintf(stderr,"can't create socket [%d]\n",socket_errno);
exit(-1);
}

memset(&sockaddr, '\0', sizeof(sockaddr));
sockaddr.sun_family = AF_UNIX;
strcpy(sockaddr.sun_path, "/tmp/unix_d_test");

if (connect(s,(struct sockaddr *)&sockaddr,sizeof(sockaddr)) == -1) {
socket_errno = errno;
fprintf(stderr,"connect error [%d]\n",errno);
exit(-1);
}

for(i = 0 ; i < 128 ; i++) {
line[i] = 0;
}
sprintf(line, "[%d]:client pid is %d", n, getpid());

vec.iov_base = line;
vec.iov_len = 128;

msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
msghdr.msg_flags = 0;

msghdr.msg_control = cmsgbuf;
msghdr.msg_controllen = sizeof cmsgbuf;
cmsg = CMSG_FIRSTHDR(&msghdr);
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 1);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
fdptr = (int *)CMSG_DATA(cmsg);
memcpy(fdptr, fd, sizeof(int) * 1);
msghdr.msg_controllen = cmsg->cmsg_len;

if ((ret = sendmsg(s, &msghdr, 0 )) < 128) {
fprintf(stderr, "sendmsg error %d\n", errno);
exit(-1);
}
fprintf(stderr, "[%d]:sendmsg() %d byte OK. fd:%d\n", n, ret, fd[0]);

vec.iov_base = reply;
vec.iov_len = 128;

msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
msghdr.msg_flags = 0;
msghdr.msg_controllen = 0;
msghdr.msg_control = NULL;

if ((ret = recvmsg(s, &msghdr, 0)) < 128) {
fprintf(stderr, "recvmsg() error %d\n", errno);
exit(-1);
}
fprintf(stderr, "recvmgs() %d byte OK.\n", ret);

close(s);
n++;
}

fprintf(stderr,"GOOD BY \n");
exit (0);
}




#include <stdio.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

main(int argc,char ** argv)
{
int s;
struct sockaddr_un sockaddr;
char line[128];
char reply[128];
int socket_errno;
int i, err;
int flags;
fd_set read_set, read_cur;
int max_fd;
int ret;
struct iovec vec;
struct msghdr msghdr;
int client_fd;
struct cmsghdr *cmsg;
int *pass_fd_ptr;
char cmsgbuf[CMSG_SPACE(sizeof (int))];

if ((s=socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
socket_errno = errno;
fprintf(stdout,"can't create socket [%d]\n",socket_errno);
exit(-1);
}

unlink("/tmp/unix_d_test");
memset(&sockaddr, '\0', sizeof(sockaddr));
sockaddr.sun_family = AF_UNIX;
strcpy(sockaddr.sun_path, "/tmp/unix_d_test");

if (bind(s,(struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
socket_errno = errno;
fprintf(stdout,"can't bind socket [%d]\n",errno);
exit(-1);
}

if (listen(s, 10) < 0) {
fprintf(stdout, "listen() error %d\n", socket_errno);
exit(-1);
}

FD_ZERO(&read_set);
FD_SET(s, &read_set);
max_fd = s;
client_fd = -1;

for(;;) {
for(i = 0 ; i < 128 ; i++) {
line[i] = 0;
}

read_cur = read_set;
ret = select(max_fd+1, &read_cur, NULL, NULL, NULL);
if (ret == -1) {
fprintf(stdout, "select() error %d\n", errno);
continue;
}
for (i = 0; i <= max_fd; i++) {
if (FD_ISSET(i, &read_cur)) {
if (i == s) {
struct sockaddr_un address;
int len;

if (client_fd != -1) {
close(client_fd);
}

len = sizeof(struct sockaddr_un);
client_fd = accept(s, (struct sockaddr *)&address, &len);
if (client_fd == -1) {
fprintf(stdout, "accept() error %d\n", errno);
exit(-1);
}
if ( client_fd > max_fd ) max_fd = client_fd;
} else if (i == client_fd) {
fprintf(stdout, "read from client_fd\n");
}

msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
msghdr.msg_control = cmsgbuf;
msghdr.msg_controllen = sizeof(cmsgbuf);
vec.iov_base = line;
vec.iov_len = 128;
if ((ret = recvmsg(client_fd, &msghdr, 0)) < 128) {
fprintf(stdout, "recvmsg() error %d\n", errno);
exit(-1);
}
for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET) {
pass_fd_ptr = (int *)CMSG_DATA(cmsg);
break;
}
}
fprintf(stdout, "recvmsg() is done.\n");
close(*pass_fd_ptr);

msghdr.msg_name = NULL;
msghdr.msg_namelen = 0;
msghdr.msg_iov = &vec;
msghdr.msg_iovlen = 1;
msghdr.msg_controllen = 0;
msghdr.msg_control = NULL;
vec.iov_base = reply;
vec.iov_len = 128;
if ((ret = sendmsg(client_fd, &msghdr, 0 )) < 128) {
fprintf(stdout, "sendmsg error %d\n", errno);
exit(-1);
}
fprintf(stdout, "sendmsg() %d byte OK. \n", ret);

FD_ZERO(&read_set);
FD_SET(s, &read_set);
break;
}
}

}
fprintf(stdout,"GOOD BY \n");
exit (0);
}
\
 
 \ /
  Last update: 2005-03-22 13:15    [W:0.069 / U:0.236 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site