1/** 2 * \file 3 * \brief XDR implementation using LWIP PBuf structures 4 * 5 * Uses standard XDR structure. Private fields in XDR are used as follows: 6 * * x_private points to the first struct pbuf in a pbuf chain 7 * * x_base points to the current struct pbuf in a pbuf chain 8 * * x_handy is the position (offset) _within the current pbuf_ 9 */ 10 11/* 12 * Copyright (c) 2008, ETH Zurich. 13 * All rights reserved. 14 * 15 * This file is distributed under the terms in the attached LICENSE file. 16 * If you do not find this file, copies can be found by writing to: 17 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 18 */ 19 20#include <assert.h> 21#include <nfs/xdr.h> 22#include "xdr_pbuf.h" 23#include <net_sockets/net_sockets.h> 24 25/* make space within the buffer, returns NULL if it won't fit */ 26static inline int32_t *make_space(XDR *xdr, size_t size) 27{ 28 if (xdr->x_handy + size > xdr->size) { 29 fprintf(stderr, "xdr_pbuf: make_space(%zu) failing (%zu available)\n", 30 size, xdr->size - (size_t)xdr->x_handy); 31 return NULL; 32 } else { 33 int32_t *ret = (int32_t *)((char *)xdr->x_base + xdr->x_handy); 34 xdr->x_handy += size; 35 return ret; 36 } 37} 38 39/* get a word from underlying stream */ 40static bool xdr_pbuf_getint32(XDR *xdr, int32_t *ret) 41{ 42 int32_t *buf = make_space(xdr, sizeof(int32_t)); 43 if (buf) { 44 *ret = ntohl((uint32_t)*buf); 45 return true; 46 } else { 47 return false; 48 } 49} 50 51/* put a word to underlying stream */ 52static bool xdr_pbuf_putint32(XDR *xdr, const int32_t *val) 53{ 54 int32_t *buf = make_space(xdr, sizeof(int32_t)); 55 if (buf) { 56 *buf = htonl((uint32_t)(*val)); 57 return true; 58 } else { 59 return false; 60 } 61} 62 63/* common implementation of getbytes and putbytes */ 64static bool movebytes(bool copyin, XDR *xdr, char *callerbuf, size_t nbytes) 65{ 66 while (nbytes > 0) { 67 size_t space = xdr->size - xdr->x_handy; 68 if (space > nbytes) { 69 space = nbytes; 70 } 71 int32_t *buf = make_space(xdr, space); 72 assert(buf != NULL); 73 if (copyin) { 74 memcpy(buf, callerbuf, space); 75 } else { 76 memcpy(callerbuf, buf, space); 77 } 78 nbytes -= space; 79 callerbuf += space; 80 } 81 return true; 82} 83 84/* get some bytes from underlying stream */ 85static bool xdr_pbuf_getbytes(XDR *xdr, char *retbuf, size_t nbytes) 86{ 87 return movebytes(false, xdr, retbuf, nbytes); 88} 89 90/* put some bytes to underlying stream */ 91static bool xdr_pbuf_putbytes(XDR *xdr, const char *inbuf, size_t nbytes) 92{ 93 return movebytes(true, xdr, (char *)inbuf, nbytes); 94} 95 96/* returns bytes off from beginning */ 97static size_t xdr_pbuf_getpostn(XDR *xdr) 98{ 99 return xdr->x_handy; 100} 101 102/* lets you reposition the stream */ 103static bool xdr_pbuf_setpostn(XDR *xdr, size_t pos) 104{ 105 if (pos > xdr->size) { 106 return false; 107 } else { 108 xdr->x_base = xdr->x_private; 109 xdr->x_handy = pos; 110 return true; 111 } 112} 113 114/* buf quick ptr to buffered data */ 115static int32_t *xdr_pbuf_inline(XDR *xdr, size_t nbytes) 116{ 117 assert(nbytes % BYTES_PER_XDR_UNIT == 0); 118 return make_space(xdr, nbytes); 119} 120 121/* free privates of this xdr_stream */ 122static void xdr_pbuf_destroy(XDR *xdr) 123{ 124 net_free(xdr->x_private); 125} 126 127/// XDR operations table 128static struct xdr_ops xdr_pbuf_ops = { 129 .x_getint32 = xdr_pbuf_getint32, 130 .x_putint32 = xdr_pbuf_putint32, 131 .x_getbytes = xdr_pbuf_getbytes, 132 .x_putbytes = xdr_pbuf_putbytes, 133 .x_getpostn = xdr_pbuf_getpostn, 134 .x_setpostn = xdr_pbuf_setpostn, 135 .x_inline = xdr_pbuf_inline, 136 .x_destroy = xdr_pbuf_destroy, 137}; 138 139/** 140 * \brief Create XDR and allocate PBUF for serialising data 141 * 142 * \param xdr Memory for XDR struct, to be initialised 143 * \param size Size of pbuf buffers to allocate 144 * 145 * \returns True on success, false on error 146 */ 147bool xdr_create_send(XDR *xdr, size_t size) 148{ 149 assert(xdr != NULL); 150 assert(size % BYTES_PER_XDR_UNIT == 0); 151 xdr->x_base = xdr->x_private = net_alloc(size); 152 xdr->size = size; 153 assert(xdr->x_private); 154 xdr->x_op = XDR_ENCODE; 155 xdr->x_ops = &xdr_pbuf_ops; 156 xdr->x_handy = 0; 157 return true; 158} 159 160/** 161 * \brief Create XDR for deserialising data in given PBUF 162 * 163 * \param xdr Memory for XDR struct, to be initialised 164 * \param pbuf LWIP packet buffer pointer 165 * 166 * \returns True on success, false on error 167 */ 168void xdr_create_recv(XDR *xdr, void *data, size_t size) 169{ 170 assert(xdr != NULL); 171 assert(size % BYTES_PER_XDR_UNIT == 0); 172 xdr->x_base = xdr->x_private = data; 173 xdr->size = size; 174 assert(xdr->x_private); 175 memcpy(xdr->x_private, data, size); 176 xdr->x_op = XDR_DECODE; 177 xdr->x_ops = &xdr_pbuf_ops; 178 xdr->x_handy = 0; 179} 180