Add more tests.
[kopensolaris-gnu/glibc.git] / sunrpc / clnt_unix.c
index ad12d5f..fae1cd8 100644 (file)
 #include <errno.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <libintl.h>
 #include <rpc/rpc.h>
 #include <sys/uio.h>
 #include <sys/poll.h>
 #include <sys/socket.h>
 #include <rpc/pmap_clnt.h>
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+extern u_long _create_xid (void);
 
 #define MCALL_MSG_SIZE 24
 
@@ -112,24 +118,22 @@ clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
 {
   CLIENT *h;
   struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
-  struct timeval now;
   struct rpc_msg call_msg;
   int len;
 
   h = (CLIENT *) mem_alloc (sizeof (*h));
-  if (h == NULL)
-    {
-      (void) fputs (_("clntunix_create: out of memory\n"), stderr);
-      rpc_createerr.cf_stat = RPC_SYSTEMERROR;
-      rpc_createerr.cf_error.re_errno = errno;
-      goto fooy;
-    }
-  /*  ct = (struct ct_data *) mem_alloc (sizeof (*ct)); */
-  if (ct == NULL)
+  if (h == NULL || ct == NULL)
     {
-      (void) fputs (_("clntunix_create: out of memory\n"), stderr);
-      rpc_createerr.cf_stat = RPC_SYSTEMERROR;
-      rpc_createerr.cf_error.re_errno = errno;
+      struct rpc_createerr *ce = &get_rpc_createerr ();
+#ifdef USE_IN_LIBIO
+      if (_IO_fwide (stderr, 0) > 0)
+       (void) __fwprintf (stderr, L"%s",
+                          _("clntunix_create: out of memory\n"));
+      else
+#endif
+       (void) fputs (_("clntunix_create: out of memory\n"), stderr);
+      ce->cf_stat = RPC_SYSTEMERROR;
+      ce->cf_error.re_errno = ENOMEM;
       goto fooy;
     }
 
@@ -143,8 +147,9 @@ clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
       if (*sockp < 0
          || __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
        {
-         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
-         rpc_createerr.cf_error.re_errno = errno;
+         struct rpc_createerr *ce = &get_rpc_createerr ();
+         ce->cf_stat = RPC_SYSTEMERROR;
+         ce->cf_error.re_errno = errno;
          if (*sockp != -1)
            __close (*sockp);
          goto fooy;
@@ -167,8 +172,7 @@ clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
   /*
    * Initialize call message
    */
-  __gettimeofday (&now, (struct timezone *) 0);
-  call_msg.rm_xid = __getpid () ^ now.tv_sec ^ now.tv_usec;
+  call_msg.rm_xid = _create_xid ();
   call_msg.rm_direction = CALL;
   call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
   call_msg.rm_call.cb_prog = prog;
@@ -177,8 +181,9 @@ clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
   /*
    * pre-serialize the static part of the call msg and stash it away
    */
-  xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
-  if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
+  INTUSE(xdrmem_create) (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
+                        XDR_ENCODE);
+  if (!INTUSE(xdr_callhdr) (&(ct->ct_xdrs), &call_msg))
     {
       if (ct->ct_closeit)
        __close (*sockp);
@@ -191,11 +196,11 @@ clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
    * Create a client handle which uses xdrrec for serialization
    * and authnone for authentication.
    */
-  xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
-                (caddr_t) ct, readunix, writeunix);
+  INTUSE(xdrrec_create) (&(ct->ct_xdrs), sendsz, recvsz,
+                        (caddr_t) ct, readunix, writeunix);
   h->cl_ops = &unix_ops;
   h->cl_private = (caddr_t) ct;
-  h->cl_auth = authnone_create ();
+  h->cl_auth = INTUSE(authnone_create) ();
   return h;
 
 fooy:
@@ -206,6 +211,7 @@ fooy:
   mem_free ((caddr_t) h, sizeof (CLIENT));
   return (CLIENT *) NULL;
 }
+INTDEF (clntunix_create)
 
 static enum clnt_stat
 clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
@@ -231,8 +237,8 @@ clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
     }
 
   shipnow =
-    (xdr_results == (xdrproc_t) 0 && timeout.tv_sec == 0
-     && timeout.tv_usec == 0) ? FALSE : TRUE;
+    (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
+     && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
 
 call_again:
   xdrs->x_op = XDR_ENCODE;
@@ -245,17 +251,17 @@ call_again:
     {
       if (ct->ct_error.re_status == RPC_SUCCESS)
        ct->ct_error.re_status = RPC_CANTENCODEARGS;
-      (void) xdrrec_endofrecord (xdrs, TRUE);
+      (void) INTUSE(xdrrec_endofrecord) (xdrs, TRUE);
       return ct->ct_error.re_status;
     }
-  if (!xdrrec_endofrecord (xdrs, shipnow))
+  if (!INTUSE(xdrrec_endofrecord) (xdrs, shipnow))
     return ct->ct_error.re_status = RPC_CANTSEND;
   if (!shipnow)
     return RPC_SUCCESS;
   /*
    * Hack to provide rpc-based message passing
    */
-  if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
+  if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
     return ct->ct_error.re_status = RPC_TIMEDOUT;
 
 
@@ -267,11 +273,11 @@ call_again:
     {
       reply_msg.acpted_rply.ar_verf = _null_auth;
       reply_msg.acpted_rply.ar_results.where = NULL;
-      reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
-      if (!xdrrec_skiprecord (xdrs))
+      reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)INTUSE(xdr_void);
+      if (!INTUSE(xdrrec_skiprecord) (xdrs))
        return ct->ct_error.re_status;
       /* now decode and validate the response header */
-      if (!xdr_replymsg (xdrs, &reply_msg))
+      if (!INTUSE(xdr_replymsg) (xdrs, &reply_msg))
        {
          if (ct->ct_error.re_status == RPC_SUCCESS)
            continue;
@@ -301,7 +307,8 @@ call_again:
       if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
        {
          xdrs->x_op = XDR_FREE;
-         (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
+         (void) INTUSE(xdr_opaque_auth) (xdrs,
+                                         &(reply_msg.acpted_rply.ar_verf));
        }
     }                          /* end successful completion */
   else
@@ -427,79 +434,103 @@ clntunix_destroy (CLIENT *h)
 
   if (ct->ct_closeit)
     {
-      (void) close (ct->ct_sock);
+      (void) __close (ct->ct_sock);
     }
   XDR_DESTROY (&(ct->ct_xdrs));
   mem_free ((caddr_t) ct, sizeof (struct ct_data));
   mem_free ((caddr_t) h, sizeof (CLIENT));
 }
 
-struct cmessage {
-  struct cmsghdr cmsg;
-  struct cmsgcred cmcred;
-};
-
 static int
-__msgread (int sock, void *buf, size_t cnt)
+__msgread (int sock, void *data, size_t cnt)
 {
-  struct iovec iov[1];
+  struct iovec iov;
   struct msghdr msg;
-  struct cmessage cm;
-  int on = 1;
+#ifdef SCM_CREDENTIALS
+  static char cm[CMSG_SPACE(sizeof (struct ucred))];
+#endif
+  int len;
 
-  iov[0].iov_base = buf;
-  iov[0].iov_len = cnt;
+  iov.iov_base = data;
+  iov.iov_len = cnt;
 
-  msg.msg_iov = iov;
+  msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_name = NULL;
   msg.msg_namelen = 0;
-  msg.msg_control = (caddr_t)&cm;
-  msg.msg_controllen = sizeof(struct cmessage);
+#ifdef SCM_CREDENTIALS
+  msg.msg_control = (caddr_t) &cm;
+  msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
+#endif
   msg.msg_flags = 0;
 
 #ifdef SO_PASSCRED
-  if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
-    return -1;
+  {
+    int on = 1;
+    if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
+      return -1;
+  }
 #endif
 
-  return recvmsg (sock, &msg, 0);
+ restart:
+  len = __recvmsg (sock, &msg, 0);
+  if (len >= 0)
+    {
+      if (msg.msg_flags & MSG_CTRUNC || len == 0)
+       return 0;
+      else
+       return len;
+    }
+  if (errno == EINTR)
+    goto restart;
+  return -1;
 }
 
 static int
-__msgwrite (int sock, void *buf, size_t cnt)
+__msgwrite (int sock, void *data, size_t cnt)
 {
-#ifndef SCM_CREDS
+#ifndef SCM_CREDENTIALS
   /* We cannot implement this reliably.  */
   __set_errno (ENOSYS);
   return -1;
 #else
-  struct iovec iov[1];
+  struct iovec iov;
   struct msghdr msg;
-  struct cmessage cm;
-
-  iov[0].iov_base = buf;
-  iov[0].iov_len = cnt;
+  struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
+  struct ucred cred;
+  int len;
 
-  cm.cmsg.cmsg_type = SCM_CREDS;
-  cm.cmsg.cmsg_level = SOL_SOCKET;
-  cm.cmsg.cmsg_len = sizeof (struct cmessage);
   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
      get?id(). But since keyserv needs geteuid(), we have no other chance.
      It would be much better, if the kernel could pass both to the server. */
-  cm.cmcred.cmcred_pid = __getpid ();
-  cm.cmcred.cmcred_uid = __geteuid ();
-  cm.cmcred.cmcred_gid = __getegid ();
+  cred.pid = __getpid ();
+  cred.uid = __geteuid ();
+  cred.gid = __getegid ();
 
-  msg.msg_iov = iov;
+  memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_CREDENTIALS;
+  cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
+
+  iov.iov_base = data;
+  iov.iov_len = cnt;
+
+  msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_name = NULL;
   msg.msg_namelen = 0;
-  msg.msg_control = (caddr_t) &cm;
-  msg.msg_controllen = sizeof (struct cmessage);
+  msg.msg_control = cmsg;
+  msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
   msg.msg_flags = 0;
 
-  return sendmsg (sock, &msg, 0);
+ restart:
+  len = __sendmsg (sock, &msg, 0);
+  if (len >= 0)
+    return len;
+  if (errno == EINTR)
+    goto restart;
+  return -1;
+
 #endif
 }