summaryrefslogtreecommitdiff
path: root/nfs
diff options
context:
space:
mode:
authorMichael I. Bushnell <mib@gnu.org>1994-08-17 16:51:39 +0000
committerMichael I. Bushnell <mib@gnu.org>1994-08-17 16:51:39 +0000
commit145956fc595c1b2574d7c0a53a17aa707496aa2a (patch)
tree2b860dad2068ac0497516be09e4db9e9288a9589 /nfs
parent0224ea409cf6637c74d25717247e441a120b7de7 (diff)
Formerly rpc.c.~2~
Diffstat (limited to 'nfs')
-rw-r--r--nfs/rpc.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/nfs/rpc.c b/nfs/rpc.c
index f04cc819..d77c4980 100644
--- a/nfs/rpc.c
+++ b/nfs/rpc.c
@@ -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;
+}
+