/*
 * nasd_edrfs_rpc.h
 *
 * Assist macros and definitions for NASD EDRFS server
 * RPC subsystem
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1997,1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#ifndef _NASD_EDRFS_RPC_H_
#define _NASD_EDRFS_RPC_H_

#include <nasd/nasd_options.h>
#include <nasd/nasd_types.h>
#include <nasd/nasd_timer.h>
#include <nasd/nasd_pipe.h>

#define NASD_EDRFS_RPC_KEEP_OP_STATS         1
#define NASD_EDRFS_RPC_DUMP_OP_STATS         0
#define NASD_EDRFS_RPC_OP_QUEUE_TIMES        0

#define NASD_EDRFS_RPC_DEBUG_RPC_START_STOP  0
#define NASD_EDRFS_RPC_DEBUG_RPC_RETURNS     0
#define NASD_EDRFS_RPC_DEBUG_RPC_ERR_RETURNS 0
#define NASD_EDRFS_RPC_DEBUG_RPC_SHUTDOWN    1
#define NASD_EDRFS_RPC_DEBUG_DCE_EXCEPTION   1

#define NASD_EDRFS_RPC_NASD_RET res.nasd_status

extern nasd_uint64 nasd_edrfs_threads_in_rpc;
extern int nasd_edrfs_wait_shutdown;
NASD_DECLARE_EXTERN_COND(nasd_edrfs_shutdown_cond)
NASD_DECLARE_EXTERN_MUTEX(nasd_edrfs_rpc_cnt_lock)
NASD_DECLARE_EXTERN_MUTEX(nasd_edrfs_rpc_qdepth_lock)

extern int nasd_edrfs_rpc_qdepth;
extern nasd_timer_t nasd_edrfs_rpc_qdepth_timer;
extern nasd_edrfs_rpc_opdepths_t nasd_edrfs_rpc_opdepths;

extern int nasd_edrfs_protseq_installed;
extern int nasd_edrfs_active;

extern nasd_edrfs_opstats_t nasd_edrfs_opstats;
extern nasd_edrfs_cachestats_t nasd_edrfs_cache_stats;

#if NASD_EDRFS_RPC_KEEP_OP_STATS > 0

#define NASD_EDRFS_RPC_OP_STATS_DECL \
  nasd_timer_t _op_timer; \
  nasd_uint64 _el;

#define NASD_EDRFS_RPC_OP_BEGIN(_opname_) { \
  NASD_ATOMIC_INC64(&nasd_edrfs_opstats._opname_.in_flight); \
  NASD_TM_START(&_op_timer); \
}

#define NASD_EDRFS_RPC_OP_END(_opname_) { \
  NASD_TM_STOP(&_op_timer); \
  NASD_TM_ELAPSED_NSEC(&_op_timer,&_el); \
  NASD_ATOMIC_INC64(&nasd_edrfs_opstats._opname_.invalid); \
  NASD_ATOMIC_INC64(&nasd_edrfs_opstats._opname_.num_ops); \
  NASD_ATOMIC_DEC64(&nasd_edrfs_opstats._opname_.in_flight); \
  NASD_ATOMIC_ADD64(&nasd_edrfs_opstats._opname_.op_nsecs,_el); \
  NASD_ATOMIC_DEC64(&nasd_edrfs_opstats._opname_.invalid); \
}

#else /* NASD_EDRFS_RPC_KEEP_OP_STATS > 0 */

#define NASD_EDRFS_RPC_OP_BEGIN(_opname_)
#define NASD_EDRFS_RPC_OP_END(_opname_)
#define NASD_EDRFS_RPC_OP_STATS_DECL \
  nasd_uint64 _el=0;

#endif /* NASD_EDRFS_RPC_KEEP_OP_STATS > 0 */

#if NASD_EDRFS_RPC_OP_QUEUE_TIMES > 0

