// $Id: RPC.h,v 1.12 2003/08/31 00:38:11 vern Exp $
//
// Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002
//      The Regents of the University of California.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that: (1) source code distributions
// retain the above copyright notice and this paragraph in its entirety, (2)
// distributions including binary code include the above copyright notice and
// this paragraph in its entirety in the documentation or other materials
// provided with the distribution, and (3) all advertising materials mentioning
// features or use of this software display the following acknowledgement:
// ``This product includes software developed by the University of California,
// Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
// the University nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#ifndef rpc_h
#define rpc_h

#include "TCP.h"
#include "UDP.h"

#define RPC_CALL 0
#define RPC_REPLY 1

#define RPC_MSG_ACCEPTED 0
#define RPC_MSG_DENIED 1

#define RPC_SUCCESS 0
#define RPC_PROG_UNAVAIL 1
#define RPC_PROG_MISMATCH 2
#define RPC_PROC_UNAVAIL 3
#define RPC_GARBAGE_ARGS 4
#define RPC_SYSTEM_ERR 5

#define RPC_MISMATCH 0
#define RPC_AUTH_ERROR 1

#define RPC_AUTH_BADCRED 1
#define RPC_AUTH_REJECTEDCRED 2
#define RPC_AUTH_BADVERF 3
#define RPC_AUTH_REJECTEDVERF 4
#define RPC_AUTH_TOOWEAK 5

#define RPC_AUTH_NULL 0
#define RPC_AUTH_UNIX 1
#define RPC_AUTH_SHORT 2
#define RPC_AUTH_DES 3

class RPC_CallInfo {
public:
	RPC_CallInfo(uint32 xid, const u_char*& buf, int& n);
	~RPC_CallInfo();

	void AddVal(Val* arg_v)		{ Unref(v); v = arg_v; }
	Val* RequestVal() const		{ return v; }
	Val* TakeRequestVal()		{ Val* rv = v; v = 0; return rv; }

	int CompareRexmit(const u_char* buf, int n) const;

	uint32 Program() const		{ return prog; }
	uint32 Version() const		{ return vers; }
	uint32 Proc() const		{ return proc; }

	int HeaderLen() const		{ return header_len; }

protected:
	uint32 xid, rpc_version, prog, vers, proc;
	uint32 cred_flavor, verf_flavor;
	u_char* call_buf;	// copy of original call buffer
	int call_n;		// size of call buf
	int header_len;		// size of data before the arguments

	Val* v;		// single (perhaps compound) value corresponding to call
};

declare(PDict,RPC_CallInfo);

class RPC_Interpreter {
public:
	RPC_Interpreter(Connection* conn);
	virtual ~RPC_Interpreter();

	// Delivers the given RPC.  Returns true if "len" bytes were
	// enough, false otherwise.  "is_orig" is true if the data is
	// from the originator of the connection.
	int DeliverRPC(double t, const u_char* data, int len, int is_orig);

	void Timeout();

	Connection* Conn() const		{ return conn; }
	TCP_Connection* TCP_Conn() const	{ return (TCP_Connection*) conn; }

protected:
	virtual int RPC_BuildCall(RPC_CallInfo* c, const u_char*& buf, int& n) = 0;
	virtual int RPC_BuildReply(const RPC_CallInfo* c, int success,
					const u_char*& buf, int& n,
					EventHandlerPtr& event, Val*& reply) = 0;

	virtual void Event(EventHandlerPtr f, Val* request, int status, Val* reply) = 0;

	void Weird(const char* name);

	PDict(RPC_CallInfo) calls;
	Connection* conn;
};

typedef enum {
	RPC_RECORD_MARKER,	// building up the stream record marker
	RPC_MESSAGE_BUFFER,	// building up the message in the buffer
	RPC_COMPLETE		// message fully built
} TCP_RPC_state;

class TCP_Endpoint_RPC : public TCP_EndpointContents {
public:
	TCP_Endpoint_RPC(RPC_Interpreter* interp, int is_orig);
	~TCP_Endpoint_RPC();

	TCP_RPC_state State() const		{ return state; }

protected:
	void Init();

	void Deliver(double t, int seq, int len, u_char* data);

	RPC_Interpreter* interp;

	u_char* msg_buf;
	int buf_n;	// number of bytes in msg_buf
	int buf_len;	// size off msg_buf
	int last_frag;	// if this buffer corresponds to the last "fragment"

	int num_records;	// number of full RPC records we've seen

	TCP_RPC_state state;
	int is_orig;
};

class UDP_RPC : public UDP_Connection {
public:
	UDP_RPC(RPC_Interpreter* interp, NetSessions* s, HashKey* k, double t,
		const ConnID* id, const struct udphdr* up);
	~UDP_RPC();
	void Done();

protected:
	int Request(double t, const u_char* data, int len);
	int Reply(double t, const u_char* data, int len);

	void ExpireTimer(double t);

	RPC_Interpreter* interp;
};

#endif
