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); }
/* * Try to get an entry from the cache * return 1 if found, 0 if not found */ static int cache_get(SVCXPRT *xprt, struct rpc_msg *msg, char **replyp, u_long *replylenp) { u_int loc; cache_ptr ent; struct svcudp_data *su = su_data(xprt); struct udp_cache *uc = (struct udp_cache *) su->su_cache; # define EQADDR(a1, a2) (memcmp(&a1, &a2, sizeof(a1)) == 0) loc = CACHE_LOC(xprt, su->su_xid); for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { if (ent->cache_xid == su->su_xid && ent->cache_proc == uc->uc_proc && ent->cache_vers == uc->uc_vers && ent->cache_prog == uc->uc_prog && EQADDR(ent->cache_addr, uc->uc_addr)) { *replyp = ent->cache_reply; *replylenp = ent->cache_replylen; return(1); } } /* * Failed to find entry * Remember a few things so we can do a set later */ uc->uc_proc = msg->rm_call.cb_proc; uc->uc_vers = msg->rm_call.cb_vers; uc->uc_prog = msg->rm_call.cb_prog; uc->uc_addr = xprt->xp_raddr; return(0); }
int svc_dg_enablecache(SVCXPRT *transp, u_int size) { struct svc_dg_data *su; struct cl_cache *uc; _DIAGASSERT(transp != NULL); su = su_data(transp); mutex_lock(&dupreq_lock); if (su->su_cache != NULL) { (void) warnx(cache_enable_str, enable_err, " "); mutex_unlock(&dupreq_lock); return (0); } uc = ALLOC(struct cl_cache, 1); if (uc == NULL) { warnx(cache_enable_str, alloc_err, " "); mutex_unlock(&dupreq_lock); return (0); } uc->uc_size = size; uc->uc_nextvictim = 0; uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); if (uc->uc_entries == NULL) { warnx(cache_enable_str, alloc_err, "data"); FREE(uc, struct cl_cache, 1); mutex_unlock(&dupreq_lock); return (0); }
/* * Enable use of the cache. * Note: there is no disable. */ int svcudp_enablecache(SVCXPRT *transp, u_long size) { struct svcudp_data *su = su_data(transp); struct udp_cache *uc; if (su->su_cache != NULL) return(0); uc = malloc(sizeof(*uc)); if (uc == NULL) return(0); uc->uc_size = size; uc->uc_nextvictim = 0; if (size > SIZE_MAX / (sizeof(cache_ptr) * SPARSENESS) || (uc->uc_entries = calloc(size, sizeof(cache_ptr) * SPARSENESS)) == NULL) { free(uc); return(0); } uc->uc_fifo = calloc(sizeof(cache_ptr), size); if (uc->uc_fifo == NULL) { free(uc->uc_entries); free(uc); return(0); } su->su_cache = (char *) uc; return(1); }
static bool_t svcudp_recv( register SVCXPRT *xprt, struct rpc_msg *msg) { register struct svcudp_data *su = su_data(xprt); register XDR *xdrs = &(su->su_xdrs); register ssize_t rlen; char *reply; unsigned long replylen; socklen_t len; again: len = xprt->xp_addrlen = sizeof(struct sockaddr_in); rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz, 0, (struct sockaddr *)&(xprt->xp_raddr), &len); if (rlen == -1 && errno == EINTR) goto again; if (rlen < 4*sizeof(uint32_t)) return (FALSE); xprt->xp_addrlen = len; xdrs->x_op = XDR_DECODE; XDR_SETPOS(xdrs, 0); if (! xdr_callmsg(xdrs, msg)) return (FALSE); su->su_xid = msg->rm_xid; if (su->su_cache != NULL) { if (cache_get(xprt, msg, &reply, &replylen)) { (void) sendto(xprt->xp_sock, reply, replylen, 0, (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen); return (TRUE); } } return (TRUE); }
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); }
static bool_t svcudp_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) { XDR *xdrs = &(su_data(xprt)->su_xdrs); xdrs->x_op = XDR_FREE; return ((*xdr_args)(xdrs, args_ptr)); }
static bool_t svcudp_getargs( SVCXPRT *xprt, xdrproc_t xdr_args, char* args_ptr) { return ((*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr)); }
/* * Set an entry in the cache */ static void cache_set(SVCXPRT *xprt, u_long replylen) { cache_ptr victim; cache_ptr *vicp; struct svcudp_data *su = su_data(xprt); struct udp_cache *uc = (struct udp_cache *) su->su_cache; u_int loc; char *newbuf; /* * Find space for the new entry, either by * reusing an old entry, or by mallocing a new one */ victim = uc->uc_fifo[uc->uc_nextvictim]; if (victim != NULL) { loc = CACHE_LOC(xprt, victim->cache_xid); for (vicp = &uc->uc_entries[loc]; *vicp != NULL && *vicp != victim; vicp = &(*vicp)->cache_next) ; if (*vicp == NULL) { return; } *vicp = victim->cache_next; /* remote from cache */ newbuf = victim->cache_reply; } else { victim = malloc(sizeof(struct cache_node)); if (victim == NULL) { return; } newbuf = malloc(su->su_iosz); if (newbuf == NULL) { free(victim); return; } } /* * Store it away */ victim->cache_replylen = replylen; victim->cache_reply = rpc_buffer(xprt); rpc_buffer(xprt) = newbuf; xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_ENCODE); victim->cache_xid = su->su_xid; victim->cache_proc = uc->uc_proc; victim->cache_vers = uc->uc_vers; victim->cache_prog = uc->uc_prog; victim->cache_addr = uc->uc_addr; loc = CACHE_LOC(xprt, victim->cache_xid); victim->cache_next = uc->uc_entries[loc]; uc->uc_entries[loc] = victim; uc->uc_fifo[uc->uc_nextvictim++] = victim; uc->uc_nextvictim %= uc->uc_size; }
unsigned long svcudp_get_xid(SVCXPRT *xprt) { struct svc_dg_data *su; if (xprt == NULL) return(0); su = su_data(xprt); return(su->su_xid); }
static bool_t svc_dg_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) { XDR *xdrs; _DIAGASSERT(xprt != NULL); xdrs = &(su_data(xprt)->su_xdrs); xdrs->x_op = XDR_FREE; return (*xdr_args)(xdrs, args_ptr); }
static void svc_dg_xprt_setup(SVCXPRT **sxpp) { if (unlikely(*sxpp)) { svc_dg_xprt_free(su_data(*sxpp)); *sxpp = NULL; } else { struct svc_dg_xprt *su = svc_dg_xprt_zalloc(0); *sxpp = &su->su_dr.xprt; } }
static bool_t svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg) { struct svc_dg_data *su; XDR *xdrs; char *reply; struct sockaddr_storage ss; socklen_t alen; size_t replylen; ssize_t rlen; _DIAGASSERT(xprt != NULL); _DIAGASSERT(msg != NULL); su = su_data(xprt); xdrs = &(su->su_xdrs); again: alen = sizeof (struct sockaddr_storage); rlen = recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, 0, (struct sockaddr *)(void *)&ss, &alen); if (rlen == -1 && errno == EINTR) goto again; if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t)))) return (FALSE); if (xprt->xp_rtaddr.len < alen) { if (xprt->xp_rtaddr.len != 0) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len); xprt->xp_rtaddr.buf = mem_alloc(alen); xprt->xp_rtaddr.len = alen; } memcpy(xprt->xp_rtaddr.buf, &ss, alen); #ifdef PORTMAP if (ss.ss_family == AF_INET) { xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf; xprt->xp_addrlen = sizeof (struct sockaddr_in); } #endif xdrs->x_op = XDR_DECODE; XDR_SETPOS(xdrs, 0); if (! xdr_callmsg(xdrs, msg)) { return (FALSE); } su->su_xid = msg->rm_xid; if (su->su_cache != NULL) { if (cache_get(xprt, msg, &reply, &replylen)) { (void)sendto(xprt->xp_fd, reply, replylen, 0, (struct sockaddr *)(void *)&ss, alen); return (FALSE); } } return (TRUE); }
static bool_t svcudp_recv( SVCXPRT *xprt, struct rpc_msg *msg) { struct msghdr dummy; struct iovec dummy_iov[1]; struct svcudp_data *su = su_data(xprt); XDR *xdrs = &su->su_xdrs; int rlen; char *reply; uint32_t replylen; socklen_t addrlen; again: memset(&dummy, 0, sizeof(dummy)); dummy_iov[0].iov_base = rpc_buffer(xprt); dummy_iov[0].iov_len = (int) su->su_iosz; dummy.msg_iov = dummy_iov; dummy.msg_iovlen = 1; dummy.msg_namelen = xprt->xp_laddrlen = sizeof(struct sockaddr_in); dummy.msg_name = (char *) &xprt->xp_laddr; rlen = recvmsg(xprt->xp_sock, &dummy, MSG_PEEK); if (rlen == -1) { if (errno == EINTR) goto again; else return (FALSE); } addrlen = sizeof(struct sockaddr_in); rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz, 0, (struct sockaddr *)&(xprt->xp_raddr), &addrlen); if (rlen == -1 && errno == EINTR) goto again; if (rlen < (int) (4*sizeof(uint32_t))) return (FALSE); xprt->xp_addrlen = addrlen; xdrs->x_op = XDR_DECODE; XDR_SETPOS(xdrs, 0); if (! xdr_callmsg(xdrs, msg)) return (FALSE); su->su_xid = msg->rm_xid; if (su->su_cache != NULL) { if (cache_get(xprt, msg, &reply, &replylen)) { (void) sendto(xprt->xp_sock, reply, (int) replylen, 0, (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen); return (TRUE); } } return (TRUE); }
static bool_t svcudp_getargs( SVCXPRT *xprt, xdrproc_t xdr_args, void * args_ptr) { if (! SVCAUTH_UNWRAP(xprt->xp_auth, &(su_data(xprt)->su_xdrs), xdr_args, args_ptr)) { (void)svcudp_freeargs(xprt, xdr_args, args_ptr); return FALSE; } return TRUE; }
unsigned long svcudp_set_xid(SVCXPRT *xprt, unsigned long xid) { struct svc_dg_data *su; unsigned long old_xid; if (xprt == NULL) return(0); su = su_data(xprt); old_xid = su->su_xid; su->su_xid = xid; return(old_xid); }
static void svcudp_destroy( register SVCXPRT *xprt) { register struct svcudp_data *su = su_data(xprt); xprt_unregister(xprt); (void)close(xprt->xp_sock); XDR_DESTROY(&(su->su_xdrs)); mem_free(rpc_buffer(xprt), su->su_iosz); mem_free((char*)su, sizeof(struct svcudp_data)); mem_free((char*)xprt, sizeof(SVCXPRT)); }
static void svcudp_destroy(SVCXPRT *xprt) { struct svcudp_data *su = su_data(xprt); xprt_unregister(xprt); if (xprt->xp_sock != -1) (void)close(xprt->xp_sock); xprt->xp_sock = -1; XDR_DESTROY(&(su->su_xdrs)); mem_free(rpc_buffer(xprt), su->su_iosz); mem_free((caddr_t)su, sizeof(struct svcudp_data)); mem_free((caddr_t)xprt, sizeof(SVCXPRT)); }
static void svcudp_destroy(register SVCXPRT *xprt) { register struct svcudp_data *su = su_data(xprt); xprt_unregister(xprt); if (xprt->xp_sock != INVALID_SOCKET) (void)closesocket(xprt->xp_sock); xprt->xp_sock = INVALID_SOCKET; if (xprt->xp_auth != NULL) { SVCAUTH_DESTROY(xprt->xp_auth); xprt->xp_auth = NULL; } XDR_DESTROY(&(su->su_xdrs)); mem_free(rpc_buffer(xprt), su->su_iosz); mem_free((caddr_t)su, sizeof(struct svcudp_data)); mem_free((caddr_t)xprt, sizeof(SVCXPRT)); }
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 svc_dg_destroy(SVCXPRT *xprt) { struct svc_dg_data *su; _DIAGASSERT(xprt != NULL); su = su_data(xprt); xprt_unregister(xprt); if (xprt->xp_fd != -1) (void)close(xprt->xp_fd); XDR_DESTROY(&(su->su_xdrs)); (void) mem_free(rpc_buffer(xprt), su->su_iosz); (void) mem_free(su, sizeof (*su)); if (xprt->xp_rtaddr.buf) (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); if (xprt->xp_ltaddr.buf) (void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen); if (xprt->xp_tp) (void) free(xprt->xp_tp); (void) mem_free(xprt, sizeof (SVCXPRT)); }
static enum xprt_stat svc_dg_rendezvous(SVCXPRT *xprt) { struct svc_dg_xprt *req_su = su_data(xprt); struct svc_dg_xprt *su = svc_dg_xprt_zalloc(req_su->su_dr.maxrec); SVCXPRT *newxprt = &su->su_dr.xprt; struct sockaddr *sp = (struct sockaddr *)&newxprt->xp_remote.ss; struct msghdr *mesgp; struct timespec now; struct iovec iov; ssize_t rlen; newxprt->xp_fd = xprt->xp_fd; newxprt->xp_flags = SVC_XPRT_FLAG_INITIAL | SVC_XPRT_FLAG_INITIALIZED; (void)clock_gettime(CLOCK_MONOTONIC_FAST, &now); su->su_dr.call_xid = __RPC_GETXID(&now); su->su_dr.sendsz = req_su->su_dr.sendsz; su->su_dr.recvsz = req_su->su_dr.recvsz; su->su_dr.maxrec = req_su->su_dr.maxrec; svc_dg_override_ops(newxprt, xprt); again: iov.iov_base = &su[1]; iov.iov_len = su->su_dr.maxrec; mesgp = &su->su_msghdr; memset(mesgp, 0, sizeof(*mesgp)); mesgp->msg_iov = &iov; mesgp->msg_iovlen = 1; mesgp->msg_name = sp; sp->sa_family = (sa_family_t) 0xffff; mesgp->msg_namelen = sizeof(struct sockaddr_storage); mesgp->msg_control = su->su_cmsg; mesgp->msg_controllen = sizeof(su->su_cmsg); rlen = recvmsg(newxprt->xp_fd, mesgp, 0); if (sp->sa_family == (sa_family_t) 0xffff) { svc_dg_xprt_free(su); return (XPRT_DIED); } if (rlen == -1 && errno == EINTR) goto again; if (rlen == -1 || (rlen < (ssize_t) (4 * sizeof(u_int32_t)))) { svc_dg_xprt_free(su); return (XPRT_DIED); } if (unlikely(svc_rqst_rearm_events(xprt))) { __warnx(TIRPC_DEBUG_FLAG_ERROR, "%s: %p fd %d svc_rqst_rearm_events failed (will set dead)", __func__, xprt, xprt->xp_fd); svc_dg_xprt_free(su); return (XPRT_DIED); } __rpc_address_setup(&newxprt->xp_local); __rpc_address_setup(&newxprt->xp_remote); newxprt->xp_remote.nb.len = mesgp->msg_namelen; /* Check whether there's an IP_PKTINFO or IP6_PKTINFO control message. * If yes, preserve it for svc_dg_reply; otherwise just zap any cmsgs */ if (!svc_dg_store_pktinfo(mesgp, newxprt)) { mesgp->msg_control = NULL; mesgp->msg_controllen = 0; newxprt->xp_local.nb.len = 0; } XPRT_TRACE(newxprt, __func__, __func__, __LINE__); #if defined(HAVE_BLKIN) __rpc_set_blkin_endpoint(newxprt, "svc_dg"); #endif xdrmem_create(su->su_dr.ioq.xdrs, iov.iov_base, iov.iov_len, XDR_DECODE); SVC_REF(xprt, SVC_REF_FLAG_NONE); newxprt->xp_parent = xprt; return (xprt->xp_dispatch.rendezvous_cb(newxprt)); }
static bool_t svc_dg_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) { return (*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr); }