Messages in this thread Patch in this message | | | Date | Mon, 7 Jan 2002 17:39:44 +0900 | From | Yasuma Takeda <> | 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); }
| |