X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Fpdu.c;h=276515e64ea5c5b6e2493965a4376d4d3254b2e0;hb=f314b3df7df086ced6ffb18e03db900ad2ea5567;hp=64a4af8e2eb68562d964096f8b8be194f9236cd9;hpb=ea98629aef9428ca270a76b77e8de49e523be0e4;p=deb_libnfs.git diff --git a/lib/pdu.c b/lib/pdu.c index 64a4af8..276515e 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -14,13 +14,14 @@ You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ - -#if defined(WIN32) -#include +#ifdef WIN32 +#include "win32_compat.h" +#ifndef MSG_DONTWAIT #define MSG_DONTWAIT 0 +#endif #else #include -#endif +#endif/*WIN32*/ #include #include @@ -140,11 +141,6 @@ int rpc_get_pdu_size(char *buf) size = ntohl(*(uint32_t *)buf); - if ((size & 0x80000000) == 0) { - /* cant handle oncrpc fragments */ - return -1; - } - return (size & 0x7fffffff) + 4; } @@ -213,8 +209,9 @@ int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size) { struct rpc_pdu *pdu; XDR xdr; - int pos, recordmarker; + int pos, recordmarker = 0; unsigned int xid; + char *reasbuf = NULL; memset(&xdr, 0, sizeof(XDR)); @@ -225,11 +222,50 @@ int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size) xdr_destroy(&xdr); return -1; } + if (!(recordmarker&0x80000000)) { + xdr_destroy(&xdr); + if (rpc_add_fragment(rpc, buf+4, size-4) != 0) { + rpc_set_error(rpc, "Failed to queue fragment for reassembly."); + return -1; + } + return 0; + } + } + + /* reassembly */ + if (recordmarker != 0 && rpc->fragments != NULL) { + struct rpc_fragment *fragment; + uint64_t total = size - 4; + char *ptr; + + xdr_destroy(&xdr); + for (fragment = rpc->fragments; fragment; fragment = fragment->next) { + total += fragment->size; + } + + reasbuf = malloc(total); + if (reasbuf == NULL) { + rpc_set_error(rpc, "Failed to reassemble PDU"); + rpc_free_all_fragments(rpc); + return -1; + } + ptr = reasbuf; + for (fragment = rpc->fragments; fragment; fragment = fragment->next) { + memcpy(ptr, fragment->data, fragment->size); + ptr += fragment->size; + } + memcpy(ptr, buf + 4, size - 4); + xdrmem_create(&xdr, reasbuf, total, XDR_DECODE); + rpc_free_all_fragments(rpc); } + pos = xdr_getpos(&xdr); if (xdr_int(&xdr, (int *)&xid) == 0) { rpc_set_error(rpc, "xdr_int reading xid failed"); xdr_destroy(&xdr); + if (reasbuf != NULL) { + free(reasbuf); + } return -1; } xdr_setpos(&xdr, pos); @@ -248,10 +284,16 @@ int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size) if (rpc->is_udp == 0 || rpc->is_broadcast == 0) { rpc_free_pdu(rpc, pdu); } + if (reasbuf != NULL) { + free(reasbuf); + } return 0; } rpc_set_error(rpc, "No matching pdu found for xid:%d", xid); xdr_destroy(&xdr); + if (reasbuf != NULL) { + free(reasbuf); + } return -1; }