[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.29 and 1.42

version 1.29, 2011/02/15 10:37:07 version 1.42, 2011/03/08 18:28:01
Line 30 
Line 30 
  */   */
   
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __RCSID("$NetBSD");  __RCSID("$NetBSD$");
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/event.h>  #include <sys/event.h>
Line 43  __RCSID("$NetBSD");
Line 43  __RCSID("$NetBSD");
   
 #include <assert.h>  #include <assert.h>
 #include <dlfcn.h>  #include <dlfcn.h>
   #include <err.h>
 #include <errno.h>  #include <errno.h>
 #include <fcntl.h>  #include <fcntl.h>
 #include <link.h>  #include <link.h>
Line 65  int (*host_connect)(int, const struct so
Line 66  int (*host_connect)(int, const struct so
 int     (*host_fcntl)(int, int, ...);  int     (*host_fcntl)(int, int, ...);
 int     (*host_poll)(struct pollfd *, nfds_t, int);  int     (*host_poll)(struct pollfd *, nfds_t, int);
 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,  ssize_t (*host_sendmsg)(int, const struct msghdr *, int);
                        const struct sockaddr *, socklen_t);  
 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);
   
Line 74  int (*host_kqueue)(void);
Line 74  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 *);
   
   int     (*host_execve)(const char *, char *const[], char *const[]);
   
 #include "sp_common.c"  #include "sp_common.c"
   
 static struct spclient clispc = {  static struct spclient clispc = {
Line 86  static sigset_t fullset;
Line 88  static sigset_t fullset;
 static int doconnect(bool);  static int doconnect(bool);
 static int handshake_req(struct spclient *, int, void *, int, bool);  static int handshake_req(struct spclient *, int, void *, int, bool);
   
 time_t retrytimo = RUMPCLIENT_RETRYCONN_ONCE;  /*
    * Default: don't retry.  Most clients can't handle it
    * (consider e.g. fds suddenly going missing).
    */
   static time_t retrytimo = 0;
   
 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 97  send_with_recon(struct spclient *spc, co
Line 103  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) {
                                   rv = ENOTCONN;
                                 break;                                  break;
                           }
                         if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)                          if (retrytimo == RUMPCLIENT_RETRYCONN_DIE)
                                 exit(1);                                  exit(1);
   
Line 194  cliwaitresp(struct spclient *spc, struct
Line 202  cliwaitresp(struct spclient *spc, struct
   
                         dosig = 0;                          dosig = 0;
                         for (gotresp = 0; !gotresp; ) {                          for (gotresp = 0; !gotresp; ) {
                                 switch (readframe(spc)) {                                  /*
                                 case 0:                                   * typically we don't have a frame waiting
                                         rv = host_kevent(kq, NULL, 0,                                   * when we come in here, so call kevent now
                                             kev, __arraycount(kev), NULL);                                   */
                                   rv = host_kevent(kq, NULL, 0,
                                       kev, __arraycount(kev), NULL);
   
                                         if (__predict_false(rv == -1)) {                                  if (__predict_false(rv == -1)) {
                                                 goto cleanup;                                          goto activity;
                                         }                                  }
   
                                         /*  
                                          * XXX: don't know how this can  
                                          * happen (timeout cannot expire  
                                          * since there isn't one), but  
                                          * it does happen  
                                          */  
                                         if (__predict_false(rv == 0))  
                                                 continue;  
   
                                         for (i = 0; i < rv; i++) {  
                                                 if (kev[i].filter  
                                                     == EVFILT_SIGNAL)  
                                                         dosig++;  
                                         }  
                                         if (dosig)  
                                                 goto cleanup;  
   
                                   /*
                                    * 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;
   
                                   /*
                                    * ok, activity.  try to read a frame to
                                    * determine what happens next.
                                    */
    activity:
                                   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 278  syscall_req(struct spclient *spc, sigset
Line 297  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 285  syscall_req(struct spclient *spc, sigset
Line 305  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 310  handshake_req(struct spclient *spc, int 
Line 329  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;
         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;                  myprogname = getprogname();
                   bonus = strlen(myprogname)+1;
         }          }
   
         /* performs server handshake */          /* performs server handshake */
Line 328  handshake_req(struct spclient *spc, int 
Line 350  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(getprogname()), 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 368  prefork_req(struct spclient *spc, sigset
Line 392  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 375  prefork_req(struct spclient *spc, sigset
Line 400  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 421  send_copyin_resp(struct spclient *spc, u
Line 448  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 431  send_copyin_resp(struct spclient *spc, u
Line 459  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 442  static void
Line 472  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 449  send_anonmmap_resp(struct spclient *spc,
Line 480  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 708  doinit(void)
Line 741  doinit(void)
         return 0;          return 0;
 }  }
   
 void *(*rumpclient_dlsym)(void *, const char *);  void *rumpclient__dlsym(void *, const char *);
 static int init_done = 0;  void *rumphijack_dlsym(void *, const char *);
   void *
   rumpclient__dlsym(void *handle, const char *symbol)
   {
   
           return dlsym(handle, symbol);
   }
   __weak_alias(rumphijack_dlsym,rumpclient__dlsym);
   
   static pid_t init_done = 0;
   
 int  int
 rumpclient_init()  rumpclient_init()
Line 718  rumpclient_init()
Line 760  rumpclient_init()
         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);          /* kq does not traverse fork() */
           if (init_done != 0)
                   kq = -1;
           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 symbol 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?
          */           */
 #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)                              \
                           errx(1, "cannot find %s: %s", #_syscall_,       \
                               dlerror());                                 \
           }
 #define FINDSYM(_name_) FINDSYM2(_name_,_name_)  #define FINDSYM(_name_) FINDSYM2(_name_,_name_)
         FINDSYM2(socket,__socket30);          FINDSYM2(socket,__socket30)
         FINDSYM(close);          FINDSYM(close)
         FINDSYM(connect);          FINDSYM(connect)
         FINDSYM(fcntl);          FINDSYM(fcntl)
         FINDSYM(poll);          FINDSYM(poll)
         FINDSYM(read);          FINDSYM(read)
         FINDSYM(sendto);          FINDSYM(sendmsg)
         FINDSYM(setsockopt);          FINDSYM(setsockopt)
         FINDSYM(dup);          FINDSYM(dup)
         FINDSYM(kqueue);          FINDSYM(kqueue)
           FINDSYM(execve)
 #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
 #undef  FINDSYM  #undef  FINDSYM
 #undef  FINDSY2  #undef  FINDSY2
Line 800  rumpclient_init()
Line 856  rumpclient_init()
   
 struct rumpclient_fork {  struct rumpclient_fork {
         uint32_t fork_auth[AUTHLEN];          uint32_t fork_auth[AUTHLEN];
           struct spclient fork_spc;
           int fork_kq;
 };  };
   
 struct rumpclient_fork *  struct rumpclient_fork *
Line 813  rumpclient_prefork(void)
Line 871  rumpclient_prefork(void)
         pthread_sigmask(SIG_SETMASK, &fullset, &omask);          pthread_sigmask(SIG_SETMASK, &fullset, &omask);
         rpf = malloc(sizeof(*rpf));          rpf = malloc(sizeof(*rpf));
         if (rpf == NULL)          if (rpf == NULL)
                 return NULL;                  goto out;
   
         if ((rv = prefork_req(&clispc, &omask, &resp)) != 0) {          if ((rv = prefork_req(&clispc, &omask, &resp)) != 0) {
                 free(rpf);                  free(rpf);
Line 825  rumpclient_prefork(void)
Line 883  rumpclient_prefork(void)
         memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));          memcpy(rpf->fork_auth, resp, sizeof(rpf->fork_auth));
         free(resp);          free(resp);
   
           rpf->fork_spc = clispc;
           rpf->fork_kq = kq;
   
  out:   out:
         pthread_sigmask(SIG_SETMASK, &omask, NULL);          pthread_sigmask(SIG_SETMASK, &omask, NULL);
         return rpf;          return rpf;
Line 859  rumpclient_fork_init(struct rumpclient_f
Line 920  rumpclient_fork_init(struct rumpclient_f
         return 0;          return 0;
 }  }
   
   /*ARGSUSED*/
   void
   rumpclient_fork_cancel(struct rumpclient_fork *rpf)
   {
   
           /* EUNIMPL */
   }
   
   void
   rumpclient_fork_vparent(struct rumpclient_fork *rpf)
   {
   
           clispc = rpf->fork_spc;
           kq = rpf->fork_kq;
   }
   
 void  void
 rumpclient_setconnretry(time_t timeout)  rumpclient_setconnretry(time_t timeout)
 {  {
Line 926  rumpclient__closenotify(int *fdp, enum r
Line 1003  rumpclient__closenotify(int *fdp, enum r
         return 0;          return 0;
 }  }
   
   pid_t
   rumpclient_fork()
   {
   
           return rumpclient__dofork(fork);
   }
   
 /*  /*
  * Process is about to exec.  Save info about our existing connection   * Process is about to exec.  Save info about our existing connection
  * in the env.  rumpclient will check for this info in init().   * in the env.  rumpclient will check for this info in init().
Line 933  rumpclient__closenotify(int *fdp, enum r
Line 1017  rumpclient__closenotify(int *fdp, enum r
  * may use it as well.   * may use it as well.
  */   */
 int  int
 rumpclient__exec_augmentenv(char *const oenv1[], char *const oenv2[],  rumpclient_exec(const char *path, char *const argv[], char *const envp[])
         char ***newenvp)  
 {  {
         char buf[4096];          char buf[4096];
         char **newenv;          char **newenv;
         char *envstr, *envstr2;          char *envstr, *envstr2;
         size_t nelem1, nelem2;          size_t nelem;
           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, kq);
Line 963  rumpclient__exec_augmentenv(char *const 
Line 1047  rumpclient__exec_augmentenv(char *const 
                 envstr2 = NULL;                  envstr2 = NULL;
         }          }
   
         nelem1 = 0;          for (nelem = 0; envp && envp[nelem]; nelem++)
         if (oenv1) {                  continue;
                 for (; oenv1[nelem1]; nelem1++)  
                         continue;  
         }  
         nelem2 = 0;  
         if (oenv2) {  
                 for (; oenv2[nelem2]; nelem2++)  
                         continue;  
         }  
   
         newenv = malloc(sizeof(*newenv) * nelem1+nelem2+3);          newenv = malloc(sizeof(*newenv) * (nelem+3));
         if (newenv == NULL) {          if (newenv == NULL) {
                 free(envstr2);                  free(envstr2);
                 free(envstr);                  free(envstr);
                 return ENOMEM;                  return ENOMEM;
         }          }
         memcpy(&newenv[0], oenv1, sizeof(*oenv1) * nelem1);          memcpy(&newenv[0], envp, nelem*sizeof(*envp));
         memcpy(&newenv[nelem1], oenv2, sizeof(*oenv2) * nelem2);  
   
         newenv[nelem1+nelem2] = envstr;          newenv[nelem] = envstr;
         newenv[nelem1+nelem2+1] = envstr2;          newenv[nelem+1] = envstr2;
         newenv[nelem1+nelem2+2] = NULL;          newenv[nelem+2] = NULL;
   
           rv = host_execve(path, argv, newenv);
   
           _DIAGASSERT(rv != 0);
           sverrno = errno;
           free(envstr2);
           free(envstr);
           free(newenv);
           errno = sverrno;
           return rv;
   }
   
         *newenvp = newenv;  int
   rumpclient_daemon(int nochdir, int noclose)
   {
           struct rumpclient_fork *rf;
           int sverrno;
   
           if ((rf = rumpclient_prefork()) == NULL)
                   return -1;
   
           if (daemon(nochdir, noclose) == -1) {
                   sverrno = errno;
                   rumpclient_fork_cancel(rf);
                   errno = sverrno;
                   return -1;
           }
   
           if (rumpclient_fork_init(rf) == -1)
                   return -1;
   
         return 0;          return 0;
 }  }

Legend:
Removed from v.1.29  
changed lines
  Added in v.1.42

CVSweb <webmaster@jp.NetBSD.org>