OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [inet/] [rpc/] [clnt_unix.c] - Blame information for rev 1325

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/*
2
 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3
 * unrestricted use provided that this legend is included on all tape
4
 * media and as a part of the software program in whole or part.  Users
5
 * may copy or modify Sun RPC without charge, but are not authorized
6
 * to license or distribute it to anyone else except as part of a product or
7
 * program developed by the user.
8
 *
9
 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12
 *
13
 * Sun RPC is provided with no support and without any obligation on the
14
 * part of Sun Microsystems, Inc. to assist in its use, correction,
15
 * modification or enhancement.
16
 *
17
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19
 * OR ANY PART THEREOF.
20
 *
21
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22
 * or profits or other special, indirect and consequential damages, even if
23
 * Sun has been advised of the possibility of such damages.
24
 *
25
 * Sun Microsystems, Inc.
26
 * 2550 Garcia Avenue
27
 * Mountain View, California  94043
28
 */
29
 
30
/*
31
 * clnt_unix.c, Implements a TCP/IP based, client side RPC.
32
 *
33
 * Copyright (C) 1984, Sun Microsystems, Inc.
34
 *
35
 * TCP based RPC supports 'batched calls'.
36
 * A sequence of calls may be batched-up in a send buffer.  The rpc call
37
 * return immediately to the client even though the call was not necessarily
38
 * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
39
 * the rpc timeout value is zero (see clnt.h, rpc).
40
 *
41
 * Clients should NOT casually batch calls that in fact return results; that is,
42
 * the server side should be aware that a call is batched and not produce any
43
 * return message.  Batched calls that produce many result messages can
44
 * deadlock (netlock) the client and the server....
45
 *
46
 * Now go hang yourself.
47
 */
48
 
49
#define __FORCE_GLIBC
50
#include <features.h>
51
 
52
#include <netdb.h>
53
#include <errno.h>
54
#include <stdio.h>
55
#include <unistd.h>
56
#include <rpc/rpc.h>
57
#include <sys/uio.h>
58
#include <sys/poll.h>
59
#include <sys/socket.h>
60
#include <rpc/pmap_clnt.h>
61
#ifdef USE_IN_LIBIO
62
# include <wchar.h>
63
#endif
64
 
65
extern u_long _create_xid (void);
66
 
67
#define MCALL_MSG_SIZE 24
68
 
69
struct ct_data
70
  {
71
    int ct_sock;
72
    bool_t ct_closeit;
73
    struct timeval ct_wait;
74
    bool_t ct_waitset;          /* wait set by clnt_control? */
75
    struct sockaddr_un ct_addr;
76
    struct rpc_err ct_error;
77
    char ct_mcall[MCALL_MSG_SIZE];      /* marshalled callmsg */
78
    u_int ct_mpos;              /* pos after marshal */
79
    XDR ct_xdrs;
80
  };
81
 
82
static int readunix (char *, char *, int);
83
static int writeunix (char *, char *, int);
84
 
85
static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
86
                                    xdrproc_t, caddr_t, struct timeval);
87
static void clntunix_abort (void);
88
static void clntunix_geterr (CLIENT *, struct rpc_err *);
89
static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
90
static bool_t clntunix_control (CLIENT *, int, char *);
91
static void clntunix_destroy (CLIENT *);
92
 
93
static struct clnt_ops unix_ops =
94
{
95
  clntunix_call,
96
  clntunix_abort,
97
  clntunix_geterr,
98
  clntunix_freeres,
99
  clntunix_destroy,
100
  clntunix_control
101
};
102
 
103
/*
104
 * Create a client handle for a tcp/ip connection.
105
 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
106
 * connected to raddr.  If *sockp non-negative then
107
 * raddr is ignored.  The rpc/tcp package does buffering
108
 * similar to stdio, so the client must pick send and receive buffer sizes,];
109
 * 0 => use the default.
110
 * If raddr->sin_port is 0, then a binder on the remote machine is
111
 * consulted for the right port number.
112
 * NB: *sockp is copied into a private area.
113
 * NB: It is the clients responsibility to close *sockp.
114
 * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
115
 * something more useful.
116
 */
