#include "sm/generic.h" SM_RCSID("@(#)$Id: recvfd.c,v 1.5 2005/06/16 20:39:02 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/io.h" #include "sm/varargs.h" #include "sm/limits.h" #include "sm/types.h" /* Receive a file descriptor from another process (a server). * In addition, any data received from the server is passed * to (*userfunc)(STDERR_FILENO, buf, nbytes). We have a * 2-byte protocol for receiving the fd from send_fd(). */ #define MAXLINE 16 #if LIB44_FD #include #include /* struct msghdr */ #include /* struct iovec */ #include static struct cmsghdr *cmptr = NULL; /* malloc'ed first time */ #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) /* size of control buffer to send/recv one file descriptor */ sm_ret_T recv_fd(int servfd) { int newfd, nread, status; char *ptr, buf[MAXLINE]; struct iovec iov[1]; struct msghdr msg; status = -1; for ( ; ; ) { iov[0].iov_base = buf; iov[0].iov_len = sizeof(buf); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL) return sm_error_temp(SM_EM_IO, ENOMEM); msg.msg_control = (caddr_t) cmptr; msg.msg_controllen = CONTROLLEN; if ((nread = recvmsg(servfd, &msg, 0)) < 0) return sm_error_perm(SM_EM_IO, errno); else if (nread == 0) { return SM_IO_EOF; } /* See if this is the final data with null & status. Null must be next to last byte of buffer, status byte is last byte. Zero status means there must be a file descriptor to receive. */ for (ptr = buf; ptr < &buf[nread]; ) { if (*ptr++ == 0) { if (ptr != &buf[nread-1]) return sm_error_perm(SM_EM_IO, EINVAL); status = *ptr & 255; if (status == 0) { if (msg.msg_controllen != CONTROLLEN) return sm_error_perm(SM_EM_IO, EINVAL); /* err_dump("status = 0 but no fd"); */ newfd = *(int *)CMSG_DATA(cmptr); /* new descriptor */ } else newfd = -status; nread -= 2; } } #if 0 if (nread > 0) if ((*userfunc)(STDERR_FILENO, buf, nread) != nread) return(-1); #endif /* 0 */ if (status >= 0) /* final data has arrived */ return(newfd); /* descriptor, or -status */ } } #endif /* LIB44_FD */ #if LIBSUN_FD #include #include /* struct msghdr */ #include /* struct iovec */ #include /* Receive a file descriptor from another process (a server). * In addition, any data received from the server is passed * to (*userfunc)(STDERR_FILENO, buf, nbytes). We have a * 2-byte protocol for receiving the fd from send_fd(). */ sm_ret_T recv_fd(int servfd) { int newfd, nread, status; char *ptr, buf[MAXLINE]; struct iovec iov[1]; struct msghdr msg; status = -1; for ( ; ; ) { iov[0].iov_base = buf; iov[0].iov_len = sizeof(buf); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_accrights = (caddr_t) &newfd;/* addr of descriptor */ msg.msg_accrightslen = sizeof(int); /* receive 1 descriptor */ if ( (nread = recvmsg(servfd, &msg, 0)) < 0) return sm_error_perm(SM_EM_IO, errno); else if (nread == 0) { return SM_IO_EOF; } /* See if this is the final data with null & status. Null must be next to last byte of buffer, status byte is last byte. Zero status means there must be a file descriptor to receive. */ for (ptr = buf; ptr < &buf[nread]; ) { if (*ptr++ == 0) { if (ptr != &buf[nread-1]) return sm_error_perm(SM_EM_IO, EINVAL); status = *ptr & 255; if (status == 0) { if (msg.msg_accrightslen != sizeof(int)) return sm_error_perm(SM_EM_IO, EINVAL); /* newfd = the new descriptor */ } else newfd = -status; nread -= 2; } } /* if (nread > 0) if ((*userfunc)(STDERR_FILENO, buf, nread) != nread) return(-1); */ if (status >= 0) /* final data has arrived */ return(newfd); /* descriptor, or -status */ } } #endif /* LIBSUN_FD */ #if LIBSYSV_FD #include #include sm_ret_T recv_fd(int servfd, ssize_t (*userfunc)(int, const void *, size_t)) { int newfd, nread, flag, status; char *ptr, buf[MAXLINE]; struct strbuf dat; struct strrecvfd recvfd; status = -1; for ( ; ; ) { dat.buf = buf; dat.maxlen = MAXLINE; flag = 0; if (getmsg(servfd, NULL, &dat, &flag) < 0) return sm_error_temp(SM_EM_IO, ENOMEM); nread = dat.len; if (nread == 0) { return SM_IO_EOF; } /* See if this is the final data with null & status. Null must be next to last byte of buffer, status byte is last byte. Zero status means there must be a file descriptor to receive. */ for (ptr = buf; ptr < &buf[nread]; ) { if (*ptr++ == 0) { if (ptr != &buf[nread-1]) return sm_error_perm(SM_EM_IO, errno); status = *ptr & 255; if (status == 0) { if (ioctl(servfd, I_RECVFD, &recvfd) < 0) return SM_IO_EOF; newfd = recvfd.fd; /* new descriptor */ } else newfd = -status; nread -= 2; } } /* if (nread > 0) if ((*userfunc)(STDERR_FILENO, buf, nread) != nread) return(-1); */ if (status >= 0) /* final data has arrived */ return(newfd); /* descriptor, or -status */ } } #endif /* LIBSYSV_FD */