X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Fpdu.c;h=276515e64ea5c5b6e2493965a4376d4d3254b2e0;hb=ac559609a3893e80cd7390f0c6c9ab10ae1ca635;hp=3427446319d2a8f47b51c26fa8a1453fe9dec75b;hpb=1896d37bfaae78bfa0e6ee3e3fb19b0a92bb1adb;p=deb_libnfs.git diff --git a/lib/pdu.c b/lib/pdu.c index 3427446..276515e 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -14,10 +14,18 @@ You should have received a copy of the GNU Lesser General Public License along with this program; if not, see . */ +#ifdef WIN32 +#include "win32_compat.h" +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif +#else +#include +#endif/*WIN32*/ #include -#include #include +#include #include #include #include @@ -40,7 +48,7 @@ struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int versi rpc_set_error(rpc, "Out of memory: Failed to allocate pdu structure"); return NULL; } - bzero(pdu, sizeof(struct rpc_pdu)); + memset(pdu, 0, sizeof(struct rpc_pdu)); pdu->xid = rpc->xid++; pdu->cb = cb; pdu->private_data = private_data; @@ -48,9 +56,11 @@ struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int versi pdu->xdr_decode_bufsize = xdr_decode_bufsize; xdrmem_create(&pdu->xdr, rpc->encodebuf, rpc->encodebuflen, XDR_ENCODE); - xdr_setpos(&pdu->xdr, 4); /* skip past the record marker */ + if (rpc->is_udp == 0) { + xdr_setpos(&pdu->xdr, 4); /* skip past the record marker */ + } - bzero(&msg, sizeof(struct rpc_msg)); + memset(&msg, 0, sizeof(struct rpc_msg)); msg.rm_xid = pdu->xid; msg.rm_direction = CALL; msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; @@ -84,6 +94,7 @@ void rpc_free_pdu(struct rpc_context *rpc _U_, struct rpc_pdu *pdu) } xdr_destroy(&pdu->xdr); + free(pdu); } @@ -94,6 +105,17 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu) size = xdr_getpos(&pdu->xdr); + /* for udp we dont queue, we just send it straight away */ + if (rpc->is_udp != 0) { + if (sendto(rpc->fd, rpc->encodebuf, size, MSG_DONTWAIT, rpc->udp_dest, sizeof(struct sockaddr_in)) < 0) { + rpc_set_error(rpc, "Sendto failed with errno %s", strerror(errno)); + rpc_free_pdu(rpc, pdu); + return -1; + } + SLIST_ADD_END(&rpc->waitpdu, pdu); + return 0; + } + /* write recordmarker */ xdr_setpos(&pdu->xdr, 0); recordmarker = (size - 4) | 0x80000000; @@ -119,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; } @@ -131,16 +148,19 @@ static int rpc_process_reply(struct rpc_context *rpc, struct rpc_pdu *pdu, XDR * { struct rpc_msg msg; - bzero(&msg, sizeof(struct rpc_msg)); + memset(&msg, 0, sizeof(struct rpc_msg)); msg.acpted_rply.ar_verf = _null_auth; if (pdu->xdr_decode_bufsize > 0) { + if (pdu->xdr_decode_buf != NULL) { + free(pdu->xdr_decode_buf); + } pdu->xdr_decode_buf = malloc(pdu->xdr_decode_bufsize); if (pdu->xdr_decode_buf == NULL) { rpc_set_error(rpc, "xdr_replymsg failed in portmap_getport_reply"); pdu->cb(rpc, RPC_STATUS_ERROR, "Failed to allocate buffer for decoding of XDR reply", pdu->private_data); return 0; } - bzero(pdu->xdr_decode_buf, pdu->xdr_decode_bufsize); + memset(pdu->xdr_decode_buf, 0, pdu->xdr_decode_bufsize); } msg.acpted_rply.ar_results.where = pdu->xdr_decode_buf; msg.acpted_rply.ar_results.proc = pdu->xdr_decode_fn; @@ -189,21 +209,63 @@ 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; - bzero(&xdr, sizeof(XDR)); + memset(&xdr, 0, sizeof(XDR)); xdrmem_create(&xdr, buf, size, XDR_DECODE); - if (xdr_int(&xdr, &recordmarker) == 0) { - rpc_set_error(rpc, "xdr_int reading recordmarker failed"); + if (rpc->is_udp == 0) { + if (xdr_int(&xdr, &recordmarker) == 0) { + rpc_set_error(rpc, "xdr_int reading recordmarker failed"); + 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); - return -1; + 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); @@ -212,16 +274,26 @@ int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size) if (pdu->xid != xid) { continue; } - SLIST_REMOVE(&rpc->waitpdu, pdu); + if (rpc->is_udp == 0 || rpc->is_broadcast == 0) { + SLIST_REMOVE(&rpc->waitpdu, pdu); + } if (rpc_process_reply(rpc, pdu, &xdr) != 0) { rpc_set_error(rpc, "rpc_procdess_reply failed"); } xdr_destroy(&xdr); - rpc_free_pdu(rpc, pdu); + 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; }