// -*-c++-*- /* $Id: nfsserv.h,v 1.8 2001/04/05 19:12:21 dm Exp $ */ /* * * Copyright (C) 2000 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ #ifndef _SFSMISC_NFSSERV_H_ #define _SFSMISC_NFSSERV_H_ 1 /* * This file adds a layer of indirection between the RPC layer and * code implementing an NFS3 server. Thus, one can reuse the server * code with non-NFS3 clients by adding a translation layer (e.g., * from UVFS to NFS3, or NFS2 to NFS3). The class adds one fake NFS * call, CLOSE, which in NFS must be simulated using timing * heuristics, but can be implemented reliably under UVFS. */ #include "arpc.h" #include "nfs3_prot.h" #include "blowfish.h" #include "sfsmisc.h" enum { lastnfscall = NFSPROC3_COMMIT }; enum { NFSPROC_CLOSE = lastnfscall+1 }; template struct nfs3proc {}; #define defineproc(proc, arg, res) \ template<> struct nfs3proc { \ typedef arg arg_type; \ typedef res res_type; \ }; NFS_PROGRAM_3_APPLY (defineproc) defineproc (NFSPROC_CLOSE, nfs_fh3, nfsstat3) #undef defineproc struct nfsserv; struct nfscall { static const rpcgen_table closert; const authunix_parms *const aup; const u_int32_t procno; void *const argp; void *resp; xdrproc_t xdr_res; accept_stat acstat; auth_stat austat; bool nocache; bool nofree; nfsserv *stopserv; nfsserv *curserv; nfscall (const authunix_parms *aup, u_int32_t p, void *a); virtual ~nfscall () { clearres (); } void sendreply (); void setreply (void *, xdrproc_t = NULL, bool nc = false); void reply (void *, xdrproc_t = NULL, bool nc = false); void seterr (nfsstat3 err); void error (nfsstat3 err) { seterr (err); sendreply (); } void reject (accept_stat s) { acstat = s; error (NFS3ERR_IO); } void reject (auth_stat s) { austat = s; error (NFS3ERR_PERM); } const rpcgen_table &getrpct () const; void pinres (); sfs_aid getaid () const { return aup2aid (aup); } const authunix_parms *getaup () const { return aup; } u_int32_t proc () const { return procno; } void *getvoidarg () { return argp; } nfs_fh3 *getfh3arg () { return static_cast (argp); } template T *getarg () { #ifdef CHECK_BOUNDS assert ((typeid (T) == typeid (nfs_fh3) && proc () != NFSPROC3_NULL) || typeid (T) == *getrpct ().type_arg); #endif /* !CHECK_BOUNDS */ return static_cast (getvoidarg ()); } template const T *getarg () const { const_cast (this)->template getarg (); } void clearres (); void *getvoidres (); template T *getres () { return static_cast (getvoidres ()); } }; template class nfscall_cb : public nfscall { typedef typename nfs3proc::arg_type *arg_type; typedef typename nfs3proc::res_type *res_type; typedef callback::ref cb_t; cb_t cb; public: nfscall_cb (const authunix_parms *au, arg_type a, cb_t c, nfsserv *srv = NULL) : nfscall (au, N, a), cb (c) { if ((stopserv = srv)) srv->mkcb (this); } ~nfscall_cb () { /* Note, if xdr_res is not the default, we could always marshall * and unmarshall the result to get it in the right type. That * would be slow, however, and if it were actually happening, it * would probably indicate something wrong with the code. Thus, * we force an assertion failure in this case. */ assert (!xdr_res); (*cb) (static_cast (resp)); } }; struct nfscall_rpc : nfscall { svccb *sbp; nfscall_rpc (svccb *sbp); ~nfscall_rpc (); }; struct nfsserv : public virtual refcount { typedef callback::ref cb_t; static const cb_t stalecb; cb_t cb; const ptr nextserv; explicit nfsserv (ptr n = NULL); void setcb (const cb_t &c) { cb = c; } void mkcb (nfscall *nc) { nc->curserv = this; (*cb) (nc); } virtual void getcall (nfscall *nc) { mkcb (nc); } virtual void getreply (nfscall *nc) { nc->sendreply (); } virtual bool encodefh (nfs_fh3 &fh); }; class nfsserv_udp : public nfsserv { int fd; ptr x; ptr s; void getsbp (svccb *sbp); public: nfsserv_udp (); // void getreply (nfscall *nc); int getfd () { return fd; } }; /* Work around some bugs in NFS servers */ class nfsserv_fixup : public nfsserv { void getattr (nfscall *nc, nfs_fh3 *, getattr3res *res); public: explicit nfsserv_fixup (ref s) : nfsserv (s) {} void getreply (nfscall *nc); }; struct nfsserv_link : public nfsserv { ref next; nfsserv_link (const ref &n) : next (n) {} virtual void getreply (nfscall *); }; class nfsdemux : public virtual refcount { public: struct nfsserv_cryptfh : public nfsserv { const ref d; const u_int32_t srvno; ihash_entry hlink; nfsserv_cryptfh (const ref &dd, u_int32_t s); ~nfsserv_cryptfh (); virtual void getcall (nfscall *nc) { mkcb (nc); } virtual void getreply (nfscall *nc); bool encodefh (nfs_fh3 &fh); }; friend class nfsserv_cryptfh; private: const ref ns; u_int32_t srvnoctr; ihash srvnotab; void getcall (nfscall *nc); public: blowfish fhkey; nfsdemux (const ref &n); ref servalloc (); }; ref close_simulate (ref ns); #endif /* _SFSMISC_NFSSERV_H_ */