117
CLIENT *
118
clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
119
                 int *sockp, u_int sendsz, u_int recvsz)
120
{
121
  CLIENT *h;
122
  struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
123
  struct rpc_msg call_msg;
124
  int len;
125
 
126
  h = (CLIENT *) mem_alloc (sizeof (*h));
127
  if (h == NULL || ct == NULL)
128
    {
129
      struct rpc_createerr *ce = &get_rpc_createerr ();
130
#ifdef USE_IN_LIBIO
131
      if (_IO_fwide (stderr, 0) > 0)
132
        (void) __fwprintf (stderr, L"%s",
133
                           _("clntunix_create: out of memory\n"));
134
      else
135
#endif
136
        (void) fputs (_("clntunix_create: out of memory\n"), stderr);
137
      ce->cf_stat = RPC_SYSTEMERROR;
138
      ce->cf_error.re_errno = ENOMEM;
139
      goto fooy;
140
    }
141
 
142
  /*
143
   * If no socket given, open one
144
   */
145
  if (*sockp < 0)
146
    {
147
      *sockp = socket (AF_UNIX, SOCK_STREAM, 0);
148
      len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
149
      if (*sockp < 0
150
          || connect (*sockp, (struct sockaddr *) raddr, len) < 0)
151
        {
152
          struct rpc_createerr *ce = &get_rpc_createerr ();
153
          ce->cf_stat = RPC_SYSTEMERROR;
154
          ce->cf_error.re_errno = errno;
155
          if (*sockp != -1)
156
            close (*sockp);
157
          goto fooy;
158
        }
159
      ct->ct_closeit = TRUE;
160
    }
161
  else
162
    {
163
      ct->ct_closeit = FALSE;
164
    }
165
 
166
  /*
167
   * Set up private data struct
168
   */
169
  ct->ct_sock = *sockp;
170
  ct->ct_wait.tv_usec = 0;
171
  ct->ct_waitset = FALSE;
172
  ct->ct_addr = *raddr;
173
 
174
  /*
175
   * Initialize call message
176
   */
177
  call_msg.rm_xid = _create_xid ();
178
  call_msg.rm_direction = CALL;
179
  call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
180
  call_msg.rm_call.cb_prog = prog;
181
  call_msg.rm_call.cb_vers = vers;
182
 
183
  /*
184
   * pre-serialize the static part of the call msg and stash it away
185
   */
186
  xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
187
  if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
188
    {
189
      if (ct->ct_closeit)
190
        close (*sockp);
191
      goto fooy;
192
    }
193
  ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
194
  XDR_DESTROY (&(ct->ct_xdrs));
195
 
196
  /*
197
   * Create a client handle which uses xdrrec for serialization
198
   * and authnone for authentication.
199
   */
200
  xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
201
                 (caddr_t) ct, readunix, writeunix);
202
  h->cl_ops = &unix_ops;
203
  h->cl_private = (caddr_t) ct;
204
  h->cl_auth = authnone_create ();
205
  return h;
206
 
207
fooy:
208
  /*
209
   * Something goofed, free stuff and barf
210
   */
211
  mem_free ((caddr_t) ct, sizeof (struct ct_data));
212
  mem_free ((caddr_t) h, sizeof (CLIENT));
213
  return (CLIENT *) NULL;
214
}
215
 
216
static enum clnt_stat
217
clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
218
     CLIENT *h;
219
     u_long proc;
220
     xdrproc_t xdr_args;
221
     caddr_t args_ptr;
222
     xdrproc_t xdr_results;
223
     caddr_t results_ptr;
224
     struct timeval timeout;
225
{
226
  struct ct_data *ct = (struct ct_data *) h->cl_private;
227
  XDR *xdrs = &(ct->ct_xdrs);
228
  struct rpc_msg reply_msg;
229
  u_long x_id;
230
  u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall);   /* yuk */
231
  bool_t shipnow;
232
  int refreshes = 2;
233
 
234
  if (!ct->ct_waitset)