#define NASD_EDRFS_RPC_QBEGIN() { \
  nasd_timespec_t _ts; \
  int _qd; \
  NASD_LOCK_MUTEX(nasd_edrfs_rpc_qdepth_lock); \
  if (nasd_edrfs_rpc_qdepth) { \
    NASD_TM_STOP(&nasd_edrfs_rpc_qdepth_timer); \
    NASD_TM_ELAPSED_TS(&nasd_edrfs_rpc_qdepth_timer, &_ts); \
  } \
  NASD_TM_START(&nasd_edrfs_rpc_qdepth_timer); \
  if (nasd_edrfs_rpc_qdepth) { \
    _qd = NASD_MIN(nasd_edrfs_rpc_qdepth, NASD_EDRFS_RPC_OPDEPTHS); \
    NASD_ATOMIC_TIMESPEC_ADD(&nasd_edrfs_rpc_opdepths.opdepths[_qd-1], &_ts); \
  } \
  nasd_edrfs_rpc_qdepth++; \
  NASD_UNLOCK_MUTEX(nasd_edrfs_rpc_qdepth_lock); \
}

#define NASD_EDRFS_RPC_QEND() { \
  nasd_timespec_t _ts; \
  int _qd; \
  NASD_LOCK_MUTEX(nasd_edrfs_rpc_qdepth_lock); \
  NASD_ASSERT(nasd_edrfs_rpc_qdepth > 0); \
  NASD_TM_STOP(&nasd_edrfs_rpc_qdepth_timer); \
  NASD_TM_ELAPSED_TS(&nasd_edrfs_rpc_qdepth_timer, &_ts); \
  nasd_edrfs_rpc_qdepth--; \
  if (nasd_edrfs_rpc_qdepth) { \
    NASD_TM_START(&nasd_edrfs_rpc_qdepth_timer); \
  } \
  _qd = NASD_MIN(nasd_edrfs_rpc_qdepth, NASD_EDRFS_RPC_OPDEPTHS); \
  NASD_ATOMIC_TIMESPEC_ADD(&nasd_edrfs_rpc_opdepths.opdepths[_qd], &_ts); \
  NASD_UNLOCK_MUTEX(nasd_edrfs_rpc_qdepth_lock); \
}

#else /* NASD_EDRFS_RPC_OP_QUEUE_TIMES > 0 */

#define NASD_EDRFS_RPC_QBEGIN() { /* noop */ }
#define NASD_EDRFS_RPC_QEND()   { /* noop */ }

#endif /* NASD_EDRFS_RPC_OP_QUEUE_TIMES > 0 */

#if NASD_EDRFS_RPC_DEBUG_RPC_START_STOP > 0
#define NASD_EDRFS_RPC_SS_DBG_PRINTF(_a_) nasd_printf _a_
#else /* NASD_EDRFS_RPC_DEBUG_RPC_START_STOP > 0 */
#define NASD_EDRFS_RPC_SS_DBG_PRINTF(_a_)
#endif /* NASD_EDRFS_RPC_DEBUG_RPC_START_STOP > 0 */

#if NASD_EDRFS_RPC_DEBUG_RPC_RETURNS > 0
#define NASD_EDRFS_RPC_RET_DBG_PRINTF(_a_) nasd_printf _a_
#else /* NASD_EDRFS_RPC_DEBUG_RPC_RETURNS > 0 */

#if NASD_EDRFS_RPC_DEBUG_RPC_ERR_RETURNS > 0
#define NASD_EDRFS_RPC_RET_DBG_PRINTF(_a_) if (NASD_EDRFS_RPC_NASD_RET) { nasd_printf _a_; }
#else /* NASD_EDRFS_RPC_DEBUG_RPC_ERR_RETURNS > 0 */
#define NASD_EDRFS_RPC_RET_DBG_PRINTF(_a_)
#endif /* NASD_EDRFS_RPC_DEBUG_RPC_ERR_RETURNS > 0 */

#endif /* NASD_EDRFS_RPC_DEBUG_RPC_RETURNS > 0 */


#define NASD_EDRFS_RPC_DOBEGIN(_opname_,_file_) { \
  if (nasd_edrfs_active == 0) { \
    /* \
     * XXX should never happen, but DCE RPC \
     * is not as good at "shutdown" as we \
     * want. Ideally, this would set *op_status \
     * equal to 0, and a useful error code in \
     * the nasd status field, but that would \
     * involve marshalling a reply here, which \
     * is more than we want to do. \
     */ \
    NASD_EDRFS_RPC_RETURN(999); \
  } \
  NASD_EDRFS_RPC_QBEGIN(); \
  nasd_edrfs_begin_rpc(&nasd_edrfs_opstats._opname_); \
  NASD_EDRFS_RPC_OP_BEGIN(_opname_); \
  NASD_EDRFS_RPC_SS_DBG_PRINTF(("Begin %s (file %s line %d) thread %" \
    NASD_THREAD_ID_FMT "\n", \
    NASD_STRING(_opname_), _file_, __LINE__, nasd_thread_self())); \
}

