Import TBBT (NFS trace replay).
[bluesky.git] / TBBT / trace_play / rpc / svc.c
1 #ifndef lint
2 static char sfs_svc_c_id[] = "@(#)svc.c     2.1     97/10/23";
3 #endif
4 /* @(#)svc.c    2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */
5 /*
6  *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
7  *      All rights reserved.
8  *              Standard Performance Evaluation Corporation (SPEC)
9  *              6585 Merchant Place, Suite 100
10  *              Warrenton, VA 20187
11  *
12  *      This product contains benchmarks acquired from several sources who
13  *      understand and agree with SPEC's goal of creating fair and objective
14  *      benchmarks to measure computer performance.
15  *
16  *      This copyright notice is placed here only to protect SPEC in the
17  *      event the source is misused in any manner that is contrary to the
18  *      spirit, the goals and the intent of SPEC.
19  *
20  *      The source code is provided to the user or company under the license
21  *      agreement for the SPEC Benchmark Suite for this product.
22  */
23 /*
24  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
25  * unrestricted use provided that this legend is included on all tape
26  * media and as a part of the software program in whole or part.  Users
27  * may copy or modify Sun RPC without charge, but are not authorized
28  * to license or distribute it to anyone else except as part of a product or
29  * program developed by the user.
30  * 
31  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
32  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
33  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
34  * 
35  * Sun RPC is provided with no support and without any obligation on the
36  * part of Sun Microsystems, Inc. to assist in its use, correction,
37  * modification or enhancement.
38  * 
39  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
40  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
41  * OR ANY PART THEREOF.
42  * 
43  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
44  * or profits or other special, indirect and consequential damages, even if
45  * Sun has been advised of the possibility of such damages.
46  * 
47  * Sun Microsystems, Inc.
48  * 2550 Garcia Avenue
49  * Mountain View, California  94043
50  */
51 #if !defined(lint) && defined(SCCSIDS)
52 static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro";
53 #endif
54
55 /*
56  * svc.c, Server-side remote procedure call interface.
57  *
58  * There are two sets of procedures here.  The xprt routines are
59  * for handling transport handles.  The svc routines handle the
60  * list of service routines.
61  *
62  * Copyright (C) 1984, Sun Microsystems, Inc.
63  */
64
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <unistd.h>
68 #include <string.h>
69 #include <errno.h>
70 #include "rpc/rpc.h"
71 #include "rpc/pmap_clnt.h"
72
73 #ifdef FD_SETSIZE
74 static SVCXPRT **xports;
75 #else
76 #define NOFILE 32
77
78 static SVCXPRT *xports[NOFILE];
79 #endif /* def FD_SETSIZE */
80
81 #define NULL_SVC ((struct svc_callout *)0)
82 #define RQCRED_SIZE     400             /* this size is excessive */
83
84 /*
85  * The services list
86  * Each entry represents a set of procedures (an rpc program).
87  * The dispatch routine takes request structs and runs the
88  * apropriate procedure.
89  */
90 static struct svc_callout {
91         struct svc_callout *sc_next;
92         uint32_t            sc_prog;
93         uint32_t            sc_vers;
94         void                (*sc_dispatch)();
95 } *svc_head;
96
97 static struct svc_callout *svc_find();
98
99 /* ***************  SVCXPRT related stuff **************** */
100
101 /*
102  * Activate a transport handle.
103  */
104 void
105 xprt_register(
106         SVCXPRT *xprt)
107 {
108         int sock = xprt->xp_sock;
109
110 #ifdef FD_SETSIZE
111         if (xports == NULL) {
112                 xports = (SVCXPRT **)
113                         mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *));
114         }
115         if (sock < _rpc_dtablesize()) {
116                 xports[sock] = xprt;
117                 FD_SET(sock, &svc_fdset);
118         }
119 #else
120         if (sock < NOFILE) {
121                 xports[sock] = xprt;
122                 svc_fds |= (1 << sock);
123         }
124 #endif /* def FD_SETSIZE */
125
126 }
127
128 /*
129  * De-activate a transport handle. 
130  */
131 void
132 xprt_unregister(
133         SVCXPRT *xprt)
134
135         int sock = xprt->xp_sock;
136
137 #ifdef FD_SETSIZE
138         if ((sock < _rpc_dtablesize()) && (xports[sock] == xprt)) {
139                 xports[sock] = (SVCXPRT *)0;
140                 FD_CLR(sock, &svc_fdset);
141         }
142 #else
143         if ((sock < NOFILE) && (xports[sock] == xprt)) {
144                 xports[sock] = (SVCXPRT *)0;
145                 svc_fds &= ~(1 << sock);
146         }
147 #endif /* def FD_SETSIZE */
148 }
149
150
151 /* ********************** CALLOUT list related stuff ************* */
152
153 /*
154  * Add a service program to the callout list.
155  * The dispatch routine will be called when a rpc request for this
156  * program number comes in.
157  */
158 bool_t
159 svc_register(
160         SVCXPRT *xprt,
161         uint32_t prog,
162         uint32_t vers,
163         void (*dispatch)(),
164         int protocol)
165 {
166         struct svc_callout *prev;
167         struct svc_callout *s;
168
169         if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) {
170                 if (s->sc_dispatch == dispatch)
171                         goto pmap_it;  /* he is registering another xptr */
172                 return (FALSE);
173         }
174         s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout));
175         if (s == (struct svc_callout *)0) {
176                 return (FALSE);
177         }
178         s->sc_prog = prog;
179         s->sc_vers = vers;
180         s->sc_dispatch = dispatch;
181         s->sc_next = svc_head;
182         svc_head = s;
183 pmap_it:
184         /* now register the information with the local binder service */
185         if (protocol) {
186                 return (pmap_set(prog, vers, protocol, xprt->xp_port));
187         }
188         return (TRUE);
189 }
190
191 /*
192  * Remove a service program from the callout list.
193  */
194 void
195 svc_unregister(
196         uint32_t prog,
197         uint32_t vers)
198 {
199         struct svc_callout *prev;
200         struct svc_callout *s;
201
202         if ((s = svc_find(prog, vers, &prev)) == NULL_SVC)
203                 return;
204         if (prev == NULL_SVC) {
205                 svc_head = s->sc_next;
206         } else {
207                 prev->sc_next = s->sc_next;
208         }
209         s->sc_next = NULL_SVC;
210         mem_free((char *) s, (uint_t) sizeof(struct svc_callout));
211         /* now unregister the information with the local binder service */
212         (void)pmap_unset(prog, vers);
213 }
214
215 /*
216  * Search the callout list for a program number, return the callout
217  * struct.
218  */
219 static struct svc_callout *
220 svc_find(
221         uint32_t prog,
222         uint32_t vers,
223         struct svc_callout **prev)
224 {
225         struct svc_callout *s, *p;
226
227         p = NULL_SVC;
228         for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
229                 if ((s->sc_prog == prog) && (s->sc_vers == vers))
230                         goto done;
231                 p = s;
232         }
233 done:
234         *prev = p;
235         return (s);
236 }
237
238 /* ******************* REPLY GENERATION ROUTINES  ************ */
239
240 /*
241  * Send a reply to an rpc request
242  */
243 bool_t
244 svc_sendreply(
245         SVCXPRT *xprt,
246         xdrproc_t xdr_results,
247         void *xdr_location)
248 {
249         struct rpc_msg rply; 
250
251         rply.rm_direction = REPLY;  
252         rply.rm_reply.rp_stat = MSG_ACCEPTED; 
253         rply.acpted_rply.ar_verf = xprt->xp_verf; 
254         rply.acpted_rply.ar_stat = SUCCESS;
255         rply.acpted_rply.ar_results.where = xdr_location;
256         rply.acpted_rply.ar_results.proc = xdr_results;
257         return (SVC_REPLY(xprt, &rply)); 
258 }
259
260 /*
261  * No procedure error reply
262  */
263 void
264 svcerr_noproc(
265         SVCXPRT *xprt)
266 {
267         struct rpc_msg rply;
268
269         rply.rm_direction = REPLY;
270         rply.rm_reply.rp_stat = MSG_ACCEPTED;
271         rply.acpted_rply.ar_verf = xprt->xp_verf;
272         rply.acpted_rply.ar_stat = PROC_UNAVAIL;
273         SVC_REPLY(xprt, &rply);
274 }
275
276 /*
277  * Can't decode args error reply
278  */
279 void
280 svcerr_decode(
281         SVCXPRT *xprt)
282 {
283         struct rpc_msg rply; 
284
285         rply.rm_direction = REPLY; 
286         rply.rm_reply.rp_stat = MSG_ACCEPTED; 
287         rply.acpted_rply.ar_verf = xprt->xp_verf;
288         rply.acpted_rply.ar_stat = GARBAGE_ARGS;
289         SVC_REPLY(xprt, &rply); 
290 }
291
292 /*
293  * Some system error
294  */
295 void
296 svcerr_systemerr(
297         SVCXPRT *xprt)
298 {
299         struct rpc_msg rply; 
300
301         rply.rm_direction = REPLY; 
302         rply.rm_reply.rp_stat = MSG_ACCEPTED; 
303         rply.acpted_rply.ar_verf = xprt->xp_verf;
304         rply.acpted_rply.ar_stat = SYSTEM_ERR;
305         SVC_REPLY(xprt, &rply); 
306 }
307
308 /*
309  * Authentication error reply
310  */
311 void
312 svcerr_auth(
313         SVCXPRT *xprt,
314         enum auth_stat why)
315 {
316         struct rpc_msg rply;
317
318         rply.rm_direction = REPLY;
319         rply.rm_reply.rp_stat = MSG_DENIED;
320         rply.rjcted_rply.rj_stat = AUTH_ERROR;
321         rply.rjcted_rply.rj_why = why;
322         SVC_REPLY(xprt, &rply);
323 }
324
325 /*
326  * Auth too weak error reply
327  */
328 void
329 svcerr_weakauth(
330         SVCXPRT *xprt)
331 {
332
333         svcerr_auth(xprt, AUTH_TOOWEAK);
334 }
335
336 /*
337  * Program unavailable error reply
338  */
339 void 
340 svcerr_noprog(
341         SVCXPRT *xprt)
342 {
343         struct rpc_msg rply;  
344
345         rply.rm_direction = REPLY;   
346         rply.rm_reply.rp_stat = MSG_ACCEPTED;  
347         rply.acpted_rply.ar_verf = xprt->xp_verf;  
348         rply.acpted_rply.ar_stat = PROG_UNAVAIL;
349         SVC_REPLY(xprt, &rply);
350 }
351
352 /*
353  * Program version mismatch error reply
354  */
355 void  
356 svcerr_progvers(
357         SVCXPRT *xprt,
358         uint32_t low_vers,
359         uint32_t high_vers)
360 {
361         struct rpc_msg rply;
362
363         rply.rm_direction = REPLY;
364         rply.rm_reply.rp_stat = MSG_ACCEPTED;
365         rply.acpted_rply.ar_verf = xprt->xp_verf;
366         rply.acpted_rply.ar_stat = PROG_MISMATCH;
367         rply.acpted_rply.ar_vers.low = low_vers;
368         rply.acpted_rply.ar_vers.high = high_vers;
369         SVC_REPLY(xprt, &rply);
370 }
371
372 /* ******************* SERVER INPUT STUFF ******************* */
373
374 /*
375  * Get server side input from some transport.
376  *
377  * Statement of authentication parameters management:
378  * This function owns and manages all authentication parameters, specifically
379  * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
380  * the "cooked" credentials (rqst->rq_clntcred).
381  * However, this function does not know the structure of the cooked
382  * credentials, so it make the following assumptions: 
383  *   a) the structure is contiguous (no pointers), and
384  *   b) the cred structure size does not exceed RQCRED_SIZE bytes. 
385  * In all events, all three parameters are freed upon exit from this routine.
386  * The storage is trivially management on the call stack in user land, but
387  * is mallocated in kernel land.
388  */
389
390 void
391 svc_getreqset(
392 #ifdef FD_SETSIZE
393         fd_set *readfds)
394 {
395 #else
396         int *readfds)
397 {
398     int readfds_local = *readfds;
399 #endif /* def FD_SETSIZE */
400         enum xprt_stat stat;
401         struct rpc_msg msg;
402         int prog_found;
403         uint32_t low_vers;
404         uint32_t high_vers;
405         struct svc_req r;
406         SVCXPRT *xprt;
407         int setsize;
408         int sock;
409         char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
410         msg.rm_call.cb_cred.oa_base = cred_area;
411         msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
412         r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
413
414
415 #ifdef FD_SETSIZE
416         setsize = _rpc_dtablesize();    
417         for (sock = 0; sock < setsize; sock++) {
418             if (FD_ISSET(sock, readfds)) {
419 #else
420         for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) {
421             if ((readfds_local & 1) != 0) {
422 #endif /* def FD_SETSIZE */
423                 /* sock has input waiting */
424                 xprt = xports[sock];
425                 /* now receive msgs from xprtprt (support batch calls) */
426                 do {
427                         if (SVC_RECV(xprt, &msg)) {
428
429                                 /* now find the exported program and call it */
430                                 struct svc_callout *s;
431                                 enum auth_stat why;
432
433                                 r.rq_xprt = xprt;
434                                 r.rq_prog = msg.rm_call.cb_prog;
435                                 r.rq_vers = msg.rm_call.cb_vers;
436                                 r.rq_proc = msg.rm_call.cb_proc;
437                                 r.rq_cred = msg.rm_call.cb_cred;
438                                 /* first authenticate the message */
439                                 if ((why= _authenticate(&r, &msg)) != AUTH_OK) {
440                                         svcerr_auth(xprt, why);
441                                         goto call_done;
442                                 }
443                                 /* now match message with a registered service*/
444                                 prog_found = FALSE;
445                                 low_vers = 0 - 1;
446                                 high_vers = 0;
447                                 for (s = svc_head; s != NULL_SVC; s = s->sc_next) {
448                                         if (s->sc_prog == r.rq_prog) {
449                                                 if (s->sc_vers == r.rq_vers) {
450                                                         (*s->sc_dispatch)(&r, xprt);
451                                                         goto call_done;
452                                                 }  /* found correct version */
453                                                 prog_found = TRUE;
454                                                 if (s->sc_vers < low_vers)
455                                                         low_vers = s->sc_vers;
456                                                 if (s->sc_vers > high_vers)
457                                                         high_vers = s->sc_vers;
458                                         }   /* found correct program */
459                                 }
460                                 /*
461                                  * if we got here, the program or version
462                                  * is not served ...
463                                  */
464                                 if (prog_found)
465                                         svcerr_progvers(xprt,
466                                         low_vers, high_vers);
467                                 else
468                                          svcerr_noprog(xprt);
469                                 /* Fall through to ... */
470                         }
471                 call_done:
472                         if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
473                                 SVC_DESTROY(xprt);
474                                 break;
475                         }
476                 } while (stat == XPRT_MOREREQS);
477             }
478         }
479 }