235
    {
236
      ct->ct_wait = timeout;
237
    }
238
 
239
  shipnow =
240
    (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
241
     && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
242
 
243
call_again:
244
  xdrs->x_op = XDR_ENCODE;
245
  ct->ct_error.re_status = RPC_SUCCESS;
246
  x_id = ntohl (--(*msg_x_id));
247
  if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
248
      (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
249
      (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
250
      (!(*xdr_args) (xdrs, args_ptr)))
251
    {
252
      if (ct->ct_error.re_status == RPC_SUCCESS)
253
        ct->ct_error.re_status = RPC_CANTENCODEARGS;
254
      (void) xdrrec_endofrecord (xdrs, TRUE);
255
      return ct->ct_error.re_status;
256
    }
257
  if (!xdrrec_endofrecord (xdrs, shipnow))
258
    return ct->ct_error.re_status = RPC_CANTSEND;
259
  if (!shipnow)
260
    return RPC_SUCCESS;
261
  /*
262
   * Hack to provide rpc-based message passing
263
   */
264
  if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
265
    return ct->ct_error.re_status = RPC_TIMEDOUT;
266
 
267
 
268
  /*
269
   * Keep receiving until we get a valid transaction id
270
   */
271
  xdrs->x_op = XDR_DECODE;
272
  while (TRUE)
273
    {
274
      reply_msg.acpted_rply.ar_verf = _null_auth;
275
      reply_msg.acpted_rply.ar_results.where = NULL;
276
      reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
277
      if (!xdrrec_skiprecord (xdrs))
278
        return ct->ct_error.re_status;
279
      /* now decode and validate the response header */
280
      if (!xdr_replymsg (xdrs, &reply_msg))
281
        {
282
          if (ct->ct_error.re_status == RPC_SUCCESS)
283
            continue;
284
          return ct->ct_error.re_status;
285
        }
286
      if (reply_msg.rm_xid == x_id)
287
        break;
288
    }
289
 
290
  /*
291
   * process header
292
   */
293
  _seterr_reply (&reply_msg, &(ct->ct_error));
294
  if (ct->ct_error.re_status == RPC_SUCCESS)
295
    {
296
      if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
297
        {
298
          ct->ct_error.re_status = RPC_AUTHERROR;
299
          ct->ct_error.re_why = AUTH_INVALIDRESP;
300
        }
301
      else if (!(*xdr_results) (xdrs, results_ptr))
302
        {
303
          if (ct->ct_error.re_status == RPC_SUCCESS)
304
            ct->ct_error.re_status = RPC_CANTDECODERES;
305
        }
306
      /* free verifier ... */
307
      if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
308
        {
309
          xdrs->x_op = XDR_FREE;
310
          (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
311
        }
312
    }                           /* end successful completion */
313
  else
314
    {
315
      /* maybe our credentials need to be refreshed ... */
316
      if (refreshes-- && AUTH_REFRESH (h->cl_auth))
317
        goto call_again;
318
    }                           /* end of unsuccessful completion */
319
  return ct->ct_error.re_status;
320
}
321
 
322
static void
323
clntunix_geterr (CLIENT *h, struct rpc_err *errp)
324
{
325
  struct ct_data *ct = (struct ct_data *) h->cl_private;
326
 
327
  *errp = ct->ct_error;
328
}
329
 
330
static bool_t
331
clntunix_freeres (cl, xdr_res, res_ptr)
332
     CLIENT *cl;
333
     xdrproc_t xdr_res;
334
     caddr_t res_ptr;
335
{
336
  struct ct_data *ct = (struct ct_data *) cl->cl_private;
337
  XDR *xdrs = &(ct->ct_xdrs);
338
 
339
  xdrs->x_op = XDR_FREE;
340
  return (*xdr_res) (xdrs, res_ptr);
341
}
342
 
343
static void
344
clntunix_abort ()
345
{
346
}
347
 
348
static bool_t
349
clntunix_control (CLIENT *cl, int request, char *info)
350
{
351
  struct ct_data *ct = (struct ct_data *) cl->cl_private;
352
 
353
 
354
  switch (request)
355
    {
356
    case CLSET_FD_CLOSE:
357
      ct->ct_closeit = TRUE;
358
      break;
359
    case CLSET_FD_NCLOSE:
360
      ct->ct_closeit = FALSE;
361
      break;
362
    case CLSET_TIMEOUT:
363
      ct->ct_wait = *(struct timeval *) info;
364
      break;
365
    case CLGET_TIMEOUT:
366
      *(struct timeval *) info = ct->ct_wait;
367
      break;
368
    case CLGET_SERVER_ADDR:
369
      *(struct sockaddr_un *) info = ct->ct_addr;
370
      break;
371
    case CLGET_FD:
372
      *(int *)info = ct->ct_sock;
373
      break;
374
    case CLGET_XID:
375
      /*
376
       * use the knowledge that xid is the
377
       * first element in the call structure *.
378
       * This will get the xid of the PREVIOUS call
379
       */
380
      *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
381
      break;
382
    case CLSET_XID:
383
      /* This will set the xid of the NEXT call */
384
      *(u_long *) ct->ct_mcall =  htonl (*(u_long *)info - 1);
385
      /* decrement by 1 as clntunix_call() increments once */
386
    case CLGET_VERS:
387
      /*
388
       * This RELIES on the information that, in the call body,
389
       * the version number field is the fifth field from the
390
       * begining of the RPC header. MUST be changed if the
391
       * call_struct is changed
392
       */
393
      *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
394
                                             + 4 * BYTES_PER_XDR_UNIT));
395
      break;
396
    case CLSET_VERS:
397
      *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
398
        = htonl (*(u_long *) info);
399
      break;
400
    case CLGET_PROG:
401
      /*
402
       * This RELIES on the information that, in the call body,
403
       * the program number field is the  field from the
404
       * begining of the RPC header. MUST be changed if the
405
       * call_struct is changed
406
       */
407
      *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
408
                                             + 3 * BYTES_PER_XDR_UNIT));
