1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 */ 9 /* @(#)xdr.c 2.1 88/07/29 4.0 RPCSRC */ 10 /* 11 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 12 * unrestricted use provided that this legend is included on all tape 13 * media and as a part of the software program in whole or part. Users 14 * may copy or modify Sun RPC without charge, but are not authorized 15 * to license or distribute it to anyone else except as part of a product or 16 * program developed by the user. 17 * 18 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 19 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 21 * 22 * Sun RPC is provided with no support and without any obligation on the 23 * part of Sun Microsystems, Inc. to assist in its use, correction, 24 * modification or enhancement. 25 * 26 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 27 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 28 * OR ANY PART THEREOF. 29 * 30 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 31 * or profits or other special, indirect and consequential damages, even if 32 * Sun has been advised of the possibility of such damages. 33 * 34 * Sun Microsystems, Inc. 35 * 2550 Garcia Avenue 36 * Mountain View, California 94043 37 */ 38 #if !defined(lint) && defined(SCCSIDS) 39 static char sccsid[] = "@(#)xdr.c 1.35 87/08/12"; 40 #endif 41 42 /* 43 * xdr.c, Generic XDR routines implementation. 44 * 45 * Copyright (C) 1986, Sun Microsystems, Inc. 46 * 47 * These are the "generic" xdr routines used to serialize and de-serialize 48 * most common data items. See xdr.h for more info on the interface to 49 * xdr. 50 */ 51 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <rpc/types.h> 55 #include <rpc/xdr.h> 56 #include <string.h> 57 58 /* 59 * constants specific to the xdr "protocol" 60 */ 61 #define XDR_FALSE ((long) 0) 62 #define XDR_TRUE ((long) 1) 63 #define LASTUNSIGNED ((unsigned int) 0-1) 64 65 /* 66 * for unit alignment 67 */ 68 static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 }; 69 70 /* 71 * Free a data structure using XDR 72 * Not a filter, but a convenient utility nonetheless 73 */ 74 void xdr_free(xdrproc_t proc, char* objp) 75 { 76 XDR x; 77 78 x.x_op = XDR_FREE; 79 (*proc) (&x, objp); 80 } 81 82 /* 83 * XDR nothing 84 */ 85 bool_t xdr_void( /* xdrs, addr */ ) 86 /* XDR *xdrs; */ 87 /* char* addr; */ 88 { 89 90 return (TRUE); 91 } 92 93 /* 94 * XDR integers 95 */ 96 bool_t xdr_int(XDR* xdrs, int* ip) 97 { 98 if (sizeof(int) == sizeof(long)) { 99 return (xdr_long(xdrs, (long *) ip)); 100 } else if (sizeof(int) < sizeof(long)) { 101 long l; 102 switch (xdrs->x_op) { 103 case XDR_ENCODE: 104 l = (long) *ip; 105 return XDR_PUTLONG(xdrs, &l); 106 case XDR_DECODE: 107 if (!XDR_GETLONG(xdrs, &l)) 108 return FALSE; 109 *ip = (int) l; 110 case XDR_FREE: 111 return TRUE; 112 } 113 return FALSE; 114 } else { 115 return (xdr_short(xdrs, (short *) ip)); 116 } 117 } 118 119 /* 120 * XDR unsigned integers 121 */ 122 bool_t xdr_u_int(XDR* xdrs, unsigned int* up) 123 { 124 if (sizeof(unsigned int) == sizeof(unsigned long)) { 125 return (xdr_u_long(xdrs, (unsigned long *) up)); 126 } else if (sizeof(unsigned int) < sizeof(unsigned long)) { 127 unsigned long l; 128 switch (xdrs->x_op) { 129 case XDR_ENCODE: 130 l = (unsigned long) *up; 131 return XDR_PUTLONG(xdrs, (long*)&l); 132 case XDR_DECODE: 133 if (!XDR_GETLONG(xdrs, (long*)&l)) 134 return FALSE; 135 *up = (unsigned int) l; 136 case XDR_FREE: 137 return TRUE; 138 } 139 return FALSE; 140 } else { 141 return (xdr_short(xdrs, (short *) up)); 142 } 143 } 144 145 /* 146 * XDR long integers 147 * same as xdr_u_long - open coded to save a proc call! 148 */ 149 bool_t xdr_long(XDR* xdrs, long* lp) 150 { 151 152 if (xdrs->x_op == XDR_ENCODE 153 && (sizeof(int32_t) == sizeof(long) 154 || (int32_t) *lp == *lp)) 155 return (XDR_PUTLONG(xdrs, lp)); 156 157 if (xdrs->x_op == XDR_DECODE) 158 return (XDR_GETLONG(xdrs, lp)); 159 160 if (xdrs->x_op == XDR_FREE) 161 return (TRUE); 162 163 return (FALSE); 164 } 165 166 /* 167 * XDR unsigned long integers 168 * same as xdr_long - open coded to save a proc call! 169 */ 170 bool_t xdr_u_long(XDR* xdrs, unsigned long* ulp) 171 { 172 173 if (xdrs->x_op == XDR_DECODE) { 174 long l; 175 if (XDR_GETLONG(xdrs, &l) == FALSE) 176 return FALSE; 177 *ulp = (uint32_t) l; 178 return TRUE; 179 } 180 181 if (xdrs->x_op == XDR_ENCODE) { 182 if (sizeof(uint32_t) != sizeof(unsigned long) 183 && (uint32_t) *ulp != *ulp) 184 return FALSE; 185 186 return (XDR_PUTLONG(xdrs, (long *) ulp)); 187 } 188 189 if (xdrs->x_op == XDR_FREE) 190 return (TRUE); 191 192 return (FALSE); 193 } 194 195 196 /* 197 * XDR long long integers 198 */ 199 bool_t xdr_longlong_t (XDR * xdrs, long long* llp) 200 { 201 int32_t t1, t2; 202 203 switch (xdrs->x_op) 204 { 205 case XDR_ENCODE: 206 t1 = (int32_t) ((*llp) >> 32); 207 t2 = (int32_t) (*llp); 208 return (XDR_PUTLONG (xdrs, &t1) && XDR_PUTLONG (xdrs, &t2)); 209 210 case XDR_DECODE: 211 if (!XDR_GETLONG (xdrs, &t1) || !XDR_GETLONG (xdrs, &t2)) 212 return FALSE; 213 *llp = ((int64_t) t1) << 32; 214 *llp |= (uint32_t) t2; 215 return TRUE; 216 217 case XDR_FREE: 218 return TRUE; 219 } 220 return FALSE; 221 } 222 223 /* 224 * XDR unsigned long long integers 225 */ 226 bool_t xdr_u_longlong_t (XDR * xdrs, unsigned long long* ullp) 227 { 228 uint32_t t1, t2; 229 230 switch (xdrs->x_op) 231 { 232 case XDR_ENCODE: 233 t1 = (uint32_t) ((*ullp) >> 32); 234 t2 = (uint32_t) (*ullp); 235 return (XDR_PUTLONG (xdrs, (int32_t *)&t1) && 236 XDR_PUTLONG (xdrs, (int32_t *)&t2)); 237 238 case XDR_DECODE: 239 if (!XDR_GETLONG (xdrs, (int32_t *)&t1) || 240 !XDR_GETLONG (xdrs, (int32_t *)&t2)) 241 return FALSE; 242 *ullp = ((uint64_t) t1) << 32; 243 *ullp |= t2; 244 return TRUE; 245 246 case XDR_FREE: 247 return TRUE; 248 } 249 return FALSE; 250 } 251 252 /* 253 * XDR short integers 254 */ 255 bool_t xdr_short(XDR* xdrs, short* sp) 256 { 257 long l; 258 259 switch (xdrs->x_op) { 260 261 case XDR_ENCODE: 262 l = (long) *sp; 263 return (XDR_PUTLONG(xdrs, &l)); 264 265 case XDR_DECODE: 266 if (!XDR_GETLONG(xdrs, &l)) { 267 return (FALSE); 268 } 269 *sp = (short) l; 270 return (TRUE); 271 272 case XDR_FREE: 273 return (TRUE); 274 } 275 return (FALSE); 276 } 277 278 /* 279 * XDR unsigned short integers 280 */ 281 bool_t xdr_u_short(XDR* xdrs, unsigned short* usp) 282 { 283 unsigned long l; 284 285 switch (xdrs->x_op) { 286 287 case XDR_ENCODE: 288 l = (unsigned long) * usp; 289 return (XDR_PUTLONG(xdrs, (long*)&l)); 290 291 case XDR_DECODE: 292 if (!XDR_GETLONG(xdrs, (long*)&l)) { 293 return (FALSE); 294 } 295 *usp = (unsigned short) l; 296 return (TRUE); 297 298 case XDR_FREE: 299 return (TRUE); 300 } 301 return (FALSE); 302 } 303 304 305 /* 306 * XDR a char 307 */ 308 bool_t xdr_char(XDR* xdrs, char* cp) 309 { 310 int i; 311 312 i = (*cp); 313 if (!xdr_int(xdrs, &i)) { 314 return (FALSE); 315 } 316 *cp = i; 317 return (TRUE); 318 } 319 320 /* 321 * XDR an unsigned char 322 */ 323 bool_t xdr_u_char(XDR* xdrs, unsigned char* cp) 324 { 325 unsigned int u; 326 327 u = (*cp); 328 if (!xdr_u_int(xdrs, &u)) { 329 return (FALSE); 330 } 331 *cp = u; 332 return (TRUE); 333 } 334 335 /* 336 * XDR booleans 337 */ 338 bool_t xdr_bool(XDR *xdrs, bool_t *bp) 339 { 340 long lb; 341 342 switch (xdrs->x_op) { 343 344 case XDR_ENCODE: 345 lb = *bp ? XDR_TRUE : XDR_FALSE; 346 return (XDR_PUTLONG(xdrs, &lb)); 347 348 case XDR_DECODE: 349 if (!XDR_GETLONG(xdrs, &lb)) { 350 return (FALSE); 351 } 352 *bp = (lb == XDR_FALSE) ? FALSE : TRUE; 353 return (TRUE); 354 355 case XDR_FREE: 356 return (TRUE); 357 } 358 return (FALSE); 359 } 360 361 /* 362 * XDR enumerations 363 */ 364 bool_t xdr_enum(XDR *xdrs, enum_t *ep) 365 { 366 /* 367 * enums are treated as ints 368 */ 369 return (xdr_long(xdrs, (long *) ep)); 370 } 371 372 /* 373 * XDR opaque data 374 * Allows the specification of a fixed size sequence of opaque bytes. 375 * cp points to the opaque object and cnt gives the byte length. 376 */ 377 bool_t xdr_opaque(XDR *xdrs, char* cp, unsigned int cnt) 378 { 379 register unsigned int rndup; 380 static char crud[BYTES_PER_XDR_UNIT]; 381 382 /* 383 * if no data we are done 384 */ 385 if (cnt == 0) 386 return (TRUE); 387 388 /* 389 * round byte count to full xdr units 390 */ 391 rndup = cnt % BYTES_PER_XDR_UNIT; 392 if (rndup > 0) 393 rndup = BYTES_PER_XDR_UNIT - rndup; 394 395 if (xdrs->x_op == XDR_DECODE) { 396 if (!XDR_GETBYTES(xdrs, cp, cnt)) { 397 return (FALSE); 398 } 399 if (rndup == 0) 400 return (TRUE); 401 return (XDR_GETBYTES(xdrs, crud, rndup)); 402 } 403 404 if (xdrs->x_op == XDR_ENCODE) { 405 if (!XDR_PUTBYTES(xdrs, cp, cnt)) { 406 return (FALSE); 407 } 408 if (rndup == 0) 409 return (TRUE); 410 return (XDR_PUTBYTES(xdrs, xdr_zero, rndup)); 411 } 412 413 if (xdrs->x_op == XDR_FREE) { 414 return (TRUE); 415 } 416 417 return (FALSE); 418 } 419 420 /* 421 * XDR counted bytes 422 * *cpp is a pointer to the bytes, *sizep is the count. 423 * If *cpp is NULL maxsize bytes are allocated 424 */ 425 bool_t xdr_bytes(XDR *xdrs, char** cpp, unsigned int *sizep, unsigned int maxsize) 426 { 427 register char *sp = *cpp; /* sp is the actual string pointer */ 428 register unsigned int nodesize; 429 430 /* 431 * first deal with the length since xdr bytes are counted 432 */ 433 if (!xdr_u_int(xdrs, sizep)) { 434 return (FALSE); 435 } 436 nodesize = *sizep; 437 if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { 438 return (FALSE); 439 } 440 441 /* 442 * now deal with the actual bytes 443 */ 444 switch (xdrs->x_op) { 445 446 case XDR_DECODE: 447 if (nodesize == 0) { 448 return (TRUE); 449 } 450 if (sp == NULL) { 451 *cpp = sp = (char *) rt_malloc(nodesize); 452 } 453 if (sp == NULL) { 454 rt_kprintf("xdr_bytes: out of memory\n"); 455 return (FALSE); 456 } 457 /* fall into ... */ 458 459 case XDR_ENCODE: 460 return (xdr_opaque(xdrs, sp, nodesize)); 461 462 case XDR_FREE: 463 if (sp != NULL) { 464 rt_free(sp); 465 *cpp = NULL; 466 } 467 return (TRUE); 468 } 469 return (FALSE); 470 } 471 472 /* 473 * Implemented here due to commonality of the object. 474 */ 475 bool_t xdr_netobj(XDR *xdrs, struct netobj *np) 476 { 477 return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ)); 478 } 479 480 /* 481 * XDR a descriminated union 482 * Support routine for discriminated unions. 483 * You create an array of xdrdiscrim structures, terminated with 484 * an entry with a null procedure pointer. The routine gets 485 * the discriminant value and then searches the array of xdrdiscrims 486 * looking for that value. It calls the procedure given in the xdrdiscrim 487 * to handle the discriminant. If there is no specific routine a default 488 * routine may be called. 489 * If there is no specific or default routine an error is returned. 490 */ 491 bool_t xdr_union(XDR* xdrs, enum_t* dscmp, char* unp, const struct xdr_discrim* choices, xdrproc_t dfault) 492 { 493 register enum_t dscm; 494 495 /* 496 * we deal with the discriminator; it's an enum 497 */ 498 if (!xdr_enum(xdrs, dscmp)) { 499 return (FALSE); 500 } 501 dscm = *dscmp; 502 503 /* 504 * search choices for a value that matches the discriminator. 505 * if we find one, execute the xdr routine for that value. 506 */ 507 for (; choices->proc != NULL_xdrproc_t; choices++) { 508 if (choices->value == dscm) 509 return ((*(choices->proc)) (xdrs, unp, LASTUNSIGNED)); 510 } 511 512 /* 513 * no match - execute the default xdr routine if there is one 514 */ 515 return ((dfault == NULL_xdrproc_t) ? FALSE : 516 (*dfault) (xdrs, unp, LASTUNSIGNED)); 517 } 518 519 520 /* 521 * Non-portable xdr primitives. 522 * Care should be taken when moving these routines to new architectures. 523 */ 524 525 526 /* 527 * XDR null terminated ASCII strings 528 * xdr_string deals with "C strings" - arrays of bytes that are 529 * terminated by a NULL character. The parameter cpp references a 530 * pointer to storage; If the pointer is null, then the necessary 531 * storage is allocated. The last parameter is the max allowed length 532 * of the string as specified by a protocol. 533 */ 534 bool_t xdr_string(XDR *xdrs, char **cpp, unsigned int maxsize) 535 { 536 register char *sp = *cpp; /* sp is the actual string pointer */ 537 unsigned int size; 538 unsigned int nodesize; 539 540 /* 541 * first deal with the length since xdr strings are counted-strings 542 */ 543 switch (xdrs->x_op) { 544 case XDR_FREE: 545 if (sp == NULL) { 546 return (TRUE); /* already free */ 547 } 548 /* fall through... */ 549 case XDR_ENCODE: 550 size = strlen(sp); 551 break; 552 } 553 if (!xdr_u_int(xdrs, &size)) { 554 return (FALSE); 555 } 556 if (size > maxsize) { 557 return (FALSE); 558 } 559 nodesize = size + 1; 560 561 /* 562 * now deal with the actual bytes 563 */ 564 switch (xdrs->x_op) { 565 566 case XDR_DECODE: 567 if (nodesize == 0) { 568 return (TRUE); 569 } 570 if (sp == NULL) 571 *cpp = sp = (char *) rt_malloc(nodesize); 572 if (sp == NULL) { 573 rt_kprintf("xdr_string: out of memory\n"); 574 return (FALSE); 575 } 576 sp[size] = 0; 577 /* fall into ... */ 578 579 case XDR_ENCODE: 580 return (xdr_opaque(xdrs, sp, size)); 581 582 case XDR_FREE: 583 rt_free(sp); 584 *cpp = NULL; 585 return (TRUE); 586 } 587 return (FALSE); 588 } 589 590 /* 591 * Wrapper for xdr_string that can be called directly from 592 * routines like clnt_call 593 */ 594 bool_t xdr_wrapstring(XDR *xdrs, char **cpp) 595 { 596 if (xdr_string(xdrs, cpp, LASTUNSIGNED)) { 597 return (TRUE); 598 } 599 return (FALSE); 600 } 601 602 /* 603 * XDR an array of arbitrary elements 604 * *addrp is a pointer to the array, *sizep is the number of elements. 605 * If addrp is NULL (*sizep * elsize) bytes are allocated. 606 * elsize is the size (in bytes) of each element, and elproc is the 607 * xdr procedure to call to handle each element of the array. 608 */ 609 bool_t xdr_array(XDR *xdrs, char **addrp, unsigned int *sizep, unsigned int maxsize, unsigned int elsize, xdrproc_t elproc) 610 { 611 register unsigned int i; 612 register char* target = *addrp; 613 register unsigned int c; /* the actual element count */ 614 register bool_t stat = TRUE; 615 register unsigned int nodesize; 616 617 /* like strings, arrays are really counted arrays */ 618 if (!xdr_u_int(xdrs, sizep)) { 619 return (FALSE); 620 } 621 c = *sizep; 622 if ((c > maxsize) && (xdrs->x_op != XDR_FREE)) { 623 return (FALSE); 624 } 625 /* duh, look for integer overflow (fefe) */ 626 { 627 unsigned int i; 628 nodesize = 0; 629 for (i=c; i; --i) { 630 unsigned int tmp=nodesize+elsize; 631 if (tmp<nodesize) /* overflow */ 632 return FALSE; 633 nodesize=tmp; 634 } 635 } 636 637 /* 638 * if we are deserializing, we may need to allocate an array. 639 * We also save time by checking for a null array if we are freeing. 640 */ 641 if (target == NULL) 642 switch (xdrs->x_op) { 643 case XDR_DECODE: 644 if (c == 0) 645 return (TRUE); 646 *addrp = target = rt_malloc(nodesize); 647 if (target == NULL) { 648 rt_kprintf("xdr_array: out of memory\n"); 649 return (FALSE); 650 } 651 memset(target, 0, nodesize); 652 break; 653 654 case XDR_FREE: 655 return (TRUE); 656 } 657 658 /* 659 * now we xdr each element of array 660 */ 661 for (i = 0; (i < c) && stat; i++) { 662 stat = (*elproc) (xdrs, target, LASTUNSIGNED); 663 target += elsize; 664 } 665 666 /* 667 * the array may need freeing 668 */ 669 if (xdrs->x_op == XDR_FREE) { 670 rt_free(*addrp); 671 *addrp = NULL; 672 } 673 return (stat); 674 } 675 676 /* 677 * xdr_vector(): 678 * 679 * XDR a fixed length array. Unlike variable-length arrays, 680 * the storage of fixed length arrays is static and unfreeable. 681 * > basep: base of the array 682 * > size: size of the array 683 * > elemsize: size of each element 684 * > xdr_elem: routine to XDR each element 685 */ 686 bool_t xdr_vector(XDR *xdrs, char *basep, unsigned int nelem, unsigned int elemsize, xdrproc_t xdr_elem) 687 { 688 register unsigned int i; 689 register char *elptr; 690 691 elptr = basep; 692 for (i = 0; i < nelem; i++) { 693 if (!(*xdr_elem) (xdrs, elptr, LASTUNSIGNED)) { 694 return (FALSE); 695 } 696 elptr += elemsize; 697 } 698 return (TRUE); 699 } 700 701 702 /* 703 * XDR an indirect pointer 704 * xdr_reference is for recursively translating a structure that is 705 * referenced by a pointer inside the structure that is currently being 706 * translated. pp references a pointer to storage. If *pp is null 707 * the necessary storage is allocated. 708 * size is the sizeof the referneced structure. 709 * proc is the routine to handle the referenced structure. 710 */ 711 bool_t xdr_reference(XDR *xdrs, char **pp, unsigned int size, xdrproc_t proc) 712 { 713 register char* loc = *pp; 714 register bool_t stat; 715 716 if (loc == NULL) 717 switch (xdrs->x_op) { 718 case XDR_FREE: 719 return (TRUE); 720 721 case XDR_DECODE: 722 *pp = loc = (char*) rt_malloc(size); 723 if (loc == NULL) { 724 rt_kprintf("xdr_reference: out of memory\n"); 725 return (FALSE); 726 } 727 memset(loc, 0, (int) size); 728 break; 729 } 730 731 stat = (*proc) (xdrs, loc, LASTUNSIGNED); 732 733 if (xdrs->x_op == XDR_FREE) { 734 rt_free(loc); 735 *pp = NULL; 736 } 737 return (stat); 738 } 739 740 741 /* 742 * xdr_pointer(): 743 * 744 * XDR a pointer to a possibly recursive data structure. This 745 * differs with xdr_reference in that it can serialize/deserialiaze 746 * trees correctly. 747 * 748 * What's sent is actually a union: 749 * 750 * union object_pointer switch (boolean b) { 751 * case TRUE: object_data data; 752 * case FALSE: void nothing; 753 * } 754 * 755 * > objpp: Pointer to the pointer to the object. 756 * > obj_size: size of the object. 757 * > xdr_obj: routine to XDR an object. 758 * 759 */ 760 bool_t xdr_pointer(XDR *xdrs, char **objpp, unsigned int obj_size, xdrproc_t xdr_obj) 761 { 762 763 bool_t more_data; 764 765 more_data = (*objpp != NULL); 766 if (!xdr_bool(xdrs, &more_data)) { 767 return (FALSE); 768 } 769 if (!more_data) { 770 *objpp = NULL; 771 return (TRUE); 772 } 773 return (xdr_reference(xdrs, objpp, obj_size, xdr_obj)); 774 } 775