This is http_ipc.c in view mode; [Download] [Up]
/************************************************************************ * NCSA HTTPd Server * Software Development Group * National Center for Supercomputing Applications * University of Illinois at Urbana-Champaign * 605 E. Springfield, Champaign, IL 61820 * httpd@ncsa.uiuc.edu * * Copyright (C) 1995, Board of Trustees of the University of Illinois * ************************************************************************ * * http_ipc.c,v 1.20 1995/09/21 22:50:55 blong Exp * ************************************************************************ * * http_ipc.c * Handles the file descriptor passing. Should work under BSD and * SYSV. * * Based (with modifications) on code by W. Richard Stevens, * in _Advanced Programming in the UNIX Environment_ * * 03-06-95 blong * Added #ifdefs to handle not using this at all for machines like * Linux. * * 04-17-95 blong * Added NEED_SPIPE with s_pipe from Stevens _Unix Network Programming_ * for SVR3.2 systems without socketpair. */ #include "config.h" #include "portability.h" #ifndef NO_PASS #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #ifndef NO_STDLIB_H # include <stdlib.h> #endif /* NO_STDLIB_H */ #include "constants.h" #include "host_config.h" #include "http_log.h" #include "http_ipc.h" #ifdef FD_BSD # include <sys/uio.h> # include <errno.h> # include <stddef.h> #elif defined(FD_SYSV) # ifdef NEED_SPIPE # include <sys/fcntl.h> # define SPX_DEVICE "/dev/spx" # include <sys/stream.h> # endif /* NEED_SPIPE */ # include <stropts.h> #elif defined(FD_LINUX) # include <fcntl.h> #endif /* FD_BSD */ #ifdef FD_SYSV int pass_fd(int clifd, int fd) { char buf[2]; buf[0] = 0; if (fd < 0) { buf[1] = -fd; if (buf[1] == 0) buf[1] = 1; } else { buf[1] = 0; } if (write(clifd, buf, 2) != 2) { fprintf(stderr,"pass_fd: write failed\n"); perror("pass_fd"); return -1; } if (fd >= 0) if (ioctl(clifd, I_SENDFD, fd) < 0) { fprintf(stderr,"pass_fd: ioctl failed\n"); perror("ioctl"); return -1; } return 0; } int recv_fd(int servfd) { int newfd, nread, flag, status; char *ptr, buf[IOBUFSIZE]; struct strbuf dat; struct strrecvfd recvfd; status = -1; for ( ; ; ) { dat.buf = buf; dat.maxlen = IOBUFSIZE; flag = 0; if (getmsg(servfd, NULL, &dat, &flag) < 0) { fprintf(stderr,"httpd:getmsg error recv_fd\n"); perror("getmsg"); exit(1); } nread = dat.len; if (nread == 0) { fprintf(stderr,"httpd: connection closed by server\n"); exit(1); } for (ptr = buf; ptr < &buf[nread]; ) { if (*ptr++ == 0) { if (ptr != &buf[nread-1]) { fprintf(stderr,"httpd: message format error recv_fd\n"); perror("recv_fd"); exit(1); } status = *ptr & 255; if (status == 0) { if (ioctl(servfd, I_RECVFD, &recvfd) < 0) return -1; newfd = recvfd.fd; } else newfd = -status; nread -= 2; } } if (status >= 0) return (newfd); } } #ifdef NEED_SPIPE int s_pipe(int fd[2]) { struct strfdinsert ins; queue_t *pointer; /* * First open the stream clone device "/dev/spx" twice, * obtaining the two file descriptors. */ if ((fd[0] = open(SPX_DEVICE, O_RDWR)) < 0) return -1; if ((fd[1] = open(SPX_DEVICE, O_RDWR)) < 0) { close(fd[0]); return -1; } /* * Now link these two streams together with an I_FDINSERT ioctl */ ins.ctlbuf.buf = (char *) &pointer; ins.ctlbuf.maxlen = sizeof(queue_t *); ins.ctlbuf.len = sizeof(queue_t *); ins.databuf.buf = (char *) 0; ins.databuf.len = -1; ins.databuf.maxlen = 0; ins.fildes = fd[1]; ins.flags = 0; ins.offset = 0; if (ioctl(fd[0], I_FDINSERT, (char *) &ins) < 0) { close(fd[0]); close(fd[1]); return -1; } return 0; } #endif /* NEED_SPIPE */ #endif /* FD_SYSV */ #ifdef FD_BSD #ifdef FD_BSDRENO static struct cmsghdr *cmptr = NULL; #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int)) #endif /* FD_BSDRENO */ int pass_fd(int clifd, int fd) { struct iovec iov[1]; struct msghdr msg; char buf[2]; iov[0].iov_base = buf; iov[0].iov_len = 2; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; if (fd < 0) { #ifdef FD_BSDRENO msg.msg_control = NULL; msg.msg_controllen = 0; #else msg.msg_accrights = NULL; msg.msg_accrightslen = 0; #endif /* FD_BSDRENO */ buf[1] = -fd; if (buf[1] == 0) buf[1] = 1; } else { #ifdef FD_BSDRENO if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL) return -1; cmptr->cmsg_level = SOL_SOCKET; cmptr->cmsg_type = SCM_RIGHTS; cmptr->cmsg_len = CONTROLLEN; msg.msg_control = (caddr_t) cmptr; msg.msg_controllen = CONTROLLEN; *(int *)CMSG_DATA(cmptr) = fd; #else msg.msg_accrights = (caddr_t) &fd; msg.msg_accrightslen = sizeof(int); #endif /* FD_BSDRENO */ buf[1] = 0; } buf[0] = 0; /* if (write(clifd, buf, 2) != 2) return -1; */ if (sendmsg(clifd, &msg, 0) != 2) return -1; return 0; } int recv_fd(int servfd) { int nread, status; int newfd = -1; char *ptr, buf[IOBUFSIZE]; 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; #ifdef FD_BSDRENO if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL) return -1; msg.msg_control = (caddr_t) cmptr; msg.msg_controllen = CONTROLLEN; #else msg.msg_accrights = (caddr_t) &newfd; msg.msg_accrightslen = sizeof(int); #endif /* FD_BSDRENO */ if ((nread = recvmsg(servfd, &msg, 0)) < 0) { fprintf(stderr,"httpd: recvmsg error"); perror("recvmsg"); exit(1); } else if (nread == 0) { fprintf(stderr, "httpd: connection closed by server"); exit(1); } for (ptr = buf; ptr < &buf[nread]; ) { if (*ptr++ == 0) { if (ptr != &buf[nread-1]) { fprintf(stderr, "httpd:message format error"); exit(1); } status = *ptr & 255; if (status == 0) { #ifdef FD_BSDRENO if (msg.msg_controllen != CONTROLLEN) #else if (msg.msg_accrightslen != sizeof(int)) #endif /* FD_BSDRENO */ { fprintf(stderr, "httpd: status = 0 but no fd"); exit(1); } #ifdef FD_BSDRENO newfd = *(int *)CMSG_DATA(cmptr); #endif /* FD_BSDRENO */ } else newfd = -status; nread -= 2; } } if (nread > 0) return -1; if (status >= 0) return newfd; } } #endif /* FD_BSD */ #ifdef FD_LINUX int pass_fd(int clifd, int fd) { char buf[128]; sprintf(buf, "/proc/%d/fd/%d", (int)getpid(), fd); if (write(clifd, buf, sizeof(buf)) < 0) { log_error("pass_fd: write failed",gConfiguration->error_log); return(-1); } read(clifd, buf, 2); /* Wait for OK */ return(0); } int recv_fd(int servfd) { char buf[128]; int fd; if (read(servfd, buf, sizeof(buf)) != sizeof(buf)) { log_error("recv_fd: read failed",gConfiguration->error_log); return(-1); } fd = open(buf, O_RDWR); (void) write(servfd, "OK", 2); /* Tell 'em we've aquired the fd */ if (fd < 0) { log_error(strerror(errno),gConfiguration->error_log); log_error(buf,gConfiguration->error_log); log_error("recv_fd: open failed",gConfiguration->error_log); } return(fd); } #endif /* FD_LINUX */ #endif /* NO_PASS */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.