#define NASD_EDRFS_RPC_DORETURN(_opname_,_file_) { \
  NASD_EDRFS_RPC_SS_DBG_PRINTF(("End %s (file %s line %d)\n", \
    NASD_STRING(_opname_), _file_, __LINE__)); \
  NASD_EDRFS_RPC_RET_DBG_PRINTF(("%s (file %s line %d) returning %d (%s)\n", \
    NASD_STRING(_opname_), _file_, __LINE__, NASD_EDRFS_RPC_NASD_RET, \
    nasd_error_string(NASD_EDRFS_RPC_NASD_RET))); \
  NASD_EDRFS_RPC_OP_END(_opname_); \
  nasd_edrfs_end_rpc(&nasd_edrfs_opstats._opname_); \
  NASD_EDRFS_RPC_QEND(); \
  NASD_EDRFS_RPC_RETURN(0); \
}

typedef struct nasd_edrfs_rpc_basic_s {
  nasd_status_t  nasd_status;
} nasd_edrfs_rpc_basic_t;

extern void
nasd_dump_edrfs_attributes(nasd_edrfs_attributes_t  *edrfsattrp);
extern void
nasd_dump_edrfs_attributes_otw(nasd_edrfs_attributes_otw_t edrfsattrp_otw);

extern void
nasd_edrfs_real_mount(
  nasd_edrfs_credential_t   in_credential,
  char                     *dirpath,
  nasd_list_len_t           in_listlen,
  nasd_net_address_t        out_drivelist[],
  nasd_list_len_t          *out_listlen,
  nasd_cookie_t            *out_cookie,
  nasd_edrfs_identifier_t  *out_identifier,
  nasd_status_t            *nasd_status);

extern void
nasd_edrfs_real_fsstat(
  nasd_cookie_t                 in_cookie,
  nasd_edrfs_identifier_t       in_identifier,
  nasd_edrfs_credential_t       in_credential,
  nasd_edrfs_fsstat_t          *out_stat,    
  nasd_edrfs_post_attribute_t  *post_attribute,
  nasd_status_t                *nasd_status);

extern void
nasd_edrfs_real_fsinfo(
  nasd_cookie_t                 in_cookie,
  nasd_edrfs_identifier_t       in_identifier,
  nasd_edrfs_credential_t       in_credential,
  nasd_edrfs_fsinfo_t          *out_info,    
  nasd_edrfs_post_attribute_t  *post_attribute,
  nasd_status_t                *nasd_status);

extern void
nasd_edrfs_real_lookup(
  nasd_cookie_t                 in_cookie,
  nasd_edrfs_identifier_t       in_identifier,
  nasd_edrfs_credential_t       in_credential,
  char                         *in_dirpath,
  nasd_cookie_t                *out_cookie,
  nasd_edrfs_identifier_t      *out_identifier,
  nasd_edrfs_post_attribute_t  *out_attribute,
  nasd_edrfs_post_attribute_t  *post_attribute,
  nasd_status_t                *nasd_status);

extern void
nasd_edrfs_real_readdir(
  nasd_cookie_t                 in_cookie,
  nasd_edrfs_identifier_t       in_identifier,
  nasd_edrfs_credential_t       in_credential,
  nasd_edrfs_marker_t           in_marker,    
  nasd_edrfs_markerv_t          in_markerv,
  nasd_len_t                    in_count,
  nasd_edrfs_marker_t          *out_marker,
  nasd_edrfs_markerv_t         *out_markerv,
  nasd_len_t                   *out_count,
  nasd_boolean_t               *out_eof,
  nasd_procpipe_t              *byte_pipe,
  nasd_edrfs_post_attribute_t  *post_attribute,
  nasd_status_t                *nasd_status);

