ftp.nice.ch/pub/next/unix/network/www/httpd.1.5-export.NIHS.bs.gnutar.gz#/httpd_1.5-export/src/http_ipc.c

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.