[BACK]Return to rumpclient.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / librumpclient

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/librumpclient/rumpclient.c between version 1.32 and 1.51.2.3

version 1.32, 2011/02/16 19:26:58 version 1.51.2.3, 2014/08/20 00:02:20
Line 29 
Line 29 
  * Client side routines for rump syscall proxy.   * Client side routines for rump syscall proxy.
  */   */
   
 #include <sys/cdefs.h>  #include <rump/rumpuser_port.h>
 __RCSID("$NetBSD");  
   /*
    * We use kqueue on NetBSD, poll elsewhere.  Theoretically we could
    * use kqueue on other BSD's too, but I haven't tested those.  We
    * want to use kqueue because it will give us the ability to get signal
    * notifications but defer their handling to a stage where we do not
    * hold the communication lock.  Taking a signal while holding on to
    * that lock may cause a deadlock.  Therefore, block signals throughout
    * the RPC when using poll.  On Linux, we use signalfd in the same role
    * as kqueue on NetBSD to be able to take signals while waiting for a
    * response from the server.
    */
   
   #ifdef __NetBSD__
   #define USE_KQUEUE
   #endif
   #if defined(__linux__) && !defined(__ANDROID__)
   #define USE_SIGNALFD
   #endif
   
   __RCSID("$NetBSD$");
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/event.h>  
 #include <sys/mman.h>  #include <sys/mman.h>
 #include <sys/socket.h>  #include <sys/socket.h>
   #include <sys/time.h>
   
   #ifdef USE_KQUEUE
   #include <sys/event.h>
   #endif
   
 #include <arpa/inet.h>  #include <arpa/inet.h>
 #include <netinet/in.h>  #include <netinet/in.h>
Line 45  __RCSID("$NetBSD");
Line 69  __RCSID("$NetBSD");
 #include <dlfcn.h>  #include <dlfcn.h>
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  #include <fcntl.h>
 #include <link.h>  
 #include <poll.h>  #include <poll.h>
 #include <pthread.h>  #include <pthread.h>
 #include <signal.h>  #include <signal.h>
