diff options
author | Michael I. Bushnell <mib@gnu.org> | 1994-08-17 16:51:39 +0000 |
---|---|---|
committer | Michael I. Bushnell <mib@gnu.org> | 1994-08-17 16:51:39 +0000 |
commit | 145956fc595c1b2574d7c0a53a17aa707496aa2a (patch) | |
tree | 2b860dad2068ac0497516be09e4db9e9288a9589 | |
parent | 0224ea409cf6637c74d25717247e441a120b7de7 (diff) |
Formerly rpc.c.~2~
-rw-r--r-- | nfs/rpc.c | 105 |
1 files changed, 105 insertions, 0 deletions
@@ -16,3 +16,108 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +struct rpc_list +{ + struct rpc_list *next, **prevp; + + void *rpc; + size_t rpc_len; + void *reply; + size_t reply_buflen; + size_t reply_len; + int reply_received; +}; + +static struct rpc_list *outstanding_rpcs; +static struct mutex outstanding_lock = MUTEX_INITIALIZER; +static struct condition rpc_wakeup = CONDITION_INITIALIZER; + +/* Send an RPC message to target TARGET from buffer BUF of size + LEN, waiting for a reply. The expected reply length is + REPLY_LEN; a buffer that big is provided as REPLY_BUF. + Set REPLY_CONTENTS to the actual protocol-level reply, of + size REPLY_CONTENTS_LEN. AUTH is the authentication used + in constructing BUF.*/ +error_t +rpc_send (struct rpc_target *target, void *buf, size_t len, + void *reply_buf, size_t reply_len, void **reply_contents, + size_t *reply_contents_len, struct rpc_auth *auth) +{ + struct rpc_list record; + struct rpcv2_msg_hdr *reply; + struct rpcv2_msg_hdr *request; + struct rpcv2_accepted_reply *accept; + struct rpcv2_rejected_reply *reject; + struct rpcv2_auth *authdata; + struct rpcv2_verf *verf; + error_t error; + + mutex_lock (&outstanding_lock); + + record.rpc = request = buf; + record.len = len; + record.reply = reply_buf; + record.reply_len = reply_len; + record.reply_received = 0; + + record.next = outstanding_rpcs; + if (record.next) + record.next->prevp = &record.next; + outstanding_rpcs = &record; + record.prevp = &outstanding_rpcs; + + rpc_transmit (target, &record); + + while (!record.reply_received) + condition_wait (&rpc_wakeup, &outstanding_lock); + + /* Examine the reply to see whether any RPC level errors have happened. */ + + reply = record.reply; + + assert (reply->xid == request->xid); + assert (reply->mtype == RPCV2_REPLY); + + if (reply->body.reply.reply_state == RPCV2_MSG_ACCEPTED) + { + /* Ignore VERF */ + verf = &reply->body.reply.rest; + accept = (void *)verf + sizeof (struct rpcv2_verf) + verf->nbytes; + + /* The message was accepted; return the appropriate error + (or success) to the caller. */ + if (accept->stat == RPCV2_SUCCESS) + { + /* Ah hah! Return to the user */ + *reply_contents = &accept->reply_data.results; + *reply_contents_len = record.reply_len; + *reply_contents_len -= ((void *)&accept->reply_data.result + - (void *) reply); + error = 0; + } + else + error = EOPNOTSUPP; + } + else if (reply->body.reply.reply_state == RPCV2_MSG_DENIED) + { + /* For some reason we didn't win. */ + reject = &reply->body.reply.rest; + if (reject->stat == RPCV2_RPC_MISMATCH) + error = EOPNOTSUPP; + else if (reject->stat == RPCV2_AUTH_ERROR) + error = EACCES; + else + error = EIEIO; + } + else + error = EIEIO; + + *record.prevp = record.next; + if (record.next) + record.next->prevp = record.prevp; + + mutex_unlock (&outstanding_lock); + return error; +} + |