409
      break;
410
    case CLSET_PROG:
411
      *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
412
        = htonl(*(u_long *) info);
413
      break;
414
    /* The following are only possible with TI-RPC */
415
    case CLGET_RETRY_TIMEOUT:
416
    case CLSET_RETRY_TIMEOUT:
417
    case CLGET_SVC_ADDR:
418
    case CLSET_SVC_ADDR:
419
    case CLSET_PUSH_TIMOD:
420
    case CLSET_POP_TIMOD:
421
    default:
422
      return FALSE;
423
    }
424
  return TRUE;
425
}
426
 
427
 
428
static void
429
clntunix_destroy (CLIENT *h)
430
{
431
  struct ct_data *ct =
432
  (struct ct_data *) h->cl_private;
433
 
434
  if (ct->ct_closeit)
435
    {
436
      (void) close (ct->ct_sock);
437
    }
438
  XDR_DESTROY (&(ct->ct_xdrs));
439
  mem_free ((caddr_t) ct, sizeof (struct ct_data));
440
  mem_free ((caddr_t) h, sizeof (CLIENT));
441
}
442
 
443
static int
444
__msgread (int sock, void *data, size_t cnt)
445
{
446
  struct iovec iov;
447
  struct msghdr msg;
448
#ifdef SCM_CREDENTIALS
449
  static char cm[CMSG_SPACE(sizeof (struct ucred))];
450
#endif
451
  int len;
452
 
453
  iov.iov_base = data;
454
  iov.iov_len = cnt;
455
 
456
  msg.msg_iov = &iov;
457
  msg.msg_iovlen = 1;
458
  msg.msg_name = NULL;
459
  msg.msg_namelen = 0;
460
#ifdef SCM_CREDENTIALS
461
  msg.msg_control = (caddr_t) &cm;
462
  msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
463
#endif
464
  msg.msg_flags = 0;
465
 
466
#ifdef SO_PASSCRED
467
  {
468
    int on = 1;
469
    if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
470
      return -1;
471
  }
472
#endif
473
 
474
 restart:
475
  len = recvmsg (sock, &msg, 0);
476
  if (len >= 0)
477
    {
478
      if (msg.msg_flags & MSG_CTRUNC || len == 0)
479
        return 0;
480
      else
481
        return len;
482
    }
483
  if (errno == EINTR)
484
    goto restart;
485
  return -1;
486
}
487
 