extern void
nasd_edrfs_real_access(
  nasd_cookie_t                 in_cookie,
  nasd_edrfs_identifier_t       in_identifier,
  nasd_edrfs_credential_t       in_credential,
  nasd_edrfs_access_t           in_access,
  nasd_edrfs_access_t          *out_access,
  nasd_edrfs_post_attribute_t  *post_attribute,
  nasd_status_t                *nasd_status);

extern void
nasd_edrfs_real_setattr(
  nasd_cookie_t             in_cookie,
  nasd_edrfs_identifier_t   in_identifier,
  nasd_edrfs_credential_t   in_credential,
  nasd_attribute_t          in_attribute,
  nasd_fieldmask_t          in_fieldmask,
  nasd_guard_t              in_guard,
  nasd_attribute_t         *out_attribute,
  nasd_status_t            *nasd_status);

extern void
nasd_edrfs_real_create(
  nasd_cookie_t                 in_cookie,
  nasd_edrfs_identifier_t       in_directory,
  nasd_edrfs_credential_t       in_credential,
  char                         *in_dirpath,
  nasd_attribute_t              in_attribute,
  nasd_fieldmask_t              in_fieldmask,
  nasd_cookie_t                *out_cookie,
  nasd_edrfs_identifier_t      *out_identifier,
  nasd_attribute_t             *out_attribute,
  nasd_edrfs_post_attribute_t  *post_attribute,
  nasd_status_t                *nasd_status);

extern void
nasd_edrfs_real_symlink(
  nasd_cookie_t                 in_cookie,
  nasd_edrfs_identifier_t       in_directory,
  nasd_edrfs_credential_t       in_credential,
  char                         *in_dirpath,
  char                         *in_symlink,
  nasd_attribute_t              in_attribute,
  nasd_cookie_t                *out_cookie,
  nasd_edrfs_identifier_t      *out_identifier,
  nasd_attribute_t             *out_attribute,
  nasd_edrfs_post_attribute_t  *post_attribute,
  nasd_status_t                *nasd_status);

extern void
nasd_edrfs_real_remove(
  nasd_cookie_t             in_cookie,
  nasd_edrfs_identifier_t   in_directory,
  nasd_edrfs_credential_t   in_credential,
  char                     *in_dirpath,
  nasd_status_t            *nasd_status);

extern void
nasd_edrfs_real_mkdir(
  nasd_cookie_t                 in_cookie,
  nasd_edrfs_identifier_t       in_directory,
  nasd_edrfs_credential_t       in_credential,
  char                         *in_dirpath,
  nasd_attribute_t              in_attribute,
  nasd_fieldmask_t              in_fieldmask,
  nasd_cookie_t                *out_cookie,
  nasd_edrfs_identifier_t      *out_identifier,
  nasd_attribute_t             *out_attribute,
  nasd_edrfs_post_attribute_t  *post_attribute,
  nasd_status_t                *nasd_status);

extern void
nasd_edrfs_real_rmdir(
  nasd_cookie_t             in_cookie,
  nasd_edrfs_identifier_t   in_directory,
  nasd_edrfs_credential_t   in_credential,
  char                     *in_dirpath,
  nasd_status_t            *nasd_status);

extern void
nasd_edrfs_real_newcookie(
  nasd_edrfs_identifier_t   in_identifier,
  nasd_edrfs_credential_t   in_credential,
  nasd_cookie_t            *out_cookie,
  nasd_status_t            *nasd_status);

extern void
nasd_edrfs_real_rename(
  nasd_cookie_t                 in_cookie,
  nasd_edrfs_identifier_t       in_from_directory,
  nasd_edrfs_credential_t       in_credential,
  char                         *in_from_path,
  nasd_edrfs_identifier_t       in_to_directory,
  char                         *in_to_path,
  nasd_edrfs_post_attribute_t  *post_from_attribute,
  nasd_edrfs_post_attribute_t  *post_to_attribute,
  nasd_status_t                *nasd_status);

extern void
nasd_edrfs_real_getstats(
  nasd_edrfs_opstats_t       *opstats,
  nasd_edrfs_cachestats_t    *cachestats,
  nasd_edrfs_rpc_opdepths_t  *opdepths,
  nasd_status_t              *nasd_status);

extern void
nasd_edrfs_real_resetstats(
  nasd_status_t              *nasd_status);

#endif /* !_NASD_EDRFS_RPC_H_ */