Line 63  int (*host_socket)(int, int, int);
Line 86  int (*host_socket)(int, int, int);
 int     (*host_close)(int);  int     (*host_close)(int);
 int     (*host_connect)(int, const struct sockaddr *, socklen_t);  int     (*host_connect)(int, const struct sockaddr *, socklen_t);
 int     (*host_fcntl)(int, int, ...);  int     (*host_fcntl)(int, int, ...);
   #ifdef __ANDROID__
   int     (*host_poll)(struct pollfd *, nfds_t, long);
   #else
 int     (*host_poll)(struct pollfd *, nfds_t, int);  int     (*host_poll)(struct pollfd *, nfds_t, int);
   #endif
 ssize_t (*host_read)(int, void *, size_t);  ssize_t (*host_read)(int, void *, size_t);
 ssize_t (*host_sendto)(int, const void *, size_t, int,  #ifdef __ANDROID__
                        const struct sockaddr *, socklen_t);  int     (*host_sendmsg)(int, const struct msghdr *, unsigned int);
   #else
   ssize_t (*host_sendmsg)(int, const struct msghdr *, int);
   #endif
 int     (*host_setsockopt)(int, int, int, const void *, socklen_t);  int     (*host_setsockopt)(int, int, int, const void *, socklen_t);
 int     (*host_dup)(int);  int     (*host_dup)(int);
   
   #ifdef USE_KQUEUE
 int     (*host_kqueue)(void);  int     (*host_kqueue)(void);
 int     (*host_kevent)(int, const struct kevent *, size_t,  int     (*host_kevent)(int, const struct kevent *, size_t,
                        struct kevent *, size_t, const struct timespec *);                         struct kevent *, size_t, const struct timespec *);
   #endif
   
   #ifdef USE_SIGNALFD
   #include <sys/signalfd.h>
   
   int     (*host_signalfd)(int, const sigset_t *, int);
   #endif
   
 int     (*host_execve)(const char *, char *const[], char *const[]);  int     (*host_execve)(const char *, char *const[], char *const[]);
   
 #include "sp_common.c"  #include "sp_common.c"
   #include "rumpuser_sigtrans.c"
   
 static struct spclient clispc = {  static struct spclient clispc = {
         .spc_fd = -1,          .spc_fd = -1,
 };  };
   
 static int kq = -1;  static int holyfd = -1;
 static sigset_t fullset;  static sigset_t fullset;
   
 static int doconnect(bool);  static int doconnect(void);
 static int handshake_req(struct spclient *, int, void *, int, bool);  static int handshake_req(struct spclient *, int, void *, int, bool);
   
 /*  /*
Line 94  static int handshake_req(struct spclient
Line 133  static int handshake_req(struct spclient
  */   */
 static time_t retrytimo = 0;  static time_t retrytimo = 0;
   
   /* always defined to nothingness for now */
   #define ERRLOG(a)
   
 static int  static int
 send_with_recon(struct spclient *spc, const void *data, size_t dlen)  send_with_recon(struct spclient *spc, struct iovec *iov, size_t iovlen)
 {  {
         struct timeval starttime, curtime;          struct timeval starttime, curtime;
         time_t prevreconmsg;          time_t prevreconmsg;
Line 103  send_with_recon(struct spclient *spc, co
Line 145  send_with_recon(struct spclient *spc, co
         int rv;          int rv;
   
         for (prevreconmsg = 0, reconretries = 0;;) {          for (prevreconmsg = 0, reconretries = 0;;) {
                 rv = dosend(spc, data, dlen);                  rv = dosend(spc, iov, iovlen);
                 if (__predict_false(rv == ENOTCONN || rv == EBADF)) {                  if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
                         /* no persistent connections */                          /* no persistent connections */
                         if (retrytimo == 0) {                          if (retrytimo == 0) {
Line 111  send_with_recon(struct spclient *spc, co
Line 153  send_with_recon(struct spclient *spc, co
                                 break;                                  break;
                         }                          }
                         if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)                          if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)
                                 exit(1);                                  _exit(1);
   
                         if (!prevreconmsg) {                          if (!prevreconmsg) {
                                 prevreconmsg = time(NULL);                                  prevreconmsg = time(NULL);
Line 132  send_with_recon(struct spclient *spc, co
Line 174  send_with_recon(struct spclient *spc, co
   
                         /* check that we aren't over the limit */                          /* check that we aren't over the limit */
                         if (retrytimo > 0) {                          if (retrytimo > 0) {
                                 struct timeval tmp;                                  time_t tdiff;
   
                                 gettimeofday(&curtime, NULL);                                  gettimeofday(&curtime, NULL);
                                 timersub(&curtime, &starttime, &tmp);                                  tdiff = curtime.tv_sec - starttime.tv_sec;
                                 if (tmp.tv_sec >= retrytimo) {                                  if (starttime.tv_usec > curtime.tv_usec)
                                           tdiff--;
                                   if (tdiff >= retrytimo) {
                                         fprintf(stderr, "rump_sp: reconnect "                                          fprintf(stderr, "rump_sp: reconnect "
                                             "failed, %lld second timeout\n",                                              "failed, %lld second timeout\n",
                                             (long long)retrytimo);                                              (long long)retrytimo);
Line 152  send_with_recon(struct spclient *spc, co
Line 196  send_with_recon(struct spclient *spc, co
                         }                          }
                         reconretries++;                          reconretries++;
   
                         if ((rv = doconnect(false)) != 0)                          if ((rv = doconnect()) != 0)
                                 continue;                                  continue;
                         if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST,                          if ((rv = handshake_req(&clispc, HANDSHAKE_GUEST,
                             NULL, 0, true)) != 0)                              NULL, 0, true)) != 0)
Line 194  cliwaitresp(struct spclient *spc, struct
Line 238  cliwaitresp(struct spclient *spc, struct
   
                 /* are we free to receive? */                  /* are we free to receive? */
                 if (spc->spc_istatus == SPCSTATUS_FREE) {                  if (spc->spc_istatus == SPCSTATUS_FREE) {
                         struct kevent kev[8];                          int gotresp, dosig, rv;
                         int gotresp, dosig, rv, i;  
   
                         spc->spc_istatus = SPCSTATUS_BUSY;                          spc->spc_istatus = SPCSTATUS_BUSY;
                         pthread_mutex_unlock(&spc->spc_mtx);                          pthread_mutex_unlock(&spc->spc_mtx);
   
                         dosig = 0;                          dosig = 0;
                         for (gotresp = 0; !gotresp; ) {                          for (gotresp = 0; !gotresp; ) {
                                 switch (readframe(spc)) {  #ifdef USE_KQUEUE
                                 case 0:                                  struct kevent kev[8];
                                         rv = host_kevent(kq, NULL, 0,                                  int i;
                                             kev, __arraycount(kev), NULL);  
                                   /*
                                    * typically we don't have a frame waiting
                                    * when we come in here, so call kevent now
                                    */
                                   rv = host_kevent(holyfd, NULL, 0,
                                       kev, __arraycount(kev), NULL);
   
                                   if (__predict_false(rv == -1)) {
                                           goto activity;
                                   }
   
                                   /*
                                    * XXX: don't know how this can happen
                                    * (timeout cannot expire since there
                                    * isn't one), but it does happen.
                                    * treat it as an expectional condition
                                    * and go through tryread to determine
                                    * alive status.
                                    */
                                   if (__predict_false(rv == 0))
                                           goto activity;
   
                                   for (i = 0; i < rv; i++) {
                                           if (kev[i].filter == EVFILT_SIGNAL)
                                                   dosig++;
                                   }
                                   if (dosig)
                                           goto cleanup;
   
                                         if (__predict_false(rv == -1)) {                                  /*
                                                 goto cleanup;                                   * ok, activity.  try to read a frame to
                                         }                                   * determine what happens next.
                                    */
                                         /*   activity:
                                          * XXX: don't know how this can  #else /* !USE_KQUEUE */
                                          * happen (timeout cannot expire                                  struct pollfd pfd[2];
                                          * since there isn't one), but  
                                          * it does happen                                  pfd[0].fd = clispc.spc_fd;
                                          */                                  pfd[0].events = POLLIN;
                                         if (__predict_false(rv == 0))                                  pfd[1].fd = holyfd;
                                                 continue;                                  pfd[1].events = POLLIN;
   
                                         for (i = 0; i < rv; i++) {                                  rv = host_poll(pfd, 2, -1);
                                                 if (kev[i].filter                                  if (rv >= 1 && pfd[1].revents & POLLIN) {
                                                     == EVFILT_SIGNAL)                                          dosig = 1;
                                                         dosig++;                                          goto cleanup;
                                         }                                  }
                                         if (dosig)  #endif /* !USE_KQUEUE */
                                                 goto cleanup;  
   
                                   switch (readframe(spc)) {
                                   case 0:
                                         continue;                                          continue;
                                 case -1:                                  case -1:
                                         imalive = false;                                          imalive = false;
                                         goto cleanup;                                          goto cleanup;
                                 default:                                  default:
                                           /* case 1 */
                                         break;                                          break;
                                 }                                  }
   
Line 286  syscall_req(struct spclient *spc, sigset
Line 359  syscall_req(struct spclient *spc, sigset
 {  {
         struct rsp_hdr rhdr;          struct rsp_hdr rhdr;
         struct respwait rw;          struct respwait rw;
           struct iovec iov[2];
         int rv;          int rv;
   
         rhdr.rsp_len = sizeof(rhdr) + dlen;          rhdr.rsp_len = sizeof(rhdr) + dlen;
Line 293  syscall_req(struct spclient *spc, sigset
Line 367  syscall_req(struct spclient *spc, sigset
         rhdr.rsp_type = RUMPSP_SYSCALL;          rhdr.rsp_type = RUMPSP_SYSCALL;
         rhdr.rsp_sysnum = sysnum;          rhdr.rsp_sysnum = sysnum;
   
           IOVPUT(iov[0], rhdr);
           IOVPUT_WITHSIZE(iov[1], __UNCONST(data), dlen);
   
         do {          do {
                 putwait(spc, &rw, &rhdr);                  putwait(spc, &rw, &rhdr);
                 if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) {                  if ((rv = send_with_recon(spc, iov, __arraycount(iov))) != 0) {
                         unputwait(spc, &rw);  
                         continue;  
                 }  
                 if ((rv = send_with_recon(spc, data, dlen)) != 0) {  
                         unputwait(spc, &rw);                          unputwait(spc, &rw);
                         continue;                          continue;
                 }                  }
Line 318  handshake_req(struct spclient *spc, int 
Line 391  handshake_req(struct spclient *spc, int 
         int cancel, bool haslock)          int cancel, bool haslock)
 {  {
         struct handshake_fork rf;          struct handshake_fork rf;
           const char *myprogname = NULL; /* XXXgcc */
         struct rsp_hdr rhdr;          struct rsp_hdr rhdr;
         struct respwait rw;          struct respwait rw;
         sigset_t omask;          sigset_t omask;
         size_t bonus;          size_t bonus;
           struct iovec iov[2];
         int rv;          int rv;
   
         if (type == HANDSHAKE_FORK) {          if (type == HANDSHAKE_FORK) {
                 bonus = sizeof(rf);                  bonus = sizeof(rf);
         } else {          } else {
                 bonus = strlen(getprogname())+1;  #ifdef __NetBSD__
                   /* would procfs work on NetBSD too? */
                   myprogname = getprogname();
   #else
                   int fd = open("/proc/self/comm", O_RDONLY);
                   if (fd == -1) {
                           myprogname = "???";
                   } else {
                           static char commname[128];
   
                           memset(commname, 0, sizeof(commname));
                           if (read(fd, commname, sizeof(commname)) > 0) {
                                   char *n;
   
                                   n = strrchr(commname, '\n');
                                   if (n)
                                           *n = '\0';
                                   myprogname = commname;
                           } else {
                                   myprogname = "???";
                           }
                           close(fd);
                   }
   #endif
                   bonus = strlen(myprogname)+1;
         }          }
   
         /* performs server handshake */          /* performs server handshake */
Line 336  handshake_req(struct spclient *spc, int 
Line 435  handshake_req(struct spclient *spc, int 
         rhdr.rsp_type = RUMPSP_HANDSHAKE;          rhdr.rsp_type = RUMPSP_HANDSHAKE;
         rhdr.rsp_handshake = type;          rhdr.rsp_handshake = type;
   
           IOVPUT(iov[0], rhdr);
   
         pthread_sigmask(SIG_SETMASK, &fullset, &omask);          pthread_sigmask(SIG_SETMASK, &fullset, &omask);
         if (haslock)          if (haslock)
                 putwait_locked(spc, &rw, &rhdr);                  putwait_locked(spc, &rw, &rhdr);
         else          else
                 putwait(spc, &rw, &rhdr);                  putwait(spc, &rw, &rhdr);
         rv = dosend(spc, &rhdr, sizeof(rhdr));  
         if (type == HANDSHAKE_FORK) {          if (type == HANDSHAKE_FORK) {
                 memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */                  memcpy(rf.rf_auth, data, sizeof(rf.rf_auth)); /* uh, why? */
                 rf.rf_cancel = cancel;                  rf.rf_cancel = cancel;
                 rv = send_with_recon(spc, &rf, sizeof(rf));                  IOVPUT(iov[1], rf);
         } else {          } else {
                 rv = dosend(spc, getprogname(), strlen(getprogname())+1);                  IOVPUT_WITHSIZE(iov[1], __UNCONST(myprogname), bonus);
         }          }
           rv = send_with_recon(spc, iov, __arraycount(iov));
         if (rv || cancel) {          if (rv || cancel) {
                 if (haslock)                  if (haslock)
                         unputwait_locked(spc, &rw);                          unputwait_locked(spc, &rw);
Line 376  prefork_req(struct spclient *spc, sigset
Line 477  prefork_req(struct spclient *spc, sigset
 {  {
         struct rsp_hdr rhdr;          struct rsp_hdr rhdr;
         struct respwait rw;          struct respwait rw;
           struct iovec iov[1];
         int rv;          int rv;
   
         rhdr.rsp_len = sizeof(rhdr);          rhdr.rsp_len = sizeof(rhdr);
Line 383  prefork_req(struct spclient *spc, sigset
Line 485  prefork_req(struct spclient *spc, sigset
         rhdr.rsp_type = RUMPSP_PREFORK;          rhdr.rsp_type = RUMPSP_PREFORK;
         rhdr.rsp_error = 0;          rhdr.rsp_error = 0;
   
           IOVPUT(iov[0], rhdr);
   
         do {          do {
                 putwait(spc, &rw, &rhdr);                  putwait(spc, &rw, &rhdr);
                 rv = send_with_recon(spc, &rhdr, sizeof(rhdr));                  rv = send_with_recon(spc, iov, __arraycount(iov));
                 if (rv != 0) {                  if (rv != 0) {
                         unputwait(spc, &rw);                          unputwait(spc, &rw);
                         continue;                          continue;
Line 429  send_copyin_resp(struct spclient *spc, u
Line 533  send_copyin_resp(struct spclient *spc, u
         int wantstr)          int wantstr)
 {  {
         struct rsp_hdr rhdr;          struct rsp_hdr rhdr;
           struct iovec iov[2];
   
         if (wantstr)          if (wantstr)
                 dlen = MIN(dlen, strlen(data)+1);                  dlen = MIN(dlen, strlen(data)+1);
Line 439  send_copyin_resp(struct spclient *spc, u
Line 544  send_copyin_resp(struct spclient *spc, u
         rhdr.rsp_type = RUMPSP_COPYIN;          rhdr.rsp_type = RUMPSP_COPYIN;
         rhdr.rsp_sysnum = 0;          rhdr.rsp_sysnum = 0;
   
           IOVPUT(iov[0], rhdr);
           IOVPUT_WITHSIZE(iov[1], data, dlen);
   
         if (resp_sendlock(spc) != 0)          if (resp_sendlock(spc) != 0)
                 return;                  return;
         (void)dosend(spc, &rhdr, sizeof(rhdr));          (void)SENDIOV(spc, iov);
         (void)dosend(spc, data, dlen);  
         sendunlock(spc);          sendunlock(spc);
 }  }
   
Line 450  static void
Line 557  static void
 send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)  send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
 {  {
         struct rsp_hdr rhdr;          struct rsp_hdr rhdr;
           struct iovec iov[2];
   
         rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);          rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
         rhdr.rsp_reqno = reqno;          rhdr.rsp_reqno = reqno;
Line 457  send_anonmmap_resp(struct spclient *spc,
Line 565  send_anonmmap_resp(struct spclient *spc,
         rhdr.rsp_type = RUMPSP_ANONMMAP;          rhdr.rsp_type = RUMPSP_ANONMMAP;
         rhdr.rsp_sysnum = 0;          rhdr.rsp_sysnum = 0;
   
           IOVPUT(iov[0], rhdr);
           IOVPUT(iov[1], addr);
   
         if (resp_sendlock(spc) != 0)          if (resp_sendlock(spc) != 0)
                 return;                  return;
         (void)dosend(spc, &rhdr, sizeof(rhdr));          (void)SENDIOV(spc, iov);
         (void)dosend(spc, &addr, sizeof(addr));  
         sendunlock(spc);          sendunlock(spc);
 }  }
   
Line 503  handlereq(struct spclient *spc)
Line 613  handlereq(struct spclient *spc)
         void *mapaddr;          void *mapaddr;
         size_t maplen;          size_t maplen;
         int reqtype = spc->spc_hdr.rsp_type;          int reqtype = spc->spc_hdr.rsp_type;
           int sig;
   
         switch (reqtype) {          switch (reqtype) {
         case RUMPSP_COPYIN:          case RUMPSP_COPYIN:
Line 529  handlereq(struct spclient *spc)
Line 640  handlereq(struct spclient *spc)
                 /*LINTED*/                  /*LINTED*/
                 maplen = *(size_t *)spc->spc_buf;                  maplen = *(size_t *)spc->spc_buf;
                 mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,                  mapaddr = mmap(NULL, maplen, PROT_READ|PROT_WRITE,
                     MAP_ANON, -1, 0);                      MAP_ANON|MAP_PRIVATE, -1, 0);
                 if (mapaddr == MAP_FAILED)                  if (mapaddr == MAP_FAILED)
                         mapaddr = NULL;                          mapaddr = NULL;
                 DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));                  DPRINTF(("rump_sp handlereq: anonmmap: %p\n", mapaddr));
                 send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);                  send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr);
                 break;                  break;
         case RUMPSP_RAISE:          case RUMPSP_RAISE:
                 DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo));                  sig = rumpuser__sig_rump2host(rhdr->rsp_signo);
                 raise((int)rhdr->rsp_signo);                  DPRINTF(("rump_sp handlereq: raise sig %d\n", sig));
                   raise(sig);
                 /*                  /*
                  * We most likely have signals blocked, but the signal                   * We most likely have signals blocked, but the signal
                  * will be handled soon enough when we return.                   * will be handled soon enough when we return.
Line 560  static int
Line 672  static int
 dupgood(int myfd, int mustchange)  dupgood(int myfd, int mustchange)
 {  {
         int ofds[4];          int ofds[4];
         int i;          int sverrno;
           unsigned int i;
   
         for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) {          for (i = 0; (myfd <= 2 || mustchange) && myfd != -1; i++) {
                 assert(i < __arraycount(ofds));                  assert(i < __arraycount(ofds));
Line 572  dupgood(int myfd, int mustchange)
Line 685  dupgood(int myfd, int mustchange)
                 }                  }
         }          }
   
         for (i--; i >= 0; i--) {          sverrno = 0;
           if (myfd == -1 && i > 0)
                   sverrno = errno;
   
           while (i-- > 0) {
                 host_close(ofds[i]);                  host_close(ofds[i]);
         }          }
   
           if (sverrno)
                   errno = sverrno;
   
         return myfd;          return myfd;
 }  }
   
   #if defined(USE_KQUEUE)
   
   static int
   makeholyfd(void)
   {
           struct kevent kev[NSIG+1];
           int i, fd;
   
           /* setup kqueue, we want all signals and the fd */
           if ((fd = dupgood(host_kqueue(), 0)) == -1) {
                   ERRLOG(("rump_sp: cannot setup kqueue"));
                   return -1;
           }
   
           for (i = 0; i < NSIG; i++) {
                   EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
           }
           EV_SET(&kev[NSIG], clispc.spc_fd,
               EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
           if (host_kevent(fd, kev, NSIG+1, NULL, 0, NULL) == -1) {
                   ERRLOG(("rump_sp: kevent() failed"));
                   host_close(fd);
                   return -1;
           }
   
           return fd;
   }
   
   #elif defined(USE_SIGNALFD) /* !USE_KQUEUE */
   
 static int  static int
 doconnect(bool noisy)  makeholyfd(void)
   {
   
           return host_signalfd(-1, &fullset, 0);
   }
   
   #else /* !USE_KQUEUE && !USE_SIGNALFD */
   
   static int
   makeholyfd(void)
   {
   
           return -1;
   }
   
   #endif
   
   static int
   doconnect(void)
 {  {
         struct respwait rw;          struct respwait rw;
         struct rsp_hdr rhdr;          struct rsp_hdr rhdr;
         struct kevent kev[NSIG+1];  
         char banner[MAXBANNER];          char banner[MAXBANNER];
         struct pollfd pfd;          int s, error, flags;
         int s, error, flags, i;  
         ssize_t n;          ssize_t n;
   
         if (kq != -1)          if (holyfd != -1)
                 host_close(kq);                  host_close(holyfd);
         kq = -1;          holyfd = -1;
         s = -1;          s = -1;
   
         if (clispc.spc_fd != -1)          if (clispc.spc_fd != -1)
Line 630  doconnect(bool noisy)
Line 796  doconnect(bool noisy)
         if (s == -1)          if (s == -1)
                 return -1;                  return -1;
   
         pfd.fd = s;          while (host_connect(s, serv_sa, parsetab[ptab_idx].slen) == -1) {
         pfd.events = POLLIN;  
         while (host_connect(s, serv_sa, (socklen_t)serv_sa->sa_len) == -1) {  
                 if (errno == EINTR)                  if (errno == EINTR)
                         continue;                          continue;
                 error = errno;                  ERRLOG(("rump_sp: client connect failed: %s\n",
                 if (noisy)                      strerror(errno)));
                         fprintf(stderr, "rump_sp: client connect failed: %s\n",  
                             strerror(errno));  
                 errno = error;  
                 return -1;                  return -1;
         }          }
   
         if ((error = parsetab[ptab_idx].connhook(s)) != 0) {          if ((error = parsetab[ptab_idx].connhook(s)) != 0) {
                 error = errno;                  ERRLOG(("rump_sp: connect hook failed\n"));
                 if (noisy)  
                         fprintf(stderr, "rump_sp: connect hook failed\n");  
                 errno = error;  
                 return -1;                  return -1;
         }          }
   
         if ((n = host_read(s, banner, sizeof(banner)-1)) < 0) {          if ((n = host_read(s, banner, sizeof(banner)-1)) <= 0) {
                 error = errno;                  ERRLOG(("rump_sp: failed to read banner\n"));
                 if (noisy)  
                         fprintf(stderr, "rump_sp: failed to read banner\n");  
                 errno = error;  
                 return -1;                  return -1;
         }          }
   
         if (banner[n-1] != '\n') {          if (banner[n-1] != '\n') {
                 if (noisy)                  ERRLOG(("rump_sp: invalid banner\n"));
                         fprintf(stderr, "rump_sp: invalid banner\n");  
                 errno = EINVAL;  
                 return -1;                  return -1;
         }          }
         banner[n] = '\0';          banner[n] = '\0';
         /* parse the banner some day */          /* XXX parse the banner some day */
   
         flags = host_fcntl(s, F_GETFL, 0);          flags = host_fcntl(s, F_GETFL, 0);
         if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {          if (host_fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) {
                 if (noisy)                  ERRLOG(("rump_sp: socket fd NONBLOCK: %s\n", strerror(errno)));
                         fprintf(stderr, "rump_sp: socket fd NONBLOCK: %s\n",  
                             strerror(errno));  
                 errno = EINVAL;  
                 return -1;                  return -1;
         }          }
         clispc.spc_fd = s;          clispc.spc_fd = s;
         clispc.spc_state = SPCSTATE_RUNNING;          clispc.spc_state = SPCSTATE_RUNNING;
         clispc.spc_reconnecting = 0;          clispc.spc_reconnecting = 0;
           holyfd = makeholyfd();
         /* setup kqueue, we want all signals and the fd */  
         if ((kq = dupgood(host_kqueue(), 0)) == -1) {  
                 error = errno;  
                 if (noisy)  
                         fprintf(stderr, "rump_sp: cannot setup kqueue");  
                 errno = error;  
                 return -1;  
         }  
   
         for (i = 0; i < NSIG; i++) {  
                 EV_SET(&kev[i], i+1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);  
         }  
         EV_SET(&kev[NSIG], clispc.spc_fd,  
             EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);  
         if (host_kevent(kq, kev, NSIG+1, NULL, 0, NULL) == -1) {  
                 error = errno;  
                 if (noisy)  
                         fprintf(stderr, "rump_sp: kevent() failed");  
                 errno = error;  
                 return -1;  
         }  
   
         return 0;          return 0;
 }  }
Line 716  doinit(void)
Line 845  doinit(void)
         return 0;          return 0;
 }  }
   
 void *(*rumpclient_dlsym)(void *, const char *);  #ifdef RTLD_NEXT
 static int init_done = 0;  void *rumpclient__dlsym(void *, const char *);
   void *
   rumpclient__dlsym(void *handle, const char *symbol)
   {
   
           return dlsym(handle, symbol);
   }
   void *rumphijack_dlsym(void *, const char *)
       __attribute__((__weak__, alias("rumpclient__dlsym")));
   #endif
   
   static pid_t init_done = 0;
   
 int  int
 rumpclient_init()  rumpclient_init(void)
 {  {
         char *p;          char *p;
         int error;          int error;
         int rv = -1;          int rv = -1;
         int hstype;          int hstype;
           pid_t mypid;
   
         if (init_done)          /*
            * Make sure we're not riding the context of a previous
            * host fork.  Note: it's *possible* that after n>1 forks
            * we have the same pid as one of our exited parents, but
            * I'm pretty sure there are 0 practical implications, since
            * it means generations would have to skip rumpclient init.
            */
           if (init_done == (mypid = getpid()))
                 return 0;                  return 0;
         init_done = 1;  
   
         sigfillset(&fullset);  #ifdef USE_KQUEUE
           /* kq does not traverse fork() */
           holyfd = -1;
   #endif
           init_done = mypid;
   
         /* dlsym overrided by rumphijack? */          sigfillset(&fullset);
         if (!rumpclient_dlsym)  
                 rumpclient_dlsym = dlsym;  
   
         /*          /*
          * sag mir, wo die symbol sind.  zogen fort, der krieg beginnt.           * sag mir, wo die symbols sind.  zogen fort, der krieg beginnt.
          * wann wird man je verstehen?  wann wird man je verstehen?           * wann wird man je verstehen?  wann wird man je verstehen?
          */           */
   #ifdef RTLD_NEXT
 #define FINDSYM2(_name_,_syscall_)                                      \  #define FINDSYM2(_name_,_syscall_)                                      \
         if ((host_##_name_ = rumpclient_dlsym(RTLD_NEXT,                \          if ((host_##_name_ = rumphijack_dlsym(RTLD_NEXT,                \
             #_syscall_)) == NULL)                                       \              #_syscall_)) == NULL) {                                     \
                 /* host_##_name_ = _syscall_ */;                  if (rumphijack_dlsym == rumpclient__dlsym)              \
                           host_##_name_ = _name_; /* static fallback */   \
                   if (host_##_name_ == NULL) {                            \
                           fprintf(stderr,"cannot find %s: %s", #_syscall_,\
                               dlerror());                                 \
                           exit(1);                                        \
                   }                                                       \
           }
   #else
   #define FINDSYM2(_name_,_syscall)                                       \
           host_##_name_ = _name_;
   #endif
 #define FINDSYM(_name_) FINDSYM2(_name_,_name_)  #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
         FINDSYM2(socket,__socket30);  #ifdef __NetBSD__
         FINDSYM(close);          FINDSYM2(socket,__socket30)
         FINDSYM(connect);  #else
         FINDSYM(fcntl);          FINDSYM(socket)
         FINDSYM(poll);  #endif
         FINDSYM(read);  
         FINDSYM(sendto);          FINDSYM(close)
         FINDSYM(setsockopt);          FINDSYM(connect)
         FINDSYM(dup);          FINDSYM(fcntl)
         FINDSYM(kqueue);          FINDSYM(poll)
         FINDSYM(execve);          FINDSYM(read)
           FINDSYM(sendmsg)
           FINDSYM(setsockopt)
           FINDSYM(dup)
           FINDSYM(execve)
   
   #ifdef USE_KQUEUE
           FINDSYM(kqueue)
 #if !__NetBSD_Prereq__(5,99,7)  #if !__NetBSD_Prereq__(5,99,7)
         FINDSYM(kevent);          FINDSYM(kevent)
 #else  #else
         FINDSYM2(kevent,_sys___kevent50);          FINDSYM2(kevent,_sys___kevent50)
 #endif  #endif
   #endif /* USE_KQUEUE */
   
   #ifdef USE_SIGNALFD
           FINDSYM(signalfd)
   #endif
   
 #undef  FINDSYM  #undef  FINDSYM
 #undef  FINDSY2  #undef  FINDSY2
   
         if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) {          if ((p = getenv("RUMP__PARSEDSERVER")) == NULL) {
                 if ((p = getenv("RUMP_SERVER")) == NULL) {                  if ((p = getenv("RUMP_SERVER")) == NULL) {
                           fprintf(stderr, "error: RUMP_SERVER not set\n");
                         errno = ENOENT;                          errno = ENOENT;
                         goto out;                          goto out;
                 }                  }
Line 781  rumpclient_init()
Line 956  rumpclient_init()
                 goto out;                  goto out;
   
         if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {          if ((p = getenv("RUMPCLIENT__EXECFD")) != NULL) {
                 sscanf(p, "%d,%d", &clispc.spc_fd, &kq);                  sscanf(p, "%d,%d", &clispc.spc_fd, &holyfd);
                 unsetenv("RUMPCLIENT__EXECFD");                  unsetenv("RUMPCLIENT__EXECFD");
                 hstype = HANDSHAKE_EXEC;                  hstype = HANDSHAKE_EXEC;
         } else {          } else {
                 if (doconnect(true) == -1)                  if (doconnect() == -1)
                         goto out;                          goto out;
                 hstype = HANDSHAKE_GUEST;                  hstype = HANDSHAKE_GUEST;
         }          }
Line 810  rumpclient_init()
Line 985  rumpclient_init()
 struct rumpclient_fork {  struct rumpclient_fork {
         uint32_t fork_auth[AUTHLEN];          uint32_t fork_auth[AUTHLEN];
         struct spclient fork_spc;          struct spclient fork_spc;
         int fork_kq;          int fork_holyfd;
 };  };
   
 struct rumpclient_fork *  struct rumpclient_fork *
Line 837  rumpclient_prefork(void)
Line 1012  rumpclient_prefork(void)
         free(resp);          free(resp);
   
         rpf->fork_spc = clispc;          rpf->fork_spc = clispc;
         rpf->fork_kq = kq;          rpf->fork_holyfd = holyfd;
   
  out:   out:
         pthread_sigmask(SIG_SETMASK, &omask, NULL);          pthread_sigmask(SIG_SETMASK, &omask, NULL);
Line 854  rumpclient_fork_init(struct rumpclient_f
Line 1029  rumpclient_fork_init(struct rumpclient_f
         memset(&clispc, 0, sizeof(clispc));          memset(&clispc, 0, sizeof(clispc));
         clispc.spc_fd = osock;          clispc.spc_fd = osock;
   
         kq = -1; /* kqueue descriptor is not copied over fork() */  #ifdef USE_KQUEUE
           holyfd = -1; /* kqueue descriptor is not copied over fork() */
   #else
           if (holyfd != -1) {
                   host_close(holyfd);
                   holyfd = -1;
           }
   #endif
   
         if (doinit() == -1)          if (doinit() == -1)
                 return -1;                  return -1;
         if (doconnect(false) == -1)          if (doconnect() == -1)
                 return -1;                  return -1;
   
         error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth,          error = handshake_req(&clispc, HANDSHAKE_FORK, rpf->fork_auth,
Line 873  rumpclient_fork_init(struct rumpclient_f
Line 1055  rumpclient_fork_init(struct rumpclient_f
         return 0;          return 0;
 }  }
   
   /*ARGSUSED*/
 void  void
 rumpclient_fork_cancel(struct rumpclient_fork *rpf)  rumpclient_fork_cancel(struct rumpclient_fork *rpf)
 {  {
Line 885  rumpclient_fork_vparent(struct rumpclien
Line 1068  rumpclient_fork_vparent(struct rumpclien
 {  {
   
         clispc = rpf->fork_spc;          clispc = rpf->fork_spc;
         kq = rpf->fork_kq;          holyfd = rpf->fork_holyfd;
 }  }
   
 void  void
Line 907  rumpclient__closenotify(int *fdp, enum r
Line 1090  rumpclient__closenotify(int *fdp, enum r
   
         switch (variant) {          switch (variant) {
         case RUMPCLIENT_CLOSE_FCLOSEM:          case RUMPCLIENT_CLOSE_FCLOSEM:
                 untilfd = MAX(clispc.spc_fd, kq);                  untilfd = MAX(clispc.spc_fd, holyfd);
                 for (; fd <= untilfd; fd++) {                  for (; fd <= untilfd; fd++) {
                         if (fd == clispc.spc_fd || fd == kq)                          if (fd == clispc.spc_fd || fd == holyfd)
                                 continue;                                  continue;
                         rv = host_close(fd);                          rv = host_close(fd);
                         if (rv == -1)                          if (rv == -1)
Line 921  rumpclient__closenotify(int *fdp, enum r
Line 1104  rumpclient__closenotify(int *fdp, enum r
         case RUMPCLIENT_CLOSE_CLOSE:          case RUMPCLIENT_CLOSE_CLOSE:
         case RUMPCLIENT_CLOSE_DUP2:          case RUMPCLIENT_CLOSE_DUP2:
                 if (fd == clispc.spc_fd) {                  if (fd == clispc.spc_fd) {
                         struct kevent kev[2];  
   
                         newfd = dupgood(clispc.spc_fd, 1);                          newfd = dupgood(clispc.spc_fd, 1);
                         if (newfd == -1)                          if (newfd == -1)
                                 return -1;                                  return -1;
   
   #ifdef USE_KQUEUE
                           {
                           struct kevent kev[2];
   
                         /*                          /*
                          * now, we have a new socket number, so change                           * now, we have a new socket number, so change
                          * the file descriptor that kqueue is                           * the file descriptor that kqueue is
Line 935  rumpclient__closenotify(int *fdp, enum r
Line 1121  rumpclient__closenotify(int *fdp, enum r
                             EVFILT_READ, EV_DELETE, 0, 0, 0);                              EVFILT_READ, EV_DELETE, 0, 0, 0);
                         EV_SET(&kev[1], newfd,                          EV_SET(&kev[1], newfd,
                             EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);                              EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
                         if (host_kevent(kq, kev, 2, NULL, 0, NULL) == -1) {                          if (host_kevent(holyfd, kev, 2, NULL, 0, NULL) == -1) {
                                 int sverrno = errno;                                  int sverrno = errno;
                                 host_close(newfd);                                  host_close(newfd);
                                 errno = sverrno;                                  errno = sverrno;
                                 return -1;                                  return -1;
                         }                          }}
   #endif /* !USE_KQUEUE */
                         clispc.spc_fd = newfd;                          clispc.spc_fd = newfd;
                 }                  }
                 if (fd == kq) {                  if (holyfd != -1 && fd == holyfd) {
                         newfd = dupgood(kq, 1);                          newfd = dupgood(holyfd, 1);
                         if (newfd == -1)                          if (newfd == -1)
                                 return -1;                                  return -1;
                         kq = newfd;                          holyfd = newfd;
                 }                  }
                 break;                  break;
         }          }
Line 956  rumpclient__closenotify(int *fdp, enum r
Line 1143  rumpclient__closenotify(int *fdp, enum r
 }  }
   
 pid_t  pid_t
 rumpclient_fork()  rumpclient_fork(void)
 {  {
   
         return rumpclient__dofork(fork);          return rumpclient__dofork(fork);
Line 978  rumpclient_exec(const char *path, char *
Line 1165  rumpclient_exec(const char *path, char *
         int rv, sverrno;          int rv, sverrno;
   
         snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d",          snprintf(buf, sizeof(buf), "RUMPCLIENT__EXECFD=%d,%d",
             clispc.spc_fd, kq);              clispc.spc_fd, holyfd);
         envstr = malloc(strlen(buf)+1);          envstr = malloc(strlen(buf)+1);
         if (envstr == NULL) {          if (envstr == NULL) {
                 return ENOMEM;                  return ENOMEM;
Line 1002  rumpclient_exec(const char *path, char *
Line 1189  rumpclient_exec(const char *path, char *
         for (nelem = 0; envp && envp[nelem]; nelem++)          for (nelem = 0; envp && envp[nelem]; nelem++)
                 continue;                  continue;
   
         newenv = malloc(sizeof(*newenv) * nelem+3);          newenv = malloc(sizeof(*newenv) * (nelem+3));
         if (newenv == NULL) {          if (newenv == NULL) {
                 free(envstr2);                  free(envstr2);
                 free(envstr);                  free(envstr);
Line 1025  rumpclient_exec(const char *path, char *
Line 1212  rumpclient_exec(const char *path, char *
         return rv;          return rv;
 }  }
   
   /*
    * daemon() is handwritten for the benefit of platforms which
    * do not support daemon().
    */
 int  int
 rumpclient_daemon(int nochdir, int noclose)  rumpclient_daemon(int nochdir, int noclose)
 {  {
Line 1034  rumpclient_daemon(int nochdir, int noclo
Line 1225  rumpclient_daemon(int nochdir, int noclo
         if ((rf = rumpclient_prefork()) == NULL)          if ((rf = rumpclient_prefork()) == NULL)
                 return -1;                  return -1;
   
         if (daemon(nochdir, noclose) == -1) {          switch (fork()) {
                 sverrno = errno;          case 0:
                 rumpclient_fork_cancel(rf);                  break;
                 errno = sverrno;          case -1:
                 return -1;                  goto daemonerr;
           default:
                   _exit(0);
           }
   
           if (setsid() == -1)
                   goto daemonerr;
           if (!nochdir && chdir("/") == -1)
                   goto daemonerr;
           if (!noclose) {
                   int fd = open("/dev/null", O_RDWR);
                   dup2(fd, 0);
                   dup2(fd, 1);
                   dup2(fd, 2);
                   if (fd > 2)
                           close(fd);
         }          }
   
           /* note: fork is either completed or cancelled by the call */
         if (rumpclient_fork_init(rf) == -1)          if (rumpclient_fork_init(rf) == -1)
                 return -1;                  return -1;
   
         return 0;          return 0;
   
    daemonerr:
           sverrno = errno;
           rumpclient_fork_cancel(rf);
           errno = sverrno;
           return -1;
 }  }

Legend:
Removed from v.1.32  
changed lines
  Added in v.1.51.2.3

CVSweb <webmaster@jp.NetBSD.org>