488
static int
489
__msgwrite (int sock, void *data, size_t cnt)
490
{
491
#ifndef SCM_CREDENTIALS
492
  /* We cannot implement this reliably.  */
493
  __set_errno (ENOSYS);
494
  return -1;
495
#else
496
  struct iovec iov;
497
  struct msghdr msg;
498
  struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
499
  struct ucred cred;
500
  int len;
501
 
502
  /* XXX I'm not sure, if gete?id() is always correct, or if we should use
503
     get?id(). But since keyserv needs geteuid(), we have no other chance.
504
     It would be much better, if the kernel could pass both to the server. */
505
  cred.pid = getpid ();
506
  cred.uid = geteuid ();
507
  cred.gid = getegid ();
508
 
509
  memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
510
  cmsg->cmsg_level = SOL_SOCKET;
511
  cmsg->cmsg_type = SCM_CREDENTIALS;
512
  cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
513
 
514
  iov.iov_base = data;
515
  iov.iov_len = cnt;
516
 
517
  msg.msg_iov = &iov;
518
  msg.msg_iovlen = 1;
519
  msg.msg_name = NULL;
520
  msg.msg_namelen = 0;
521
  msg.msg_control = cmsg;
522
  msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
523
  msg.msg_flags = 0;
524
 
525
 restart:
526
  len = sendmsg (sock, &msg, 0);
527
  if (len >= 0)
528
    return len;
529
  if (errno == EINTR)
530
    goto restart;
531
  return -1;
532
 
533
#endif
534
}
535
 
536
 
537
/*
538
 * Interface between xdr serializer and unix connection.
539
 * Behaves like the system calls, read & write, but keeps some error state
540
 * around for the rpc level.
541
 */
542
static int
543
readunix (char *ctptr, char *buf, int len)
544
{
545
  struct ct_data *ct = (struct ct_data *) ctptr;
546
  struct pollfd fd;
547
  int milliseconds = ((ct->ct_wait.tv_sec * 1000)
548
                      + (ct->ct_wait.tv_usec / 1000));
549
 
550
  if (len == 0)
551
    return 0;
552
 
553
  fd.fd = ct->ct_sock;
554
  fd.events = POLLIN;
555
  while (TRUE)
556
    {
557
      switch (poll (&fd, 1, milliseconds))
558
        {
559
        case 0:
560
          ct->ct_error.re_status = RPC_TIMEDOUT;
561
          return -1;
562
 
563
        case -1:
564
          if (errno == EINTR)
565
            continue;
566
          ct->ct_error.re_status = RPC_CANTRECV;
567
          ct->ct_error.re_errno = errno;
568
          return -1;
569
        }
570
      break;
571
    }
572
  switch (len = __msgread (ct->ct_sock, buf, len))
573
    {
574
 
575
    case 0:
576
      /* premature eof */
577
      ct->ct_error.re_errno = ECONNRESET;
578
      ct->ct_error.re_status = RPC_CANTRECV;
579
      len = -1;                 /* it's really an error */
580
      break;
581
 
582
    case -1:
583
      ct->ct_error.re_errno = errno;
584
      ct->ct_error.re_status = RPC_CANTRECV;
585
      break;
586
    }
587
  return len;
588
}
589
 
590
static int
591
writeunix (char *ctptr, char *buf, int len)
592
{
593
  int i, cnt;
594
  struct ct_data *ct = (struct ct_data *) ctptr;
595
 
596
  for (cnt = len; cnt > 0; cnt -= i, buf += i)
597
    {
598
      if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
599
        {
600
          ct->ct_error.re_errno = errno;
601
          ct->ct_error.re_status = RPC_CANTSEND;
602
          return -1;
603
        }
604
    }
605
  return len;
606
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.