📄 clnt_udp.c
字号:
if (!timerisset(&timeout)) { if (fds != &readfds) free(fds); return (cu->cu_error.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 = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; gettimeofday(&start, NULL); for (;;) { /* XXX we know the other bits are still clear */ FD_SET(cu->cu_sock, fds); tv = cu->cu_wait; switch (select(cu->cu_sock+1, fds, NULL, NULL, &tv)) { case 0: timeradd(&time_waited, &cu->cu_wait, &tmp1); time_waited = tmp1; if (timercmp(&time_waited, &timeout, <)) goto send_again; if (fds != &readfds) free(fds); return (cu->cu_error.re_status = RPC_TIMEDOUT); case -1: if (errno == EINTR) { gettimeofday(&after, NULL); timersub(&after, &start, &tmp1); timeradd(&time_waited, &tmp1, &tmp2); time_waited = tmp2; if (timercmp(&time_waited, &timeout, <)) continue; if (fds != &readfds) free(fds); return (cu->cu_error.re_status = RPC_TIMEDOUT); } cu->cu_error.re_errno = errno; if (fds != &readfds) free(fds); return (cu->cu_error.re_status = RPC_CANTRECV); } 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 < 0) { if (errno == EWOULDBLOCK) continue; cu->cu_error.re_errno = errno; if (fds != &readfds) free(fds); return (cu->cu_error.re_status = RPC_CANTRECV); } if (inlen < sizeof(u_int32_t)) continue; /* see if reply transaction id matches sent id */ if (*((u_int32_t *)(cu->cu_inbuf)) != *((u_int32_t *)(cu->cu_outbuf))) continue; /* we now assume we have the proper reply */ break; } /* * now decode and validate the response */ xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_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 { /* * It's possible for xdr_replymsg() to fail partway * through its attempt to decode the result from the * server. If this happens, it will leave the reply * structure partially populated with dynamically * allocated memory. (This can happen if someone uses * clntudp_bufcreate() to create a CLIENT handle and * specifies a receive buffer size that is too small.) * This memory must be free()ed to avoid a leak. */ int op = reply_xdrs.x_op; reply_xdrs.x_op = XDR_FREE; xdr_replymsg(&reply_xdrs, &reply_msg); reply_xdrs.x_op = op; cu->cu_error.re_status = RPC_CANTDECODERES; } if (fds != &readfds) free(fds); return (cu->cu_error.re_status);}static voidclntudp_geterr(cl, errp) CLIENT *cl; struct rpc_err *errp;{ register struct cu_data *cu = (struct cu_data *)cl->cl_private; *errp = cu->cu_error;}static bool_tclntudp_freeres(cl, xdr_res, res_ptr) CLIENT *cl; xdrproc_t xdr_res; caddr_t res_ptr;{ register struct cu_data *cu = (struct cu_data *)cl->cl_private; register XDR *xdrs = &(cu->cu_outxdrs); xdrs->x_op = XDR_FREE; return ((*xdr_res)(xdrs, res_ptr));}static voidclntudp_abort(/*h*/) /*CLIENT *h;*/{}static bool_tclntudp_control(cl, request, info) CLIENT *cl; int request; char *info;{ register struct cu_data *cu = (struct cu_data *)cl->cl_private; register struct timeval *tv; int len; switch (request) { case CLSET_FD_CLOSE: cu->cu_closeit = TRUE; break; case CLSET_FD_NCLOSE: cu->cu_closeit = FALSE; break; case CLSET_TIMEOUT: if (info == NULL) return(FALSE); tv = (struct timeval *)info; cu->cu_total.tv_sec = tv->tv_sec; cu->cu_total.tv_usec = tv->tv_usec; break; case CLGET_TIMEOUT: if (info == NULL) return(FALSE); *(struct timeval *)info = cu->cu_total; break; case CLSET_RETRY_TIMEOUT: if (info == NULL) return(FALSE); tv = (struct timeval *)info; cu->cu_wait.tv_sec = tv->tv_sec; cu->cu_wait.tv_usec = tv->tv_usec; break; case CLGET_RETRY_TIMEOUT: if (info == NULL) return(FALSE); *(struct timeval *)info = cu->cu_wait; break; case CLGET_SERVER_ADDR: if (info == NULL) return(FALSE); *(struct sockaddr_in *)info = cu->cu_raddr; break; case CLGET_FD: if (info == NULL) return(FALSE); *(int *)info = cu->cu_sock; break; case CLGET_XID: /* * use the knowledge that xid is the * first element in the call structure *. * This will get the xid of the PREVIOUS call */ if (info == NULL) return(FALSE); *(u_long *)info = ntohl(*(u_long *)cu->cu_outbuf); break; case CLSET_XID: /* This will set the xid of the NEXT call */ if (info == NULL) return(FALSE); *(u_long *)cu->cu_outbuf = htonl(*(u_long *)info - 1); /* decrement by 1 as clntudp_call() increments once */ case CLGET_VERS: /* * This RELIES on the information that, in the call body, * the version number field is the fifth field from the * begining of the RPC header. MUST be changed if the * call_struct is changed */ if (info == NULL) return(FALSE); *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT)); break; case CLSET_VERS: if (info == NULL) return(FALSE); *(u_long *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) = htonl(*(u_long *)info); break; case CLGET_PROG: /* * This RELIES on the information that, in the call body, * the program number field is the field from the * begining of the RPC header. MUST be changed if the * call_struct is changed */ if (info == NULL) return(FALSE); *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT)); break; case CLSET_PROG: if (info == NULL) return(FALSE); *(u_long *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) = htonl(*(u_long *)info); break; case CLGET_LOCAL_ADDR: len = sizeof(struct sockaddr); if (getsockname(cu->cu_sock, (struct sockaddr *)info, &len) <0) return(FALSE); break; case CLGET_SVC_ADDR: case CLSET_SVC_ADDR: case CLSET_PUSH_TIMOD: case CLSET_POP_TIMOD: default: return (FALSE); } return (TRUE);}static voidclntudp_destroy(cl) CLIENT *cl;{ register struct cu_data *cu = (struct cu_data *)cl->cl_private; if (cu->cu_closeit) { (void)_RPC_close(cu->cu_sock); } XDR_DESTROY(&(cu->cu_outxdrs)); mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz)); mem_free((caddr_t)cl, sizeof(CLIENT));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -