static bool_t Svctcp_reply(SVCXPRT * xprt, register struct rpc_msg *msg) { register struct tcp_conn *cd = (struct tcp_conn *)(xprt->xp_p1); register XDR *xdrs = &(cd->xdrs); xdrproc_t xdr_proc; caddr_t xdr_where; xdrs->x_op = XDR_ENCODE; msg->rm_xid = cd->x_id; if(msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { xdr_proc = msg->acpted_rply.ar_results.proc; xdr_where = msg->acpted_rply.ar_results.where; msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; msg->acpted_rply.ar_results.where = NULL; if(!xdr_replymsg(xdrs, msg) || !SVCAUTH_WRAP(NULL, xdrs, xdr_proc, xdr_where)) return (FALSE); } else if(!xdr_replymsg(xdrs, msg)) { return (FALSE); } (void)xdrrec_endofrecord(xdrs, TRUE); return (TRUE); }
static bool_t svc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg, struct sockaddr *addr, struct mbuf *m, uint32_t *seq) { struct ct_data *ct; XDR xdrs; struct mbuf *mrep; bool_t stat = TRUE; int error; /* * Leave space for record mark. */ mrep = m_gethdr(M_WAITOK, MT_DATA); mrep->m_data += sizeof(uint32_t); xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { if (!xdr_replymsg(&xdrs, msg)) stat = FALSE; else xdrmbuf_append(&xdrs, m); } else { stat = xdr_replymsg(&xdrs, msg); } if (stat) { m_fixhdr(mrep); /* * Prepend a record marker containing the reply length. */ M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); *mtod(mrep, uint32_t *) = htonl(0x80000000 | (mrep->m_pkthdr.len - sizeof(uint32_t))); sx_xlock(&xprt->xp_lock); ct = (struct ct_data *)xprt->xp_p2; if (ct != NULL) error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL, 0, curthread); else error = EPIPE; sx_xunlock(&xprt->xp_lock); if (!error) { stat = TRUE; } } else { m_freem(mrep); } XDR_DESTROY(&xdrs); return (stat); }
static bool_t svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg, struct sockaddr *addr, struct mbuf *m, uint32_t *seq) { XDR xdrs; struct mbuf *mrep; bool_t stat = TRUE; int error, len; /* * Leave space for record mark. */ mrep = m_gethdr(M_WAITOK, MT_DATA); mrep->m_data += sizeof(uint32_t); xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { if (!xdr_replymsg(&xdrs, msg)) stat = FALSE; else xdrmbuf_append(&xdrs, m); } else { stat = xdr_replymsg(&xdrs, msg); } if (stat) { m_fixhdr(mrep); /* * Prepend a record marker containing the reply length. */ M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK); len = mrep->m_pkthdr.len; *mtod(mrep, uint32_t *) = htonl(0x80000000 | (len - sizeof(uint32_t))); atomic_add_32(&xprt->xp_snd_cnt, len); error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL, 0, curthread); if (!error) { atomic_add_rel_32(&xprt->xp_snt_cnt, len); if (seq) *seq = xprt->xp_snd_cnt; stat = TRUE; } else atomic_subtract_32(&xprt->xp_snd_cnt, len); } else { m_freem(mrep); } XDR_DESTROY(&xdrs); return (stat); }
static bool_t svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg) { struct svc_dg_data *su; XDR *xdrs; bool_t stat = FALSE; size_t slen; _DIAGASSERT(xprt != NULL); _DIAGASSERT(msg != NULL); su = su_data(xprt); xdrs = &(su->su_xdrs); xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); msg->rm_xid = su->su_xid; if (xdr_replymsg(xdrs, msg)) { slen = XDR_GETPOS(xdrs); if (sendto(xprt->xp_fd, rpc_buffer(xprt), slen, 0, (struct sockaddr *)xprt->xp_rtaddr.buf, (socklen_t)xprt->xp_rtaddr.len) == (ssize_t) slen) { stat = TRUE; if (su->su_cache) cache_set(xprt, slen); } } return (stat); }
void svccb::reply (const void *reply, sfs::xdrproc_t xdr, bool nocache) { rpc_msg rm; rm.rm_xid = xid (); rm.rm_direction = REPLY; rm.rm_reply.rp_stat = MSG_ACCEPTED; rm.acpted_rply.ar_verf = _null_auth; rm.acpted_rply.ar_stat = SUCCESS; rm.acpted_rply.ar_results.where = (char *) reply; rm.acpted_rply.ar_results.proc = reinterpret_cast<sun_xdrproc_t> (xdr ? xdr : srv->tbl[proc ()].xdr_res); get_rpc_stats ().end_call (this, ts_start); xdrsuio x (XDR_ENCODE); if (!xdr_replymsg (x.xdrp (), &rm)) { warn ("svccb::reply: xdr_replymsg failed\n"); delete this; return; } trace (4, "reply %s:%s x=%x\n", srv->rpcprog->name, srv->tbl[msg.rm_call.cb_proc].name, xidswap (msg.rm_xid)); if (asrvtrace >= 5 && !xdr && srv->tbl[msg.rm_call.cb_proc].print_res) srv->tbl[msg.rm_call.cb_proc].print_res (reply, NULL, asrvtrace - 4, "REPLY", ""); srv->sendreply (this, &x, nocache); }
static bool_t svcudp_reply( register SVCXPRT *xprt, struct rpc_msg *msg) { register struct svcudp_data *su = su_data(xprt); register XDR *xdrs = &(su->su_xdrs); register int slen; register bool_t stat = FALSE; xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); msg->rm_xid = su->su_xid; if (xdr_replymsg(xdrs, msg)) { slen = (int)XDR_GETPOS(xdrs); if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0, (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) == (ssize_t)slen) { stat = TRUE; if (su->su_cache) { cache_set(xprt, (unsigned long) slen); } } } return (stat); }
/* Decodes the XDR format in msgbuf into rpc_msg. * The remaining payload is returned into payload. */ int xdr_to_rpc_reply(char *msgbuf, size_t len, struct rpc_msg *reply, struct iovec *payload, char *verfbytes) { XDR xdr; int ret = -EINVAL; GF_VALIDATE_OR_GOTO("rpc", msgbuf, out); GF_VALIDATE_OR_GOTO("rpc", reply, out); memset(reply, 0, sizeof(struct rpc_msg)); reply->acpted_rply.ar_verf = _null_auth; reply->acpted_rply.ar_results.where = NULL; reply->acpted_rply.ar_results.proc = (xdrproc_t)(xdr_void); xdrmem_create(&xdr, msgbuf, len, XDR_DECODE); if (!xdr_replymsg(&xdr, reply)) { gf_log("rpc", GF_LOG_WARNING, "failed to decode reply msg"); goto out; } if (payload) { payload->iov_base = xdr_decoded_remaining_addr(xdr); payload->iov_len = xdr_decoded_remaining_len(xdr); } ret = 0; out: return ret; }
static bool_t Svcudp_reply(register SVCXPRT * xprt, struct rpc_msg *msg) { register struct Svcudp_data *su = Su_data(xprt); register XDR *xdrs = &(su->su_xdrs); register int slen; xdrproc_t xdr_proc; caddr_t xdr_where; xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); msg->rm_xid = su->su_xid; if(msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { xdr_proc = msg->acpted_rply.ar_results.proc; xdr_where = msg->acpted_rply.ar_results.where; msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; msg->acpted_rply.ar_results.where = NULL; if(!xdr_replymsg(xdrs, msg) || !SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_proc, xdr_where)) return (FALSE); } else if(!xdr_replymsg(xdrs, msg)) { return (FALSE); } slen = (int)XDR_GETPOS(xdrs); #ifdef _FREEBSD if(sendto(xprt->xp_fd, #else if(sendto(xprt->xp_sock, #endif rpc_buffer(xprt), slen, 0, (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) != slen) { return (FALSE); } return (TRUE); }
static bool_t svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg, struct sockaddr *addr, struct mbuf *m) { XDR xdrs; struct mbuf *mrep; bool_t stat = TRUE; int error; MGETHDR(mrep, M_WAIT, MT_DATA); mrep->m_len = 0; xdrmbuf_create(&xdrs, mrep, XDR_ENCODE); if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { if (!xdr_replymsg(&xdrs, msg)) stat = FALSE; else xdrmbuf_append(&xdrs, m); } else { stat = xdr_replymsg(&xdrs, msg); } if (stat) { m_fixhdr(mrep); error = sosend(xprt->xp_socket, addr, NULL, mrep, NULL, 0, curthread); if (!error) { stat = TRUE; } } else { m_freem(mrep); } XDR_DESTROY(&xdrs); xprt->xp_p2 = NULL; return (stat); }
static void asrv_accepterr (ref<xhinfo> xi, const sockaddr *addr, accept_stat stat, const rpc_msg *mp) { rpc_msg m; bzero (&m, sizeof (m)); m.rm_xid = mp->rm_xid; m.rm_direction = REPLY; m.rm_reply.rp_stat = MSG_ACCEPTED; switch (stat) { case PROG_UNAVAIL: case PROG_MISMATCH: { m.acpted_rply.ar_stat = PROG_UNAVAIL; m.acpted_rply.ar_vers.low = 0xffffffff; m.acpted_rply.ar_vers.high = 0; u_int32_t prog = mp->rm_call.cb_prog; u_int32_t vers = mp->rm_call.cb_vers; for (asrv *a = xi->stab.first (); a; a = xi->stab.next (a)) if (a->hascb () && a->pv.prog == prog) { if (a->pv.vers == vers) panic ("asrv_accepterr: prog/vers exists\n"); // m.acpted_rply.ar_stat = PROC_UNAVAIL; else if (m.acpted_rply.ar_stat != PROC_UNAVAIL) { m.acpted_rply.ar_stat = PROG_MISMATCH; if (m.acpted_rply.ar_vers.low > a->pv.vers) m.acpted_rply.ar_vers.low = a->pv.vers; if (m.acpted_rply.ar_vers.high < a->pv.vers) m.acpted_rply.ar_vers.high = a->pv.vers; } } break; } case PROC_UNAVAIL: case GARBAGE_ARGS: case SYSTEM_ERR: m.acpted_rply.ar_stat = stat; break; default: panic ("asrv_accepterr: bad stat %d\n", stat); break; } xdrsuio x (XDR_ENCODE); if (xdr_replymsg (x.xdrp (), &m)) xi->xh->sendv (x.iov (), x.iovcnt (), addr); else warn ("asrv_accepterr: xdr_replymsg failed\n"); }
static bool_t Svcudp_reply(register SVCXPRT * xprt, struct rpc_msg *msg) { register struct Svcudp_data *su = Su_data(xprt); register XDR *xdrs = &(su->su_xdrs); register int slen; xdrproc_t xdr_proc; caddr_t xdr_where; xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); msg->rm_xid = su->su_xid; if(msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { xdr_proc = msg->acpted_rply.ar_results.proc; xdr_where = msg->acpted_rply.ar_results.where; msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; msg->acpted_rply.ar_results.where = NULL; if(!xdr_replymsg(xdrs, msg) || !SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_proc, xdr_where)) return (FALSE); } else if(!xdr_replymsg(xdrs, msg)) { return (FALSE); } slen = (int)XDR_GETPOS(xdrs); if(sendto(xprt->XP_SOCK, rpc_buffer(xprt), slen, 0, (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) != slen) { LogInfo(COMPONENT_DISPATCH, "EAGAIN indicates UDP buffer is full and not" " allowed to block. sendto() returned %s", strerror(errno)); return (FALSE); } return (TRUE); }
static bool_t svctcp_reply (SVCXPRT *xprt, struct rpc_msg *msg) { struct tcp_conn *cd = (struct tcp_conn *) (xprt->xp_p1); XDR *xdrs = &(cd->xdrs); bool_t stat; xdrs->x_op = XDR_ENCODE; msg->rm_xid = cd->x_id; stat = xdr_replymsg (xdrs, msg); (void) xdrrec_endofrecord (xdrs, TRUE); return stat; }
static bool_t svcraw_reply(SVCXPRT *xprt, struct rpc_msg *msg) { register struct svcraw_private *srp = svcraw_private; register XDR *xdrs; if (srp == 0) return (FALSE); xdrs = &srp->xdr_stream; xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); if (! xdr_replymsg(xdrs, msg)) return (FALSE); (void)XDR_GETPOS(xdrs); /* called just for overhead */ return (TRUE); }
/*ARGSUSED*/ static bool_t svc_raw_reply(SVCXPRT *xprt, struct rpc_msg *msg) { struct svc_raw_private *srp; XDR *xdrs; (void) mutex_lock(&svcraw_lock); srp = svc_raw_private; if (srp == NULL) { (void) mutex_unlock(&svcraw_lock); return (FALSE); } (void) mutex_unlock(&svcraw_lock); xdrs = &srp->xdr_stream; xdrs->x_op = XDR_ENCODE; (void) XDR_SETPOS(xdrs, 0); return (xdr_replymsg(xdrs, msg)); }
static void asrv_rpc_mismatch (ref<xhinfo> xi, const sockaddr *addr, u_int32_t xid) { rpc_msg m; bzero (&m, sizeof (m)); m.rm_xid = xid; m.rm_direction = REPLY; m.rm_reply.rp_stat = MSG_DENIED; m.rjcted_rply.rj_stat = RPC_MISMATCH; m.rjcted_rply.rj_vers.low = RPC_MSG_VERSION; m.rjcted_rply.rj_vers.high = RPC_MSG_VERSION; xdrsuio x (XDR_ENCODE); if (xdr_replymsg (x.xdrp (), &m)) xi->xh->sendv (x.iov (), x.iovcnt (), addr); else warn ("asrv_rpc_mismatch: xdr_replymsg failed\n"); }
static bool_t svcudp_reply( register SVCXPRT *xprt, struct rpc_msg *msg) { register struct svcudp_data *su = su_data(xprt); register XDR *xdrs = &(su->su_xdrs); register int slen; register bool_t stat = FALSE; xdrproc_t xdr_results; caddr_t xdr_location; bool_t has_args; if (msg->rm_reply.rp_stat == MSG_ACCEPTED && msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { has_args = TRUE; xdr_results = msg->acpted_rply.ar_results.proc; xdr_location = msg->acpted_rply.ar_results.where; msg->acpted_rply.ar_results.proc = xdr_void; msg->acpted_rply.ar_results.where = NULL; } else has_args = FALSE; xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); msg->rm_xid = su->su_xid; if (xdr_replymsg(xdrs, msg) && (!has_args || (SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) { slen = (int)XDR_GETPOS(xdrs); if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0, (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) == slen) { stat = TRUE; if (su->su_cache && slen >= 0) { cache_set(xprt, (uint32_t) slen); } } } return (stat); }
static void asrv_auth_reject (ref<xhinfo> xi, const sockaddr *addr, u_int32_t xid, auth_stat stat) { rpc_msg m; bzero (&m, sizeof (m)); assert (stat != AUTH_OK); m.rm_xid = xid; m.rm_direction = REPLY; m.rm_reply.rp_stat = MSG_DENIED; m.rjcted_rply.rj_stat = AUTH_ERROR; m.rjcted_rply.rj_why = stat; xdrsuio x (XDR_ENCODE); if (xdr_replymsg (x.xdrp (), &m)) xi->xh->sendv (x.iov (), x.iovcnt (), addr); else warn ("asrv_auth_reject: xdr_replymsg failed\n"); }
/* * Field reply to call to mountd */ int pickup_rpc_reply(voidp pkt, int len, voidp where, XDRPROC_T_TYPE where_xdr) { XDR reply_xdr; int ok; struct rpc_err err; struct rpc_msg reply_msg; int error = 0; /* memset((voidp) &err, 0, sizeof(err)); */ memset((voidp) &reply_msg, 0, sizeof(reply_msg)); memset((voidp) &reply_xdr, 0, sizeof(reply_xdr)); reply_msg.acpted_rply.ar_results.where = where; reply_msg.acpted_rply.ar_results.proc = where_xdr; xdrmem_create(&reply_xdr, pkt, len, XDR_DECODE); ok = xdr_replymsg(&reply_xdr, &reply_msg); if (!ok) { error = EIO; goto drop; } _seterr_reply(&reply_msg, &err); if (err.re_status != RPC_SUCCESS) { error = EIO; goto drop; } drop: if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED && reply_msg.acpted_rply.ar_verf.oa_base) { reply_xdr.x_op = XDR_FREE; (void) xdr_opaque_auth(&reply_xdr, &reply_msg.acpted_rply.ar_verf); } xdr_destroy(&reply_xdr); return error; }
/*ARGSUSED*/ static bool svc_raw_reply(SVCXPRT *xprt, struct svc_req *req, struct rpc_msg *msg) { struct svc_raw_private *srp; XDR *xdrs; mutex_lock(&svcraw_lock); srp = svc_raw_private; if (srp == NULL) { mutex_unlock(&svcraw_lock); return (false); } mutex_unlock(&svcraw_lock); xdrs = &srp->xdr_stream; xdrs->x_op = XDR_ENCODE; (void)XDR_SETPOS(xdrs, 0); if (!xdr_replymsg(xdrs, msg)) return (false); (void)XDR_GETPOS(xdrs); /* called just for overhead */ return (true); }
int rpc_reply_to_xdr (struct rpc_msg *reply, char *dest, size_t len, struct iovec *dst) { XDR xdr; int ret = -1; GF_VALIDATE_OR_GOTO ("rpc", reply, out); GF_VALIDATE_OR_GOTO ("rpc", dest, out); GF_VALIDATE_OR_GOTO ("rpc", dst, out); xdrmem_create (&xdr, dest, len, XDR_ENCODE); if (!xdr_replymsg(&xdr, reply)) { gf_log ("rpc", GF_LOG_WARNING, "failed to encode reply msg"); goto out; } dst->iov_base = dest; dst->iov_len = xdr_encoded_length (xdr); ret = 0; out: return ret; }
static enum clnt_stat clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr, xdrproc_t xdr_results, void *results_ptr, struct timeval timeout) { struct ct_data *ct = (struct ct_data *) cl->cl_private; XDR *xdrs = &(ct->ct_xdrs); struct rpc_msg reply_msg; u_int32_t x_id; u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */ bool_t shipnow; int refreshes = 2; sigset_t mask, newmask; int rpc_lock_value; bool_t reply_stat; assert(cl != NULL); sigfillset(&newmask); thr_sigsetmask(SIG_SETMASK, &newmask, &mask); mutex_lock(&clnt_fd_lock); while (vc_fd_locks[ct->ct_fd]) cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock); if (__isthreaded) rpc_lock_value = 1; else rpc_lock_value = 0; vc_fd_locks[ct->ct_fd] = rpc_lock_value; mutex_unlock(&clnt_fd_lock); if (!ct->ct_waitset) { /* If time is not within limits, we ignore it. */ if (time_not_ok(&timeout) == FALSE) ct->ct_wait = timeout; } shipnow = (xdr_results == NULL && timeout.tv_sec == 0 && timeout.tv_usec == 0) ? FALSE : TRUE; call_again: xdrs->x_op = XDR_ENCODE; ct->ct_error.re_status = RPC_SUCCESS; x_id = ntohl(--(*msg_x_id)); if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) || (! XDR_PUTINT32(xdrs, &proc)) || (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || (! (*xdr_args)(xdrs, args_ptr))) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTENCODEARGS; (void)xdrrec_endofrecord(xdrs, TRUE); release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } } else { *(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc); if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc, ct->ct_mpos + sizeof(uint32_t), xdrs, xdr_args, args_ptr)) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTENCODEARGS; (void)xdrrec_endofrecord(xdrs, TRUE); release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } } if (! xdrrec_endofrecord(xdrs, shipnow)) { release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status = RPC_CANTSEND); } if (! shipnow) { release_fd_lock(ct->ct_fd, mask); return (RPC_SUCCESS); } /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { release_fd_lock(ct->ct_fd, mask); return(ct->ct_error.re_status = RPC_TIMEDOUT); } /* * Keep receiving until we get a valid transaction id */ xdrs->x_op = XDR_DECODE; while (TRUE) { reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; if (! xdrrec_skiprecord(xdrs)) { release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } /* now decode and validate the response header */ if (! xdr_replymsg(xdrs, &reply_msg)) { if (ct->ct_error.re_status == RPC_SUCCESS) continue; release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); } if (reply_msg.rm_xid == x_id) break; } /* * process header */ _seterr_reply(&reply_msg, &(ct->ct_error)); if (ct->ct_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { ct->ct_error.re_status = RPC_AUTHERROR; ct->ct_error.re_why = AUTH_INVALIDRESP; } else { if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { reply_stat = (*xdr_results)(xdrs, results_ptr); } else { reply_stat = __rpc_gss_unwrap(cl->cl_auth, xdrs, xdr_results, results_ptr); } if (! reply_stat) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTDECODERES; } } /* free verifier ... */ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) goto call_again; } /* end of unsuccessful completion */ release_fd_lock(ct->ct_fd, mask); return (ct->ct_error.re_status); }
static enum clnt_stat clnt_dg_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, struct timeval utimeout) { /* LINTED pointer alignment */ struct cu_data *cu = (struct cu_data *)cl->cl_private; XDR *xdrs; int outlen; struct rpc_msg reply_msg; XDR reply_xdrs; struct timeval time_waited; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ struct timeval timeout; struct timeval retransmit_time; struct timeval poll_time; struct timeval startime, curtime; struct t_unitdata tu_data; int res; /* result of operations */ uint32_t x_id; if (rpc_fd_lock(dgtbl, cu->cu_fd)) { rpc_callerr.re_status = RPC_FAILED; rpc_callerr.re_errno = errno; rpc_fd_unlock(dgtbl, cu->cu_fd); return (RPC_FAILED); } if (cu->cu_total.tv_usec == -1) { timeout = utimeout; /* use supplied timeout */ } else { timeout = cu->cu_total; /* use default timeout */ } time_waited.tv_sec = 0; time_waited.tv_usec = 0; retransmit_time = cu->cu_wait; tu_data.addr = cu->cu_raddr; call_again: xdrs = &(cu->cu_outxdrs); xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, 0); /* * Due to little endian byte order, it is necessary to convert to host * format before incrementing xid. */ /* LINTED pointer cast */ x_id = ntohl(*(uint32_t *)(cu->cu_outbuf)) + 1; /* set XID */ /* LINTED pointer cast */ *(uint32_t *)cu->cu_outbuf = htonl(x_id); if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { if ((!XDR_PUTBYTES(xdrs, cu->cu_outbuf, cu->cu_xdrpos)) || (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) || (!AUTH_MARSHALL(cl->cl_auth, xdrs)) || (!xargs(xdrs, argsp))) { rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } } else { /* LINTED pointer alignment */ uint32_t *u = (uint32_t *)&cu->cu_outbuf[cu->cu_xdrpos]; IXDR_PUT_U_INT32(u, proc); if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outbuf, ((char *)u) - cu->cu_outbuf, xdrs, xargs, argsp)) { rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } } outlen = (int)XDR_GETPOS(xdrs); send_again: tu_data.udata.buf = cu->cu_outbuf_start; tu_data.udata.len = outlen; tu_data.opt.len = 0; if (t_sndudata(cu->cu_fd, &tu_data) == -1) { rpc_callerr.re_terrno = t_errno; rpc_callerr.re_errno = errno; rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTSEND); } /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_TIMEDOUT); } /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = xdr_void; /* * Set polling time so that we don't wait for * longer than specified by the total time to wait, * or the retransmit time. */ poll_time.tv_sec = timeout.tv_sec - time_waited.tv_sec; poll_time.tv_usec = timeout.tv_usec - time_waited.tv_usec; while (poll_time.tv_usec < 0) { poll_time.tv_usec += 1000000; poll_time.tv_sec--; } if (poll_time.tv_sec < 0 || (poll_time.tv_sec == 0 && poll_time.tv_usec == 0)) { /* * this could happen if time_waited >= timeout */ rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_TIMEDOUT); } if (poll_time.tv_sec > retransmit_time.tv_sec || (poll_time.tv_sec == retransmit_time.tv_sec && poll_time.tv_usec > retransmit_time.tv_usec)) poll_time = retransmit_time; for (;;) { (void) gettimeofday(&startime, NULL); switch (poll(&cu->pfdp, 1, __rpc_timeval_to_msec(&poll_time))) { case -1: if (errno != EINTR && errno != EAGAIN) { rpc_callerr.re_errno = errno; rpc_callerr.re_terrno = 0; rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTRECV); } /*FALLTHROUGH*/ case 0: /* * update time waited */ timeout: (void) gettimeofday(&curtime, NULL); time_waited.tv_sec += curtime.tv_sec - startime.tv_sec; time_waited.tv_usec += curtime.tv_usec - startime.tv_usec; while (time_waited.tv_usec >= 1000000) { time_waited.tv_usec -= 1000000; time_waited.tv_sec++; } while (time_waited.tv_usec < 0) { time_waited.tv_usec += 1000000; time_waited.tv_sec--; } /* * decrement time left to poll by same amount */ poll_time.tv_sec -= curtime.tv_sec - startime.tv_sec; poll_time.tv_usec -= curtime.tv_usec - startime.tv_usec; while (poll_time.tv_usec >= 1000000) { poll_time.tv_usec -= 1000000; poll_time.tv_sec++; } while (poll_time.tv_usec < 0) { poll_time.tv_usec += 1000000; poll_time.tv_sec--; } /* * if there's time left to poll, poll again */ if (poll_time.tv_sec > 0 || (poll_time.tv_sec == 0 && poll_time.tv_usec > 0)) continue; /* * if there's more time left, retransmit; * otherwise, return timeout error */ if (time_waited.tv_sec < timeout.tv_sec || (time_waited.tv_sec == timeout.tv_sec && time_waited.tv_usec < timeout.tv_usec)) { /* * update retransmit_time */ retransmit_time.tv_usec *= 2; retransmit_time.tv_sec *= 2; while (retransmit_time.tv_usec >= 1000000) { retransmit_time.tv_usec -= 1000000; retransmit_time.tv_sec++; } if (retransmit_time.tv_sec >= RPC_MAX_BACKOFF) { retransmit_time.tv_sec = RPC_MAX_BACKOFF; retransmit_time.tv_usec = 0; } /* * redo AUTH_MARSHAL if AUTH_DES or RPCSEC_GSS. */ if (cl->cl_auth->ah_cred.oa_flavor == AUTH_DES || cl->cl_auth->ah_cred.oa_flavor == RPCSEC_GSS) goto call_again; else goto send_again; } rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_TIMEDOUT); default: break; } if (cu->pfdp.revents & POLLNVAL || (cu->pfdp.revents == 0)) { rpc_callerr.re_status = RPC_CANTRECV; /* * Note: we're faking errno here because we * previously would have expected select() to * return -1 with errno EBADF. Poll(BA_OS) * returns 0 and sets the POLLNVAL revents flag * instead. */ rpc_callerr.re_errno = errno = EBADF; rpc_fd_unlock(dgtbl, cu->cu_fd); return (-1); } /* We have some data now */ do { int moreflag; /* flag indicating more data */ moreflag = 0; res = t_rcvudata(cu->cu_fd, cu->cu_tr_data, &moreflag); if (moreflag & T_MORE) { /* * Drop this packet. I aint got any * more space. */ res = -1; /* I should not really be doing this */ errno = 0; /* * XXX: Not really Buffer overflow in the * sense of TLI. */ t_errno = TBUFOVFLW; } } while (res < 0 && (t_errno == TSYSERR && errno == EINTR)); if (res < 0) { int err, errnoflag = FALSE; #ifdef sun if (t_errno == TSYSERR && errno == EWOULDBLOCK) #else if (t_errno == TSYSERR && errno == EAGAIN) #endif continue; if (t_errno == TLOOK) { if ((err = _rcv_unitdata_err(cu)) == 0) continue; else if (err == 1) errnoflag = TRUE; } else { rpc_callerr.re_terrno = t_errno; } if (errnoflag == FALSE) rpc_callerr.re_errno = errno; rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status = RPC_CANTRECV); } if (cu->cu_tr_data->udata.len < (uint_t)sizeof (uint32_t)) continue; /* see if reply transaction id matches sent id */ /* LINTED pointer alignment */ if (*((uint32_t *)(cu->cu_inbuf)) != /* LINTED pointer alignment */ *((uint32_t *)(cu->cu_outbuf))) goto timeout; /* we now assume we have the proper reply */ break; } /* * now decode and validate the response */ xdrmem_create(&reply_xdrs, cu->cu_inbuf, (uint_t)cu->cu_tr_data->udata.len, XDR_DECODE); ok = xdr_replymsg(&reply_xdrs, &reply_msg); /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ if (ok) { if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && (reply_msg.acpted_rply.ar_stat == SUCCESS)) rpc_callerr.re_status = RPC_SUCCESS; else __seterr_reply(&reply_msg, &(rpc_callerr)); if (rpc_callerr.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { rpc_callerr.re_status = RPC_AUTHERROR; rpc_callerr.re_why = AUTH_INVALIDRESP; } else if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { if (!(*xresults)(&reply_xdrs, resultsp)) { if (rpc_callerr.re_status == RPC_SUCCESS) rpc_callerr.re_status = RPC_CANTDECODERES; } } else if (!__rpc_gss_unwrap(cl->cl_auth, &reply_xdrs, xresults, resultsp)) { if (rpc_callerr.re_status == RPC_SUCCESS) rpc_callerr.re_status = RPC_CANTDECODERES; } } /* end successful completion */ /* * If unsuccesful AND error is an authentication error * then refresh credentials and try again, else break */ else if (rpc_callerr.re_status == RPC_AUTHERROR) /* maybe our credentials need to be refreshed ... */ if (nrefreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) goto call_again; else /* * We are setting rpc_callerr here given that * libnsl is not reentrant thereby * reinitializing the TSD. If not set here then * success could be returned even though refresh * failed. */ rpc_callerr.re_status = RPC_AUTHERROR; /* end of unsuccessful completion */ /* free verifier */ if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED && reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end of valid reply message */ else { rpc_callerr.re_status = RPC_CANTDECODERES; } rpc_fd_unlock(dgtbl, cu->cu_fd); return (rpc_callerr.re_status); }
bool_t byz_reply(SVCXPRT *xpt, struct rpc_msg *m) { m->rm_xid = xpt->xp_sock; return xdr_replymsg(out_stream(xpt), m) ; }
enum clnt_stat qrpc_clnt_raw_call(CLIENT *cl, u_long proc, xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, struct timeval utimeout) { struct qrpc_clnt_raw_priv *priv = (struct qrpc_clnt_raw_priv *)cl->cl_private; XDR *xdrs_out = &priv->xdrs_out; XDR *xdrs_in = &priv->xdrs_in; struct rpc_msg reply_msg; struct timeval curr_time; struct qrpc_frame_hdr *hdr; uint16_t tmp; if (xargs) { xdrs_out->x_op = XDR_ENCODE; XDR_SETPOS(xdrs_out, priv->xdrs_outpos); if ((!XDR_PUTLONG(xdrs_out, (long *)&proc)) || (!AUTH_MARSHALL(cl->cl_auth, xdrs_out)) || (!(*xargs) (xdrs_out, argsp))) { priv->rpc_error.re_status = RPC_CANTENCODEARGS; return priv->rpc_error.re_status; } tmp = ntohs(priv->out_hdr.seq); priv->out_hdr.seq = htons(tmp + 1); if (qrpc_clnt_raw_call_send(priv, XDR_GETPOS(xdrs_out)) < 0) { return priv->rpc_error.re_status; } } if (gettimeofday(&curr_time, NULL) < 0) { priv->rpc_error.re_status = RPC_SYSTEMERROR; return priv->rpc_error.re_status; } utimeout.tv_sec += curr_time.tv_sec; /* Waiting for reply */ do { if (qrpc_clnt_raw_call_recv(priv) < 0) { if (priv->rpc_error.re_status == RPC_TIMEDOUT) continue; else break; } hdr = (struct qrpc_frame_hdr *)priv->inbuf; if (xargs && priv->out_hdr.seq != hdr->seq) { continue; } xdrs_in->x_op = XDR_DECODE; XDR_SETPOS(xdrs_in, 0); reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; if (xdr_replymsg(xdrs_in, &reply_msg)) { if (reply_msg.rm_xid != (unsigned long)getpid()) { continue; } _seterr_reply(&reply_msg, &priv->rpc_error); if (priv->rpc_error.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { priv->rpc_error.re_status = RPC_AUTHERROR; priv->rpc_error.re_why = AUTH_INVALIDRESP; } break; } } else { priv->rpc_error.re_status = RPC_CANTDECODERES; } } while ((gettimeofday(&curr_time, NULL) == 0) && (curr_time.tv_sec < utimeout.tv_sec)); return priv->rpc_error.re_status; }
static enum clnt_stat clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr, xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout) { struct ct_data *ct = (struct ct_data *) h->cl_private; XDR *xdrs = &(ct->ct_xdrs); struct rpc_msg reply_msg; u_long x_id; u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall); /* yuk */ bool_t shipnow; int refreshes = 2; if (!ct->ct_waitset) { ct->ct_wait = timeout; } shipnow = (xdr_results == NULL && timeout.tv_sec == 0 && timeout.tv_usec == 0) ? FALSE : TRUE; call_again: xdrs->x_op = XDR_ENCODE; ct->ct_error.re_status = RPC_SUCCESS; x_id = ntohl(--(*msg_x_id)); if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || (! XDR_PUTLONG(xdrs, (long *)&proc)) || (! AUTH_MARSHALL(h->cl_auth, xdrs)) || (! (*xdr_args)(xdrs, args_ptr))) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTENCODEARGS; (void)xdrrec_endofrecord(xdrs, TRUE); return (ct->ct_error.re_status); } if (! xdrrec_endofrecord(xdrs, shipnow)) return (ct->ct_error.re_status = RPC_CANTSEND); if (! shipnow) return (RPC_SUCCESS); /* * Hack to provide rpc-based message passing */ if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { return(ct->ct_error.re_status = RPC_TIMEDOUT); } /* * Keep receiving until we get a valid transaction id */ xdrs->x_op = XDR_DECODE; while (TRUE) { reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = NULL; reply_msg.acpted_rply.ar_results.proc = xdr_void; if (! xdrrec_skiprecord(xdrs)) return (ct->ct_error.re_status); /* now decode and validate the response header */ if (! xdr_replymsg(xdrs, &reply_msg)) { if (ct->ct_error.re_status == RPC_SUCCESS) continue; return (ct->ct_error.re_status); } if (reply_msg.rm_xid == x_id) break; } /* * process header */ _seterr_reply(&reply_msg, &(ct->ct_error)); if (ct->ct_error.re_status == RPC_SUCCESS) { if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { ct->ct_error.re_status = RPC_AUTHERROR; ct->ct_error.re_why = AUTH_INVALIDRESP; } else if (! (*xdr_results)(xdrs, results_ptr)) { if (ct->ct_error.re_status == RPC_SUCCESS) ct->ct_error.re_status = RPC_CANTDECODERES; } /* free verifier ... */ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (refreshes-- && AUTH_REFRESH(h->cl_auth)) goto call_again; } /* end of unsuccessful completion */ return (ct->ct_error.re_status); }
/* * This routine is designed to be able to "ping" * a list of hosts and create a list of responding * hosts sorted by response time. * This must be done without any prior * contact with the host - therefore the "ping" * must be to a "well-known" address. The outstanding * candidate here is the address of "rpcbind". * * A response to a ping is no guarantee that the host * is running NFS, has a mount daemon, or exports * the required filesystem. If the subsequent * mount attempt fails then the host will be marked * "ignore" and the host list will be re-pinged * (sans the bad host). This process continues * until a successful mount is achieved or until * there are no hosts left to try. */ enum clnt_stat nfs_cast(struct mapfs *mfs_in, struct mapfs **mfs_out, int timeout) { enum clnt_stat stat; AUTH *sys_auth = authsys_create_default(); XDR xdr_stream; register XDR *xdrs = &xdr_stream; int outlen; int if_inx; int tsec; int flag; int sent, addr_cnt, rcvd, if_cnt; fd_set readfds, mask; register ulong_t xid; /* xid - unique per addr */ register int i; struct rpc_msg msg; struct timeval t, rcv_timeout; char outbuf[UDPMSGSIZE], inbuf[UDPMSGSIZE]; struct t_unitdata t_udata, t_rdata; struct nd_hostserv hs; struct nd_addrlist *retaddrs; struct transp *tr_head; struct transp *trans, *prev_trans; struct addrs *a, *prev_addr; struct tstamps *ts, *prev_ts; NCONF_HANDLE *nc = NULL; struct netconfig *nconf; struct rlimit rl; int dtbsize; struct mapfs *mfs; /* * For each connectionless transport get a list of * host addresses. Any single host may have * addresses on several transports. */ addr_cnt = sent = rcvd = 0; tr_head = NULL; FD_ZERO(&mask); /* * Set the default select size to be the maximum FD_SETSIZE, unless * the current rlimit is lower. */ dtbsize = FD_SETSIZE; if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { if (rl.rlim_cur < FD_SETSIZE) dtbsize = rl.rlim_cur; } prev_trans = NULL; prev_addr = NULL; prev_ts = NULL; for (mfs = mfs_in; mfs; mfs = mfs->mfs_next) { if (trace > 2) trace_prt(1, "nfs_cast: host=%s\n", mfs->mfs_host); nc = setnetconfig(); if (nc == NULL) { stat = RPC_CANTSEND; goto done_broad; } while (nconf = getnetconfig(nc)) { if (!(nconf->nc_flag & NC_VISIBLE) || nconf->nc_semantics != NC_TPI_CLTS || (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)) continue; trans = (struct transp *)malloc(sizeof (*trans)); if (trans == NULL) { syslog(LOG_ERR, "no memory"); stat = RPC_CANTSEND; goto done_broad; } (void) memset(trans, 0, sizeof (*trans)); if (tr_head == NULL) tr_head = trans; else prev_trans->tr_next = trans; prev_trans = trans; trans->tr_fd = t_open(nconf->nc_device, O_RDWR, NULL); if (trans->tr_fd < 0) { syslog(LOG_ERR, "nfscast: t_open: %s:%m", nconf->nc_device); stat = RPC_CANTSEND; goto done_broad; } if (t_bind(trans->tr_fd, (struct t_bind *)NULL, (struct t_bind *)NULL) < 0) { syslog(LOG_ERR, "nfscast: t_bind: %m"); stat = RPC_CANTSEND; goto done_broad; } trans->tr_taddr = /* LINTED pointer alignment */ (struct t_bind *)t_alloc(trans->tr_fd, T_BIND, T_ADDR); if (trans->tr_taddr == (struct t_bind *)NULL) { syslog(LOG_ERR, "nfscast: t_alloc: %m"); stat = RPC_SYSTEMERROR; goto done_broad; } trans->tr_device = nconf->nc_device; FD_SET(trans->tr_fd, &mask); if_inx = 0; hs.h_host = mfs->mfs_host; hs.h_serv = "rpcbind"; if (netdir_getbyname(nconf, &hs, &retaddrs) == ND_OK) { /* * If mfs->ignore is previously set for * this map, clear it. Because a host can * have either v6 or v4 address */ if (mfs->mfs_ignore == 1) mfs->mfs_ignore = 0; a = (struct addrs *)malloc(sizeof (*a)); if (a == NULL) { syslog(LOG_ERR, "no memory"); stat = RPC_CANTSEND; goto done_broad; } (void) memset(a, 0, sizeof (*a)); if (trans->tr_addrs == NULL) trans->tr_addrs = a; else prev_addr->addr_next = a; prev_addr = a; a->addr_if_tstamps = NULL; a->addr_mfs = mfs; a->addr_addrs = retaddrs; if_cnt = retaddrs->n_cnt; while (if_cnt--) { ts = (struct tstamps *) malloc(sizeof (*ts)); if (ts == NULL) { syslog(LOG_ERR, "no memory"); stat = RPC_CANTSEND; goto done_broad; } (void) memset(ts, 0, sizeof (*ts)); ts->ts_penalty = mfs->mfs_penalty; if (a->addr_if_tstamps == NULL) a->addr_if_tstamps = ts; else prev_ts->ts_next = ts; prev_ts = ts; ts->ts_inx = if_inx++; addr_cnt++; } break; } else { mfs->mfs_ignore = 1; if (verbose) syslog(LOG_ERR, "%s:%s address not known", mfs->mfs_host, strcmp(nconf->nc_proto, NC_INET)?"IPv6":"IPv4"); } } /* while */ endnetconfig(nc); nc = NULL; } /* for */ if (addr_cnt == 0) { syslog(LOG_ERR, "nfscast: couldn't find addresses"); stat = RPC_CANTSEND; goto done_broad; } (void) gettimeofday(&t, (struct timezone *)0); xid = (getpid() ^ t.tv_sec ^ t.tv_usec) & ~0xFF; t.tv_usec = 0; /* serialize the RPC header */ msg.rm_direction = CALL; msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; msg.rm_call.cb_prog = RPCBPROG; /* * we can not use RPCBVERS here since it doesn't exist in 4.X, * the fix to bug 1139883 has made the 4.X portmapper silent to * version mismatches. This causes the RPC call to the remote * portmapper to simply be ignored if it's not Version 2. */ msg.rm_call.cb_vers = PMAPVERS; msg.rm_call.cb_proc = NULLPROC; if (sys_auth == (AUTH *)NULL) { stat = RPC_SYSTEMERROR; goto done_broad; } msg.rm_call.cb_cred = sys_auth->ah_cred; msg.rm_call.cb_verf = sys_auth->ah_verf; xdrmem_create(xdrs, outbuf, sizeof (outbuf), XDR_ENCODE); if (! xdr_callmsg(xdrs, &msg)) { stat = RPC_CANTENCODEARGS; goto done_broad; } outlen = (int)xdr_getpos(xdrs); xdr_destroy(xdrs); t_udata.opt.len = 0; t_udata.udata.buf = outbuf; t_udata.udata.len = outlen; /* * Basic loop: send packet to all hosts and wait for response(s). * The response timeout grows larger per iteration. * A unique xid is assigned to each address in order to * correctly match the replies. */ for (tsec = 4; timeout > 0; tsec *= 2) { timeout -= tsec; if (timeout <= 0) tsec += timeout; rcv_timeout.tv_sec = tsec; rcv_timeout.tv_usec = 0; sent = 0; for (trans = tr_head; trans; trans = trans->tr_next) { for (a = trans->tr_addrs; a; a = a->addr_next) { struct netbuf *if_netbuf = a->addr_addrs->n_addrs; ts = a->addr_if_tstamps; if_cnt = a->addr_addrs->n_cnt; while (if_cnt--) { /* * xid is the first thing in * preserialized buffer */ /* LINTED pointer alignment */ *((ulong_t *)outbuf) = htonl(xid + ts->ts_inx); (void) gettimeofday(&(ts->ts_timeval), (struct timezone *)0); /* * Check if already received * from a previous iteration. */ if (ts->ts_rcvd) { sent++; ts = ts->ts_next; continue; } t_udata.addr = *if_netbuf++; if (t_sndudata(trans->tr_fd, &t_udata) == 0) { sent++; } ts = ts->ts_next; } } } if (sent == 0) { /* no packets sent ? */ stat = RPC_CANTSEND; goto done_broad; } /* * Have sent all the packets. Now collect the responses... */ rcvd = 0; recv_again: msg.acpted_rply.ar_verf = _null_auth; msg.acpted_rply.ar_results.proc = xdr_void; readfds = mask; switch (select(dtbsize, &readfds, (fd_set *)NULL, (fd_set *)NULL, &rcv_timeout)) { case 0: /* Timed out */ /* * If we got at least one response in the * last interval, then don't wait for any * more. In theory we should wait for * the max weighting (penalty) value so * that a very slow server has a chance to * respond but this could take a long time * if the admin has set a high weighting * value. */ if (rcvd > 0) goto done_broad; stat = RPC_TIMEDOUT; continue; case -1: /* some kind of error */ if (errno == EINTR) goto recv_again; syslog(LOG_ERR, "nfscast: select: %m"); if (rcvd == 0) stat = RPC_CANTRECV; goto done_broad; } /* end of select results switch */ for (trans = tr_head; trans; trans = trans->tr_next) { if (FD_ISSET(trans->tr_fd, &readfds)) break; } if (trans == NULL) goto recv_again; try_again: t_rdata.addr = trans->tr_taddr->addr; t_rdata.udata.buf = inbuf; t_rdata.udata.maxlen = sizeof (inbuf); t_rdata.udata.len = 0; t_rdata.opt.len = 0; if (t_rcvudata(trans->tr_fd, &t_rdata, &flag) < 0) { if (errno == EINTR) goto try_again; syslog(LOG_ERR, "nfscast: t_rcvudata: %s:%m", trans->tr_device); stat = RPC_CANTRECV; continue; } if (t_rdata.udata.len < sizeof (ulong_t)) goto recv_again; if (flag & T_MORE) { syslog(LOG_ERR, "nfscast: t_rcvudata: %s: buffer overflow", trans->tr_device); goto recv_again; } /* * see if reply transaction id matches sent id. * If so, decode the results. * Note: received addr is ignored, it could be * different from the send addr if the host has * more than one addr. */ xdrmem_create(xdrs, inbuf, (uint_t)t_rdata.udata.len, XDR_DECODE); if (xdr_replymsg(xdrs, &msg)) { if (msg.rm_reply.rp_stat == MSG_ACCEPTED && (msg.rm_xid & ~0xFF) == xid) { struct addrs *curr_addr; i = msg.rm_xid & 0xFF; for (curr_addr = trans->tr_addrs; curr_addr; curr_addr = curr_addr->addr_next) { for (ts = curr_addr->addr_if_tstamps; ts; ts = ts->ts_next) if (ts->ts_inx == i && !ts->ts_rcvd) { ts->ts_rcvd = 1; calc_resp_time(&ts->ts_timeval); stat = RPC_SUCCESS; rcvd++; break; } } } /* otherwise, we just ignore the errors ... */ } xdrs->x_op = XDR_FREE; msg.acpted_rply.ar_results.proc = xdr_void; (void) xdr_replymsg(xdrs, &msg); XDR_DESTROY(xdrs); if (rcvd == sent) goto done_broad; else goto recv_again; } if (!rcvd) stat = RPC_TIMEDOUT; done_broad: if (rcvd) { *mfs_out = sort_responses(tr_head); stat = RPC_SUCCESS; } if (nc) endnetconfig(nc); free_transports(tr_head); AUTH_DESTROY(sys_auth); return (stat); }
/* ARGSUSED */ static enum clnt_stat clnt_door_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, struct timeval utimeout) { /* LINTED pointer alignment */ struct cu_data *cu = (struct cu_data *)cl->cl_private; XDR xdrs; door_arg_t params; char *outbuf_ref; struct rpc_msg reply_msg; bool_t need_to_unmap; int nrefreshes = 2; /* number of times to refresh cred */ rpc_callerr.re_errno = 0; rpc_callerr.re_terrno = 0; if ((params.rbuf = alloca(cu->cu_sendsz)) == NULL) { rpc_callerr.re_terrno = 0; rpc_callerr.re_errno = errno; return (rpc_callerr.re_status = RPC_SYSTEMERROR); } outbuf_ref = params.rbuf; params.rsize = cu->cu_sendsz; if ((params.data_ptr = alloca(cu->cu_sendsz)) == NULL) { rpc_callerr.re_terrno = 0; rpc_callerr.re_errno = errno; return (rpc_callerr.re_status = RPC_SYSTEMERROR); } call_again: xdrmem_create(&xdrs, params.data_ptr, cu->cu_sendsz, XDR_ENCODE); /* LINTED pointer alignment */ (*(uint32_t *)cu->cu_header)++; /* increment XID */ (void) memcpy(params.data_ptr, cu->cu_header, cu->cu_xdrpos); XDR_SETPOS(&xdrs, cu->cu_xdrpos); if ((!XDR_PUTINT32(&xdrs, (int32_t *)&proc)) || (!AUTH_MARSHALL(cl->cl_auth, &xdrs)) || (!(*xargs)(&xdrs, argsp))) { return (rpc_callerr.re_status = RPC_CANTENCODEARGS); } params.data_size = (int)XDR_GETPOS(&xdrs); params.desc_ptr = NULL; params.desc_num = 0; if (door_call(cu->cu_fd, ¶ms) < 0) { rpc_callerr.re_errno = errno; return (rpc_callerr.re_status = RPC_CANTSEND); } if (params.rbuf == NULL || params.rsize == 0) { return (rpc_callerr.re_status = RPC_FAILED); } need_to_unmap = (params.rbuf != outbuf_ref); /* LINTED pointer alignment */ if (*(uint32_t *)params.rbuf != *(uint32_t *)cu->cu_header) { rpc_callerr.re_status = RPC_CANTDECODERES; goto done; } xdrmem_create(&xdrs, params.rbuf, params.rsize, XDR_DECODE); reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; if (xdr_replymsg(&xdrs, &reply_msg)) { if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED && reply_msg.acpted_rply.ar_stat == SUCCESS) rpc_callerr.re_status = RPC_SUCCESS; else __seterr_reply(&reply_msg, &rpc_callerr); if (rpc_callerr.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { rpc_callerr.re_status = RPC_AUTHERROR; rpc_callerr.re_why = AUTH_INVALIDRESP; } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs.x_op = XDR_FREE; (void) xdr_opaque_auth(&xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* * If unsuccesful AND error is an authentication error * then refresh credentials and try again, else break */ else if (rpc_callerr.re_status == RPC_AUTHERROR) { /* * maybe our credentials need to be refreshed ... */ if (nrefreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg)) { if (need_to_unmap) (void) munmap(params.rbuf, params.rsize); goto call_again; } else /* * We are setting rpc_callerr here given that * libnsl is not reentrant thereby * reinitializing the TSD. If not set here then * success could be returned even though refresh * failed. */ rpc_callerr.re_status = RPC_AUTHERROR; } } else rpc_callerr.re_status = RPC_CANTDECODERES; done: if (need_to_unmap) (void) munmap(params.rbuf, params.rsize); return (rpc_callerr.re_status); }
enum clnt_stat clnt_broadcast(u_long prog, /* program number */ u_long vers, /* version number */ u_long proc, /* procedure number */ xdrproc_t xargs, /* xdr routine for args */ caddr_t argsp, /* pointer to args */ xdrproc_t xresults, /* xdr routine for results */ caddr_t resultsp, /* pointer to results */ resultproc_t eachresult) /* call with each result obtained */ { enum clnt_stat stat; AUTH *unix_auth; XDR xdr_stream; XDR *xdrs = &xdr_stream; int outlen, inlen, nets; socklen_t fromlen; int sock = -1; int on = 1; struct pollfd pfd[1]; int i; int timo; bool_t done = FALSE; u_long xid; u_long port; struct in_addr *addrs = NULL; struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ struct rmtcallargs a; struct rmtcallres r; struct rpc_msg msg; char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; if ((unix_auth = authunix_create_default()) == NULL) { stat = RPC_AUTHERROR; goto done_broad; } /* * initialization: create a socket, a broadcast address, and * preserialize the arguments into a send buffer. */ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { stat = RPC_CANTSEND; goto done_broad; } #ifdef SO_BROADCAST if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { stat = RPC_CANTSEND; goto done_broad; } #endif /* def SO_BROADCAST */ pfd[0].fd = sock; pfd[0].events = POLLIN; nets = newgetbroadcastnets(&addrs); if (nets == 0) { stat = RPC_CANTSEND; goto done_broad; } memset(&baddr, 0, sizeof (baddr)); baddr.sin_len = sizeof(struct sockaddr_in); baddr.sin_family = AF_INET; baddr.sin_port = htons(PMAPPORT); baddr.sin_addr.s_addr = htonl(INADDR_ANY); msg.rm_xid = xid = arc4random(); msg.rm_direction = CALL; msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; msg.rm_call.cb_prog = PMAPPROG; msg.rm_call.cb_vers = PMAPVERS; msg.rm_call.cb_proc = PMAPPROC_CALLIT; msg.rm_call.cb_cred = unix_auth->ah_cred; msg.rm_call.cb_verf = unix_auth->ah_verf; a.prog = prog; a.vers = vers; a.proc = proc; a.xdr_args = xargs; a.args_ptr = argsp; r.port_ptr = &port; r.xdr_results = xresults; r.results_ptr = resultsp; xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); if (!xdr_callmsg(xdrs, &msg) || !xdr_rmtcall_args(xdrs, &a)) { stat = RPC_CANTENCODEARGS; goto done_broad; } outlen = (int)xdr_getpos(xdrs); xdr_destroy(xdrs); /* * Basic loop: broadcast a packet and wait a while for response(s). * The response timeout grows larger per iteration. * * XXX This will loop about 5 times the stop. If there are * lots of signals being received by the process it will quit * send them all in one quick burst, not paying attention to * the intended function of sending them slowly over half a * minute or so */ for (timo = 4000; timo <= 14000; timo += 2000) { for (i = 0; i < nets; i++) { baddr.sin_addr = addrs[i]; if (sendto(sock, outbuf, outlen, 0, (struct sockaddr *)&baddr, sizeof (struct sockaddr)) != outlen) { stat = RPC_CANTSEND; goto done_broad; } } if (eachresult == NULL) { stat = RPC_SUCCESS; goto done_broad; } recv_again: msg.acpted_rply.ar_verf = _null_auth; msg.acpted_rply.ar_results.where = (caddr_t)&r; msg.acpted_rply.ar_results.proc = xdr_rmtcallres; switch (poll(pfd, 1, timo)) { case 0: /* timed out */ stat = RPC_TIMEDOUT; continue; case 1: if (pfd[0].revents & POLLNVAL) errno = EBADF; else if (pfd[0].revents & POLLERR) errno = EIO; else break; /* FALLTHROUGH */ case -1: /* some kind of error */ if (errno == EINTR) goto recv_again; stat = RPC_CANTRECV; goto done_broad; } try_again: fromlen = sizeof(struct sockaddr); inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0, (struct sockaddr *)&raddr, &fromlen); if (inlen < 0) { if (errno == EINTR) goto try_again; stat = RPC_CANTRECV; goto done_broad; } if (inlen < sizeof(u_int32_t)) goto recv_again; /* * see if reply transaction id matches sent id. * If so, decode the results. */ xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); if (xdr_replymsg(xdrs, &msg)) { if ((msg.rm_xid == xid) && (msg.rm_reply.rp_stat == MSG_ACCEPTED) && (msg.acpted_rply.ar_stat == SUCCESS)) { raddr.sin_port = htons((u_short)port); done = (*eachresult)(resultsp, &raddr); } /* otherwise, we just ignore the errors ... */ } xdrs->x_op = XDR_FREE; msg.acpted_rply.ar_results.proc = xdr_void; (void)xdr_replymsg(xdrs, &msg); (void)(*xresults)(xdrs, resultsp); xdr_destroy(xdrs); if (done) { stat = RPC_SUCCESS; goto done_broad; } else { goto recv_again; } } done_broad: if (addrs) free(addrs); if (sock >= 0) (void)close(sock); if (unix_auth != NULL) AUTH_DESTROY(unix_auth); return (stat); }
static enum clnt_stat clntudp_call(CLIENT *cl, unsigned long proc, xdrproc_t xargs, char* argsp, xdrproc_t xresults, char* resultsp, struct timeval utimeout) { register struct cu_data *cu = (struct cu_data *) cl->cl_private; register XDR *xdrs; register int outlen; register int inlen; socklen_t fromlen; struct sockaddr_in from; struct rpc_msg reply_msg; XDR reply_xdrs; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ call_again: xdrs = &(cu->cu_outxdrs); xdrs->x_op = XDR_ENCODE; XDR_SETPOS(xdrs, cu->cu_xdrpos); /* * the transaction is the first thing in the out buffer */ (*(unsigned long *) (cu->cu_outbuf))++; if ((!XDR_PUTLONG(xdrs, (long *) &proc)) || (!AUTH_MARSHALL(cl->cl_auth, xdrs)) || (!(*xargs) (xdrs, argsp))) return (cu->cu_error.re_status = RPC_CANTENCODEARGS); outlen = (int) XDR_GETPOS(xdrs); send_again: if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, (struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen) != outlen) { cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTSEND); } /* * sub-optimal code appears here because we have * some clock time to spare while the packets are in flight. * (We assume that this is actually only executed once.) */ reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; /* do recv */ do { fromlen = sizeof(struct sockaddr); inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, (int) cu->cu_recvsz, 0, (struct sockaddr *) &from, &fromlen); }while (inlen < 0 && errno == EINTR); if (inlen < 4) { rt_kprintf("recv error, len %d\n", inlen); cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } /* see if reply transaction id matches sent id */ if (*((uint32_t *) (cu->cu_inbuf)) != *((uint32_t *) (cu->cu_outbuf))) goto send_again; /* we now assume we have the proper reply */ /* * now decode and validate the response */ xdrmem_create(&reply_xdrs, cu->cu_inbuf, (unsigned int) inlen, XDR_DECODE); ok = xdr_replymsg(&reply_xdrs, &reply_msg); /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ if (ok) { _seterr_reply(&reply_msg, &(cu->cu_error)); if (cu->cu_error.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(cl->cl_auth, &reply_msg.acpted_rply.ar_verf)) { cu->cu_error.re_status = RPC_AUTHERROR; cu->cu_error.re_why = AUTH_INVALIDRESP; } if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { xdrs->x_op = XDR_FREE; (void) xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); } } /* end successful completion */ else { /* maybe our credentials need to be refreshed ... */ if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) { nrefreshes--; goto call_again; } } /* end of unsuccessful completion */ } /* end of valid reply message */ else { cu->cu_error.re_status = RPC_CANTDECODERES; } return (cu->cu_error.re_status); }
enum clnt_stat clnt_broadcast( unsigned long prog, /* program number */ unsigned long vers, /* version number */ unsigned long proc, /* procedure number */ xdrproc_t xargs, /* xdr routine for args */ char* argsp, /* pointer to args */ xdrproc_t xresults, /* xdr routine for results */ char* resultsp, /* pointer to results */ resultproc_t eachresult) /* call with each result obtained */ { enum clnt_stat stat; AUTH *unix_auth = authunix_create_default(); XDR xdr_stream; register XDR *xdrs = &xdr_stream; int outlen, nets; ssize_t inlen; socklen_t fromlen; register int sock; int on = 1; #ifdef FD_SETSIZE fd_set mask; fd_set readfds; #else int readfds; register int mask; #endif /* def FD_SETSIZE */ register int i; bool_t done = FALSE; register unsigned long xid; unsigned long port; struct in_addr addrs[20]; struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ struct rmtcallargs a; struct rmtcallres r; struct rpc_msg msg; struct timeval t; char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; /* * initialization: create a socket, a broadcast address, and * preserialize the arguments into a send buffer. */ if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { perror("Cannot create socket for broadcast rpc"); stat = RPC_CANTSEND; goto done_broad; } #ifdef SO_BROADCAST if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) { perror("Cannot set socket option SO_BROADCAST"); stat = RPC_CANTSEND; goto done_broad; } #endif /* def SO_BROADCAST */ #ifdef FD_SETSIZE FD_ZERO(&mask); FD_SET(sock, &mask); #else mask = (1 << sock); #endif /* def FD_SETSIZE */ nets = getbroadcastnets(addrs, sock, inbuf); bzero((char *)&baddr, sizeof (baddr)); baddr.sin_family = AF_INET; baddr.sin_port = htons(PMAPPORT); baddr.sin_addr.s_addr = htonl(INADDR_ANY); /* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */ (void)gettimeofday(&t, NULL); msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec; t.tv_usec = 0; msg.rm_direction = CALL; msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; msg.rm_call.cb_prog = PMAPPROG; msg.rm_call.cb_vers = PMAPVERS; msg.rm_call.cb_proc = PMAPPROC_CALLIT; msg.rm_call.cb_cred = unix_auth->ah_cred; msg.rm_call.cb_verf = unix_auth->ah_verf; a.prog = prog; a.vers = vers; a.proc = proc; a.xdr_args = xargs; a.args_ptr = argsp; r.port_ptr = &port; r.xdr_results = xresults; r.results_ptr = resultsp; xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) { stat = RPC_CANTENCODEARGS; goto done_broad; } outlen = (int)xdr_getpos(xdrs); xdr_destroy(xdrs); /* * Basic loop: broadcast a packet and wait a while for response(s). * The response timeout grows larger per iteration. */ for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) { for (i = 0; i < nets; i++) { baddr.sin_addr = addrs[i]; if (sendto(sock, outbuf, outlen, 0, (struct sockaddr *)&baddr, sizeof (struct sockaddr)) != (ssize_t)outlen) { perror("Cannot send broadcast packet"); stat = RPC_CANTSEND; goto done_broad; } } if (eachresult == NULL) { stat = RPC_SUCCESS; goto done_broad; } recv_again: msg.acpted_rply.ar_verf = _null_auth; msg.acpted_rply.ar_results.where = (char*)&r; msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_rmtcallres; readfds = mask; { struct timeval tmp = t; switch (select(sock+1, &readfds, NULL, NULL, &tmp)) { case 0: /* timed out */ stat = RPC_TIMEDOUT; continue; case -1: /* some kind of error */ if (errno == EINTR) goto recv_again; perror("Broadcast select problem"); stat = RPC_CANTRECV; goto done_broad; } /* end of select results switch */ } /* end of temporary timeout variable */ try_again: fromlen = (socklen_t)sizeof(struct sockaddr); inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0, (struct sockaddr *)&raddr, &fromlen); if (inlen < 0) { if (errno == EINTR) goto try_again; perror("Cannot receive reply to broadcast"); stat = RPC_CANTRECV; goto done_broad; } if (inlen < sizeof(uint32_t)) goto recv_again; /* * see if reply transaction id matches sent id. * If so, decode the results. */ xdrmem_create(xdrs, inbuf, (unsigned)inlen, XDR_DECODE); if (xdr_replymsg(xdrs, &msg)) { if ((msg.rm_xid == xid) && (msg.rm_reply.rp_stat == MSG_ACCEPTED) && (msg.acpted_rply.ar_stat == SUCCESS)) { raddr.sin_port = htons((unsigned short)port); done = (*eachresult)(resultsp, &raddr); } /* otherwise, we just ignore the errors ... */ } else { #ifdef notdef /* some kind of deserialization problem ... */ if (msg.rm_xid == xid) (void)fprintf(stderr, "Broadcast deserialization problem"); /* otherwise, just random garbage */ #endif } xdrs->x_op = XDR_FREE; msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void; (void)xdr_replymsg(xdrs, &msg); (void)(*xresults)(xdrs, resultsp); xdr_destroy(xdrs); if (done) { stat = RPC_SUCCESS; goto done_broad; } else { goto recv_again; } } done_broad: (void)close(sock); AUTH_DESTROY(unix_auth); return (stat); }