home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / rpc2 / part04 / rpc / doc / xdr.spec.p2 < prev   
Encoding:
Text File  |  1986-11-30  |  15.6 KB  |  660 lines

  1. .LS
  2. bool_t
  3. xdr_wrap_list(xdrs, glp)
  4.     XDR *xdrs;
  5.     gnumbers_list *glp;
  6. {
  7.     return(xdr_reference(xdrs, glp, sizeof(struct gnnode),
  8.         xdr_gnnode));
  9. }
  10. .Lf
  11. .LS
  12. struct xdr_discrim choices[2] = {
  13.     /*
  14.      * called if another node needs (de)serializing
  15.      */
  16.     { TRUE, xdr_wrap_list },
  17.     /*
  18.      * called when no more nodes need (de)serializing
  19.      */
  20.     { FALSE, xdr_void }
  21. }
  22. .sp.5
  23. bool_t
  24. xdr_gnumbers_list(xdrs, glp)
  25.     XDR *xdrs;
  26.     gnumbers_list *glp;
  27. {
  28.     bool_t more_data;
  29. .sp.5
  30.     more_data = (*glp != (gnumbers_list)NULL);
  31.     return(xdr_union(xdrs, &more_data, glp, choices, NULL);
  32. }
  33. .Lf
  34. The entry routine is
  35. .LW xdr_gnumbers_list() ;
  36. its job is to translate between the boolean value
  37. .LW more_data
  38. and the list pointer values.
  39. If there is no more data, the
  40. .LW xdr_union()
  41. primitive calls
  42. .LW xdr_void()
  43. and the recursion is terminated.
  44. Otherwise,
  45. .LW xdr_union()
  46. calls
  47. .LW xdr_wrap_list() ,
  48. whose job is to dereference the list pointers.
  49. The
  50. .LW xdr_gnnode()
  51. routine actually (de)serializes data of the current node
  52. of the linked list, and recursively calls
  53. .LW xdr_gnumbers_list()
  54. to handle the remainder of the list.
  55. .LP
  56. You should convince yourself that these routines
  57. function correctly in all three directions
  58. .LW (XDR_ENCODE ,
  59. .LW XDR_DECODE ,
  60. and
  61. .LW XDR_FREE)
  62. for linked lists of any length (including zero).
  63. Note that the boolean
  64. .LW more_data
  65. is always initialized, but in the
  66. .LW XDR_DECODE
  67. case it is overwritten by an externally generated value.
  68. Also note that the value of the
  69. .LW bool_t
  70. is lost in the stack.
  71. The essence of the value is reflected in the list's pointers.
  72. .LP
  73. The unfortunate side effect of (de)serializing a list
  74. with these routines is that the C stack grows linearly
  75. with respect to the number of nodes in the list.
  76. This is due to the recursion.
  77. The routines are also hard to 
  78. code (and understand) due to the number and nature of primitives involved
  79. (such as
  80. .LW xdr_reference ,
  81. .LW xdr_union ,
  82. and
  83. .LW xdr_void ).
  84. .LP
  85. The following routine collapses the recursive routines.
  86. It also has other optimizations that are discussed below.
  87. .LS
  88. bool_t
  89. xdr_gnumbers_list(xdrs, glp)
  90.     XDR *xdrs;
  91.     gnumbers_list *glp;
  92. {
  93.     bool_t more_data;
  94. .sp.5
  95.     while (TRUE) {
  96.         more_data = (*glp != (gnumbers_list)NULL);
  97.         if (!xdr_bool(xdrs, &more_data))
  98.             return(FALSE);
  99.         if (!more_data)
  100.             return(TRUE);  /* we are done */
  101.         if (!xdr_reference(xdrs, glp, sizeof(struct gnnode),
  102.             xdr_gnumbers))
  103.             return(FALSE);
  104.         glp = &((*glp)->nxt); 
  105.     }
  106. }
  107. .Lf
  108. The claim is that this one routine is easier to code and understand than the
  109. three recursive routines above.
  110. (It is also buggy, as discussed below.)
  111. The parameter
  112. .LW glp
  113. is treated as the address of the pointer 
  114. to the head of the
  115. remainder of the list to be (de)serialized.
  116. Thus,
  117. .LW glp
  118. is set to the
  119. address of the current node's
  120. .LW nxt
  121. field at the end of the while loop.
  122. The discriminated union is implemented in-line; the variable
  123. .LW more_data
  124. has the same use in this routine as in the routines above.
  125. Its value is
  126. recomputed and re-(de)serialized each iteration of the loop.
  127. Since
  128. .LW *glp
  129. is a pointer to a node, the pointer is dereferenced using 
  130. .LW xdr_reference() .
  131. Note that the third parameter is truly the size of a node
  132. (data values plus
  133. .LW nxt
  134. pointer), while
  135. .LW xdr_gnumbers()
  136. only (de)serializes the data values.
  137. We can get away with this tricky optimization only because the
  138. .LW nxt
  139. data comes after all legitimate external data.
  140. .LP
  141. The routine is buggy in the
  142. .LW XDR_FREE
  143. case.  The bug is that
  144. .LW xdr_reference()
  145. will free the node
  146. .LW *glp .
  147. Upon return the assignment
  148. .LW "glp = &((*glp)->nxt)"
  149. cannot be guaranteed to work since
  150. .LW *glp
  151. is no longer a legitimate node.
  152. The following is a rewrite that works in all cases.
  153. The hard part is to avoid dereferencing a pointer
  154. which has not been initialized or which has been freed.
  155. .LS
  156. bool_t
  157. xdr_gnumbers_list(xdrs, glp)
  158.     XDR *xdrs;
  159.     gnumbers_list *glp;
  160. {
  161.     bool_t more_data;
  162.     bool_t freeing;
  163.     gnumbers_list *next;  /* the next value of glp */
  164. .sp.5
  165.     freeing = (xdrs->x_op == XDR_FREE);
  166.     while (TRUE) {
  167.         more_data = (*glp != (gnumbers_list)NULL);
  168.         if (!xdr_bool(xdrs, &more_data))
  169.             return(FALSE);
  170.         if (!more_data)
  171.             return(TRUE);  /* we are done */
  172.         if (freeing)
  173.             next = &((*glp)->nxt);
  174.         if (!xdr_reference(xdrs, glp, sizeof(struct gnnode),
  175.             xdr_gnumbers))
  176.             return(FALSE);
  177.         glp = (freeing) ? next : &((*glp)->nxt);
  178.     }
  179. }
  180. .Lf
  181. Note that this is the first example in this document
  182. that actually inspects the direction of the operation
  183. .LW xdrs->x_op ). (
  184. The claim is that the correct iterative implementation is still 
  185. easier to understand or code than the recursive implementation.
  186. It is certainly more efficient with respect to C stack requirements.
  187. .NH 2
  188. The Record Marking Standard
  189. .LP
  190. A record is composed of one or more record fragments.
  191. A record fragment is a four-byte header followed by
  192. $ 0 ~ "\fRto\fP" ~ {2 sup 31} - 1$ bytes of fragment data.
  193. The bytes encode an unsigned binary number;
  194. as with XDR integers, the byte order is from highest to lowest.
  195. The number encodes two values \(em
  196. a boolean that indicates whether the fragment is the last fragment
  197. of the record (bit value 1 implies the fragment is the last fragment),
  198. and a 31-bit unsigned binary value
  199. which is the length in bytes of the fragment's data.
  200. The boolean value is the high-order bit of the
  201. header; the length is the 31 low-order bits.
  202. .LP
  203. (Note that this record specification is
  204. .I not
  205. in XDR standard form
  206. and cannot be implemented using XDR primitives!)
  207. .\"
  208. .bp
  209. .SH
  210. Appendix A -- Synopsis of XDR Routines
  211. .LP
  212. .LW xdr_array()
  213. .LS
  214. xdr_array(xdrs, arrp, sizep, maxsize, elsize, elproc)
  215.     XDR *xdrs;
  216.     char **arrp;
  217.     u_int *sizep, maxsize, elsize;
  218.     xdrproc_t elproc;
  219. .Lf
  220. A filter primitive that translates between arrays
  221. and their corresponding external representations.
  222. The parameter
  223. .LW arrp
  224. is the address of the pointer to the array, while
  225. .LW sizep
  226. is the address of the element count of the array;
  227. this element count cannot exceed
  228. .LW maxsize .
  229. The parameter
  230. .LW elsize
  231. is the
  232. .LW sizeof()
  233. each of the array's elements, and
  234. .LW elproc
  235. is an XDR filter that translates between
  236. the array elements' C form, and their external representation.  
  237. This routine returns one if it succeeds, zero otherwise.
  238. .LP
  239. .LW xdr_bool()
  240. .LS
  241. xdr_bool(xdrs, bp)
  242.     XDR *xdrs;
  243.     bool_t *bp;
  244. .Lf
  245. A filter primitive that translates between booleans (C integers)
  246. and their external representations.
  247. When encoding data, this filter produces values of either one or zero.
  248. This routine returns one if it succeeds, zero otherwise.
  249. .LP
  250. .LW xdr_bytes()
  251. .LS
  252. xdr_bytes(xdrs, sp, sizep, maxsize)
  253.     XDR *xdrs;
  254.     char **sp;
  255.     u_int *sizep, maxsize;
  256. .Lf
  257. A filter primitive that translates between counted byte strings
  258. and their external representations.
  259. The parameter
  260. .LW sp
  261. is the address of the string pointer.
  262. The length of the string is located at address
  263. .LW sizep ;
  264. strings cannot be longer than
  265. .LW maxsize .
  266. This routine returns one if it succeeds, zero otherwise.
  267. .LP
  268. .LW xdr_destroy()
  269. .LS
  270. void
  271. xdr_destroy(xdrs)
  272.     XDR *xdrs;
  273. .Lf
  274. A macro that invokes the destroy routine
  275. associated with the XDR stream,
  276. .LW xdrs .
  277. Destruction usually involves freeing private data structures
  278. associated with the stream.  Using
  279. .LW xdrs
  280. after invoking
  281. .LW xdr_destroy()
  282. is undefined.
  283. .LP
  284. .LW xdr_double()
  285. .LS
  286. xdr_double(xdrs, dp)
  287.     XDR *xdrs;
  288.     double *dp;
  289. .Lf
  290. A filter primitive that translates between C
  291. .LW double
  292. precision numbers and their external representations.
  293. This routine returns one if it succeeds, zero otherwise.
  294. .LP
  295. .LW xdr_enum()
  296. .LS
  297. xdr_enum(xdrs, ep)
  298.     XDR *xdrs;
  299.     enum_t *ep;
  300. .Lf
  301. A filter primitive that translates between C
  302. .LW enum s
  303. (actually integers) and their external representations.
  304. This routine returns one if it succeeds, zero otherwise.
  305. .LP
  306. .LW xdr_float()
  307. .LS
  308. xdr_float(xdrs, fp)
  309.     XDR *xdrs;
  310.     float *fp;
  311. .Lf
  312. A filter primitive that translates between C
  313. .LW float s
  314. and their external representations.
  315. This routine returns one if it succeeds, zero otherwise.
  316. .LP
  317. .LW xdr_getpos()
  318. .LS
  319. u_int
  320. xdr_getpos(xdrs)
  321.     XDR *xdrs;
  322. .Lf
  323. A macro that invokes the get-position routine
  324. associated with the XDR stream,
  325. .LW xdrs .
  326. The routine returns an unsigned integer,
  327. which indicates the position of the XDR byte stream.
  328. A desirable feature of XDR streams
  329. is that simple arithmetic works with this number,
  330. although the XDR stream instances need not guarantee this.
  331. .LP
  332. .LW xdr_inline()
  333. .LS
  334. long *
  335. xdr_inline(xdrs, len)
  336.     XDR *xdrs;
  337.     int len;
  338. .Lf
  339. A macro that invokes the in-line routine associated with the XDR stream,
  340. .LW xdrs .
  341. The routine returns a pointer
  342. to a contiguous piece of the stream's buffer;
  343. .LW len
  344. is the byte length of the desired buffer.
  345. Note that the pointer is cast to
  346. .LW "long *" .
  347. Warning:
  348. .LW xdr_inline()
  349. may return 
  350. .LW NULL
  351. if it cannot allocate a contiguous piece of a buffer.
  352. Therefore the behavior may vary among stream instances;
  353. it exists for the sake of efficiency.
  354. .LP
  355. .LW xdr_int()
  356. .LS
  357. xdr_int(xdrs, ip)
  358.     XDR *xdrs;
  359.     int *ip;
  360. .Lf
  361. A filter primitive that translates between C integers
  362. and their external representations.
  363. This routine returns one if it succeeds, zero otherwise.
  364. .LP
  365. .LW xdr_long()
  366. .LS
  367. xdr_long(xdrs, lp)
  368.     XDR *xdrs;
  369.     long *lp;
  370. .Lf
  371. A filter primitive that translates between C
  372. .LW long
  373. integers and their external representations.
  374. This routine returns one if it succeeds, zero otherwise.
  375. .LP
  376. .LW xdr_opaque()
  377. .LS
  378. xdr_opaque(xdrs, cp, cnt)
  379.     XDR *xdrs;
  380.     char *cp;
  381.     u_int cnt;
  382. .Lf
  383. A filter primitive that translates between fixed size opaque data
  384. and its external representation.
  385. The parameter
  386. .LW cp
  387. is the address of the opaque object, and
  388. .LW cnt
  389. is its size in bytes.
  390. This routine returns one if it succeeds, zero otherwise.
  391. .LP
  392. .LW xdr_reference()
  393. .LS
  394. xdr_reference(xdrs, pp, size, proc)
  395.     XDR *xdrs;
  396.     char **pp;
  397.     u_int size;
  398.     xdrproc_t proc;
  399. .Lf
  400. A primitive that provides pointer chasing within structures.
  401. The parameter
  402. .LW pp
  403. is the address of the pointer;
  404. .LW size
  405. is the
  406. .LW sizeof()
  407. the structure that
  408. .LW *pp
  409. points to; and
  410. .LW proc
  411. is an XDR procedure that filters the structure
  412. between its C form and its external representation.
  413. This routine returns one if it succeeds, zero otherwise.
  414. .LP
  415. .LW xdr_setpos()
  416. .LS
  417. xdr_setpos(xdrs, pos)
  418.     XDR *xdrs;
  419.     u_int pos;
  420. .Lf
  421. A macro that invokes the set position routine associated with the XDR stream
  422. .LW xdrs .
  423. The parameter
  424. .LW pos
  425. is a position value obtained from
  426. .LW xdr_getpos() .
  427. This routine returns one if the XDR stream could be repositioned,
  428. and zero otherwise.
  429. Warning: it is difficult to reposition some types of XDR streams,
  430. so this routine may fail with one type of stream and succeed with another. 
  431. .LP
  432. .LW xdr_short()
  433. .LS
  434. xdr_short(xdrs, sp)
  435.     XDR *xdrs;
  436.     short *sp;
  437. .Lf
  438. A filter primitive that translates between C
  439. .LW short
  440. integers and their external representations.
  441. This routine returns one if it succeeds, zero otherwise.
  442. .LP
  443. .LW xdr_string()
  444. .LS
  445. xdr_string(xdrs, sp, maxsize)
  446.     XDR *xdrs;
  447.     char **sp;
  448.     u_int maxsize;
  449. .Lf
  450. A filter primitive that translates between C strings and their
  451. corresponding external representations.
  452. Strings cannot cannot be longer than
  453. .LW maxsize .
  454. Note that
  455. .LW sp
  456. is the address of the string's pointer.
  457. This routine returns one if it succeeds, zero otherwise.
  458. .LP
  459. .LW xdr_u_int()
  460. .LS
  461. xdr_u_int(xdrs, up)
  462.     XDR *xdrs;
  463.     unsigned *up;
  464. .Lf
  465. A filter primitive that translates between C
  466. .LW unsigned
  467. integers and their external representations.
  468. This routine returns one if it succeeds, zero otherwise.
  469. .LP
  470. .LW xdr_u_long()
  471. .LS
  472. xdr_u_long(xdrs, ulp)
  473.     XDR *xdrs;
  474.     unsigned long *ulp;
  475. .Lf
  476. A filter primitive that translates between C
  477. .LW "unsigned long"
  478. integers and their external representations.
  479. This routine returns one if it succeeds, zero otherwise.
  480. .LP
  481. .LW xdr_u_short()
  482. .LS
  483. xdr_u_short(xdrs, usp)
  484.     XDR *xdrs;
  485.     unsigned short *usp;
  486. .Lf
  487. A filter primitive that translates between C
  488. .LW "unsigned short"
  489. integers and their external representations.
  490. This routine returns one if it succeeds, zero otherwise.
  491. .br
  492. .ne 2i
  493. .LW xdr_union()
  494. .LS
  495. xdr_union(xdrs, dscmp, unp, choices, dfault)
  496.     XDR *xdrs;
  497.     int *dscmp;
  498.     char *unp;
  499.     struct xdr_discrim *choices;
  500.     xdrproc_t dfault;
  501. .Lf
  502. A filter primitive that translates between a discriminated C
  503. .LW union
  504. and its corresponding external representation.  The parameter 
  505. .LW dscmp
  506. is the address of the union's discriminant, while
  507. .Lunp
  508. in the address of the union.
  509. This routine returns one if it succeeds, zero otherwise.
  510. .LP
  511. .LW xdr_void()
  512. .LS
  513. xdr_void()
  514. .Lf
  515. This routine always returns one.
  516. It may be passed to RPC routines that require a function parameter,
  517. where nothing is to be done.
  518. .LP
  519. .LW xdr_wrapstring()
  520. .LS
  521. xdr_wrapstring(xdrs, sp)
  522.     XDR *xdrs;
  523.     char **sp;
  524. .Lf
  525. A primitive that calls
  526. .LW xdr_string(xdrs,sp,MAXUNSIGNED);
  527. where
  528. .LW MAXUNSIGNED
  529. is the maximum value of an unsigned integer.
  530. This is handy because the RPC package passes
  531. only two parameters XDR routines, whereas
  532. .LW xdr_string() ,
  533. one of the most frequently used primitives, requires three parameters.
  534. This routine returns one if it succeeds, zero otherwise.
  535. .LP
  536. .LW xdrmem_create()
  537. .LS
  538. void
  539. xdrmem_create(xdrs, addr, size, op)
  540.     XDR *xdrs;
  541.     char *addr;
  542.     u_int size;
  543.     enum xdr_op op;
  544. .Lf
  545. This routine initializes the XDR stream object pointed to by
  546. .LW xdrs .
  547. The stream's data is written to, or read from,
  548. a chunk of memory at location
  549. .LW addr
  550. whose length is no more than
  551. .LW size
  552. bytes long.  The
  553. .LW op
  554. determines the direction of the XDR stream
  555. (either
  556. .LW XDR_ENCODE ,
  557. .LW XDR_DECODE ,
  558. or
  559. .LW XDR_FREE ).
  560. .LP
  561. .LW xdrrec_create()
  562. .LS
  563. void
  564. xdrrec_create(xdrs,
  565.   sendsize, recvsize, handle, readit, writeit)
  566.     XDR *xdrs;
  567.     u_int sendsize, recvsize;
  568.     char *handle;
  569.     int (*readit)(), (*writeit)();
  570. .Lf
  571. This routine initializes the XDR stream object pointed to by
  572. .LW xdrs .
  573. The stream's data is written to a buffer of size
  574. .LW sendsize ;
  575. a value of zero indicates the system should use a suitable default.
  576. The stream's data is read from a buffer of size
  577. .LW recvsize ;
  578. it too can be set to a suitable default by passing a zero value.
  579. When a stream's output buffer is full,
  580. .LW writeit()
  581. is called.  Similarly, when a stream's input buffer is empty,
  582. .LW readit()
  583. is called.  The behavior of these two routines
  584. is similar to the
  585. .UX
  586. system calls
  587. .LW read
  588. and
  589. .LW write ,
  590. except that
  591. .LW handle
  592. is passed to the former routines as the first parameter.
  593. Note that the XDR stream's
  594. .LW op
  595. field must be set by the caller.
  596. Warning: this XDR stream implements an intermediate record stream.
  597. Therefore there are additional bytes in the stream
  598. to provide record boundary information.
  599. .LP
  600. .LW xdrrec_endofrecord()
  601. .LS
  602. xdrrec_endofrecord(xdrs, sendnow)
  603.     XDR *xdrs;
  604.     int sendnow;
  605. .Lf
  606. This routine can be invoked only on streams created by
  607. .LW xdrrec_create() .
  608. The data in the output buffer is marked as a completed record,
  609. and the output buffer is optionally written out if
  610. .LW sendnow
  611. is non-zero.  This routine returns one if it succeeds, zero otherwise.
  612. .LP
  613. .LW xdrrec_eof()
  614. .LS
  615. xdrrec_eof(xdrs)
  616.     XDR *xdrs;
  617.     int empty;
  618. .Lf
  619. This routine can be invoked only on streams created by
  620. .LW xdrrec_create() .
  621. After consuming the rest of the current record in the stream,
  622. this routine returns one if the stream has no more input, zero otherwise.
  623. .LP
  624. .LW xdrrec_skiprecord()
  625. .LS
  626. xdrrec_skiprecord(xdrs)
  627.     XDR *xdrs;
  628. .Lf
  629. This routine can be invoked only on streams created by
  630. .LW xdrrec_create() .
  631. It tells the XDR implementation that the rest of the current record
  632. in the stream's input buffer should be discarded.
  633. This routine returns one if it succeeds, zero otherwise.
  634. .LP
  635. .LW xdrstdio_create()
  636. .LS
  637. void
  638. xdrstdio_create(xdrs, file, op)
  639.     XDR *xdrs;
  640.     FILE *file;
  641.     enum xdr_op op;
  642. .Lf
  643. This routine initializes the XDR stream object pointed to by
  644. .LW xdrs .
  645. The XDR stream data is written to, or read from, the Standard I/O stream
  646. .LW file .
  647. The parameter
  648. .LW op
  649. determines the direction of the XDR stream (either
  650. .LW XDR_ENCODE ,
  651. .LW XDR_DECODE ,
  652. or
  653. .LW XDR_FREE ).
  654. Warning: the destroy routine associated with such XDR streams calls
  655. .LW fflush()
  656. on the
  657. .LW file
  658. stream, but never
  659. .LW fclose() . 
  660.